逆向脱壳分析基础学习笔记八 反汇编分析C语言(逆向脱壳什么意思)

网友投稿 312 2022-10-06


逆向脱壳分析基础学习笔记八 反汇编分析C语言(逆向脱壳什么意思)

本文为本人在大神论坛破解脱壳学习笔记之一,为本人对以往所学的回顾和总结,可能会有谬误之处,欢迎大家指出。

陆续将不断有笔记放出,希望能对想要入门的萌新有所帮助,一起进步

反汇编分析C语言

环境:VC6.0

为什么不使用Visual Studio?

Visual Studio的反汇编代码更复杂一些,如下为VS2019的空函数反汇编代码

可以看到有CheckForDebuggerJustMyCode等一些额外的函数

为了便于理解和学习,便采用VC6.0来进行学习

空函数反汇编

#include "stdafx.h" //空函数 void function(){ } int main(int argc, char* argv[]) { //调用空函数 function(); return 0; }

我们通过反汇编来分析这段空函数

函数外部

12: function(); 00401048 call @ILT+5(function) (0040100a) 13: return 0; 0040104D xor eax,eax 14: } 0040104F pop edi 00401050 pop esi 00401051 pop ebx 00401052 add esp,40h 00401055 cmp ebp,esp 00401057 call __chkesp (004010e0) 0040105C mov esp,ebp 0040105E pop ebp 0040105F ret

函数内部

6: void function(){ 00401010 push ebp 00401011 mov ebp,esp 00401013 sub esp,40h 00401016 push ebx 00401017 push esi 00401018 push edi 00401019 lea edi,[ebp-40h] 0040101C mov ecx,10h 00401021 mov eax,0CCCCCCCCh 00401026 rep stos dword ptr [edi] 7: 8: } 00401028 pop edi 00401029 pop esi 0040102A pop ebx 0040102B mov esp,ebp 0040102D pop ebp 0040102E ret

分析函数

函数调用

00401048 call @ILT+5(function) (0040100a)

首先就是通过call来调用我们的function函数

函数内部

接着进到函数的内部

有了之前画堆栈图的经验,我们不难看出,尽管我们的函数是个空函数,但其汇编代码依然完成了以下流程:

提升堆栈 保护现场 初始化提升的堆栈 恢复现场 返回

提升堆栈

00401010 push ebp 00401011 mov ebp,esp 00401013 sub esp,40h

保护现场

00401016 push ebx 00401017 push esi 00401018 push edi

PS:前面的push ebp也是保护现场

初始化提升的堆栈

00401019 lea edi,[ebp-40h] 0040101C mov ecx,10h 00401021 mov eax,0CCCCCCCCh 00401026 rep stos dword ptr [edi]

恢复现场

00401028 pop edi 00401029 pop esi 0040102A pop ebx 0040102B mov esp,ebp 0040102D pop ebp

PS:这里的mov esp,ebp就是降低堆栈,与前面的提升堆栈相对应,所以也属于恢复现场的一部分

返回

0040102E ret

函数返回后不出意料地返回到了调用CALL地下一行语句,我们接着看

0040104D xor eax,eax

这里是将eax清零,注意到我们的语句为return 0 这里就是将eax作为返回值来传递

一般来说eax都是作为函数的返回值,但不绝对,有的函数返回值是存在内存里或其它情况,要具体情况具体分析

接着看下面的代码:

0040104F pop edi 00401050 pop esi 00401051 pop ebx

很明显,这里是在还原现场,别忘了我们的主程序main本身也是个函数,这是在还原调用main前保护的现场

接着往下走

00401052 add esp,40h 00401055 cmp ebp,esp 00401057 call __chkesp (004010e0)

这里首先是将esp减少了40h,然后比较ebp和esp,最后再调用一个chkesp函数

从名称就不难看出chkesp = check esp ,检查esp,这个函数就是用来检查堆栈是否平衡的

继续

