在挂钩函数之后调用原始函数
Call original function after hooked function
我想学习如何制作钩子,所以我制作了一个简单的程序来测试我。钩子工作得很好,但我也想在调用钩子后调用原始函数。尝试了多种方法,移动堆栈,恢复原始字节,然后在挂钩函数的末尾调用原始函数,但都没有成功。
我的程序只需等待任何键并打印文本。
我的钩子(DLL):
#include <windows.h>
#include <stdio.h>
void WriteMem(DWORD dwAddr, BYTE *dwNew, int Size);
void MyPrintf(char *text)
{
printf("n Original message: %sn", buff);
}
void WriteMem(DWORD dwAddr, BYTE *dwNew, int Size)
{
DWORD OldProt;
VirtualProtect((void*)dwAddr, Size, PAGE_EXECUTE_READWRITE, &OldProt);
memset((void*)(dwAddr), 0x90, Size);
memcpy((void*)(dwAddr), (void*)(dwNew), Size);
VirtualProtect((void*)(dwAddr), Size, OldProt, &OldProt);
}
void SetJMP(INT32 dwOld, LPVOID dwNew, INT32 Size)
{
BYTE dwNewBytes[5] = {0xE9, 0x00, 0x00, 0x00, 0x00};
DWORD calc = ((DWORD)dwNew - dwOld - 5);
memcpy(&dwNewBytes[1], &calc, 4);
WriteMem(dwOld, dwNewBytes, Size);
}
int SetIntercepet()
{ // 0x40102A printf address
SetJMP(0x40102A, MyPrintf, 7);
return 0;
}
BOOL APIENTRY DllMain(HANDLE hModule, DWORD fdwReason, LPVOID lpReserved)
{
switch(fdwReason)
{
case DLL_PROCESS_ATTACH:
SetIntercepet();
break;
}
return TRUE;
}
我的测试程序(C):
#include <stdio.h>
#include <windows.h>
int main()
{
while (1)
{
system("pause");
printf("ORIGINALn");
}
}
部分测试程序反编译:
00401000 /$ 55 PUSH EBP
00401001 |. 8BEC MOV EBP,ESP
00401003 |> B8 01000000 /MOV EAX,1
00401008 |. 85C0 |TEST EAX,EAX
0040100A |. 74 1C |JE SHORT test.00401028
0040100C |. 68 00E04000 |PUSH test.0040E000 ; ASCII "pause"
00401011 |. E8 D9000000 |CALL test.004010EF
00401016 |. 83C4 04 |ADD ESP,4
00401019 |. 68 08E04000 |PUSH test.0040E008 ; ASCII "ORIGINAL"
0040101E |. E8 07000000 |CALL test.0040102A
00401023 |. 83C4 04 |ADD ESP,4
00401026 |.^EB DB JMP SHORT test.00401003
00401028 |> 5D POP EBP
00401029 . C3 RETN
0040102A /$ 6A 0C PUSH 0C
0040102C |. 68 50D44000 PUSH test.0040D450
00401031 |. E8 52140000 CALL test.00402488
00401036 |. 33C0 XOR EAX,EAX
00401038 |. 33F6 XOR ESI,ESI
0040103A |. 3975 08 CMP DWORD PTR SS:[EBP+8],ESI
由于您要覆盖实际的printf函数,您必须将指令复制到那里,然后执行相关的"修复"以使其在新位置工作,并跳回"在您的补丁之后"。这要么涉及到确切地知道原始代码是什么(换句话说,push 0c, push test.0040d450
),要么涉及到对机器代码的足够了解,以在其边界上分割指令。
另一种更简单的方法是用新代码替换原来的调用点。因此,与其将代码修补到0x40102a,不如将代码修补成40101E,将40102a从原始调用点保存下来,一旦完成了需要做的操作,就回调到40102a。
像这样的东西可以做到:
void* origPrintf;
void MyPrintf(char *text)
{
void (*orig)(char *text) = reinterpret_cast<void (*)(char *text)>(origPrintf);
printf("n Original message: %sn", buff);
orig(text);
}
void WriteMem(DWORD dwAddr, BYTE *dwNew, int Size, void &*oldCall)
{
DWORD OldProt;
int offset;
VirtualProtect((void*)dwAddr, Size, PAGE_EXECUTE_READWRITE, &OldProt);
memcpy(offset, (void*)(dwAddr + 1), sizeof(offset));
oldCall = (void*)dwAddr + 5 + offset; // 5 byte call instruction assumed.
memset((void*)(dwAddr), 0x90, Size);
memcpy((void*)(dwAddr), (void*)(dwNew), Size);
VirtualProtect((void*)(dwAddr), Size, OldProt, &OldProt);
}
void SetJMP(INT32 dwOld, LPVOID dwNew, INT32 Size, void&*oldCall)
{
BYTE dwNewBytes[5] = {0xE9, 0x00, 0x00, 0x00, 0x00};
DWORD calc = ((DWORD)dwNew - dwOld - 5);
memcpy(&dwNewBytes[1], &calc, 4);
WriteMem(dwOld, dwNewBytes, Size, oldCall);
}
int SetIntercepet()
{ // 0x40102A printf address
SetJMP(0x40102A, MyPrintf, 7);
return 0;
}
[我无法检查代码,因为我很确定我的64位Linux机器上的地址有很大不同,但它应该给出一个合理的原则]
相关文章:
- 函数调用中参数的顺序重要吗
- 基于另一个成员参数将函数调用从类传递给它的一个成员
- 变量没有改变?通过向量的函数调用
- 在两个类中共享相同的函数调用,并在不需要时避免空实例化
- 是否有C++编译器选项允许激进地删除所有函数调用,并将参数传递给具有空体的函数
- 我知道函数调用中存在歧义.有没有办法调用foo()函数
- 模板函数调用
- 获取从C++中同一类中的构造函数调用的方法返回的值
- 析构函数调用
- 成员函数调用和C++对象模型
- 使用共享指针的函数调用,其对象应为 const
- C++:编译时检查匹配的函数调用对?
- 函数调用C++中的参数太少
- 来自 DLL 的函数调用 [表观调用的括号前面的表达式必须具有(指向-)函数类型]
- 返回指向对象的指针的函数调用是否为 prvalue?
- C++ 如何重载 [] 运算符并进行函数调用
- 代码的效率. 转到和函数调用
- 是同一作用域的函数部分中的函数调用
- 如何封装一个函数,以便它只能由同一类中的一个其他函数调用?
- 类型擦除的std::function与虚拟函数调用的开销