如果有错误请各位指正
参考书籍:
C++反汇编与逆向分析技术揭秘
汇编教学 by charme
老码识途
主要内容(不分先后顺序):
1.寻址Main函数入口点(为什么找3个push 1个call)
2.指令地址是如何计算出来的
3.所谓程序入口地址Main函数
4.调用约定(很重要)
5.汇编指令并非固定1+1=2(没兴趣可以无视)
使用到的工具:
OD
编译环境:VS2013 Debug
直接上代码:
非常经典的一个程序Hello World,麻雀虽小五脏俱全
很简单直接调用一个函数打印Hello World
1.寻址Main函数入口点
找到Main函数入口点就要知道Main函数的入口特征,我们可以通过VS2013调试。F10走出Main函数
我们发现Main函数其实也是一个函数,并非程序一开始就调用Main(IDA可以看的更直观)
main函数定义有三个参数
main(int
argc,char *argv[],char *envp[])
1.argc:命令行参数个数,整数
2.argv:命令行信息,保存字符串数组首地址的指针变量,是一个指向数组的指针。
3.envp:环境变量的信息,和argv类型相同
参数argv与envp就是两个指针数组,当数组作为参数时,实际上以指针方式进行数据传递,这两个参数可以转换为char**二级指针类型。
默认情况下argv第0项是保存路径字符串的首地址
1.1:OD打开EXE程序
方法1:
F7跟进遇到了两个call,先去看看第一个call有没有我们要找的特征(3个push 1个call)
很遗憾并不在第一个call
F7跟进第二个call找找看(找3个push 1个call的函数)
小知识(所谓程序入口地址Main函数):
我们还可以发现程序并非从Main函数开始运行的,main函数也是一个参数,也需要被人调用。main函数只是我们语法规定的用户入口,而不是应用程序入口。
F7跟进历尽千辛万苦终于找到了
方法2:使用OD自带的字符串搜索法
2:解析汇编代码
我们用VS2013来调试比较方便
补充知识:
补码表示:既其正整数值求反加1。比如,-1就是1求反,它只有最后一位是0,其他位均为1,再加上1,那么所有位均为1,即0xFFFFFFFF。对有符号数,最高bit为1,则说明它是一个负数如果对一个补码形式的负数求正整值,就是求反加1。比如,对-1求其整数值,就是对0xFFFFFFFF求反,即0。再加1,就是1。
指令地址是如何计算出来的:
E8是call的机器码,占一个字节,后面4个字节是call的地址,小端在内存中存放的是倒序的所以是FFFFFD8B。其实计算机寻址方式分为两种,一种是call 123432(绝对值),另外一种是相对定位就是用偏移量。偏移量是区分正与负(往前往后跳)。
FF FF FD 8B最高位是1,所以是负数。将其取反+1后,结果是275,再用call当前的地址00381455-275=3811E0+5(call字节数)=3811E5H
2.1:一些基础知识
基础汇编知识:
eax一般是当作函数的返回值
push esp-4
pop esp+4
Call指令= push 下一条指令(程序从上往下走,jmp到一个地方执行完代码你要记得你回去的路吧)
jmp 标号处
Ret指令= 将栈顶保存的地址弹入指令寄存器EIP,相当于"pop eip",从而让程序跳转到该地址。执行ret指令后,寄存器eip存储了栈顶保存的那个地址和ESP在(32位X86+4)的值有变化。
栈的理解:
可以把栈理解成一个箱子,先放进去的东西最后才能拿出来(遵循先进后出的原则)
图片:
第一个先拿出来的是英语书
第二本拿出来的是数学书
最先进去的语文书,是最后拿出来的
2.2:函数汇编方式展示出来的样子
我们必须要了解的是,调用call函数进去的时候它原来是什么样子,执行完call你要给它还原回去,所以每次进去函数就会看见push xxx,因为函数内部要用到
汇编代码详解:
003813C0 push ebp //保存ebp,ebp就相当于esp的备份
003813C1 mov ebp,esp //esp后面要进行操作,所以要让ebp先帮它保存原来的值。这样esp怎么改变都不怕影响到后面的操作
003813C3 sub esp,0C0h //开辟空间
003813C9 push ebx //保存寄存器,因为后面要用到
003813CA push esi
003813CB push edi
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!