admin 发表于 2015-11-22 23:49:09

【转】《基于VC平台下C++反汇编与逆向分析研究——No.4》

————————————————————————————————————————————————
分析环境:WIN7sp1
所用工具:VC++6.0/OllyDBG/IDA
适用人群:有一定计算机基础,熟悉C/C++编程,熟悉X86系列汇编/了解OD/IDA等调试工具使用,对逆向安全有极大兴趣者!
————————————————————————————————————————————————
开篇前言:
      数据类型和运算符是任何编程语言的基础,而对于逆向而言亦是,只有牢固的基础才能走得更远...


————————————————————————————————————————————————
正文部分:
       本节主要从汇编层面来全面解析程序的基本流程控制语句:while,do-while,goto 如下:
___________________________________________________________________________________________________
本帖隐藏的内容
[*]#include < stdio.h >
[*]int main()
[*]{
[*]    int x = 1,
[*]    y = 0;
[*]    while (x <= 100)
[*]    {
[*]      y = x + y;
[*]      x++;
[*]    }
[*]    printf("%d", y);
[*]    return 0;
[*]}

复制代码

___________________________________________________________________________________________________
上面是一个使用while语句来计算1+2+3...+100的和的程序,使用了一个计数器!

Debug版本:
00401010 >|> \55            push ebp                                 ;ebp入栈保存
00401011|.8BEC          mov ebp,esp                              ;esp保存到ebp
00401013|.83EC 48       sub esp,0x48                           ;开辟局部变量空间
00401016|.53            push ebx                                 ;ebx入栈保存
00401017|.56            push esi                                 ;esi入栈保存
00401018|.57            push edi                                 ;edi入栈保存
00401019|.8D7D B8       lea edi,                     ;设置CC操作起始化地址
0040101C|.B9 12000000   mov ecx,0x12                           ;设置循环次数
00401021|.B8 CCCCCCCC   mov eax,0xCCCCCCCC                     ;赋值eax CC int 3
00401026|.F3:AB         rep stos dword ptr es:            ;循环复制cc
00401028|.C745 FC 01000>mov ,0x1                        ;赋值局部变量x
0040102F|.C745 F8 00000>mov ,0x0                        ;赋值局部变量y
00401036|>837D FC 64    /cmp ,0x64                      ;测试x是否为100
0040103A|.7F 14         |jg short Test3.00401050               ;如果为100就跳出while循环
0040103C|.8B45 FC       |mov eax,                     ;变量x值放入eax
0040103F|.0345 F8       |add eax,                     ;x+y的值放入eax
00401042|.8945 F8       |mov ,eax                     ;eax的值放入变量y
00401045|.8B4D FC       |mov ecx,                     ;变量x的值放入ecx
00401048|.83C1 01       |add ecx,0x1                           ;exc自加1
0040104B|.894D FC       |mov ,ecx                     ;ecx赋值到变量x
0040104E|.^ EB E6         \jmp short Test3.00401036                ;无条件跳转到while条件判断处
00401050|>8B55 F8       mov edx,                        ;最终y的值放入edx
00401053|.52            push edx                                 ; /<%d>
00401054|.68 1C204200   push Test3.0042201C                      ; |format = "%d"
00401059|.E8 32000000   call Test3.printf                        ; \printf
0040105E|.83C4 08       add esp,0x8                              ;恢复esp
00401061|.33C0          xor eax,eax                              ;eax清零
00401063|.5F            pop edi                                  ;恢复edi
00401064|.5E            pop esi                                  ;恢复esi
00401065|.5B            pop ebx                                  ;恢复ebx
00401066|.83C4 48       add esp,0x48                           ;恢复局部变量空间
00401069|.3BEC          cmp ebp,esp                              ;测试堆栈平衡
0040106B|.E8 A0000000   call Test3._chkesp                     ;调用调试信息
00401070|.8BE5          mov esp,ebp                              ;恢复esp
00401072|.5D            pop ebp                                  ;恢复ebp
00401073\.C3            retn                                     ;返回ret   add esp,4


while循环基本结构:

