);
}
printf("\n");
system("pause");
}
(之前从VS2008复制过来的时候代码有高亮的,现在换了VC6就木有了。。)
进入正题!
照样F8到程序跑飞,断下Call F7跟进代码如下
00401000 81EC C0010000 sub esp,1C0 ; 1c0=448,448=101*4+11*4
00401006 B9 0B000000 mov ecx,0B ; ecx=11
0040100B 33C0 xor eax,eax ; eax=0
0040100D 56 push esi
0040100E 57 push edi
0040100F 8D7C24 08 lea edi,dword ptr ss:[esp+8] ; 访问缓冲区的地址
00401013 BE 01000000 mov esi,1 ; esi=1
00401018 F3:AB rep stos dword ptr es:[edi] ; 将eax往es:[edi]放11次
0040101A 8D7C24 38 lea edi,dword ptr ss:[esp+38] ; 访问数组x的末尾+1也就是数组a的起始
0040101E E8 74010000 call asm.00401197 ; rand
00401023 99 cdq ; edx变成eax的符号位
00401024 B9 64000000 mov ecx,64 ; ecx=100
00401029 F7F9 idiv ecx ; eax除以ecx,商在eax 余数在edx
0040102B 52 push edx
0040102C 68 44804000 push asm.00408044 ; ASCII "%4d"
00401031 8917 mov dword ptr ds:[edi],edx ; 把余数转存到ds:[edi]??噢噢.. ds:[edi]就是相当于a了
00401033 E8 2E010000 call asm.00401166
00401038 8BC6 mov eax,esi
0040103A B9 0A000000 mov ecx,0A
0040103F 99 cdq
00401040 F7F9 idiv ecx ; eax除以10
00401042 83C4 08 add esp,8 ; 我靠,401033call的堆栈平衡的语句还跑那么远来执行
00401045 85D2 test edx,edx
00401047 75 0D jnz short asm.00401056
00401049 68 40804000 push asm.00408040
0040104E E8 13010000 call asm.00401166
00401053 83C4 04 add esp,4 ; 还是堆栈平衡,这次像样点。
00401056 46 inc esi
00401057 83C7 04 add edi,4
0040105A 83FE 64 cmp esi,64
0040105D ^ 7E BF jle short asm.0040101E
0040105F 8D4C24 38 lea ecx,dword ptr ss:[esp+38] ; 数组a的地址放到ecx
00401063 BE 64000000 mov esi,64 ; esi=100
00401068 8B01 mov eax,dword ptr ds:[ecx] ; 循环起始
0040106A BF 0A000000 mov edi,0A ; edi=10
0040106F 99 cdq
00401070 F7FF idiv edi
00401072 85D2 test edx,edx
00401074 75 02 jnz short asm.00401078 ; if eax/10没有余数则跳转
00401076 8BD7 mov edx,edi
00401078 8B7C94 08 mov edi,dword ptr ss:[esp+edx*4+8] ; 这两条啊 +了8,是因为之前还push了两个寄存器 还记得吗?就是最前面的那两个push
0040107C 8D4494 08 lea eax,dword ptr ss:[esp+edx*4+8] ; 从上面三句看出 edx是作为变量p了
00401080 47 inc edi
00401081 83C1 04 add ecx,4 ; 把a数组的下标往后挪
00401084 4E dec esi
00401085 8938 mov dword ptr ds:[eax],edi
00401087 ^ 75 DF jnz short asm.00401068 ; 循环结束
00401089 BE 01000000 mov esi,1 ; esi是循环变量咯
0040108E 83FE 0A cmp esi,0A
00401091 8BC6 mov eax,esi
00401093 75 02 jnz short asm.00401097
00401095 33C0 xor eax,eax
00401097 8B54B4 08 mov edx,dword ptr ss:[esp+esi*4+8]
0040109B 52 push edx
0040109C 50 push eax
0040109D 68 38804000 push asm.00408038 ; ASCII "%d,%d
"
004010A2 E8 BF000000 call asm.00401166
004010A7 83C4 0C add esp,0C
004010AA 46 inc esi
004010AB 83FE 0A cmp esi,0A
004010AE ^ 7E DE jle short asm.0040108E
004010B0 68 40804000 push asm.00408040
004010B5 E8 AC000000 call asm.00401166
004010BA 68 30804000 push asm.00408030 ; ASCII "pause"
004010BF E8 0C000000 call asm.004010D0
004010C4 83C4 08 add esp,8
004010C7 5F pop edi
004010C8 5E pop esi
004010C9 81C4 C0010000 add esp,1C0
004010CF C3 retn
这次逆向的这个算法总结了一些经验 分享一下
1 遇到跳转跨度较大的,例如跨了20条语句左右的,那大概就是一个C语言里的for while do这些循环了。
2 认清循环之后要找准循环变量再进行后续分析
3 很多时候程序会以ecx作为循环变量,如果ecx用作其他用途的话 也会选择其他寄存器做循环变量
4 在程序里面有些局部变量编译器会直接用寄存器把他替换掉,所以要认清哪个寄存器把这个变量替换掉了
5
00401000 81EC C0010000 sub esp,1C0 ; 1c0=448,448=101*4+11*4
00401006 B9 0B000000 mov ecx,0B ; ecx=11
0040100B 33C0 xor eax,eax ; eax=0
0040100D 56 push esi
0040100E 57 push edi
0040100F 8D7C24 08 lea edi,dword ptr ss:[esp+8] ; 访问缓冲区的地址
这里的最后一条语句的意思我开始以为是访问CALL语句的下一条指令的地址呢,原来是因为在程序开头用sub esp,1c0开辟了一段缓冲区,
然后push了两个寄存器,所以访问这段缓冲区自然就是esp+8了
6
程序开始时分配的这一段缓冲区是一下子分配给了一个或者一个以上的数组和变量了,这里的缓冲区包含数组a和数组x
原来后声明的变量还排在缓冲区的前面。。也就是,这里的缓冲区数组x的11个元素排前面 接着才是数组a
从这里可以看出:0040101A 8D7C24 38 lea edi,dword ptr ss:[esp+38] ; 访问数组x的末尾+1也就是数组a的起始
esp+38,38h也就是56D,就是56了,56减去之前的两个寄存器占的8个字节,也就是48了,每个int变量占4个字节,那么这里就是有12个变量了,什么?12???,x不是11个元素吗?怎么成12了,呵呵因为第12已经是接下来的数组的第一个元素了!!