案例一: 使用IDA PRO+OllyDbg+PEview 追踪windows API 动态链接库函数的调用过程。 首先用文本编辑器写一个C++源程序名为StackFrame.cpp ,代码如下:

案例一: 使用IDA PRO+OllyDbg+PEview 追踪windows API 动态链接库函数的调用过程。

首先用文本编辑器写一个C++源程序名为StackFrame.cpp ,代码如下:



1
<span style= 'font-family: "微软雅黑", "Microsoft YaHei"; font-size: 20px;' >#include  "stdio.h" <br><br> long  add( long  a,  long  b)<br>{<br>     long  x = a, y = b;<br>     return  (x + y);<br>}<br><br> int  main( int  argc,  char * argv[])<br>{<br>     long  a = 1, b = 2;<br>    <br>     printf ( "%d\n" , add(a, b));<br><br>     return  0;<br>}<br></span>



使用visual C++ IDE 对该源文件执行编译,汇编,链接一系列的操作后,最终生成的二进制可执行文件(PE格式)名为StackFrame.exe 

回顾上述源码,main函数调用了标准C库函数printf打印信息,我们想要知道,

visual C++ 编译器是如何实现printf库函数的,并且StackFrame.exe采用的是静态链接还是动态链接,如果是后者,那么printf又调用了哪些位于动态链接库中的windows API函数?抑或是“动静”兼用?

要解答这些疑问,首先使用IDA PRO打开StackFrame.exe ,它会自动查找程序入口点,这是由编译器自动生成的启动代码,用于初始化我们编写的main函数执行前的环境,以及执行main函数退出后的收尾工作。

一般而言,只要反汇编的对象不是经过加壳或者插入了模糊代码,IDA PRO可以轻松识别程序入口点与main函数,这里为了简化分析流程,我们直接进入main函数的反汇编代码段,如下所示:


wKioL1TbbbPBGLcqABAIPg_RLYg481.jpg


wKioL1Tbcivwf3UoAAlj6kCCqdI043.jpg


wKiom1TbdTTgqzIgAAvlvsmTEvU125.jpg


wKioL1Tbfyywlv9FAA8qq8cSFTo648.jpg


wKioL1Tbgh_jMZe2AAt1eR1_4Nc772.jpg



我们通过上面一系列的IDA PRO截图可以看到,地址 0x00404063处的call指令想要调用EnterCriticalSection函数,后者的地址尝试以call的操作数0x0040A018给出,但是这个地址处的值,即EnterCriticalSection函数的最终地址,需要操作系统加载器加载StackFrame.exe文件时才能确定,因此我们对磁盘上的文件反汇编时,无法确定动态链接库中函数的地址。

下面以PEview工具查看StackFrame.exe在磁盘上的“真实”面貌(而不是由IDA PRO “模拟”的运行时地址空间面貌)

之所以要先使用PEview工具,是因为后面的动态调试中,会与此处的信息对比,来加深理解程序在磁盘上与在内存中的异同。

使用PEview工具打开StackFrame.exe ,我们的重点是定位到PE文件中的导入表,因为无论是操作系统加载器,反汇编器,还是动态调试器,都依赖该表来解析导入的动态链接库与其中的函数。


wKioL1TbiofwxVjtAAmeNfpB1Z0302.jpg


wKiom1TbjLnRGqHrAAw-GjmL46A946.jpg

我们尝试在原始PE文件中,计算并找出call ds:EnterCriticalSection 指令对应的字节序列,其实这没有想象中困难,而且在这里提出计算方法的原因是,后面会用同样的计算手法来判断Ollydbg中追踪到的EnterCriticalSection函数的实际地址,

该地址究竟属于kernel32.dll还是ntdll.dll?(因为有时Ollydbg给出的信息并不十分准确)届时会用到下面的计算方法。


首先,回到IDA PRO,打开StackFrame.exe的程序段窗口,如下所示:


wKiom1Tbkq3DyKNDAAVvE6vU8kQ650.jpg


wKioL1Tbldri-CmrAAffX-nW7UQ395.jpg


前面指出,地址 0x00404063处的call指令想要调用EnterCriticalSection函数,因此计算 404063 - 401000 = 3063 , 3063 + 400 = 3463

3463这个值就是该指令字节码在StackFrame.exe的位置,下面验证: 


wKioL1Tbmr-B2lGwAA3vB71tAAA572.jpg


接下来,使用Ollydbg打开StackFrame.exe进行动态调试,我们的目标在于定位EnterCriticalSection函数的入口处,并且单步跟进,查看其中的机器码,然后使用PEview工具,以上面的计算方法,验证Ollydbg给出的该函数所属的动态链接库文件信息是否准确,如下截图所示: 


wKiom1TbnqnAh3gkAAow_3pB2IY289.jpg


wKiom1TboaWzelH7AAzXqvho7qE832.jpg


wKioL1TbpVah8efOAAfQRIkbYmQ235.jpg


wKiom1TbqgrzKxN2AA3RefVz9Mc758.jpg


wKioL1TbsGSw9c-_ABKkav4RGXM533.jpg


上面验证了StackFrame.exe 在运行时调用的共享库函数,与它在磁盘文件上的导入表中描述的行为一致。

最后,我们验证EnterCriticalSection这个 windows API函确实位于ntdll.dll这个动态链接库中,作为本案例的结尾。

首先,可以访问微软MSDN站点,查找关于EnterCriticalSection函数的信息:

https://msdn.microsoft.com/zh-cn/library/windows/desktop/ms682608(v=vs.85).aspx


wKiom1Tbsr-zx68cAAh_aDz-bPY562.jpg



wKioL1TbuN_zrYvDABBgkv1c-z4322.jpg


wKiom1Tbu2OxbrVlAAn-SR0DdEM199.jpg


wKioL1TbwMaDy4Q6ABJwA3gsSrg850.jpg


wKioL1TbxKuSVWqmAA2ihTrrXCw406.jpg


最后总结一下: 

stack.exe使用“部分”静态链接,其中多数的代码为库代码,

这包含由“编译器库”添加的,处理程序初始化的启动代码与程序退出善后的结束代码,

以及程序中调用的库函数,如printf等函数的代码。

由于 printf 函数需要在屏幕打印信息,涉及更底层的系统I/O操作,因此它需要调用封装这些系统功能的 windows API 函数,

除了windows API 函数所在的DLL(kernel32.dll,ntdll.dll)作为动态链接库在运行时加载以外,

所有其它被调用函数的二进制目标代码都被链接器复制一份副本,然后链接到最终的可执行文件stack.exe中,

因此,stack.exe包含的库代码数量远多于程序员自行编写的代码数量。

使用静态链接的程序,很容易通过IDA PRO的全局函数调用拓扑图识别出来,如下所示:


wKiom1TcXfvxjG5FABLBV86WfPs750.jpg




上面只是抛砖引玉,类似的将IDA PRO,Ollydbg,PEview,甚至WinHex,PEiD等工具结合起来应用,交叉验证的例子不胜枚举,通过熟练使用这些工具,不仅能提高逆向工程的效率与准确度,更重要的是,我们对处理器指令集体系结构,操作系统内存管理,以及动态链接的机制,编译器,链接器的运行原理等等系统底层机理的认识又提升了一个档次。

最后,限于个人知识水平有限,文中若有错误以及误导之处,还请提出指正,不胜感激。


wKioL1VosLezmXm4ABXYIzf4PUQ271.jpg

wKiom1VorzfCRG1wABVrRUjQ7uo310.jpg

本文出自 “自由,平等,共享,互助” 博客,请务必保留此出处http://shayi1983.blog.51cto.com/4681835/1613615

http://www.360doc.com/content/15/0524/14/12129652_472898279.shtml

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值