0040105C mov esp,ebp 0040105E pop ebp

依旧是恢复现场

最后就是返回

0040105F ret

总结空函数分析

我们可以看到,即便一个空函数什么都没有做,但调用一个空函数所产生的汇编代码却不少

保护现场、恢复现场以及堆栈平衡的检查等等都没少,可谓麻雀虽小五脏俱全

简单加法函数反汇编

有了前面分析空函数的经验,我们再来分析分析一个简单的加法函数

#include "stdafx.h" int Plus(int x,int y){ return x+y; } int main(int argc, char* argv[]) { //调用加法函数 Plus(1,2); return 0; }

函数外部

16: Plus(1,2); 004010A8 push 2 004010AA push 1 004010AC call @ILT+0(Plus) (00401005) 004010B1 add esp,8 17: return 0; 004010B4 xor eax,eax 18: } 004010B6 pop edi 004010B7 pop esi 004010B8 pop ebx 004010B9 add esp,40h 004010BC cmp ebp,esp 004010BE call __chkesp (004010e0) 004010C3 mov esp,ebp 004010C5 pop ebp 004010C6 ret

函数内部

10: int Plus(int x,int y){ 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] 11: return x+y; 00401078 mov eax,dword ptr [ebp+8] 0040107B add eax,dword ptr [ebp+0Ch] 12: } 0040107E pop edi 0040107F pop esi 00401080 pop ebx 00401081 mov esp,ebp 00401083 pop ebp 00401084 ret

分析函数

函数调用

004010A8 push 2 004010AA push 1 004010AC call @ILT+0(Plus) (00401005)

结合前面的空函数分析,我们可以明显发现这里的函数调用环节,多了两个push

就是将函数所需的参数压入堆栈,这里的参数为 2 和 1,注意压入的顺序是反着的(由调用协定决定,下篇笔记会详细说明)

函数内部

提升堆栈保护现场初始化

提升堆栈、保护现场、初始化部分和空函数如出一辙,这里就不再赘述

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]

实际执行

00401078 mov eax,dword ptr [ebp+8] 0040107B add eax,dword ptr [ebp+0Ch]

里的[ebp+8]就是我们前面压入的参数1,[ebp+c]就是前面压入的参数2

于是这两条语句其实就是

00401078 mov eax,1 0040107B add eax,2

将1+2的结果保存到eax中(此时eax又作为函数返回值的载体)

恢复现场和返回

接下来的内容就和空函数一样了,恢复现场和返回,也不再赘述

0040107E pop edi 0040107F pop esi 00401080 pop ebx 00401081 mov esp,ebp 00401083 pop ebp 00401084 ret

004010B1 add esp,8 17: return 0; 004010B4 xor eax,eax 18: } 004010B6 pop edi 004010B7 pop esi 004010B8 pop ebx 004010B9 add esp,40h 004010BC cmp ebp,esp 004010BE call __chkesp (004010e0) 004010C3 mov esp,ebp 004010C5 pop ebp 004010C6 ret

函数返回后我们会发现与先前的空函数相比多了这一行代码:

004010B1 add esp,8

这里是对应我们前面压入的两个参数1和2,压入参数后esp减少了8,这里我们函数调用结束后,就不再需要之前压入的两个参数了,于是将esp恢复到压入参数前,这其实也算在恢复现场里,用来平衡堆栈

我们可以发现,这条语句是在我们call调用完毕返回后执行的平衡堆栈操作,所以这种操作也被称为堆栈外平衡

与之相对就是堆栈内平衡:即在call里面就把堆栈平衡好了

之后的代码就和空函数无异了,也不再赘述,简单的加法函数分析到这也就告一段落了

本系列逆向脱壳基础学习都在下方链接中,欢迎下载并交流沟通


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:我看到的未来的信息安全
下一篇:#导入MD文档图片#金融行业安全体系建设咨询实践-TOPIC 1
相关文章

 发表评论

暂时没有评论,来抢沙发吧~