没有什么特别有效的方法,靠的就是耐心和经验,反复验证,直到调用成功。 有个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 55 push ebp :0040C1B1 8BEC mov ebp, esp :0040C1B3 53 push ebx :0040C1B4 56 push esi :0040C1B5 57 push edi :0040C1B6 8B5D08 mov ebx, dword ptr [ebp+08] :0040C1B9 33F6 xor esi, esi :0040C1BB 8BC3 mov eax, ebx :0040C1BD E846A5FFFF call 00406708 :0040C1C2 6685C0 test ax, ax :0040C1C5 7212 jb 0040C1D9 :0040C1C7 40 inc eax :0040C1C8 33D2 xor edx, edx
* Referenced by a (U)nconditional or (C)ondITional Jump at Address: |:0040C1D7(C) | :0040C1CA 0FB7CA movzx ecx, dx :0040C1CD 0FB60C0B movzx ecx, byte ptr [ebx+ecx] :0040C1D1 03F1 add esi, ecx :0040C1D3 42 inc edx :0040C1D4 66FFC8 dec ax :0040C1D7 75F1 jne 0040C1CA
* Referenced by a (U)nconditional or (C)ondITional Jump at Address: |:0040C1C5(C) | :0040C1D9 8B450C mov eax, dword ptr [ebp+0C] :0040C1DC 8A4012 mov al, byte ptr [eax+12] :0040C1DF 3C61 cmp al, 61 :0040C1E1 720B jb 0040C1EE :0040C1E3 25FF000000 and eax, 000000FF :0040C1E8 6683E861 sub ax, 0061 :0040C1EC EB09 jmp 0040C1F7
* Referenced by a (U)nconditional or (C)ondITional Jump at Address: |:0040C1E1(C) | :0040C1EE 25FF000000 and eax, 000000FF :0040C1F3 6683E841 sub ax, 0041
* Referenced by a (U)nconditional or (C)ondITional Jump at Address: |:0040C1EC(U) | :0040C1F7 8B550C mov edx, dword ptr [ebp+0C] :0040C1FA 8A5213 mov dl, byte ptr [edx+13] :0040C1FD 80FA61 cmp dl, 61 :0040C200 720C jb 0040C20E :0040C202 81E2FF000000 and edx, 000000FF :0040C208 6683EA61 sub dx, 0061 :0040C20C EB0A jmp 0040C218
* Referenced by a (U)nconditional or (C)ondITional Jump at Address: |:0040C200(C) | :0040C20E 81E2FF000000 and edx, 000000FF :0040C214 6683EA41 sub dx, 0041
* Referenced by a (U)nconditional or (C)ondITional Jump at Address: |:0040C20C(U) | :0040C218 0FB7C0 movzx eax, ax :0040C21B 6BF81A imul edi, eax, 0000001A :0040C21E 0FB7C2 movzx eax, dx :0040C221 03F8 add edi, eax :0040C223 81F74D010000 xor edi, 0000014D :0040C229 83F701 xor edi, 00000001 :0040C22C 8BC3 mov eax, ebx :0040C22E E8D5A4FFFF call 00406708 :0040C233 2BF8 sub edi, eax :0040C235 8BC6 mov eax, esi :0040C237 B91A000000 mov ecx, 0000001A :0040C23C 99 cdq :0040C23D F7F9 idiv ecx :0040C23F 2BFA sub edi, edx :0040C241 8BC7 mov eax, edi :0040C243 5F pop edi :0040C244 5E pop esi :0040C245 5B pop ebx :0040C246 5D pop ebp :0040C247 C20800 ret 0008
通过ret 008我们可以知道这个函数需要两个参数,通过mov eax, esi,我们可以知道这个函数有反回
值(这是因为在高级语言里面一般通过eax设置函数返回值)具体返回什么类型现在还没办法知道,但是不管这么
多,我们假设此函数是这样的:
int GetUserNumber(int a1,int a2)
我们会在后续分析后,慢慢修正他,现在我们开始一点点分析。
:0040C1B0 55 push ebp :0040C1B1 8BEC mov ebp, esp :0040C1B3 53 push ebx :0040C1B4 56 push esi :0040C1B5 57 push edi 这个是function prolog,建立堆栈和寄存器的保存,没什么可多说的。 :0040C1B6 8B5D08 mov ebx, dword ptr [ebp+08] :0040C1B9 33F6 xor esi, esi :0040C1BB 8BC3 mov eax, ebx :0040C1BD E846A5FFFF call 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 8B5D08 mov ebx, dword ptr [ebp+08]; ebx保存第一个参数 :0040C1B9 33F6 xor esi, esi :0040C1BB 8BC3 mov eax, ebx :0040C1BD E846A5FFFF call 00406708
这个很简单esi清零,把第一个参数传递给eax,然后调用00406708
所以我们接下来就是要到00406708里面去看看 :00406708 89FA mov edx, edi :0040670A 89C7 mov edi, eax :0040670C B9FFFFFFFF mov ecx, FFFFFFFF :00406711 30C0 xor al, al :00406713 F2 repnz :00406714 AE scasb :00406715 B8FEFFFFFF mov eax, FFFFFFFE :0040671A 29C8 sub eax, ecx :0040671C 89D7 mov edi, edx :0040671E C3 ret
这个是很典型的求字符串长度的代码 :00406708 89FA mov edx, edi ;保存edi :0040670A 89C7 mov edi, eax ;eax是我们调用前的a1 :0040670C B9FFFFFFFF mov ecx, FFFFFFFF ecx设置成最大32数 :00406711 30C0 xor al, al ;al清零
我们知道汇编指令的字符串操作一般通过esi和edi,上面的过程在注释里给出解释 :00406713 F2 repnz :00406714 AE scasb ;判断字符串是否结束 :00406715 B8FEFFFFFF mov eax, FFFFFFFE :0040671A 29C8 sub eax, ecx ;eax保存了字符串长度 :0040671C 89D7 mov edi, edx ;恢复edi :0040671E C3 ret
上面分析我们知道参数a1是一个字符串,现在把我们的函数修正如下 int GetUserNumber(char * a1,int a2)
继续我们的分析:
:0040C1C2 6685C0 test ax, ax ;长度是否为零 :0040C1C5 7212 jb 0040C1D9 ;为零则跳转 :0040C1C7 40 inc eax ;eax加一 :0040C1C8 33D2 xor edx, edx ;edx清零
我们用c语言写出等价程序如下: int GetUserNumber(char * strUserName,test * pt) { esi = 0;
int len = strlen(strUserName); if(len <= 0) goto _SKIP_USERNAME;
_SKIP_USERNAME:
}
继续分析并且进一步修正我们的代码
[1] [2] [3] 下一页 |