反汇编分析--寄存器状态

一直对反汇编分析代码有兴趣,但是一直没静下心来研究一下,昨天腾讯笔试,有一题就是考察大端小端模式(见下面C代码段),涉及到函数调用,大端小端模式前些时间复习过,但是即便如此,做的时候还是感觉思路不清,回头想想,一是对函数调用中栈的变化过程不甚了解,一是对long long结构不了解,而如果我知道如何反汇编的话,可以直接在调试过程中解开疑虑,这样就不用盲目地在网上搜集了。因此我决定这些天弄一弄反汇编。

在VS2008中反汇编很容易,进入debug模式之后,在代码区域“右键->反汇编” 或者“调试->窗口->反汇编” 就可以看到程序对应的汇编代码,同样的方式“调试->窗口->寄存器” 就可以查看寄存器的状态。

 

/*-----------------lp横刀立马------------------------------
-----------------腾讯2013春季实习生笔试4.13---------------------
题目描述:代码如下,win32 环境,CPU小端模式,参数用栈来传递,请问输出--

*/
#include <stdio.h>

int main()
{
    long long a=1;
    long long b=2;
    long long c=3;

    printf("%d%d%d",a,b,c);
}

VS2008反汇编代码如下:

#include <stdio.h>

int main()
{
00D813B0  push        ebp  
00D813B1  mov         ebp,esp 
00D813B3  sub         esp,0F0h 
00D813B9  push        ebx  
00D813BA  push        esi  
00D813BB  push        edi  
00D813BC  lea         edi,[ebp-0F0h] 
00D813C2  mov         ecx,3Ch 
00D813C7  mov         eax,0CCCCCCCCh 
00D813CC  rep stos    dword ptr es:[edi] 
/* 说明: rep 表示重复,重复的次数由ecx决定,在执行这一句话的过程中,ecx自动减小直至为零,这也是为什么ecx叫做计数器
另外,stos表示将edi指向的内容写成eax中的值,rep过程中edi自动增加,从这个行为也可以感受到为什么edi叫做目标变址寄存器*/
long long a=
1; 00D813CE mov dword ptr [a],1 00D813D5 mov dword ptr [ebp-8],0
/* long long 类型占8个字节,而双字是4个字节,所以要分两次写入,可以看出,栈顶在低地址,栈底在高地址,push操作对应着esp的减小 */
long long b=
2; 00D813DC mov dword ptr [b],2 00D813E3 mov dword ptr [ebp-18h],0
/*为啥这里是ebp-18h?不是只需要8个字节就够了吗?*/ long long c=
3; 00D813EA mov dword ptr [c],3 00D813F1 mov dword ptr [ebp-28h],0 printf("%d%d%d",a,b,c); 00D813F8 mov esi,esp 00D813FA mov eax,dword ptr [ebp-28h] 00D813FD push eax 00D813FE mov ecx,dword ptr [c] 00D81401 push ecx 00D81402 mov edx,dword ptr [ebp-18h] 00D81405 push edx 00D81406 mov eax,dword ptr [b] 00D81409 push eax 00D8140A mov ecx,dword ptr [ebp-8] 00D8140D push ecx 00D8140E mov edx,dword ptr [a] 00D81411 push edx 00D81412 push offset string "%d%d%d" (0D8573Ch) 00D81417 call dword ptr [__imp__printf (0D882BCh)] 00D8141D add esp,1Ch 00D81420 cmp esi,esp 00D81422 call @ILT+310(__RTC_CheckEsp) (0D8113Bh) } 00D81427 xor eax,eax 00D81429 pop edi 00D8142A pop esi 00D8142B pop ebx 00D8142C add esp,0F0h 00D81432 cmp ebp,esp 00D81434 call @ILT+310(__RTC_CheckEsp) (0D8113Bh) 00D81439 mov esp,ebp 00D8143B pop ebp 00D8143C ret

 

