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

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



————————————————————————————————————————————————
正文部分:
       本节主要从汇编层面来全面解析基本的数据类型和运算符,如下:
___________________________________________________________________________________________________
本帖隐藏的内容
  1. #include<stdio.h>
  2. int main()
  3. {
  4.         int a,b,c,s;
  5.         scanf("%d%d%d",&a,&b,&c);
  6.         s=a+b+c;
  7.         printf("%d",s);
  8.         return 0;
  9. }
复制代码

_______________________________________________________________________________________________________
       上面的源码是一个简单的三角形求周边的程序,好了,直接复制到VC++6.0中选择Debug方式编译生成,直接载入OD,来到main函数:
Debug版本:
00401010 >|> \55            push ebp                                 ;  保存ebp
00401011  |.  8BEC          mov ebp,esp                              ;  保存esp到ebp
00401013  |.  83EC 50       sub esp,0x50                             ;  开辟局部变量空间
00401016  |.  53            push ebx                                 ;  入栈ebx
00401017  |.  56            push esi                                 ;  入栈esi
00401018  |.  57            push edi                                 ;  入栈edi
00401019  |.  8D7D B0       lea edi,[local.20]                       ;  设置初始化内存地址
0040101C  |.  B9 14000000   mov ecx,0x14                             ;  设置循环次数
00401021  |.  B8 CCCCCCCC   mov eax,0xCCCCCCCC                       ;  赋值eax int 3中断
00401026  |.  F3:AB         rep stos dword ptr es:[edi]              ;  循环复制int 3
00401028  |.  8D45 F4       lea eax,[local.3]                        ;  变量c的内存地址放到eax
0040102B  |.  50            push eax                                 ;  入栈c的地址
0040102C  |.  8D4D F8       lea ecx,[local.2]                        ;  变量b地址放到eax
0040102F  |.  51            push ecx                                 ;  入栈b的地址
00401030  |.  8D55 FC       lea edx,[local.1]                        ;  变量a地址放到eax
00401033  |.  52            push edx                                 ;  入栈a的地址
00401034  |.  68 20504200   push Test2.00425020                      ; /format = "%d%d%d"
00401039  |.  E8 D2000000   call Test2.scanf                         ; \scanf
0040103E  |.  83C4 10       add esp,0x10                             ;  恢复esp的值  4个push
00401041  |.  8B45 FC       mov eax,[local.1]                        ;  变量a的值放入eax
00401044  |.  0345 F8       add eax,[local.2]                        ;  变量b的值加上a的和放入eax中
00401047  |.  0345 F4       add eax,[local.3]                        ;  变量c的值加上ab的和放入eax
0040104A  |.  8945 F0       mov [local.4],eax                        ;  把abc的和放入变量s中
0040104D  |.  8B4D F0       mov ecx,[local.4]                        ;  变量s的值放入ecx
00401050  |.  51            push ecx                                    ; /<%d>
00401051  |.  68 1C504200   push Test2.0042501C                      ; |format = "%d"
00401056  |.  E8 35000000   call Test2.printf                        ; \printf
0040105B  |.  83C4 08       add esp,0x8                              ;  恢复esp,2个push
0040105E  |.  33C0          xor eax,eax                              ;  eax清零
00401060  |.  5F            pop edi                                  ;  恢复寄存器edi
00401061  |.  5E            pop esi                                  ;  恢复寄存器esi
00401062  |.  5B            pop ebx                                  ;  恢复寄存器ebx
00401063  |.  83C4 50       add esp,0x50                             ;  恢复局部变量空间
00401066  |.  3BEC          cmp ebp,esp                              ;  测试esp值是否与之前一致
00401068  |.  E8 03010000   call Test2._chkesp                       ;  如esp值不一致,调用调试信息
0040106D  |.  8BE5          mov esp,ebp                              ;  恢复esp值
0040106F  |.  5D            pop ebp                                  ;  恢复ebp
00401070  \.  C3            retn                                     ;  返回 等于ret加上add esp,4

       和之前的Hello World大同小异,相信大家看起来都没问题,我希望大家能记熟这种框架模式,对以后逆向的深入有很大用处,我们再来看看 Release版本的:
Release版本:
00401000  /$  83EC 0C       sub esp,0xC                              ;  开辟局部变量空间
00401003  |.  8D4424 08     lea eax,dword ptr ss:[esp+0x8]           ;  把变量c的地址放入eax
00401007  |.  8D4C24 04     lea ecx,dword ptr ss:[esp+0x4]           ;  把变量b的地址放入ecx
0040100B  |.  8D5424 00     lea edx,dword ptr ss:[esp]               ;  把变量a的地址放入edx
0040100F  |.  50            push eax                                 ;  入栈c的地址
00401010  |.  51            push ecx                                 ;  入栈b的地址
00401011  |.  52            push edx                                 ;  入栈a的地址
00401012  |.  68 34804000   push Test2.00408034                      ;  ASCII "%d%d%d"
00401017  |.  E8 55000000   call Test2.00401071                      ;  调用scanf函数
0040101C  |.  8B4424 10     mov eax,dword ptr ss:[esp+0x10]          ;  把a的值放入eax
00401020  |.  8B4C24 14     mov ecx,dword ptr ss:[esp+0x14]          ;  把b的值放入ecx
00401024  |.  03C1          add eax,ecx                              ;  a+b的和放入eax中
00401026  |.  8B4C24 18     mov ecx,dword ptr ss:[esp+0x18]          ;  把c的值放入ecx
0040102A  |.  03C1          add eax,ecx                              ;  c的值和ab的和放入eax中
0040102C  |.  50            push eax                                 ;  入栈三数之和
0040102D  |.  68 30804000   push Test2.00408030                      ;  ASCII "%d"
00401032  |.  E8 09000000   call Test2.00401040                      ;  调用printf函数
00401037  |.  33C0          xor eax,eax                              ;  eax清零
00401039  |.  83C4 24        add esp,0x24                             ;  恢复esp   
0040103C  \.  C3            retn                                     ;  返回  等于ret  add esp,4

            大家可能不理解的就是最后的 add esp,0x24,OK,先看下入口处的sub esp,0xC,注意次数是十六进制,大家都知道一个push操作,eap就相当于sub esp,4 此处共6个push,所以这里的值等于6个push的值 0x18加上sub esp,0xc 的 0xC 正好是 0x24,有疑问的大家可以试试在源码中多添加一个push操作来看看此处add esp的值!
_______________________________________________________________________________________________________
#include<stdio.h>
int main()
{
short int a=1;
int b=2;
long int c=3;
float d=1.222;
double e=1.333;
long double f=1.234;
char g='a';
char *h;
h=&g;
return 0;
}
_______________________________________________________________________________________________________

       上面这段简单的源码中,涉及了很多基本数据类型,如:int整型 ,float单精度浮点型,double双精度浮点型,char字符型,指针类型,本节重要点就是来分析这些基本数据类型在汇编中的表现形式,先看下Debug版本的:

Debug版本:
00401250 >/> \55            push ebp                                 ;  保存ebp
00401251  |.  8BEC          mov ebp,esp                              ;  保存esp到ebp
00401253  |.  83EC 68       sub esp,0x68                             ;  开辟局部变量空间
00401256  |.  53            push ebx                                 ;  入栈ebx
00401257  |.  56            push esi                                 ;  入栈esi
00401258  |.  57            push edi                                 ;  入栈edi
00401259  |.  8D7D 98       lea edi,[local.26]                       ;  设置初始化局部变量地址
0040125C  |.  B9 1A000000   mov ecx,0x1A                             ;  设置循环次数
00401261  |.  B8 CCCCCCCC   mov eax,0xCCCCCCCC                       ;  赋值eax int 3中断
00401266  |.  F3:AB         rep stos dword ptr es:[edi]              ;  循环复制int3
00401268  |.  66:C745 FC 01>mov word ptr ss:[ebp-0x4],0x1            ;  赋值1到局部变量short int类型a中,参数:word  16位
0040126E  |.  C745 F8 02000>mov [local.2],0x2                        ;  赋值2到局部变量int类型b中,参数:dword  32位
00401275  |.  C745 F4 03000>mov [local.3],0x3                        ;  赋值3到局部变量float类型c中,参数:dword  32位
0040127C  |.  C745 F0 7F6A9>mov [local.4],0x3F9C6A7F                 ;  赋值0x3F9DF3B6到局部变量float类型d中,参数:dword  32位
00401283  |.  C745 E8 8716D>mov [local.6],0xCED91687                 ;  存放低位
0040128A  |.  C745 EC F753F>mov [local.5],0x3FF553F7                 ;  double类型e 存放高位  参数:qword 64位
00401291  |.  C745 E0 5839B>mov [local.8],0xC8B43958                 ;  存放低位
00401298  |.  C745 E4 76BEF>mov [local.7],0x3FF3BE76                 ;  long double类型f 存放高位  参数:qword 64位
0040129F  |.  C645 DC 61    mov byte ptr ss:[ebp-0x24],0x61          ;  char类型g Ascll码的a对应0x61  参数:byte 8位
004012A3  |.  8D45 DC       lea eax,[local.9]                        ;  获取字符变量地址到eax
004012A6  |.  8945 D8       mov [local.10],eax                       ;  把eax放入指针中h中
004012A9  |.  33C0          xor eax,eax                              ;  eax清零
004012AB  |.  5F            pop edi                                  ;  出栈edi
004012AC  |.  5E            pop esi                                  ;  出栈esi
004012AD  |.  5B            pop ebx                                  ;  出栈ebx
004012AE  |.  8BE5          mov esp,ebp                              ;  恢复esp
004012B0 >|.  5D            pop ebp                                  ;  恢复ebp
004012B1  \.  C3            retn                                     ;  返回 等于ret add esp,4

       分析前,我们先普及一下计算机微计量单位, 位bit    即10101010   每个数为1位, 字节byte 即大家看到的文件大小字节,一个字节等于8位, 字word  1个字等于2个字节即16位  双字Dword  1个双字等于2个字,即32位  eax寄存器就是32位,4字qword  同理就是64位!当然还有更大的,我们这里不做描述!
        short int 类型为16位故:mov word ptr ss:[ebp-0x4],0x1    int类型为32位,故:mov [local.2],0x2    默认就是32位,double为64位,就会使用2个32位来存放,即一个存放高位,一个低位!例如这句:double e=1.333; 1.333在内存中是以IEEE编码来存储,1.333对应的IEEE是3FF553F7CED91687,故会出现这两句汇编指令:mov [local.6],0xCED91687    mov [local.5],0x3FF553F7,Ascll码的0x61对应的就是小写字母a,好了,看下Release版


Release版本:
00401000  /$  33C0          xor eax,eax         ;  eax清零
00401002  \.  C3            retn         ;  返回  等于ret  add esp,4
这些变量未参数实际使用,Release会自动优化掉!
_______________________________________________________________________________________________________

  1. #include < stdio.h > 
  2. int main() 
  3. {
  4.     int a = 2,
  5.     b = 4,
  6.     c;
  7.     c = a + b;
  8.     c = a * b;
  9.     c = a / b;
  10.     c = a % b;
  11.     c = a && b;
  12.     c = a || b;
  13.     c = !b;
  14.     c++;
  15.     c--;
  16.     return 0;
  17. }
复制代码

______________________________________________________________________________________________________