cmp ;判断while条件是否满足
jg ;不满足就跳出while循环
... ;while执行体
jmp ;无条件跳转到条件判断处

Release版本:
00401000/$B8 01000000   mov eax,1                              ;eax赋值为1
00401005|.33C9          xor ecx,ecx                              ;清零ecx,计数之用
00401007|>03C8          /add ecx,eax                           ;eax加上ecx放入ecx
00401009|.40            |inc eax                                 ;eax自加1
0040100A|.83F8 64       |cmp eax,64                              ;和100做比较
0040100D|.^ 7E F8         \jle short Test3.00401007                ;如果不满足条件就跳回add ecx,eax
0040100F|.51            push ecx                                 ;参数
00401010|.68 30704000   push Test3.00407030                      ;ASCII "%d"
00401015|.E8 06000000   call Test3.00401020                      ;printf函数
0040101A|.83C4 08       add esp,8                              ;恢复esp
0040101D|.33C0          xor eax,eax                              ;eax清零
0040101F\.C3            retn                                     ;返回retadd esp,4

while循环基本结构:

自动判断是否满足while条件,如果否就直接跳过while,这里满足
... ;while执行体
cmp ;判断while条件是否满足
jle ;不满足就跳出while循环

总结:根据反汇编两种不同的编译方式可以看出,编译器已经自动识别出原始条件是否满足首次while条件,如满足则直接执行while内容,不满足就直接跳过while。
___________________________________________________________________________________________________


[*]#include < stdio.h >
[*]int main()
[*]{
[*]    int x;
[*]    do
[*]    {
[*]      printf("请输入一个数字");
[*]      scanf("%d", &x);
[*]      printf("你输入的数字是:%d\n", x);
[*]    } while ( x != 0 );
[*]    return 0;
[*]}
[*]

复制代码

___________________________________________________________________________________________________

上面程序是判断用户的输入数值,不等于0就一直输入,直到等于0就跳出do-while循环

Debug版本:
00401010   |> \55             push ebp                         ;ebp入栈保存
00401011   |.8BEC         mov ebp,esp                      ;esp保存到ebp
00401013   |.83EC 44      sub esp,44                     ;开辟局部变量空间
00401016   |.53             push ebx                         ;ebx入栈保存
00401017   |.56             push esi                         ;esi入栈保存
00401018   |.57             push edi                         ;edi入栈保存
00401019   |.8D7D BC      lea edi,dword ptr ss:    ;设置CC操作起始地址
0040101C   |.B9 11000000    mov ecx,11                     ;设置循环次数
00401021   |.B8 CCCCCCCC    mov eax,CCCCCCCC               ;赋值 eax CCint 3
00401026   |.F3:AB          rep stos dword ptr es:      ;循环复制 CC
00401028   |>68 B82F4200    /push Test3.00422FB8             ; /参数入栈
0040102D   |.E8 5E000000    |call Test3.00401090             ; \调用printf函数
00401032   |.83C4 04      |add esp,4                     ;恢复esp
00401035   |.8D45 FC      |lea eax,dword ptr ss:    ;取变量x的地址到eax
00401038   |.50             |push eax                        ; /参数入栈
00401039   |.68 1C204200    |push Test3.0042201C             ; |Arg1 = 0042201C ASCII "%d"
0040103E   |.E8 BDE80000    |call Test3.0040F900             ; \调用scanf函数
00401043   |.83C4 08      |add esp,8                     ;恢复esp
00401046   |.8B4D FC      |mov ecx,dword ptr ss:    ;变量x的值放入ecx
00401049   |.51             |push ecx                        ; /参数入栈
0040104A   |.68 A42F4200    |push Test3.00422FA4             ; |参数入栈
0040104F   |.E8 3C000000    |call Test3.00401090             ; \调用printf函数
00401054   |.83C4 08      |add esp,8                     ;恢复esp
00401057   |.837D FC 00   |cmp dword ptr ss:,0      ;判断x值是否为0
0040105B   |.^ 75 CB          \jnz short Test3.00401028      ;不为0即跳到到do循环出执行
0040105D   |.33C0         xor eax,eax                      ;eax清零
0040105F   |.5F             pop edi                        ;恢复edi
00401060   |.5E             pop esi                        ;恢复esi
00401061   |.5B             pop ebx                        ;恢复ebx
00401062   |.83C4 44      add esp,44                     ;恢复局部变量空间
00401065   |.3BEC         cmp ebp,esp                      ;测试堆栈平衡
00401067   |.E8 A4000000    call Test3.00401110            ;调用调试信息
0040106C   |.8BE5         mov esp,ebp                      ;恢复esp
0040106E   |.5D             pop ebp                        ;恢复ebp
0040106F   \.C3             retn                           ;返回retadd esp,4

