MAGE_IMPORT_DESCRIPTOR里的Name成员变量是模块名字的指针。如果我们想要挂钩某个函数比如是来自kernel32.dll我们就在导入表里找属于名字kernel32.dll的描述符号。我们先调用ImageDirectoryEntryToData然后找到名字是"kernel32.dll"的描述符号(可能不只一个描述符号是这个名字),最后我们在这个模块的记录里所有函数的列表里找到我们想要的函数(函数地址通过GetProcAddress函数获得)。如果我们找到了就必须用VirtualProtect函数来改变内存页面的保护属性,然后就可以在内存中的这些部分写入代码了。在改写了地址之后我们要把保护属性改回来。在调用VirtualProtect之前我们还要先知道有关页面的信息,这通过VirtualQuery来实现。我们可以加入一些测试以防某些函数会失败(比方说如果第一次调用VirtualProctect就失败了,我们就没办法继续)。 PCSTR pszHookModName = "kernel32.dll",pszSleepName = "Sleep";
HMODULE hKernel = GetModuleHandle(pszHookModName);
PROC pfnNew = (PROC)0x12345678, //这里存放新地址
pfnHookAPIAddr = GetProcAddress(hKernel,pszSleepName); ULONG ulSize;
PIMAGE_IMPORT_DESCRIPTOR pImportDesc =
(PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData(
hKernel,
TRUE,
IMAGE_DIRECTORY_ENTRY_IMPORT,
&ulSize
); while (pImportDesc->Name)
{
PSTR pszModName = (PSTR)((PBYTE) hKernel + pImportDesc->Name);
if (stricmp(pszModName, pszHookModName) == 0)
break;
pImportDesc++;
} PIMAGE_THUNK_DATA pThunk =
(PIMAGE_THUNK_DATA)((PBYTE) hKernel + pImportDesc->FirstThunk); while (pThunk->u1.Function)
{
PROC* ppfn = (PROC*) &pThunk->u1.Function; /这1句不明白/
BOOL bFound = (*ppfn == pfnHookAPIAddr); /这1句不明白/ if (bFound)
{
MEMORY_BASIC_INFORMATION mbi;
VirtualQuery(
ppfn,
&mbi,
sizeof(MEMORY_BASIC_INFORMATION)
);
VirtualProtect(
mbi.BaseAddress,
mbi.RegionSize,
PAGE_READWRITE,
&mbi.Protect)
) *ppfn = *pfnNew; DWORD dwOldProtect;
VirtualProtect(
mbi.BaseAddress,
mbi.RegionSize,
mbi.Protect,
&dwOldProtect
);
break;
}
pThunk++;
}
PROC* ppfn = (PROC*) &pThunk->u1.Function;
BOOL bFound = (*ppfn == pfnHookAPIAddr);
我自己认pThunk指向IMAGE_THUNK_DATA这个结构体的指针
那么
IMAGE_THUNK_DATA结构体的定义是这样的
IMAGE_THUNK_DATA
{
union
{
PBYTE ForwarderString;
PDWORD Function;
DWORTD Ordinal;
PIMAGE_INPORT_BY_NAME AddressOfData;
}u1;
}
那么
PROC* ppfn = (PROC*) &pThunk->u1.Function
我不明白pThunk->u1.Function前面要加&
因为pThunk->u1.Function这个成员是PDWORD指针!指向dword那么为什么还要加&号呢?
应该直接把这个地址转化为(PROC*)这个地址啊!
应该这样
PROC* ppfn = (PROC*) pThunk->u1.Function
还有这一句
BOOL bFound = (*ppfn == pfnHookAPIAddr);
为什么要是*ppfn==pfnHookAPIAddr
我觉得应该是
ppfn==pfnHookAPIAddr
因为前面这个
pfnHookAPIAddr = GetProcAddress(hKernel,pszSleepName);
那么pfnHookAPIAddr这个是在pszSleepName在hKernel的地址!
因为函数的名称可以代表函数的地址那么
这里的ppfn应该也代表函数名为什么还要加上*ppfn==pfnHookAPIAddr
请高手指教!
HMODULE hKernel = GetModuleHandle(pszHookModName);
PROC pfnNew = (PROC)0x12345678, //这里存放新地址
pfnHookAPIAddr = GetProcAddress(hKernel,pszSleepName); ULONG ulSize;
PIMAGE_IMPORT_DESCRIPTOR pImportDesc =
(PIMAGE_IMPORT_DESCRIPTOR)ImageDirectoryEntryToData(
hKernel,
TRUE,
IMAGE_DIRECTORY_ENTRY_IMPORT,
&ulSize
); while (pImportDesc->Name)
{
PSTR pszModName = (PSTR)((PBYTE) hKernel + pImportDesc->Name);
if (stricmp(pszModName, pszHookModName) == 0)
break;
pImportDesc++;
} PIMAGE_THUNK_DATA pThunk =
(PIMAGE_THUNK_DATA)((PBYTE) hKernel + pImportDesc->FirstThunk); while (pThunk->u1.Function)
{
PROC* ppfn = (PROC*) &pThunk->u1.Function; /这1句不明白/
BOOL bFound = (*ppfn == pfnHookAPIAddr); /这1句不明白/ if (bFound)
{
MEMORY_BASIC_INFORMATION mbi;
VirtualQuery(
ppfn,
&mbi,
sizeof(MEMORY_BASIC_INFORMATION)
);
VirtualProtect(
mbi.BaseAddress,
mbi.RegionSize,
PAGE_READWRITE,
&mbi.Protect)
) *ppfn = *pfnNew; DWORD dwOldProtect;
VirtualProtect(
mbi.BaseAddress,
mbi.RegionSize,
mbi.Protect,
&dwOldProtect
);
break;
}
pThunk++;
}
PROC* ppfn = (PROC*) &pThunk->u1.Function;
BOOL bFound = (*ppfn == pfnHookAPIAddr);
我自己认pThunk指向IMAGE_THUNK_DATA这个结构体的指针
那么
IMAGE_THUNK_DATA结构体的定义是这样的
IMAGE_THUNK_DATA
{
union
{
PBYTE ForwarderString;
PDWORD Function;
DWORTD Ordinal;
PIMAGE_INPORT_BY_NAME AddressOfData;
}u1;
}
那么
PROC* ppfn = (PROC*) &pThunk->u1.Function
我不明白pThunk->u1.Function前面要加&
因为pThunk->u1.Function这个成员是PDWORD指针!指向dword那么为什么还要加&号呢?
应该直接把这个地址转化为(PROC*)这个地址啊!
应该这样
PROC* ppfn = (PROC*) pThunk->u1.Function
还有这一句
BOOL bFound = (*ppfn == pfnHookAPIAddr);
为什么要是*ppfn==pfnHookAPIAddr
我觉得应该是
ppfn==pfnHookAPIAddr
因为前面这个
pfnHookAPIAddr = GetProcAddress(hKernel,pszSleepName);
那么pfnHookAPIAddr这个是在pszSleepName在hKernel的地址!
因为函数的名称可以代表函数的地址那么
这里的ppfn应该也代表函数名为什么还要加上*ppfn==pfnHookAPIAddr
请高手指教!
这代码我看过~~没明白多少~~哈哈~~
等我明白了告诉你的~~
而PROC* ppfn 是一个指向函数地址的指针