第56章 Win32环境下与外部通信

在了解函数的输入和输出的情况下,我们基本可以判断出函数的具体功能。这种分析方法能够显著地节省分析时间。

如需关注文件和注册表层面的行为,使用SysInternals的Process Monitor即可,它可以给我们提供关于以上这两者的基本信息。

如需查看网络层面的通信数据,完全可以使用Wireshark这类软件。

然而要进一步分析行为级数据,就得深入程序内部挖掘指令层面的信息。

首先就要调查该程序调用的操作系统API和标准库函数。

如果目标程序由可执行文件和多个DLL文件构成,那么由这些DLL文件所提供的、可调用的函数名称就很有指标性意义。

如果我们只关心那些调用MessageBox()、显示特定文字的指令,我们可以在程序的数据段检索文本字符,找到引用这个字符串的指令,再顺藤摸瓜地找到那些调用既定MessageBox()函数的代码。

在分析电脑游戏时,如果可以确定特定关卡里出现的敌人总数是随机数,那么我们可以在代码中查找rand()函数或者类似的随机数生成函数(例如梅森旋转算法),继而找到这些函数的调用指令,最终调整程序里使用随机数的那些指令。本书75章演示了这种分析实例。

那些电脑游戏以外的、仍然调用rand()函数的程序就更值得关注了。令人感到吃惊的是,某些著名软件采用的数据压缩算法(加密机制)都调用了rand()函数。有兴趣的读者可参阅https://yurichev.com/blog/44/

56.1 在Windows API中最经常使用的函数

这里列出了一些最常使用的API函数。需要特别说明的是,这些函数可能不是由程序源代码直接调用的。在程序调用库函数或者调用CRT的时候,下述函数可能会被后者间接调用。

56.2 tracer:解析指定模块的所有函数

在调试程序时,tracer会给目标程序设置很多INT3断点。虽然这种类型的断点只能运行一次,但是它同样可以用截获特定DLL文件的所有函数。

一个典型的使用例子为:

--one-time-INT3-bp:somedll.dll!.*

如果要在调用所有以xml 开头的函数之前设置INT 3断点,那么可以采用命令:

--one-time-INT3-bp:somedll.dll!xml.*

稍显遗憾的是,这些断点只能触发一次。

如果程序执行到函数断点且成功发生中断,tracer就会显示该函数的调用信息,只是它只能显示一次。另外一个美中不足的地方是,tracer不能查看被调用方函数获取的外来参数。

无论如何,tracer的这项功能还是非常有用的。一个DLL文件通常会定义大量的函数。当我们知道既定程序调用了某个的DLL文件、想要确切知道它调用了DLL里的哪些函数的时候,我们就特别需要这样的一款工具。

举例来讲,我们可以使用tracer给cygwin的程序uptime.exe设置断点,看它调用了哪些系统函数:

tracer -l:uptime.exe --one-time-INT3-bp:cygwin1.dll!.*

这样一来,我们就可以看到它调用了cygwin1.dll的哪些库函数(虽然只会显示一次)以及调用指令的地偏移量信息:

One-time INT3 breakpoint: cygwin1.dll!__main (called from uptime.exe!OEP+0x6d (0x40106d))
One-time INT3 breakpoint: cygwin1.dll!_geteuid32 (called from uptime.exe!OEP+0xba3 (0x401ba3))
One-time INT3 breakpoint: cygwin1.dll!_getuid32 (called from uptime.exe!OEP+0xbaa (0x401baa))
One-time INT3 breakpoint: cygwin1.dll!_getegid32 (called from uptime.exe!OEP+0xcb7 (0x401cb7))
One-time INT3 breakpoint: cygwin1.dll!_getgid32 (called from uptime.exe!OEP+0xcbe (0x401cbe))
One-time INT3 breakpoint: cygwin1.dll!sysconf (called from uptime.exe!OEP+0x735 (0x401735))
One-time INT3 breakpoint: cygwin1.dll!setlocale (called from uptime.exe!OEP+0x7b2 (0x4017b2))
One-time INT3 breakpoint: cygwin1.dll!_open64 (called from uptime.exe!OEP+0x994 (0x401994))
One-time INT3 breakpoint: cygwin1.dll!_lseek64 (called from uptime.exe!OEP+0x7ea (0x4017ea))
One-time INT3 breakpoint: cygwin1.dll!read (called from uptime.exe!OEP+0x809 (0x401809))
One-time INT3 breakpoint: cygwin1.dll!sscanf (called from uptime.exe!OEP+0x839 (0x401839))
One-time INT3 breakpoint: cygwin1.dll!uname (called from uptime.exe!OEP+0x139 (0x401139))
One-time INT3 breakpoint: cygwin1.dll!time (called from uptime.exe!OEP+0x22e (0x40122e))
One-time INT3 breakpoint: cygwin1.dll!localtime (called from uptime.exe!OEP+0x236 (0x401236))
One-time INT3 breakpoint: cygwin1.dll!sprintf (called from uptime.exe!OEP+0x25a (0x40125a))
One-time INT3 breakpoint: cygwin1.dll!setutent (called from uptime.exe!OEP+0x3b1 (0x4013b1))
One-time INT3 breakpoint: cygwin1.dll!getutent (called from uptime.exe!OEP+0x3c5 (0x4013c5))
One-time INT3 breakpoint: cygwin1.dll!endutent (called from uptime.exe!OEP+0x3e6 (0x4013e6))
One-time INT3 breakpoint: cygwin1.dll!puts (called from uptime.exe!OEP+0x4c3 (0x4014c3))