以前曾写过一个利用 API HOOKING
原理记录可疑程序对文件、注册表、服务和网络操作的小工具。API HOOKING
方式的优点在于,当调用 CreateFile 时可将文件名与句柄关联,等调用
WriteFile 对句柄操作时便能轻易取到文件名,对 hKey、socket
等句柄操作亦是如此。但该方式的缺点也显而易见,首先必须为每个感兴趣的
API 函数编写代码,“体力工作”繁重;其次我们不可能 HOOK 所有的 API
函数,由于缺乏完整的 API
调用序列作参考,在分析日志时很可能漏掉某些小动作。
另一种思路是采用调试技术,在所有被引入的 DLL
的各函数入口处预先设置断点,调试期间再通过堆栈信息获取参数。IDA pro
和 OllyDbg
都可用于动态调试,同时还提供了脚本/插件功能。上周在北京开会的时候,我利用酒醒的时间写了一个简单的
OllyDbg 插件,仅从 CALL 指令处通过 ESP
指针获取8个函数参数,不对函数返回后的 EAX
及堆栈内容进行记录,在对普通(未加壳)程序的测试中效果还算理想。只要先在“Search
for -> All intermodular calls”窗口中执行“Set breakpoint on
every command”设置断点,再运行插件的“Fast
trace”功能即可。日志文件片断如下:
-------------------------------------------------------------------
00409ACF: CALL DWORD PTR
DS:[<&ADVAPI32.CreateServiceA>]
(ADVAPI32.CreateServiceA)
-------------------------------------------------------------------
ESP+00 (0012F6DC): 0014F9C0
F8 F9 14 00 98 BA DC FE 00 00 00 00 B4 F9 CC 53
...............S
82 6C FC 42 BF 8C 55 14 00 44 14 F4 AB AB AB AB
.l.B..U..D......
AB AB AB AB EE FE EE FE 00 00 00 00 00 00 00 00
................
20 00 07 00 09 07 18 00 58 FA C3 77 EF CD AB
89 .......X..w....
00 00 01 00 01 00 00 00 00 00 00 00 00 00 00 00
................
00 00 00 00 00 00 00 00 05 00 00 00 01 00 00 00
................
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
................
06 00 00 00 0A 00 00 00 00 00 00 00 30 FB 14 00
............0...
ESP+04 (0012F6E0): 0042008C "trojan"
ESP+08 (0012F6E4): 004200C0 "Back door for
testing"
ESP+0C (0012F6E8): 000F01FF 000F01FF ???
ESP+10 (0012F6EC): 00000120 00000120 ???
ESP+14 (0012F6F0): 00000002 00000002 ???
ESP+18 (0012F6F4): 00000001 00000001 ???
ESP+1C (0012F6F8):
0012F71C "C:\WINDOWS\system32\trojan.exe -start"
......
这种简单粗糙的日志对我来说已经够用了。若希望以更友好的形式显示参数信息,就必须有一些数据文件来描述各
API 函数的调用方式、返回值类型、参数个数等内容。比如这样:
int LoadLibraryA([in] char *lpLibFileName);
int LoadLibraryW([in] wchar *lpLibFileName);
void *GetProcAddress([in] int hModule, [in] char
*lpProcName);
int GetModuleFileNameA([in] int hModule, [out] char
*lpFilename, [in] int nSize);
int GetModuleFileNameW([in] int hModule, [out] wchar
*lpFilename, [in] int nSize);
BOOL WINAPI DllEntryPoint(HINSTANCE hi, DWORD reason, LPVOID
reserved)
{
FILE *fLog;
if (reason == DLL_PROCESS_ATTACH) {
hinst = hi; // Mark plugin
instance
fLog = fopen(LOG_FILENAME, "w");
if (fLog) {
fprintf(fLog, "API tracing plugin v%i.%02i, written
by glacier_at_xfocus.org\n",
VERSIONHI, VERSIONLO);
fclose(fLog);
}
}
return 1; // Report success
}
// Report plugin name and return version of plugin
interface.
extc int _export cdecl ODBG_Plugindata(char
shortname[32])
{
strcpy(shortname, "API tracing"); // Name of command line
plugin
return PLUGIN_VERSION;
}
extc int _export cdecl ODBG_Plugininit(int ollydbgversion, HWND
hw, ulong *features)
{
// This plugin uses some newest features,
// check that version of OllyDbg is correct.
if (ollydbgversion < PLUGIN_VERSION)
return -1;
// Function adds items to main OllyDbg menu
(origin=PM_MAIN).
extc int _export cdecl ODBG_Pluginmenu(int origin, char
data[4096], void *item)
{
if (origin != PM_MAIN)
return 0; // No pop-up menus in
OllyDbg's windows
strcpy(data, "0 &Fast trace,1 &Slow trace|2
&About");
return 1;
}
// Receives commands from main menu.
extc void _export cdecl ODBG_Pluginaction(int origin, int
action, void *item)
{
char szLine[MAX_PATH] = {0};
if (origin != PM_MAIN)
return;