使用Detours跟踪WinAPI调用情况

Detours是微软研究院的一个用于hook WinAPI的工具。

安装后安装目录的samples目录里面有很多项目。我们用到的是traceapi和withdll项目。

自定义traceapi

打开traceapi目录里面的_win32.cpp,可以看到已经默认hook了绝大部分的WinAPI。我们可以把大多数注释掉,只保留我们关心的几个函数,免得之后要分析的log过大。

以ReadProcessMemory为例,看看如何自定义trace的结果。在_win32.cpp,关于一个WinAPI函数会有四处地方:

第一处:

 

BOOL (__stdcall * Real_ReadProcessMemory)(HANDLE a0,
                                          LPCVOID a1,
                                          LPVOID a2,
                                          DWORD_PTR a3,
                                          PDWORD_PTR a4)
    = ReadProcessMemory;

第二处:

BOOL __stdcall Mine_ReadProcessMemory(HANDLE a0,
                                      LPCVOID a1,
                                      LPVOID a2,
                                      DWORD_PTR a3,
                                      PDWORD_PTR a4)
{
    _PrintEnter("ReadProcessMemory(%p,%p,%p,%p,%p)n", a0, a1, a2, a3, a4);

    BOOL rv = 0;
    __try {
        rv = Real_ReadProcessMemory(a0, a1, a2, a3, a4);
    } __finally {
        _PrintExit("ReadProcessMemory(,,,,) -> %pn", rv);
    };
    return rv;
}

第三处

ATTACH(&(PVOID&)Real_ReadProcessMemory, Mine_ReadProcessMemory);

第四处

DETACH(&(PVOID&)Real_ReadProcessMemory, Mine_ReadProcessMemory);

如果不想trace某个函数,将第一、第二和第四处注释掉即可。

主要自定义的点在第二处,例如a2是buffer地址,a4是读取的字节数。当真正的ReadProcessMemory读取完毕后,我们就可以用这两个信息来看看究竟读了什么。因此在finally子句可以改成一下这样:

int size = (int) a4;
char buf[MAXBUF];
PrintByte(buf, a2, size);

_PrintExit("ReadProcessMemory(,,,,) -> %p,%p -> %sn", rv, a2, buf);

这里的PrintByte函数是将字节数组转为十六进制字符串。

使用

withdll的使用很简单,看看命令行说明即可。

下载安装打开DbgView。使用withdll启动目标程序并将自定义好的traceapi.dll注入进程,即可在DbgView的窗口里看到traceapi打印的信息了。