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

转载来自 “鱼C工作室” 作者: 小生我怕怕

分析环境:WIN7sp1
所用工具:VC++6.0/OllyDBG/IDA
适用人群:有一定计算机基础,熟悉C/C++编程,熟悉X86系列汇编/了解OD/IDA等调试工具使用,对逆向安全有极大兴趣者!

开篇前言:
        数据类型和运算符是任何编程语言的基础,而对于逆向而言亦是,只有牢固的基础才能走得更远...

正文部分:
       本节主要从汇编层面来全面解析程序的基本流程控制语句:if -else,switch,for 如下:

源码:

#include<stdio.h>
int main()
{
        int x;
        printf("请输入密码");
        scanf("%d",&x);
        if(x==123456)
                printf("成功");
        else
                printf("失败");
        return 0;
}

Debug版本:

00401010 >|> \55            push ebp                                 ;  ebp入栈保存
00401011  |.  8BEC          mov ebp,esp                              ;  esp保存到ebp中
00401013  |.  83EC 44       sub esp,0x44                             ;  开辟局部变量空间
00401016  |.  53            push ebx                                 ;  入栈ebx
00401017  |.  56            push esi                                 ;  入栈esi
00401018  |.  57            push edi                                 ;  入栈edi
00401019  |.  8D7D BC       lea edi,[local.17]                       ;  设置CC操作起始地址
0040101C  |.  B9 11000000   mov ecx,0x11                             ;  设置循环次数
00401021  |.  B8 CCCCCCCC   mov eax,0xCCCCCCCC                       ;  赋值eax CC,int 3
00401026  |.  F3:AB         rep stos dword ptr es:[edi]              ;  循环赋值
00401028  |.  68 10604200   push Test3.00426010                      ; /format = "请输入密码"
0040102D  |.  E8 6E000000   call Test3.printf                        ; \printf
00401032  |.  83C4 04       add esp,0x4                              ;  恢复esp
00401035  |.  8D45 FC       lea eax,[local.1]                        ;  变量地址放入eax
00401038  |.  50            push eax                                 ;  参数入栈
00401039  |.  68 1C504200   push Test3.0042501C                      ; /format = "%d"
0040103E  |.  E8 DD000000   call Test3.scanf                         ; \scanf
00401043  |.  83C4 08       add esp,0x8                              ;  恢复esp
00401046  |.  817D FC 40E20>cmp [local.1],0x1E240                    ;  判断是否为123456
0040104D  |.  75 0F         jnz short Test3.0040105E                 ;  不等于就跳转
0040104F  |.  68 20504200   push Test3.00425020                      ; /format = "成功"
00401054  |.  E8 47000000   call Test3.printf                        ; \printf
00401059  |.  83C4 04       add esp,0x4                              ;  恢复esp
0040105C  |.  EB 0D         jmp short Test3.0040106B                 ;  跳出循环
0040105E  |>  68 08604200   push Test3.00426008                      ; /format = "失败"
00401063  |.  E8 38000000   call Test3.printf                        ; \printf
00401068  |.  83C4 04       add esp,0x4                              ;  恢复esp
0040106B  |>  33C0          xor eax,eax                              ;  eax清零
0040106D  |.  5F            pop edi                                  ;  恢复edi
0040106E  |.  5E            pop esi                                  ;  恢复esi
0040106F  |.  5B            pop ebx                                  ;  恢复ebx
00401070  |.  83C4 44       add esp,0x44                             ;  恢复局部变量空间
00401073  |.  3BEC          cmp ebp,esp                              ;  判断堆栈平衡
00401075  |.  E8 06010000   call Test3._chkesp                       ;  调用调试信息
0040107A  |.  8BE5          mov esp,ebp                              ;  恢复esp
0040107C  |.  5D            pop ebp                                  ;  恢复ebp
0040107D  \.  C3            retn                                     ;  返回  ret  add esp,4

if-else的基本框架:
cmp xx1,xx2     ;测试比较指令,如test
jnz  ;条件转移指令,如jle,jne等
........... ;if 语句内容 
jmp   ;跳出判断
........... ;else语句内容 

Release版本:

00401000  /$  51            push ecx                                 ;  ecx入栈保存
00401001  |.  68 44804000   push Test3.00408044                      ;  请输入密码
00401006  |.  E8 5C000000   call Test3.00401067                      ;  printf函数
0040100B  |.  8D4424 04     lea eax,dword ptr ss:[esp+4]             ;  获取变量指针到eax
0040100F  |.  50            push eax                                 ;  参数
00401010  |.  68 40804000   push Test3.00408040                      ;  %d
00401015  |.  E8 36000000   call Test3.00401050                      ;  scanf函数
0040101A  |.  8B4424 0C     mov eax,dword ptr ss:[esp+C]             ;  获取输入数到eax
0040101E  |.  83C4 0C       add esp,0C                               ;  恢复esp
00401021  |.  3D 40E20100   cmp eax,1E240                            ;  比较是否相等
00401026  |.  75 11         jnz short Test3.00401039                 ;  不相等就跳转
00401028  |.  68 38804000   push Test3.00408038                      ;  成功
0040102D  |.  E8 35000000   call Test3.00401067                      ;  printf函数
00401032  |.  83C4 04       add esp,4                                ;  恢复esp
00401035  |.  33C0          xor eax,eax                              ;  eax清零
00401037  |.  59            pop ecx                                  ;  恢复ecx
00401038  |.  C3            retn                                     ;  返回 ret  add esp,4
00401039  |>  68 30804000   push Test3.00408030                      ;  失败
0040103E  |.  E8 24000000   call Test3.00401067                      ;  printf函数
00401043  |.  83C4 04       add esp,4                                ;  恢复esp
00401046  |.  33C0          xor eax,eax                              ;  eax清零
00401048  |.  59            pop ecx                                  ;  恢复ecx
00401049  \.  C3            retn                                     ;  返回 ret  add esp,4

if-else的基本框架:

cmp xx1,xx2     ;测试比较指令,如test
jnz  ;条件转移指令,如jle,jne等
........... ;if 语句内容 
retn
........... ;else语句内容 
retn

#include<stdio.h>
int main()
{
        int x;
        printf("请输入一个数字");
        scanf("%d",&x);
        switch(x)
        {
        case 0:
                 printf("你输入的数字是0");
                 break;
        case 1:
                 printf("你输入的数字是1");
                 break;
        case 2:
                 printf("你输入的数字是2");
                 break;
        default:
                 printf("你输入的数字大于2");
        }
        return 0;
}

上面通过switch语句,来判断用户输入,有默认执行部分!

Debug版本:

0040F980 >/> \55            push ebp                                 ;  ebp入栈保存
0040F981  |.  8BEC          mov ebp,esp                              ;  esp保存到ebp中
0040F983  |.  83EC 48       sub esp,0x48                             ;  开辟局部变量空间
0040F986  |.  53            push ebx                                 ;  ebx入栈保存
0040F987  |.  56            push esi                                 ;  esi入栈保存
0040F988  |.  57            push edi                                 ;  edi入栈保存
0040F989  |.  8D7D B8       lea edi,[local.18]                       ;  设置CC初始化起始地址
0040F98C  |.  B9 12000000   mov ecx,0x12                             ;  设置循环次数
0040F991  |.  B8 CCCCCCCC   mov eax,0xCCCCCCCC                       ;  赋值eax CC,int 3
0040F996  |.  F3:AB         rep stos dword ptr es:[edi]              ;  循环复制cc
0040F998  |.  68 4C604200   push Test3.0042604C                      ; /format = "请输入一个数字"
0040F99D  |.  E8 FE16FFFF   call Test3.printf                        ; \printf
0040F9A2  |.  83C4 04       add esp,0x4                              ;  恢复esp
0040F9A5  |.  8D45 FC       lea eax,[local.1]                        ;  取变量地址放入eax
0040F9A8  |.  50            push eax                                 ;  参数入栈
0040F9A9  |.  68 1C504200   push Test3.0042501C                      ; /format = "%d"
0040F9AE  |.  E8 6D17FFFF   call Test3.scanf                         ; \scanf
0040F9B3  |.  83C4 08       add esp,0x8                              ;  恢复esp
0040F9B6  |.  8B4D FC       mov ecx,[local.1]                        ;  赋值变量值到ecx
0040F9B9  |.  894D F8       mov [local.2],ecx                        ;  ecx放入局部变量中
0040F9BC  |.  837D F8 00    cmp [local.2],0x0                        ;  判断是否为0
0040F9C0  |.  74 0E         je short Test3.0040F9D0                  ;  等于0就跳转,执行相应内容
0040F9C2  |.  837D F8 01    cmp [local.2],0x1                        ;  判断是否为1
0040F9C6  |.  74 17         je short Test3.0040F9DF                  ;  等于1就跳转,执行相应内容
0040F9C8  |.  837D F8 02    cmp [local.2],0x2                        ;  判断是否为2
0040F9CC  |.  74 20         je short Test3.0040F9EE                  ;  等于2就跳转,执行相应内容
0040F9CE  |.  EB 2D         jmp short Test3.0040F9FD                 ;  条件均不成立时,跳到默认执行处
0040F9D0  |>  68 3C604200   push Test3.0042603C                      ; /format = "你输入的数字是0"
0040F9D5  |.  E8 C616FFFF   call Test3.printf                        ; \printf
0040F9DA  |.  83C4 04       add esp,0x4                              ;  恢复esp
0040F9DD  |.  EB 2B         jmp short Test3.0040FA0A                 ;  跳出switch语句
0040F9DF  |>  68 2C604200   push Test3.0042602C                      ; /format = "你输入的数字是1"
0040F9E4  |.  E8 B716FFFF   call Test3.printf                        ; \printf
0040F9E9  |.  83C4 04       add esp,0x4                              ;  恢复esp
0040F9EC  |.  EB 1C         jmp short Test3.0040FA0A                 ;  跳出switch语句
0040F9EE  |>  68 1C604200   push Test3.0042601C                      ; /format = "你输入的数字是2"
0040F9F3  |.  E8 A816FFFF   call Test3.printf                        ; \printf
0040F9F8  |.  83C4 04       add esp,0x4                              ;  恢复esp
0040F9FB  |.  EB 0D         jmp short Test3.0040FA0A                 ;  跳出switch语句
0040F9FD  |>  68 08604200   push Test3.00426008                      ; /format = "你输入的数字大于2"
0040FA02  |.  E8 9916FFFF   call Test3.printf                        ; \printf
0040FA07  |.  83C4 04       add esp,0x4                              ;  恢复esp
0040FA0A  |>  33C0          xor eax,eax                              ;  eax清零
0040FA0C  |.  5F            pop edi                                  ;  恢复edi
0040FA0D  |.  5E            pop esi                                  ;  恢复esi
0040FA0E  |.  5B            pop ebx                                  ;  恢复ebx
0040FA0F  |.  83C4 48       add esp,0x48                             ;  恢复局部变量空间
0040FA12  |.  3BEC          cmp ebp,esp                              ;  堆栈平衡判断
0040FA14  |.  E8 6717FFFF   call Test3._chkesp                       ;  调用调试信息
0040FA19  |.  8BE5          mov esp,ebp                              ;  恢复esp
0040FA1B  |.  5D            pop ebp                                  ;  恢复ebp
0040FA1C  \.  C3            retn                                     ;  返回 ret add esp,4

switch语句基本框架:

cmp xx0,xx1       ;可以是test等
je  ;跳转执行体1  ;此处也可以是其他条件转移指令
cmp xx0,xx2
je ;跳转执行体2
0,xx3
je cmp xx;跳转执行体3
jmp ;跳转默认执行体处
...... ;执行体1
jmp
...... ;执行体2
jmp
...... ;执行体3
jmp
...... ;默认执行体

Release版本:

00401000  /$  51            push ecx                                 ;  ecx入栈
00401001  |.  68 78804000   push Test3.00408078                      ;  请输入一个数字
00401006  |.  E8 7C000000   call Test3.00401087                      ;  printf函数
0040100B  |.  8D4424 04     lea eax,dword ptr ss:[esp+0x4]           ;  取变量指针到eax
0040100F  |.  50            push eax                                 ;  参数
00401010  |.  68 74804000   push Test3.00408074                      ;  %d
00401015  |.  E8 56000000   call Test3.00401070                      ;  scanf函数
0040101A  |.  8B4424 0C     mov eax,dword ptr ss:[esp+0xC]           ;  输入数值到eax
0040101E  |.  83C4 0C       add esp,0xC                              ;  恢复esp
00401021  |.  83E8 00       sub eax,0x0                              ;  判断; Switch (cases 0..2)
00401024  |.  74 39         je short Test3.0040105F                  ;  如为0就跳转
00401026  |.  48            dec eax                                  ;  判断
00401027  |.  74 25         je short Test3.0040104E                  ;  如为1就跳转
00401029  |.  48            dec eax                                  ;  判断
0040102A  |.  74 11         je short Test3.0040103D                  ;  如为2就跳转
0040102C  |.  68 60804000   push Test3.00408060                      ;  你输入的数字大于2; Default case of switch 00401021
00401031  |.  E8 51000000   call Test3.00401087                      ;  printf函数
00401036  |.  83C4 04       add esp,0x4                              ;  恢复esp
00401039  |.  33C0          xor eax,eax                              ;  eax清零
0040103B  |.  59            pop ecx                                  ;  恢复ecx
0040103C  |.  C3            retn                                     ;  返回
0040103D  |>  68 50804000   push Test3.00408050                      ;  你输入的数字是2; Case 2 of switch 00401021
00401042  |.  E8 40000000   call Test3.00401087                      ;  printf函数
00401047  |.  83C4 04       add esp,0x4                              ;  恢复esp
0040104A  |.  33C0          xor eax,eax                              ;  eax清零
0040104C  |.  59            pop ecx                                  ;  恢复ecx
0040104D  |.  C3            retn                                     ;  返回
0040104E  |>  68 40804000   push Test3.00408040                      ;  你输入的数字是1; Case 1 of switch 00401021
00401053  |.  E8 2F000000   call Test3.00401087                      ;  printf函数
00401058  |.  83C4 04       add esp,0x4                              ;  恢复esp
0040105B  |.  33C0          xor eax,eax                              ;  eax清零
0040105D  |.  59            pop ecx                                  ;  恢复ecx
0040105E  |.  C3            retn                                     ;  返回
0040105F  |>  68 30804000   push Test3.00408030                      ;  你输入的数字是0; Case 0 of switch 00401021
00401064  |.  E8 1E000000   call Test3.00401087                      ;  printf函数
00401069  |.  83C4 04       add esp,0x4                              ;  恢复esp
0040106C  |.  33C0          xor eax,eax                              ;  eax清零
0040106E  |.  59            pop ecx                                  ;  恢复ecx
0040106F  \.  C3            retn                                     ;  返回

switch语句基本框架:

cmp xx0,xx1       ;可以是test等
je  ;跳转执行体1  ;此处也可以是其他条件转移指令
cmp xx0,xx2
je ;跳转执行体2
cmp xx0,xx3
je ;跳转执行体3
...... ;默认执行体
retn
...... ;执行体1
retn
...... ;执行体2
retn
...... ;执行体3
retn

#include<stdio.h>
int main()
{
        int x,y=0;
        for(x=1;x<=100;x++)
        {
                y=x+y;
        }
        printf("%d",y);
        return 0;
}

上述程序通过for循环来计算1+2+3...+100的值

Debug版本:

0040F980 >/> \55            push ebp                                 ;  ebp入栈保存
0040F981  |.  8BEC          mov ebp,esp                              ;  保存esp到ebp
0040F983  |.  83EC 48       sub esp,0x48                             ;  开辟局部变量空间
0040F986  |.  53            push ebx                                 ;  ebx入栈保存
0040F987  |.  56            push esi                                 ;  esi入栈保存
0040F988  |.  57            push edi                                 ;  edi入栈保存
0040F989  |.  8D7D B8       lea edi,[local.18]                       ;  设置CC操作起始地址
0040F98C  |.  B9 12000000   mov ecx,0x12                             ;  设置循环地址
0040F991  |.  B8 CCCCCCCC   mov eax,0xCCCCCCCC                       ;  赋值eax CC  int 3
0040F996  |.  F3:AB         rep stos dword ptr es:[edi]              ;  循环复制CC
0040F998  |.  C745 F8 00000>mov [local.2],0x0                        ;  赋值变量y
0040F99F  |.  C745 FC 01000>mov [local.1],0x1                        ;  赋值变量x
0040F9A6  |.  EB 09         jmp short Test3.0040F9B1                 ;  跳转到for循环判断
0040F9A8  |>  8B45 FC       /mov eax,[local.1]                       ;  x的值放入eax
0040F9AB  |.  83C0 01       |add eax,0x1                             ;  eax加1
0040F9AE  |.  8945 FC       |mov [local.1],eax                       ;  自加1的值放入变量x
0040F9B1  |>  837D FC 64     cmp [local.1],0x64                      ;  判断x值是否为100
0040F9B5  |.  7F 0B         |jg short Test3.0040F9C2                 ;  相等就跳转
0040F9B7  |.  8B4D FC       |mov ecx,[local.1]                       ;  变量x值放入ecx
0040F9BA  |.  034D F8       |add ecx,[local.2]                       ;  x+y的值放入ecx
0040F9BD  |.  894D F8       |mov [local.2],ecx                       ;  把ecx的值放入变量y
0040F9C0  |.^ EB E6         \jmp short Test3.0040F9A8                ;  跳转到判断处
0040F9C2  |>  8B55 F8       mov edx,[local.2]                        ;  最终变量y的值放入edx
0040F9C5  |.  52            push edx                                 ; /<%d>
0040F9C6  |.  68 08604200   push Test3.00426008                      ; |format = "%d"
0040F9CB  |.  E8 D016FFFF   call Test3.printf                        ; \printf
0040F9D0  |.  83C4 08       add esp,0x8                              ;  恢复esp
0040F9D3  |.  33C0          xor eax,eax                              ;  eax清零
0040F9D5  |.  5F            pop edi                                  ;  恢复edi
0040F9D6  |.  5E            pop esi                                  ;  恢复esi
0040F9D7  |.  5B            pop ebx                                  ;  恢复ebx
0040F9D8  |.  83C4 48       add esp,0x48                             ;  恢复局部变量空间
0040F9DB  |.  3BEC          cmp ebp,esp                              ;  测试堆栈平衡
0040F9DD  |.  E8 9E17FFFF   call Test3._chkesp                       ;  调用调试信息
0040F9E2  |.  8BE5          mov esp,ebp                              ;  恢复esp
0040F9E4  |.  5D            pop ebp                                  ;  恢复ebp
0040F9E5  \.  C3            retn                                     ;  返回  ret   add esp,4

for基本循环框架:
jmp  ;无条件跳转到条件判断语句
.... ;for循环条件
cmp  ;判断是否满足条件 ;可以是其他条件测试指令
jg ;如果不满足就跳出for循环;可以是其他条件转移指令
.... ;for循环执行体
jmp ;无条件跳转到for循环条件

Release版本:

00401000  /$  33C9          xor ecx,ecx                              ;  ecx清零,作为计数器
00401002  |.  B8 01000000   mov eax,0x1                              ;  eax初始化为为1
00401007  |>  03C8          /add ecx,eax                             ;  eax加上ecx的值放入ecx中
00401009  |.  40            |inc eax                                 ;  eax自加1
0040100A  |.  83F8 64       |cmp eax,0x64                            ;  判断是否为100
0040100D  |.^ 7E F8         \jle short Test3.00401007                ;  如不为100就跳转
0040100F  |.  51            push ecx                                 ;  参数入栈
00401010  |.  68 30704000   push Test3.00407030                      ;  ASCII "%d"
00401015  |.  E8 06000000   call Test3.00401020                      ;  printf函数
0040101A  |.  83C4 08       add esp,0x8                              ;  恢复esp
0040101D  |.  33C0          xor eax,eax                              ;  eax清零
0040101F  \.  C3            retn                                     ;  返回

for基本循环框架:

......  ;初始化各个参数
jle ;判断是否满足条件
......  ;跳出循环
___________________________________________________________________________________________________

本节主要对程序的流程化控制做逆向分析,此节对以后无论是逆向还是病毒分析都极其重要,下半节更新,while,do-while,goto语句

 

posted @ 2014-11-26 17:39  我是小三  阅读(240)  评论(0)    收藏  举报