飘云阁

 找回密码
 加入我们

QQ登录

只需一步,快速开始

查看: 4964|回复: 5

[原创] 逆向分析入门之for循环

[复制链接]

该用户从未签到

发表于 2007-11-12 21:13:43 | 显示全部楼层 |阅读模式
回想一下,从毕业后到现在,学编程有三年了,这三年来学了很多的东西,网络安全的知识面算是有了,可是却发现没有一样擅长的,于是乎打算找一样专攻,想来想去还是觉得逆向分析比较好,吸星大法嘛,哈哈.
    这篇文章我个人感觉是非常简单的逆向分析的文章,所以高手就不要见笑啊.当然它还是需要一定的基础的,比如什么叫入栈,什么叫出栈,什么叫栈顶,如果这些都不清楚的话,估计还是会看不懂.之所以抽时间写下来,一是为了记录一下自已的成长过程,二是为了把学习结果总结一下和大家分享.
    OK,废话不多说了,文章开始.

; ========================================================================
; 作者:∮明天去要饭
; Blog: http://hi.baidu.com/kgdiwss
; 论坛: http://bbs.80dnst.com
; ========================================================================

源代码:
#include <stdio.h>

int main(int argc, char *argv[])
{
    for(int i = 0; i < 10; i++)
    {
       printf("i = %d\n", i);
     }
     return 0;
}
  
用VC6.0的cl.exe编译,命令如下:

cl.exe for1.cpp

就可以得到for1.exe了(见附件)
然后用 IDA5.0.0.879 反汇编后的代码:

.text:00401000 ; int __cdecl main(int argc,const char **argv,const char *envp)
                         ; 从 00401000 这一行代码可以看出来, c的缺省入栈方式是 __cdecl ,即调用者调整堆栈 .
                         ; char *argv[] 变成了 char **argv ,说明 argv 是一个指针的指针
                         ; 反汇编后还多了一个参数: const char *envp
               
.text:00401000 _main           proc near               ; CODE XREF: start+AF↓p
.text:00401000
.text:00401000 var_4           = dword ptr -4        ; 这个变量偏移是-4,即在基地址上方.在基址上方的比较可能是局部变量
                                                                           ; 这里把内存用高址和低址来表示,内存地址从下往上依次减小
                                                                           ; 上方表示比基地址小,下方表示比基址大,暂时可以这么理解.
                                                                           ; 它的长度是4,至于这个变量用来干什么暂时不太清楚,跳过去
                                                      
.text:00401000 argc            = dword ptr  8          ; 参数:argc,偏移为8,表示在基址的下方,下面两个变量也是在基址下方
.text:00401000 argv            = dword ptr  0Ch     ; 参数:argv,偏移为0ch(即十进制的12),所以argv的长度是12-8=4,这和指针的长度是4字节相符.
.text:00401000 envp            = dword ptr  10h     ; 比原代码多出来的变量,偏移为10h(即16),所以它的长度是16-12=4.
.text:00401000 ; ---------------------------------------------------------------------------
                         ; 以下代码保存main函数运行前的环境
                         ; 基地址入栈,函数运行完要pop出来以恢复原来的运行环境.
                         ; ---------------------------------------------------------------------------
.text:00401000                 push    ebp                  ; 基地址入栈,main函数运行完后会pop出来的
.text:00401001                 mov     ebp, esp           ; ebp指向基址入栈后的顶栈,此时ebp是main函数地址的开始
.text:00401003                 push    ecx                   ; 计数器入栈
.text:00401004                 mov     [ebp+var_4], 0  ; 初始化变量 var_4 为0,即[ebp-4]位置处置0
.text:0040100B                 jmp     short loc_401016
.text:0040100B
.text:0040100D ; ---------------------------------------------------------------------------
.text:0040100D
.text:0040100D loc_40100D:                                   ; CODE XREF: _main+2D↓j
.text:0040100D                 mov     eax, [ebp+var_4] ; [ebp-4]处的值赋给eax
.text:00401010                 add     eax, 1                   ; eax值加1
.text:00401013                 mov     [ebp+var_4], eax  ; 将加1后的结果赋回给[ebp-4]
.text:00401013
.text:00401016 ; ---------------------------------------------------------------------------
.text:00401016 loc_401016:                                    ; CODE XREF: _main+B↑j
.text:00401016                 cmp     [ebp+var_4], 0Ah ; 判断[ebp-4]处的值 与 0A(即10) 的大小
.text:0040101A                 jge     short loc_40102F  ; 大于或等于10时跳到loc_40102F处,即退出程序
.text:0040101A
.text:0040101C                 mov     ecx, [ebp+var_4] ; 如果小于10则将值赋给计数器ecx
.text:0040101F                 push    ecx                      ; 值入栈
.text:00401020                 push    offset s_ID           ; 字符串 "i = %d\n" 入栈
.text:00401025                 call    sub_401035           ; 对比一下源码 sub_401035 应该是printf的地址
                                                                                ; 分析到这里我们可以确定, var_4 就是源代码中的变量i
