吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 18190|回复: 21
收起左侧

[原创] 菜鸟学逆向——简单的反汇编阅读与逆向(1)

  [复制链接]
cu629944 发表于 2012-4-1 13:18
本帖最后由 cu629944 于 2012-4-1 13:20 编辑

  【文章标题】: 菜鸟学逆向——简单的反汇编阅读与逆向(1)
  【文章作者】: Silence(cu629944,等试用期通过,我会修改ID为Silecne)
  【作者邮箱】: mohen_ng@sina.cn
  【下载地址】: 自己搜索下载
  【编写语言】: VC++6.0
  【操作平台】: WIN 7
  【软件介绍】: IDA VC++6.0
  【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
  --------------------------------------------------------------------------------
  【详细过程】
    我会写一个系列的文,希望大家能够支持,这是第一篇  

    我们先启动VC++6.0,输入下面的程序

    程序很短,大家看我输入一次,留意成对编码原则,防止对低级的错误

 #include <stdio.h>
    void Silence(int a,int b)
    {
            int c =a + b; 
    }
    void main()
    {
            Silence(1,2);
    }

    一个简单的有2个形参的Silence()函数,接着在main()主函数调用Silence()函数。

    编译成Debug模式,Realse版本会把调试信息等去掉。

    我们用VC6.0自带的调试器,复制一个反汇编代码出来(为什么不立即用IDA看呢?因为VC6.0会把源码和反汇编代码一一对应起来,方便我们在IDA对照查看)

  
