Windows 的通用 Thunk
通用 Thunk 的最小应用。
引言
通用 Thunk 是微软的一项技术,允许 16 位 Windows 应用程序对 32 位 DLL 的导出函数进行进程内调用。本文介绍该技术的一个简单应用。
使用代码
#include <Windows.h>
// KERNEL.DLL
DWORD (FAR PASCAL *LoadLibraryEx32W)(
LPCSTR lpszLibFile,
DWORD hFile,
DWORD dwFlags
);
DWORD (FAR PASCAL *FreeLibrary32W)(
DWORD hInst
);
DWORD (FAR PASCAL *GetProcAddress32W)(
DWORD hModule,
LPCSTR lpszProc
);
DWORD (FAR PASCAL *CallProc32W0)(
DWORD lpProcAddress,
DWORD fAddressConvert,
DWORD nParams
);
static HINSTANCE ghKernelDll;
void PASCAL LoadKernelDll(void)
{
ghKernelDll = LoadLibrary("Kernel.DLL");
LoadLibraryEx32W = (DWORD (FAR PASCAL *)(LPCSTR, DWORD, DWORD))
GetProcAddress(ghKernelDll, "LoadLibraryEx32W");
FreeLibrary32W = (DWORD (FAR PASCAL *)(DWORD))
GetProcAddress(ghKernelDll, "FreeLibrary32W");
GetProcAddress32W = (DWORD (FAR PASCAL *)(DWORD, LPCSTR))
GetProcAddress(ghKernelDll, "GetProcAddress32W");
CallProc32W0 = (DWORD (FAR PASCAL *)(DWORD, DWORD, DWORD))
GetProcAddress(ghKernelDll, "CallProc32W");
}
void PASCAL FreeKernelDll(void)
{
FreeLibrary(ghKernelDll);
}
// KERNEL32.DLL
static DWORD ghKernel32Dll;
static DWORD ghGetTickCount32;
void PASCAL LoadKernel32Dll(void)
{
LoadKernelDll();
ghKernel32Dll = LoadLibraryEx32W("Kernel32.DLL", 0, 0);
ghGetTickCount32 = GetProcAddress32W(ghKernel32Dll, "GetTickCount");
}
void PASCAL FreeKernel32Dll(void)
{
FreeLibrary32W(ghKernel32Dll);
FreeKernelDll();
}
DWORD PASCAL GetTickCount32(void)
{
DWORD ret;
LoadKernel32Dll();
ret = CallProc32W0(ghGetTickCount32, 0, 0);
FreeKernel32Dll();
return ret;
}
// WinMain
int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrevInst,
LPSTR lpCmdLine, int nCmdShow)
{
DWORD tick16, tick32;
tick16 = GetTickCount();
tick32 = GetTickCount32();
MessageBox(NULL, tick16 <= tick32 ? "Success" :
"Failure", "GetTickCount32", MB_ICONASTERISK);
return 0;
}
这是用 C 语言编写的完整代码,适用于 Win16 平台。我们将重点关注 GetTickCount32
函数。
GetTickCount32
函数由入口点函数 WinMain
调用一次。GetTickCount32
函数调用 LoadKernel32Dll
函数、CallProc32W0
函数和 FreeKernel32Dll
函数。
调用 CallProc32W0
是对所需 32 位 DLL 函数的进程内跨边界调用。为了使用 CallProc32W0
函数,我们需要获取它的过程地址。它是 KERNEL.DLL 库的 CallProc32W
函数的过程地址。
调用 LoadKernel32Dll
获取一个 32 位值,该值表示 KERNEL32.DLL 库的 GetTickCount
过程。此外,它通过调用 LoadKernelDll
函数获取 KERNEL.DLL 库的 CallProc32W
函数的过程地址。
调用 FreeKernel32Dll
递减已加载的 KERNEL32.DLL 库的引用计数。此外,它通过调用 FreeKernelDll
函数递减已加载的 KERNEL.DLL 库的引用计数。
摘要
本文演示了从 Win16 平台调用 KERNEL32.DLL 库的 GetTickCount
函数。