【问题标题】:Call original function after hooked function在钩子函数之后调用原始函数
【发布时间】:2014-09-06 18:42:02
【问题描述】:

我想学习如何制作钩子,所以我做了一个简单的程序来测试我。钩子工作得很好,但我也想在调用钩子后调用原始函数。尝试了多种方式,移动堆栈,恢复原始字节,然后在挂钩函数结束时调用原始函数,但没有奏效。

我的程序只是等待任何键并打印文本。

我的钩子(DLL):

#include <windows.h>
#include <stdio.h>

void WriteMem(DWORD dwAddr, BYTE *dwNew, int Size);

void MyPrintf(char *text)
{
    printf("\n Original message: %s\n", 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("ORIGINAL\n");
    }
}

部分测试程序反编译:

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

【问题讨论】:

  • 函数的位置不能保证在构建之间是相同的。在继续之前,您应该解决这个缺陷。

标签: c++ c windows dll hook


【解决方案1】:

由于您要覆盖实际的 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: %s\n", 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 机器上的地址完全不同,但它应该给出一个合理的原则]

【讨论】:

  • 那个答案太糟糕了,代码到处都是坏的。我知道你提到你无法检查它。但是出现一般语法错误void&amp;*SetJMP(4 parameters) 称为SetJMP(3 arguments)
  • 我修复了一般问题,但并没有真正改变任何东西。当尝试从挂钩函数调用原始函数时,这会导致明显的系统崩溃。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-09-27
  • 1970-01-01
  • 2013-06-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多