Debug版本:
00410680 >/> \55            push ebp                                 ;  ebp入栈保存
00410681  |.  8BEC          mov ebp,esp                              ;  保存esp
00410683  |.  83EC 54       sub esp,0x54                             ;  开辟局部变量空间
00410686  |.  53            push ebx                                 ;  入栈ebx
00410687  |.  56            push esi                                 ;  入栈esi
00410688  |.  57            push edi                                 ;  入栈edi
00410689  |.  8D7D AC       lea edi,[local.21]                       ;  设置初始化局部变量地址
0041068C  |.  B9 15000000   mov ecx,0x15                             ;  循环次数
00410691  |.  B8 CCCCCCCC   mov eax,0xCCCCCCCC                       ;  赋值eax int 中断
00410696  |.  F3:AB         rep stos dword ptr es:[edi]              ;  循环复制int 3 中断
00410698  |.  C745 FC 05000>mov [local.1],0x5                        ;  赋值2到变量a
0041069F  |.  C745 F8 02000>mov [local.2],0x2                        ;  赋值4到变量b
004106A6  |.  8B45 FC       mov eax,[local.1]                        ;  赋值a的值到eax
004106A9  |.  0345 F8       add eax,[local.2]                        ;  b的值与a的值相加放入eax
004106AC  |.  8945 F4       mov [local.3],eax                        ;  ab的和放入变量c
004106AF  |.  8B4D FC       mov ecx,[local.1]                        ;  赋值a的值到ecx
004106B2  |.  0FAF4D F8     imul ecx,[local.2]                       ;  变量b与变量a的乘积放入ecx
004106B6  |.  894D F4       mov [local.3],ecx                        ;  ab的积值放入变量c
004106B9  |.  8B45 FC       mov eax,[local.1]                        ;  赋值a的值到eax
004106BC  |.  99            cdq                                      ;  双字32位扩展到64位,eax的高位放入edx中
004106BD  |.  F77D F8       idiv [local.2]                           ;  除法运算   idiv无符号除法
004106C0  |.  8945 F4       mov [local.3],eax                        ;  ab的商放入变量c
004106C3  |.  8B45 FC       mov eax,[local.1]                        ;  赋值a的值到eax
004106C6  |.  99            cdq                                      ;  双字32位扩展到64位,eax的高位放入edx中
004106C7  |.  F77D F8       idiv [local.2]                           ;  除法运算   idiv无符号除法
004106CA  |.  8955 F4       mov [local.3],edx                        ;  ab的余数放入变量c
004106CD  |.  837D FC 00    cmp [local.1],0x0                        ;  与运算,测试变量a是否为0,如为0就跳转
004106D1  |.  74 0F         je short Test2.004106E2                  ;  a值不为0,未发生跳转
004106D3  |.  837D F8 00    cmp [local.2],0x0                        ;  与运算,测试变量b是否为0,如为0就跳转
004106D7  |.  74 09         je short Test2.004106E2                  ;  b值不为0,未发生跳转
004106D9  |.  C745 F0 01000>mov [local.4],0x1                        ;  与运算为真
004106E0  |.  EB 07         jmp short Test2.004106E9                 ;  无条件跳转
004106E2  |>  C745 F0 00000>mov [local.4],0x0
004106E9  |>  8B55 F0       mov edx,[local.4]                        ;  与运算值放入edx
004106EC  |.  8955 F4       mov [local.3],edx                        ;  ab的与运算值放入变量c
004106EF  |.  837D FC 00    cmp [local.1],0x0                        ;  或运算,测试变量a是否为0,如不等于0就跳转
004106F3  |.  75 0F         jnz short Test2.00410704                 ;  a值不为0,发生跳转
004106F5  |.  837D F8 00    cmp [local.2],0x0
004106F9  |.  75 09         jnz short Test2.00410704
004106FB  |.  C745 EC 00000>mov [local.5],0x0
00410702  |.  EB 07         jmp short Test2.0041070B
00410704  |>  C745 EC 01000>mov [local.5],0x1                  ;  ab或运算为真
0041070B  |>  8B45 EC       mov eax,[local.5]                        ;  或运算值放入edx
0041070E  |.  8945 F4       mov [local.3],eax                        ;  ab的或运算值放入变量c
00410711  |.  33C9          xor ecx,ecx                              ;  ecx清零
00410713  |.  837D F8 00    cmp [local.2],0x0                        ;  求反运算,测试变量b是否为0
00410717  |.  0F94C1        sete cl                                  ;  依据zf标志位的值设置cl的值
0041071A  |.  894D F4       mov [local.3],ecx                        ;  b逻辑取反的值放入变量c
0041071D  |.  8B55 F4       mov edx,[local.3]                        ;  变量c的值放入edx
00410720  |.  83C2 01       add edx,0x1                              ;  edx自加1
00410723  |.  8955 F4       mov [local.3],edx                        ;  edx的值放入变量c
00410726  |.  8B45 F4       mov eax,[local.3]                        ;  变量c的值放入eax
00410729  |.  83E8 01       sub eax,0x1                              ;  eax自减1
0041072C  |.  8945 F4       mov [local.3],eax                        ;  eax的值放入变量c
0041072F  |.  33C0          xor eax,eax                              ;  eax清零
00410731  |?  5F            pop edi         ;  恢复edi
00410732  |.  5E            pop esi                                  ;  恢复esi
00410733  |?  5B            pop ebx         ;  恢复ebx
00410734  |?  8BE5          mov esp,ebp         ;  恢复esp的值
00410736  |?  5D            pop ebp         ;  恢复ebp
00410737  |?  C3            retn         ;  返回  等于ret add esp,4
       上述每条汇编指令的注释我写的都很详细,大家可以对照源码来看,注意 cdq指令 ,重点看下理解乘除法运算,以及逻辑运算!Release版本同上。

Release版本:
00401000  /$  33C0          xor eax,eax
00401002  \.  C3            retn

这些变量未参数实际使用,Release会自动优化掉!
_______________________________________________________________________________________________________

         本节中,肯定没有全面涉及数据类型和运算符,这里只做为一种分析的方法,各位私下多练习下这些基础,吃透吃熟,对以深入后尤关重要!至于逻辑判断,下节我会详细介绍。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值