反汇编DLL文件 HOOKAPI 作者 彬
前段时间在CSDN上有位网友问过一个问题。如何在WINDOWS下使删除文件、复制文件、变更文件名失效呢?
有一个办法,就是通过拦截系统的I/O中断,可以实现此操作。但是因为网友只是问如何在WINDOWS下失效,那我们也可以试着拦截API函数。众所周知,在WINDOWS下的文件操作一般是通过调用WINAPI函数实现的,再由WINAPI函数调用系统的I/O中断实现最终的文件操作。如果我们在系统调用WINAPI函数时将其拦下,那么文件操作不就失效啦吗?
现在摆在我们面前的一个问题是,我们用何种方法来实现HOOKAPI函数,总的来分一共有两种:软模式和硬模式(呵呵,我起的名)。那什么叫软模式呢?软模式就是通过编写程序,使程序自动获得我们要截获得API函数的RVA(相对虚拟地址),然后在地址处写入我们的代码,使程序调用此API函数时先执行我们的代码,再返回执行原代码,别看我说得简单,但实际操作起来很麻烦,如程序在更改原API代码时必须进入RING0特权级等等问题都会摆在你的面前;硬模式是指利用手头上的软件直接更改相关DLL文件。由于软模式麻烦而且在2000下获得RING0特权级更麻烦,因此我们在此先讲如何利用硬模式达到我们预期的效果。
系统常用的API函数基本都存在于Gdi32.dll、Kernel32.dll和Shell32.dll三个文件中,通过文件名我们就可以知道每个DLL文件中的API函数主要用在哪方面。
这里我们要拦截的API函数是 SHFileOperation,是Shell32.dll中的函数此函数的用途删除文件、复制文件、移动文件、对文件更名。他有一个参数,是指向SHFILEOPSTRUCT结构的指针,其在ASM中的定义如下:
SHFILEOPSTRUCT STRUCT
hwnd DWORD ? ;调用者的窗口句柄
wFunc DWORD ? ;指定是何种操作。(复制、删除等)
pFrom DWORD ? ;来源目录或文件
pTo DWORD ? ;目的目录或文件
fFlags FILEOP_FLAGS ? ;操作文件的旗标
fAnyOperationsAborted DWORD ? ;是否允许使用者中断
hNameMappings DWORD ? ;不常用
lpszProgressTitle DWORD ? ;不常用
SHFILEOPSTRUCT ENDS
关于此结构的详细资料,可以通过查阅MSDN来获得。
好啦,函数名也知道啦,出自哪个文件也知道啦。下一步如何做呢?
我们只要找到此函数在Shell32.dll中的位置,在其头部插入ret 4这条语句就可以啦。为什么要插入这条语句呢?我们不要系统对删除文件、复制文件等做出任何响应,只能让此API函数一调用时就马上返回就可以啦,因为此函数有一个参数,为了使堆栈恢复原状,因此堆栈指针需要加4。
万事俱备,只欠不知道此函数在DLL文件中的地址啦。
要知道其位置,我们可以自己编写个程序,算出来,不过现在我手头上已经有一个现成的啦,为什么还要再编一个呢?????打开getModule程序,此程序可以获得某个函数在某个DLL中的RVA地址。在软件的请输入DLL名框中键入“Shell32.dll“,在请输入函数名框中键入“SHFileOperation“,按下获取,得到地址:7fcedcf1h(可能由于98版本的不同,这里的数值会不一样。注意:此软件区分大小写。)。我们要对Shell32.dll文件反汇编所用的软件是HIEW,此软件中显示的地址是指文件内部的偏移地址,因此我们还需要将RVA地址转换成文件内部偏移地址。打开第二个软件RVA Converter点击菜单“FILE“中的“LOAD“选项“,选中我们要加载的文件“Shell32.dll“,然后再下面的RVA框中键入刚才得到的RVA地址,键入完毕后,FILE框中所显示的地址:3DCF1即“SHFileOperation“函数在“Shell32.dll“文件内的偏移地址。
最关键的一步开始啦,打开HIEW软件,加载“Shell32.dll“,按下F4键,选择“DECODE“(反汇编),再按下F5键,键入刚才所得到的地址3DCF1,来到了我们要更改的函数的开头处,按下F3键进行编辑,再按下“TAB“键,可以直接键入汇编代码ret 4,之后按下F9键保存,退出程序。
重新启动机器,来到DOS下,将改好的Shell32.dll替换掉原先的文件。再重启机器进入WINDOWS,试试删除文件,怎么样?删除不了吧!
可能有人会问,我只想屏删除文件,我是不是只要按此方法拦DeleteFileA函数就可以啦?答案是不行的,开始我试验时拦的就是此函数,很怪的是如果你按下的是SHIFT+DEL进行删除文件,文件消失啦,但按一下F5刷新,文件就回来啦,达到要求,但是如果你通过回收站删除文件,那就不好用啦。因此最后我选择拦截SHFileOperation函数,如果你真得只想拦删除文件,可以通过编写程序检测SHFILEOPSTRUCT结构中的wFunc参数,来进行相应的操作达到你所想要的效果。这里有点唠叨啦。
总是让系统不删文件,我想硬盘空间会慢慢变小,呵呵,有点像病毒啦!
这种状态下我试了一个小时啦,不过没事,大家自己试试吧,出了问题可别找我啊!:)
最后我们总结一下,这种硬模式法有好处有坏处,好处是操作简单,稍懂一些汇编的人都会理解整个操作步骤的,坏处是,如果98版本不一样的话,手工改动太麻烦啦,而且由于我们只是拦下了API函数,在98内好用,但是打开98的DOS窗口仍可以进行删除操作,这一点请大家注意。这里只是教大家一种方法,具体用到哪方面,就看你自己了。
dll反汇编初步
2004-5-15 2:17:52 (文章类别:编程基础)
ozymandias(原作)
在论坛里面看到一些人讨论dll的反汇编,这几天帮一个朋友分析一个dll,此dll非常简单,现在把我的分析过
程和大家分享一下,这里没有什么特别有效的方法,靠的就是耐心和经验,反复验证,直到调用成功。
有个dll2lib的工具,不知道是我不会使用还是怎么的,反正我是没有使用成功过,所以我只能靠自己
来分析了。
首先是使用的工具,ida/win32dasm/ollydbg
win32dasm分析的速度快一些,但是智能程度不如ida,ida这个2001开发工具亚军绝对不是浪得虚名的
,它的智能程度非常高,可是识别出常用的函数,这两个都是静态反汇编的工具,必须配以动态分析的工具,
毕竟你很难一下子就分析对(至少我是这样),当然你可以使用s-ice或者trw,但是这些工具都有限制,trw不支
持2000,s-ice一旦装载只能reboot才能取消装载,还有其工作在ring0,所以你只能对者黑乎乎的屏幕,很痛
苦,这里选用的ollydbg是最新版本,支持dll的跟踪。
下面列出win32dasm反汇编的结果:
Exported fn(): GetUserNumber - Ord:0004h
:0040C1B0 55push ebp
:0040C1B1 8BECmov ebp, esp
:0040C1B3 53push ebx
:0040C1B4 56push esi
:0040C1B5 57push edi
:0040C1B6 8B5D08mov ebx, dword ptr [ebp+08]
:0040C1B9 33F6xor esi, esi
:0040C1BB 8BC3mov eax, ebx
:0040C1BD E846A5FFFFcall 00406708
:0040C1C2 6685C0test ax, ax
:0040C1C5 7212jb 0040C1D9
:0040C1C7 40inc eax
:0040C1C8 33D2xor edx, edx
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040C1D7(C)
|
:0040C1CA 0FB7CAmovzx ecx, dx
:0040C1CD 0FB60C0Bmovzx ecx, byte ptr [ebx+ecx]
:0040C1D1 03F1add esi, ecx
:0040C1D3 42inc edx
:0040C1D4 66FFC8dec ax
:0040C1D7 75F1jne 0040C1CA
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040C1C5(C)
|
:0040C1D9 8B450Cmov eax, dword ptr [ebp+0C]
:0040C1DC 8A4012mov al, byte ptr [eax+12]
:0040C1DF 3C61cmp al, 61
:0040C1E1 720Bjb 0040C1EE
:0040C1E3 25FF000000and eax, 000000FF
:0040C1E8 6683E861sub ax, 0061
:0040C1EC EB09jmp 0040C1F7
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040C1E1(C)
|
:0040C1EE 25FF000000and eax, 000000FF
:0040C1F3 6683E841sub ax, 0041
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040C1EC(U)
|
:0040C1F7 8B550Cmov edx, dword ptr [ebp+0C]
:0040C1FA 8A5213mov dl, byte ptr [edx+13]
:0040C1FD 80FA61cmp dl, 61
:0040C200 720Cjb 0040C20E
:0040C202 81E2FF000000and edx, 000000FF
:0040C208 6683EA61sub dx, 0061
:0040C20C EB0Ajmp 0040C218
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040C200(C)
|
:0040C20E 81E2FF000000and edx, 000000FF
:0040C214 6683EA41sub dx, 0041
* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040C20C(U)
|
:0040C218 0FB7C0movzx eax, ax
:0040C21B 6BF81Aimul edi, eax, 0000001A
:0040C21E 0FB7C2movzx eax, dx
:0040C221 03F8add edi, eax
:0040C223 81F74D010000xor edi, 0000014D
:0040C229 83F701xor edi, 00000001
:0040C22C 8BC3mov eax, ebx
:0040C22E E8D5A4FFFFcall 00406708
:0040C233 2BF8sub edi, eax
:0040C235 8BC6mov eax, esi
:0040C237 B91A000000mov ecx, 0000001A
:0040C23C 99cdq
:0040C23D F7F9idiv ecx
:0040C23F 2BFAsub edi, edx
:0040C241 8BC7mov eax, edi
:0040C243 5Fpop edi
:0040C244 5Epop esi
:0040C245 5Bpop ebx
:0040C246 5Dpop ebp
:0040C247 C20800ret 0008
通过ret 008我们可以知道这个函数需要两个参数,通过mov eax, esi,我们可以知道这个函数有反回
值(这是因为在高级语言里面一般通过eax设置函数返回值)具体返回什么类型现在还没办法知道,但是不管这么
多,我们假设此函数是这样的:
int GetUserNumber(int a1,int a2)
我们会在后续分析后,慢慢修正他,现在我们开始一点点分析。
:0040C1B0 55push ebp
:0040C1B1 8BECmov ebp, esp
:0040C1B3 53push ebx
:0040C1B4 56push esi
:0040C1B5 57push edi
这个是function prolog,建立堆栈和寄存器的保存,没什么可多说的。
:0040C1B6 8B5D08mov ebx, dword ptr [ebp+08]
:0040C1B9 33F6xor esi, esi
:0040C1BB 8BC3mov eax, ebx
:0040C1BD E846A5FFFFcall 00406708
这里你需要知道函数调用过程的参数传递,可以到asm.yeah.net看看罗云彬那篇很好的关于参数传递和堆栈修
复的文章,这里简单说一下,调用函数的时候如果通过堆栈来传递参数的话,那么对于我们讨论的函数可能是
这样的:
push a2
push a1
call GetUserNumber
此时堆栈看起来是这样的
-----a2
-----a1
esp-> -----returnaddress
这时候进入函数内部push ebp后
esp+c -----a2
esp+8 -----a1
esp+4 -----returnaddress
esp-> -----ebp
mov ebp,esp
此时要寻址a1可以通过ebp+8
:0040C1B6 8B5D08mov ebx, dword ptr [ebp+08]; ebx保存第一个参数
:0040C1B9 33F6xor esi, esi
:0040C1BB 8BC3mov eax, ebx
:0040C1BD E846A5FFFFcall 00406708
这个很简单esi清零,把第一个参数传递给eax,然后调用00406708
所以我们接下来就是要到00406708里面去看看
:00406708 89FAmov edx, edi
:0040670A 89C7mov edi, eax
:0040670C B9FFFFFFFFmov ecx, FFFFFFFF
:00406711 30C0xor al, al
:00406713 F2repnz
:00406714 AEscasb
:00406715 B8FEFFFFFFmov eax, FFFFFFFE
:0040671A 29C8sub eax, ecx
:0040671C 89D7mov edi, edx
:0040671E C3ret
这个是很典型的求字符串长度的代码
:00406708 89FAmov edx, edi;保存edi
:0040670A 89C7mov edi, eax ;eax是我们调用前的a1
:0040670C B9FFFFFFFFmov ecx, F