注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

风雨夜归人

专业收集资料,个人爱好!

 
 
 

日志

 
 

逆向反汇编第一课  

2010-03-08 06:39:43|  分类: 逆向 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
       开篇总要说点什么,我也避免不了这种套俗.老生常谈还是那些东西.谁让我们现在的机子大部分都是32位的系统呢.当然也有不少人使用64的了.既然大部分都在32的机子,那我们还是说32咯.
        在编写32位机子的应用程序的时候,都有一个启动函数WinMain,不管是C或D还是E,但是Windows程序执行并不是从这个函数开始执行的,首先被执行的是启动函数的相关代码,这段代码是由IDE生成的,也就是编译器.首先由启动代码完成一些初始化的进程,再调用WinMain函数.
       对已C/C++的程序来说,它调用的事C/C++运行时的启动函数,这个函数负责对C/C++运行库进行初始化.所有的C/C++运行时启动函数的作用都是相同的:检索指向新进程的命令行指针,检索指向新进程的环境变量指针,全局变量初始化,内存堆栈初始化等.当所有的初始化操作完毕后,启动函数就调用应用程序的进入点函数.
       在我们E中为了省事,避免重复造轮子的这种繁琐无聊工作,可以新建一些子程序,作为一个长吁的集块,用来实现一个特定的功能.在C和D中当然也有的.在D中又按有无返回值称为函数和过程,而在C/C++中称为函数,下面我们就说说函数这个东西.
       在研究逆向分析/找CALL的时候,重点就是放在函数的识别以及参数的传递上这是明智的做法,这样可以在成千上万行代码中将我们的精力集中放在某一段代码上.一个函数有如下几部分组成:函数名 入口参数 返回值 函数功能.程序中通过调用程序调用函数,而函数执行完之后又会返回调用程序继续执行函数是怎么知道要返回的地址呢?实际上调用函数的代码保存了一个返回地址,并连同参数一起传递给被调用的函数.有许多中的方法可以实现这个功能的,在大多数情况下,编译器都使用CALL和RET指令来调用函数与返回调用位置.所以我们在找CALL的时候,就是在OD里面找程序调用的一个关键函数(子程序).
        CALL指令与跳转指令功能类似,所不同的是,CALL指令保存返回的信息,也就是将其之后的指令地址压入堆栈的顶部,当遇到RET指令结束函数的时候来执行(但是要注意哦,并不是所有的RET指令都标识函数的结束).这一机制使得很容易的把函数调用和其他跳转指令区别开来.


004011DF  |.  59            pop     ecx
004011E0  |.  85C0          test    eax, eax
004011E2  |.  75 08         jnz     short ReverseM.004011EC
004011E4  |.  6A 1C         push    1C
004011E6  |.  E8 B0000000   call    ReverseM.0040129B
004011EB  |.  59            pop     ecx
004011EC  |>  8975 FC       mov     dword ptr ss:[ebp-4], esi
004011EF  |.  E8 E1070000   call    ReverseM.004019D5
004011F4  |.  FF15 3C404000 call    near dword ptr ds:[<&KERNEL32.GetCommandLineA>; [GetCommandLineA
004011FA  |.  A3 D8594000   mov     dword ptr ds:[4059D8], eax


比如说这个CALL,004011EF  |.  E8 E1070000   call    ReverseM.004019D5,它上面没有PUSH入栈的命令,但是实际上却是PUSH  004011F4,然后JMP   ReverseM.004019D5,这样的操作.于是呢就可以通过定位CALL机器指令或利用RET指令结束的标识来识别函数.CALL指令的操作数就是所调用函数的首地址.先看一个简单的例子.


int Add(int x,int y)
main()
{
int a=3,b=4;
Add(a,b);
return 0;
}
Add (int x,int y)
{
return (x+y);
}
        很简单,先定义两个int类型的变量a和b,然后调用函数Add,函数Add在下面的声明是返回输入的两个参数的值,用E写呢大体就是下面这个样子:
启动窗口创建完毕
全局变量 a 整数型
全局变量 b 整数型
a=3,b=4
相加子程序(a,b)
返回


相加子程序
局部变量 x 整数型
局部变量 y 整数型
返回 x+y
而把他们反汇编的样子呢就是下面这样了
push 4
push 3
call 00401010 ;这个地方是调用"相加子程序",这个子程序在内存中的地址是00401010
add esp,8
xor eax,eax
retn
nop
00401010 mov eax,dword ptr [esp+8] ;一般[esp+*]这种格式的就表示是变量
00401014 mov ecx,dword ptr [esp+4]
add eax,ecx
retn
        这是函数直接调用方式,使得程序很简单,所幸的是大部分的情况都是这样的.当然也有一些情况不是这样,程序调用函数是间接调用的,也就是通过寄存器传递函数地址或动态计算函数地址的,比如:
CALL [4*eax+10h]
  评论这张
 
阅读(1073)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017