void main()
    9:    {
    00401060   push                ebp                        
    00401061   mov                ebp,esp
    00401063   sub                 esp,40h
    00401066   push                ebx
    00401067   push                esi
    00401068   push                edi
    00401069   lea                 edi,[ebp-40h]
    0040106C   mov               ecx,10h
    00401071   mov                eax,0CCCCCCCCh
    00401076   rep stos     dword ptr [edi]
    10:       Silence(1,2);
    00401078   push               2
    0040107A   push               1
    0040107C   call                @ILT+5(_Silence) (0040100a)
    00401081   add                 esp,8
    11:   }
    00401084   pop         edi
    00401085   pop         esi
    00401086   pop         ebx
    00401087   add         esp,40h
    0040108A   cmp        ebp,esp
    0040108C   call       __chkesp (004010b0)
    00401091   mov        esp,ebp
    00401093   pop        ebp
    00401094   ret

    然后我们载入IDA里面。IDA非常智能,载入分析完成后,直接停到了我们的main()函数处。我们就离线分析下他的每句话的作用。

 ; Attributes: bp-based frame

    _main proc near

    var_40= byte ptr -40h

    push    ebp             ; 保存EBP
    mov     ebp, esp        ; 原EBP值已经被压栈(位于栈顶),而新的EBP又恰恰指向栈顶。
                            ; 此时EBP寄存器就已经处于一个非常重要的地位,该寄存器中存储着栈中的一个地址(原EBP入栈后的栈顶),
                            ; 从该地址为基准,向上(栈底方向)能获取返回地址、参数值,向下(栈顶方向)能获取函数局部变量值,
                            ; 而该地址处又存储着上一层函数调用时的EBP值!
    sub     esp, 40h        ; 为局部变量申请空间,大小为40h(注意40h是16进制数,用IDA看看转换成10进制为多少,为64)
    push    ebx
    push    esi
    push    edi
    lea     edi, [ebp-40h]  ; Var_40是IDA自己分析出来的,表示为局部变量,就是SUB ESP,40h分配的40h个大小,目的是保存局部变量的区域
    mov     ecx, 10h
    mov     eax, 0CCCCCCCCh ; 从ebp-40h开始的区域初始化成全部0CCCCCCCCh,就是int3断点
    rep stosd               ; 拷贝字符串,初始化局部变量空间
                            ; 以上的语句就是在栈中开辟一块空间放局部变量
                            ; 然后把这块空间都初始化为0CCCCCCCCh,就是int3断点,一个中断指令。
                            ; 因为局部变量不可能被执行,执行了就会出错,这时候发生中断提示开发者。
    push    2               ;
                            ; 参数2入栈
                            ; 这里就是我们在test.c的源代码里面写的那个Silence(1,2);函数,这里有一个很重要的概念
                            ; 就是调用约定,在 c/c++ 中, 函数的默认调用约定为 cdecl, 它约定参数从右到左入栈,
                            ; 由调用者清理堆栈, 所谓清理, 即调整ESP的值, 使得原来的局部数据不再属于栈
                            ;
    push    1               ; 参数1入栈
                            ;
    call    Func__Silence   ; 调用我们定义的Silence函数
                            ; 其实call 指令调用一个过程, 但它有一个小动作
                            ; 在参数入栈以后, 被调用函数执行 之前, 它会将当前函数的下一条指令地址, 即EIP的值压入
                            ;
    add     esp, 8          ; 调用完函数后恢复/释放栈
    pop     edi             ; 以下三句都是恢复三个保存的寄存器
    pop     esi
    pop     ebx
    add     esp, 40h        ; 这句对应的是上面的SUB ESP,40h,恢复堆栈,
    cmp     ebp, esp        ; 检测ESP是否恢复正常,如果不正常将调用下面的Chkesp
    call    __chkesp        ; 处理可能出现的堆栈错误(如果出错,将陷入debug)。
    mov     esp, ebp        ; 还记得上面那句mov ebp,esp吗?EBP里面保存着我们初始状态的ESP值,这句是将栈顶指针放回esp
    pop     ebp             ; 恢复原来的ebp和esp,让上一个调用的函数正常使用
    retn                    ; 将返回地址存入EIP, 转移流程
    _main endp              ;
                            ; 以上那部分代码在VC的Debug调试版才会有,主要检查栈是否被破坏了。这样就能及时在你出错的地方停下了告诉你。
                            ; 发行版自动消除这些代码(调试产生的)。
                            ; 如果函数有返回值,返回值将放在eax返回(这就是很多软件给秒杀爆破的原因了,因为eax的返回值是可以改的)
    下面来看看Silence()函数

 ; Attributes: bp-based frame

    _Silence proc near

    var_44= byte ptr -44h
    var_4= dword ptr -4
    arg_0= dword ptr  8
    arg_4= dword ptr  0Ch

    push    ebp             ; 下面的这几句和上面我们分析的一样,所以我们对Silence函数只分析不同的地方
    mov     ebp, esp
    sub     esp, 44h        ; 这里将局部变量的大小分配为44h
    push    ebx
    push    esi
    push    edi
    lea     edi, [ebp-44h]
    mov     ecx, 11h
    mov     eax, 0CCCCCCCCh
    rep stosd
    mov     eax, [ebp+8]    ; 取第一个参数放到EAX里面,即参数a
    add     eax, [ebp+0Ch]  ; 与保存在EBP+0Ch里面的参数b相加
    mov     [ebp-4], eax    ; 返回值放到ebp - 4里面,即最终结果放到参数c里面
                            ;
                            ; 一般而言,ss:[ebp+4]处为返回地址
                            ; ss:[ebp+8]处为第一个参数值(这里是a),ss:[ebp+0Ch]处为第二个参数(这里是b,这里8+4=12=0Ch)
                            ; ss:[ebp-4]处为第一个局部变量(这里是c),ss:[ebp]处为上一层EBP值
                            ; ebp和函数返回值是32位,所以占4个字节
    pop     edi
    pop     esi
    pop     ebx
    mov     esp, ebp
    pop     ebp
    retn
    _Silence endp

    到此处,我们就将这些代码翻译完毕了。有很多收获。

    根据我们这些分析,我们就可以逆向出我们的源码了(只看IDA反汇编的部分哈!):


    我们可以在IDA里面看到main函数没有返回值,和Cdecl调用约定的规则,我们就可以恢复出来main函数的代码。

  void main()
    {
        Silence(1,2);
    }
    我们分析Silecne函数的反汇编代码,可以看出在每个局部变量里面,都是用的[EBP - 4],[EBP + 8] ,[EBP + 0Ch]等,我们可以发现都是4的倍数,我们知道INT类型,占4个字节,且这个函数有三个参数,而且也没有返回值,下面我们就可以恢复Silence的函数部分的代码:

 void  Silence(int a,int b)
    {
          int c = a + b;
    } 
    然后我们整理下,就可以得到完整的代码:

   void Silence(int a,int b)
    {
         int c = a +b;
    }

    void main()
    {
        Silence(1,2);
    }

  --------------------------------------------------------------------------------
  【经验总结】
    里面讲了比较重要的,调用约定,大家可以百度下看看什么叫做调用约定。还有局部变量等是怎么在汇编中存在的,已经返回值的保存地址,及如何对返回值修改达到对程序的爆破。这就是一个简单的反汇编阅读和逆向了。我们可以恢复出我们的代码。

  --------------------------------------------------------------------------------
  【版权声明】: 本文原创于吾爱破解技术论坛, 转载请注明作者并保持文章的完整, 谢谢!

                                                         2012年04月01日 11:38:05



免费评分

参与人数 6热心值 +6 收起 理由
吾爱破解账号 + 1 已答复!
liuxuda + 1 谢谢@Thanks!
水云陆上飘 + 1 我很赞同!
Emil + 1 又被你强迫评分了!~哎 不过对得起我的份
pking5465 + 1 谢谢@Thanks!
又一菜鸟 + 1 已答复!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

wgz001 发表于 2012-4-1 13:25
期待后续  
又一菜鸟 发表于 2012-4-1 13:36
formore 发表于 2012-4-1 14:00
willJ 发表于 2012-4-1 15:05
LZ可以将几种调用约定都讲下就更好了,不错的文章
夏若 发表于 2012-4-1 17:50
膜拜,给我加分!

点评

你啥时候在52注册账号呢……  发表于 2012-4-1 17:52
明次 发表于 2012-4-1 19:42
好,支持笨笨阿姨
12394613643 发表于 2012-4-1 20:08
实用的教程
0#1 发表于 2012-4-1 20:26
支持原创,期待后续
pking5465 发表于 2012-4-2 11:34
先压箱底,以后绝对能用上   感谢原创
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-11-17 22:43

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表