一个简单的C程序反汇编解析.docx
- 文档编号:27816009
- 上传时间:2023-07-05
- 格式:DOCX
- 页数:8
- 大小:17.48KB
一个简单的C程序反汇编解析.docx
《一个简单的C程序反汇编解析.docx》由会员分享,可在线阅读,更多相关《一个简单的C程序反汇编解析.docx(8页珍藏版)》请在冰豆网上搜索。
一个简单的C程序反汇编解析
一个简单的C++程序反汇编解析
本系列主要从汇编角度研究c++语言机制和汇编的对应关系。
第一篇自然应该从最简单的开始。
c++的源代码如下:
classmy_class
{
public:
my_class(
{
m_member=1;
}
voidmethod(intn
{
m_member=n;
}
~my_class(
{
m_member=0;
}
private:
intm_member;
};
int_tmain(intargc,_tchar*argv[]
{
my_classa_class;
a_class.method(10;
return0;
}
可以直接debug的时候看到assembly代码,不过这样获得的代码注释比较少。
比较理想的方法是利用vc编译器的一个选项/fas来生成对应的汇编代码。
/fas还会在汇编代码中加入注释注明和c++代码的对应关系,十分有助于分析。
build代码便可以在输出目录下发现对应的.asm文件。
本文将逐句分析汇编代码和c++的对应关系。
首先是winmain:
_textsegment
_wmainproc
pushebp;保存旧的ebp
movebp,esp;ebp保存当前栈的位置
push-1;建立seh(structuredexceptionhandler链
;-1表示表头,没有prev
push__ehhandler$_wmain;seh异常处理程序的地址
moveax,dwordptrfs:
0;fs:
0指向teb的内容,头4个字节是当前seh链的地址
pusheax;保存起来
subesp,d8h;分配d8h字节的空间
pushebx
pushesi
pushedi
leaedi,dwordptr[ebp-e4h];e4h=d8h+4*3,跳过中间ebx,esi,edimovecx,36h;36h*4h=d8h,也就是用36h个cccccccch填满刚才分配的d8h字节空间
moveax,cccccccch
repstosd
moveax,dwordptr___security_cookie
xoreax,ebp
pusheax;ebp^__security_cookie压栈保存leaeax,dwordptr[ebp-0ch];ebp-0ch是新的seh链的结构地址(刚压入栈中的栈地址
movdwordptrfs:
0,eax;设置到teb中作为当前active的seh链表末尾
到此为止栈的内容是这样的:
低地址
securitycookieafterxor
edi
esi
ebx
localstack:
d8h
oldfs:
0
__ehhandler$_wmain
ffffffffh
oldebp
高地址
main接着后面调用my_class的构造函数
leaecx,dwordptr[ebp-14h]
call?
?
0my_class@@qae@xz;调用my_class:
:
my_class,?
?
my_class@@qae@xz是经过namemangling后的名字
movdwordptr[ebp-4],0;进入__try块,在main中有一个隐式的__try/__except块
接着调用my_class:
:
method
push10;参数入栈
leaecx,dwordptr[ebp-14h];遵循thiscall调用协定,ecx存放的是this指针
call?
method@my_class@@qaexh@z;调用子程序my_class:
method(10
之后是析构:
movdwordptr[ebp-e0h],0;用来放置返回值
movdwordptr[ebp-4],-1;标记try的正常结束
leaecx,dwordptr[ebp-14h];a_class的地址作为this存入ecx
call?
?
1my_class@@qae@xz;my_class:
:
~my_class
moveax,dwordptr[ebp-e0h];返回值按照约定放入eax中
main函数退出代码如下:
pushedx
movecx,ebp
pusheax
leaedx,dwordptr$ln7@wmain
call@_rtc_checkstackvars@8;检查栈
popeax
popedx
movecx,dwordptr[ebp-0ch];取出之前保存的旧的fs:
0,并恢复movdwordptrfs:
0,ecx
popecx
popedi
popesi
popebx
addesp,e4h;退掉分配的d8h+建立seh链所需的0ch字节
cmpebp,esp
call__rtc_checkesp;检查esp值,这个时候esp应该和ebp匹配,否则说明出现了栈不平衡的情况,这种情况下调用子程序报错
movesp,ebp;恢复ebp到esp
popebp;恢复原来的ebp值
ret0
_wmainendp
专门用于seh的子程序。
__unwindfunclet$_wmain$0当异常发生的时候被调,负责进行栈展开,主要是调用析构函数。
__ehhandler$_wmain则是在exception被抛出的时候调用。
text$xsegment
__unwindfunclet$_wmain$0:
;当seh发生的时候会调用该函数,析购a_class
leaecx,dwordptr[ebp-14h];ecx=[ebp–14h],也就是a_class的地址
jmp?
?
1my_class@@qae@xz;调用my_class:
:
~my_class__ehhandler$_wmain:
movedx,dwordptr[esp+8];esp=当前的fs:
0,[esp+8]=之前的seh结构,也就是main中建立的
leaeax,dwordptr[edx+0ch];edx+0ch=当前的ebp,也就是main的ebp,此时不能直接使用ebp因为可能会从任意函数调过来,此时ebp是该函数的ebp,而不是main的ebp
movecx,dwordptr[edx-e0h];之前存下去的__security_cookie^ebpxorecx,eax;再次和ebp相异或
call@__security_check_cookie@4;此时ecx应该等于__security_cookie,否则说明栈的内容被恶意改动(或者编程错误
moveax,offset__ehfuncinfo$_wmain
jmp___cxxframehandler3
text$xends
my_class:
:
my_class构造函数如下。
构造函数本质上就是一个全局函数,名字是经过打乱的(namemangling,这样可以和同一class和其他class的同名方法区别开来。
不同编译器有不同规则,因此不必过于深究。
_textsegment
?
?
0my_class@@qae@xzproc
pushebp;保存旧的ebp
movebp,esp;ebp保存当前栈的位置
subesp,cch;给栈分配cch个字节
pushebx;保存常用寄存器
pushesi
pushedi
pushecx
leaedi,dwordptr[ebp-cch];从分配的位置开始
movecx,33h;写33h个cccccccch
moveax,cccccccch;也就是33h*4h=cch,正好是分配的大小
repstosd;从而把整个栈上当前分配的空间用cch填满
popecx
movdwordptr[ebp-8],ecx;按照约定,一般用ecx保存this指针;把this存入到ebp-8,并不是很必要,因为这是debug版本
;10:
{
;11:
m_member=1;
moveax,dwordptr[ebp-8];eax中存放this
movdwordptr[eax],1;this的头四个byte是m_member的内容;12:
}
moveax,dwordptr[ebp-8];多余的一句话,可以优化掉
popedi
popesi
popebx
movesp,ebp;恢复esp,因此就算是中间栈运算出错,最后也不会导致灾难性的结果,只要ebp还是正确的
popebp
ret0
?
?
0my_class@@qae@xzendp
my_class:
:
method的实现如下:
_textsegment
?
method@my_class@@qaexh@zproc;my_class:
:
method
;15:
{
pushebp
movebp,esp
subesp,cch
pushebx
pushesipushedipushecxleaedi,dwordptr[ebp-cch]movecx,33hmoveax,cccccccchrepstosdpopecxmovdwordptr[ebp-8],ecx;16:
movmovm_member=n;eax,dwordptr[ebp-8]ecx,dwordptr[ebp+8];eax中存放this;ebp->ebp;ebp+4->ip;ebp+8->n;把n存入ecx中;this头四个字节是m_member,因此这movdwordptr[eax],ecx句话就是m_member=n;17:
}popedipopesipopebxmovesp,ebppopebpret4;等价于;ret恢复eip,返回调用地址;addesp,4->把n从栈上pop掉?
method@my_class@@qaexh@zendp最后的析构函数,和前面的代码并无区别。
_textsegment?
?
1my_class@@qae@xzproc;20:
{;my_class:
:
~my_classpushebpmovebp,espsubesp,204pushebx
pushesipushedipushecxleaedi,dwordptr[ebp-204]movecx,33hmoveax,cccccccchrepstosdpopecxmovdwordptr_this$[ebp],ecx;21:
movmov;22:
m_member=0;eax,dwordptr[ebp-8]dwordptr[eax],0}popedipopesipopebxmovesp,ebppopebpret0?
?
1my_class@@qae@xzendp_textends;my_class:
:
~my_class本文来自CSDN博客,转载请标明出处:
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 一个 简单 程序 汇编 解析