反汇编的过程如果不懂每个寄存器分别是干啥的,无异于没学单词就开始念英文,那么今天就存寄存器开始吧。先进行一个简要的概述,然后挨个分析。

1.寄存器组概述

数据寄存器:保存操作数和运算结果等信息。
    EAX:Accumulator。函数返回值。取低16位为AX,分割为8位寄存器AH-AL。指令ret返回用到。
    EBX:Base Register。
    ECX:Count Register。
    EDX:Data Register。

指针寄存器:EBP,ESP可作为通用寄存器,即可存储算术逻辑运算的操作数和运算结果。
    EBP:Base Pointer,基指针寄存器,直接访问栈中的数据。
    ESP:Stack Pointer,栈指针寄存器,只可访问栈顶。指令pop/push时自动变。
    EIP:Instruction Pointer,指令指针寄存器,存放下次将要执行的指令在代码段中的偏移量。每走一条指令自动变一次,如果希望跳转后能返回继续就需要跳转前把它放入栈中,返回时出栈。

变址寄存器:主要用于存放存储单元在段内的偏移量。
    ESI: Source Index,源变址寄存器。EDS:ESI即源串段寄存器:源串变址,ESI在串操作中自动增减。
    EDI:Destination Index,目标变址寄存器。EES:EDI即目标串段寄存器:目标串变址,EDI在串操作中自动增减。

段寄存器:内存分段。这里最多为6个内存段,不同的内存段放入不同的东西。
    ECS:Code Segment Register,代码段寄存器。
    EDS:Data Segment Register,数据段寄存器。
    EES:Extra Segment Register,附加段寄存器。
    ESS:Stack Segment Register,栈段寄存器。
    EFS:Extra Segment Register,附加段寄存器。
    EGS:Extra Segment Register,附加段寄存器。

2.EBP 和 ESP

最简单的说法是:EBP 指向栈底 ,ESP指向栈顶。

分析一段简短的c代码

void Layer02()
{
       int b = 2;
}
 
void Layer01()
{
       int a = 1;
       Layer02();
}

其反汇编代码如下:

void Layer02()
{
00413700 push        ebp 
00413701 mov         ebp,esp
00413703 sub         esp,0CCh
00413709 push        ebx 
0041370A push        esi 
0041370B push        edi 
0041370C lea         edi,[ebp-0CCh]
00413712 mov         ecx,33h
00413717 mov         eax,0CCCCCCCCh
0041371C rep stos    dword ptr es:[edi]
       int b = 2;
0041371E mov         dword ptr [b],2
}
00413725 pop         edi 
00413726 pop         esi 
00413727 pop         ebx 
00413728 mov         esp,ebp
0041372A pop         ebp 
0041372B ret

如上,可以看到,这几段函数调用反汇编代码的头两句都是一样的,调用时先保存栈底指针,在将栈底指针设为栈顶指针,此时的栈底就为被调用函数的栈的栈底。

push ebp
mov ebp ,esp

 

结尾也都是一样的,一旦调用完毕,栈底栈顶都恢复到调用之前的状态。

mov esp,ebp
pop ebp
ret

上面代码是参考solidMango的博客 ,里面的配图简单形象,可以参考。

 

3.EDI ,ESI 

ESI/EDI 分别叫做"源/目标索引寄存器"(source/destination index),因为在很多字符串操作指令中, DS:ESI指向源串,而ES:EDI指向目标串.

 

4.EAX,EBX,ECX,EDX

EAX 是"累加器"(accumulator), 它是很多加法乘法指令的缺省寄存器。

EBX 是"基地址"(base)寄存器, 在内存寻址时存放基地址。

ECX 是计数器(counter), 是重复(REP)前缀指令和LOOP指令的内定计数器。

EDX 则总是被用来放整数除法产生的余数。

 

 

 经过这么一分析,可以知道,这一题的结果实际为102

 

参考网址:博客园--石头儿   C++内嵌汇编 

posted @ 2013-04-14 15:58  曾见绝美的阳光  阅读(781)  评论(0编辑  收藏  举报