.text:00401025
.text:0040102A                 add     esp, 8                   ; 调用了 printf 函数后,要调整一下堆栈以恢复当前函数的堆栈
                                                                                ; 从这里可以看出来__cdecl方式是调用者调整堆栈
                                                                                ; 如果是__stdcall方式的话,这句话就会在printf函数的堆栈中完成
.text:0040102D                 jmp     short loc_40100D ; 跳到 loc_40100D 继续下一轮的比较
.text:0040102D
.text:0040102F ; ---------------------------------------------------------------------------
                         ; 以下代码恢复main函数运行前的堆栈
.text:0040102F ; ---------------------------------------------------------------------------
.text:0040102F loc_40102F:                                    ; CODE XREF: _main+1A↑j
.text:0040102F                 xor     eax, eax
.text:00401031                 mov     esp, ebp
.text:00401033                 pop     ebp
.text:00401034                 retn
.text:00401034
.text:00401034 _main           endp

    怎么样,是不是很简单啊,分析的过程倒是很简单,不过要写成文章倒是花了我不少时间.
    如果你发现有什么错误请告诉我,非常感谢。
    如果有什么疑问,也欢迎到『80王朝』论坛来提,我会抽时间回复的。

    提示:
    不知道为什么我排好版后的文章发到这来版面就不整齐了,而且颜色也没了,如果看不太清楚可以到这里看(有颜色标记应该容易看懂点):
    http://b0d.5d6d.com/viewthread.p ... &extra=page%3D1

[ 本帖最后由 kgdiwss 于 2007-11-21 10:40 编辑 ]

for1.rar

114.65 KB, 下载次数: 4, 下载积分: 飘云币 -2 枚

评分

参与人数 1威望 +40 飘云币 +40 收起 理由
lxk836 + 40 + 40 感谢您发布的原创作品!

查看全部评分

PYG19周年生日快乐!
  • TA的每日心情
    开心
    2023-7-26 16:07
  • 签到天数: 8 天

    [LV.3]偶尔看看II

    发表于 2007-11-13 12:07:23 | 显示全部楼层
    我是个新手 看完以后有3个问题 希望高手解答
    1 )“如果是__stdcall方式的话,这句话就会在printf函数的堆栈中完成” 这句话怎么理解 计算机的堆栈不是只有一个 从上到下分配的吗 可以另外分出一个堆栈吗
    2 ) 程序push了很多东西进去 却只pop出一个ebp 要是根据后进先出原理 pop给ebp的应该是最后push的 offset s_ID  这怎么理解阿
    3)就是最后的这句.text:0040102F                 xor     eax, eax有什么用啊
    都是些菜鸟问题 主要是刚接触 不太懂 希望高手不要笑话
    PYG19周年生日快乐!

    该用户从未签到

     楼主| 发表于 2007-11-13 15:39:17 | 显示全部楼层
    1、堆栈只有一个,调用什么函数,堆栈中当前值就是什么函数的,调用了printf,堆栈中当前值都是printf中的,你不恢复的话,main函数怎么继续啊。
    2、mov     esp, ebp光是这句话,就把栈顶位置都改了。所以不能死记pop出来的是最后一次push进去的,要看栈顶在哪。你不信可以用OllyDbg跟一下看看。
    3、xor     eax, eax这句话不知道解释成清零合不合适。
    PYG19周年生日快乐!

    该用户从未签到

    发表于 2007-11-13 16:46:03 | 显示全部楼层
    呵呵虽然看不懂 我还是新手 但我能做的事就是帮你顶
    PYG19周年生日快乐!
  • TA的每日心情
    开心
    2023-7-26 16:07
  • 签到天数: 8 天

    [LV.3]偶尔看看II

    发表于 2007-11-13 17:46:13 | 显示全部楼层
    mov     ebp, esp           ; ebp指向基址入栈后的顶栈,此时ebp是main函数地址的开始
    mov     esp, ebp 理解了  非常感谢
    PYG19周年生日快乐!

    该用户从未签到

    发表于 2007-12-1 19:44:09 | 显示全部楼层
    楼主厉害啊 虽然我不是很精通但是看你的解答很专业啊向你学习
    PYG19周年生日快乐!
    您需要登录后才可以回帖 登录 | 加入我们

    本版积分规则

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