MSDetour 不绕道 SHGetKnownFolderPath

逆向工程 dll 登录 函数挂钩
2021-06-25 17:02:10

尝试使用正常的 DetourFunctionWithTrampoline 从 shell32 挂钩 SHGetKnownFolderPath,但它不能。

经查,应用程序使用GetProcAddress加载函数,并使用函数指针。

所以我做了同样的事情,并使用 DetourFunction 进行了钩子,它成功了。

我查看了程序集,发现当我直接调用 SHGetKnownFolderPath 时,它在到达 shell32 之前经历了两次跳转。我不认为它对其他功能这样做。

到底是怎么回事?

分享代码:

#include "stdafx.h"
#include "windows.h"
#include "FileAPI.h"
#include "Shlobj.h"


int main()
{
    HANDLE hFile = CreateFileA(NULL, 0, 0, NULL, 0, 0, NULL);
    SHGetKnownFolderPath(FOLDERID_LocalAppDataLow, 0, NULL, NULL);
    return 0;
}

在 IDA 中,我看到 CreateFileA:

call    ds:__imp__CreateFileA@28 ; CreateFileA(x,x,x,x,x,x,x)

这让我:

.idata:0041B000 ; HANDLE __stdcall CreateFileA(LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
.idata:0041B000                 extrn __imp__CreateFileA@28:dword ; CODE XREF: _main+2Ep
.idata:0041B000                                         ; DATA XREF: _main+2Er ...

另一方面,对于 SHGetKnownFolderPath 我看到:

call    j__SHGetKnownFolderPath@16 ; SHGetKnownFolderPath(x,x,x,x)

哪个重定向到:

; __stdcall SHGetKnownFolderPath(x, x, x, x)
j__SHGetKnownFolderPath@16 proc near
jmp     _SHGetKnownFolderPath@16 ; SHGetKnownFolderPath(x,x,x,x)
j__SHGetKnownFolderPath@16 endp

哪个重定向到:

; __stdcall SHGetKnownFolderPath(x, x, x, x)
_SHGetKnownFolderPath@16 proc near
jmp     ds:__imp__SHGetKnownFolderPath@16 ; SHGetKnownFolderPath(x,x,x,x)
_SHGetKnownFolderPath@16 endp

哪个重定向到:

.idata:0041B09C ; __declspec(dllimport) __stdcall SHGetKnownFolderPath(x, x, x, x)
.idata:0041B09C                 extrn __imp__SHGetKnownFolderPath@16:dword
.idata:0041B09C                                         ; DATA XREF: SHGetKnownFolderPath(x,x,x,x)r

所以 SHGetKnownFolderPath比 CreateFileA 多了两个跳转。我没有对这个项目做任何事情来让它做到这一点。所以为什么?

2个回答
  1. DetourFunction()来自旧版本的 Detours。可能最好升级到最新版本的库。(等效函数现在是DetourAttach()。)
  2. 如果您使用的是DetourFunction(SHGetKnownFolderPath, Hook),则第一个参数的值可能指向编译器为实际SHGetKnownFolderPath()函数创建的存根相反,您应该使用DetourFunction(GetProcAddress(GetModuleHandle("shell32.dll"), "SHGetKnownFolderPath"), Hook)来确保您使用的是导出 API 函数的实际地址。

我发现 SHGetKnownFolderPath 在头文件的定义中没有 declspec(dllimport) 标志。
添加它使其与 CreateFile 调用相同。

没有它,编译器为未知函数制作了一个存根,链接器因为增量链接而制作了自己的存根,然后才将调用转发到DLL。