do-while基本结构:
.... ;do循环执行体
cmp ;条件判断
jnz ;如果不满足条件就跳出循环

Release版本:
00401000/$51            push ecx                                 ;ecx入栈保存
00401001|>68 48804000   /push Test3.00408048                     ;参数
00401006|.E8 4C000000   |call Test3.00401057                     ;printf函数
0040100B|.8D4424 04   |lea eax,dword ptr ss:            ;取变量x地址到eax
0040100F|.50            |push eax                              ;参数入栈
00401010|.68 44804000   |push Test3.00408044                     ;ASCII "%d"
00401015|.E8 26000000   |call Test3.00401040                     ;scanf函数
0040101A|.8B4C24 0C   |mov ecx,dword ptr ss:            ;变量值赋值到ecx
0040101E|.51            |push ecx                              ;参数
0040101F|.68 30804000   |push Test3.00408030                     ;参数
00401024|.E8 2E000000   |call Test3.00401057                     ;printf函数
00401029|.8B4424 14   |mov eax,dword ptr ss:         ;变量值赋值到eax中
0040102D|.83C4 14       |add esp,14                              ;恢复esp
00401030|.85C0          |test eax,eax                            ;判断eax是否为零
00401032|.^ 75 CD         \jnz short Test3.00401001                ;如果不为零,就跳回执行
00401034|.33C0          xor eax,eax                              ;eax清零
00401036|.59            pop ecx                                  ;恢复ecx
00401037\.C3            retn                                     ;返回 retadd esp,4

do-while基本结构:
.... ;do循环执行体
test ;条件判断
jnz ;如果不满足条件就跳出循环

两种编译模式的汇编判断流程很相似,这也就是do-while和while的区别,不管是否满足条件,都会先执行一次再做判断!

___________________________________________________________________________________________________

goto语句:


[*]#include < stdio.h >
[*]int main()
[*]{
[*]    int a;
[*]    qq: printf("请输入一个数字:");
[*]    scanf("%d", &a);
[*]    if (a == 0)
[*]      goto qq;
[*]    return 0;
[*]}

复制代码

___________________________________________________________________________________________________
上面程序是判断用户输入,如果值为0就跳回重新输入判断,这里使用了goto语句

Debug版本:
00401010 >|> \55            push ebp                                                ;保存ebp
00401011|.8BEC          mov ebp,esp                                             ;保存esp到ebp
00401013|.83EC 44       sub esp,44                                                ;开辟局部变量空间
00401016|.53            push ebx                                                ;ebx入栈保存
00401017|.56            push esi                                                ;esi入栈保存
00401018|.57            push edi                                                ;edi入栈保存
00401019|.8D7D BC       lea edi,                                        ;设置CC操作起始地址
0040101C|.B9 11000000   mov ecx,11                                                ;设置循环次数
00401021|.B8 CCCCCCCC   mov eax,CCCCCCCC                                          ;赋值 eax CCint 3
00401026|.F3:AB         rep stos dword ptr es:                               ;循环复制 CC
00401028|>68 20504200   /push offset Test3.??_C@_0BB@FLPH@?G?k?J?d?H?k?R?$LL?$LI?>;参数
0040102D|.E8 AE000000   |call Test3.printfgvdbgind_blockeressges                  ;printf函数
00401032|.83C4 04       |add esp,4                                                ;恢复esp
00401035|.8D45 FC       |lea eax,                                        ;取变量地址到eax
00401038|.50            |push eax                                                 ;参数
00401039|.68 1C504200   |push offset Test3.??_C@_02MECO@?$CFd?$AA@4k?5at?50x?$CF0>;ASCII "%d"
0040103E|.E8 3D000000   |call Test3.scanfalloc_basee_block_pages                  ;scanf函数
00401043|.83C4 08       |add esp,8                                                ;恢复esp
00401046|.837D FC 00    |cmp ,0                                          ;比较是否为0
0040104A|.75 02         |jnz short Test3.0040104E                                 ;为0就执行if语句内容
0040104C|.^ EB DA         \jmp short Test3.00401028                                 ;jmp无条件跳转
0040104E|>33C0          xor eax,eax                                             ;eax清零
00401050|.5F            pop edi                                                   ;恢复edi
00401051|.5E            pop esi                                                   ;恢复esi
00401052|.5B            pop ebx                                                   ;恢复ebx
00401053|.83C4 44       add esp,44                                                ;恢复局部变量空间
00401056|.3BEC          cmp ebp,esp                                             ;测试堆栈平衡
00401058|.E8 03010000   call Test3.__chkespleBuffers@4ingsW@4location?5size?3?5?$>;调用调试信息
0040105D|.8BE5          mov esp,ebp                                             ;恢复esp
0040105F|.5D            pop ebp                                                   ;恢复ebp
00401060\.C3            retn                                                      ;返回retadd esp,4

Release版本:
00401000/$51            push ecx                                                ;ecx入栈保存
00401001|.68 34804000   push Test3.00408034                                       ;参数
00401006|.E8 5C000000   call Test3.00401067                                       ;printf函数
0040100B|.8D4424 04   lea eax,dword ptr ss:                              ;取变量地址到eax
0040100F|.50            push eax                                                ;参数
00401010|.68 30804000   push Test3.00408030                                       ;ASCII "%d"
00401015|.E8 36000000   call Test3.00401050                                       ;scanf函数
0040101A|.8B4424 0C   mov eax,dword ptr ss:                              ;变量值赋值到eax
0040101E|.83C4 0C       add esp,0C                                                ;恢复esp
00401021|.85C0          test eax,eax                                              ;测试eax是否为0
00401023|.75 24         jnz short Test3.00401049                                  ;不满足就跳出if语句
00401025|>68 34804000   /push Test3.00408034                                    ;参数
0040102A|.E8 38000000   |call Test3.00401067                                    ;printf函数
0040102F|.8D4C24 04   |lea ecx,dword ptr ss:                           ;取变量地址到ecx
00401033|.51            |push ecx                                                 ;参数
00401034|.68 30804000   |push Test3.00408030                                    ;ASCII "%d"
00401039|.E8 12000000   |call Test3.00401050                                    ;scanf函数
0040103E|.8B4424 0C   |mov eax,dword ptr ss:                           ;变量值赋值到eax
00401042|.83C4 0C       |add esp,0C                                             ;恢复esp
00401045|.85C0          |test eax,eax                                             ;测试eax是否为0
00401047|.^ 74 DC         \je short Test3.00401025                                  ;满足就跳回执行if语句
00401049|>33C0          xor eax,eax                                             ;eax清零
0040104B|.59            pop ecx                                                   ;恢复ecx
0040104C\.C3            retn                                                      ;返回retadd esp,4

goto语句框架:

在debug版本中,goto语句等价鱼jmp指令,但在这个Release版本中却没有goto语句的影子,原因在于由于if语句的原因,这里直接忽略了goto语句,而是把goto语句对应的内容直接拷贝到了if语句下!换种情况,也是jmp指令!

___________________________________________________________________________________________________


本节主要对程序的流程化控制逆向分析完毕,各位私下还需要多多逆向联系,对日后大有帮助!好了,基础篇到此为止,中级篇主要讲解数组,指针,函数,以及类和对象...


页: [1]
查看完整版本: 【转】《基于VC平台下C++反汇编与逆向分析研究——No.4》