DLL导出的挂钩API

时间:2018-10-25 15:52:08

标签: c windows assembly dll hook

我有另一个进程启动的应用程序,该程序加载一些dll(具有很多导出的函数)并在启动后的短时间内调用它们。由于我们不能在此处使用传统的API挂钩(通过替换指向函数的指针),并且我不会使用蹦床(因为它需要反汇编程序来获取指令长度),因此我已经编写了代码以修补dll文件,因此所有导出的函数都将以“无限跳转”操作码开头:{0xEB,0xFE}。

操作顺序为:

  1. 修补dll文件
  2. 启动最终将调用我们应用程序的过程
  3. 打开应用程序的进程句柄
  4. 枚举线程以查找进程卡住的IP地址
  5. 现在我们可以附加调试器并单步执行该功能,或者我们可以“跳过”它

以下是“跳过”功能的代码:

extern "C" void asm_proc();

#define PATCH_SIZE      2

UCHAR g_Patch[PATCH_SIZE] = { 0xEB, 0xFE };

void SkipFunction(FUNCTION_ITEM *func, HANDLE hProcess, HANDLE hThread)
{
    CONTEXT lcContext;
    UCHAR *ReturnAddress;
    UCHAR *TargetAddress;
    UCHAR *BlockAddress;
    DWORD ProcSize;
    UCHAR Ret;

    Ret = 0xC3;
    ProcSize = 14;

    lcContext.ContextFlags = CONTEXT_ALL;
    if (!GetThreadContext(hThread, &lcContext)) DbgRaiseAssertionFailure();

    BlockAddress = (UCHAR*)VirtualAllocEx(hProcess, NULL, sizeof(ReturnAddress) + ProcSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    TargetAddress = BlockAddress + sizeof(ReturnAddress);

    ReadProcessMemoryEx(hProcess, lcContext.Rsp, (UCHAR*)&ReturnAddress, sizeof(ReturnAddress));
    WriteProcessMemoryEx(hProcess, lcContext.Rsp, (UCHAR*)&TargetAddress, sizeof(TargetAddress));

    WriteProcessMemoryEx(hProcess, (DWORD64)BlockAddress, (UCHAR*)&ReturnAddress, sizeof(ReturnAddress));
    // disable incremental linking to make it work
    WriteProcessMemoryEx(hProcess, (DWORD64)TargetAddress, (UCHAR*)asm_proc, ProcSize);

    WriteProcessMemoryEx(hProcess, func->Rip, func->OriginalBytes, PATCH_SIZE);

    while (TRUE)
    {
        Sleep(100);

        lcContext.ContextFlags = CONTEXT_ALL;
        if (!GetThreadContext(hThread, &lcContext)) DbgRaiseAssertionFailure();

        if (lcContext.Rip == (DWORD64)(TargetAddress + 12)) break;
    }

    WriteProcessMemoryEx(hProcess, func->Rip, g_Patch, PATCH_SIZE);

    WriteProcessMemoryEx(hProcess, (DWORD64)(TargetAddress + 12), &Ret, sizeof(Ret));

    VirtualFreeEx(hProcess, BlockAddress, 0, MEM_RELEASE);
}

asm_proc 功能代码:

PUBLIC asm_proc

.code

asm_proc PROC
    call $+5
    pop rcx
    sub rcx, 13
    push qword ptr [rcx]
    jmp $
asm_proc ENDP

END

func-> Rip 保留修补功能的IP地址 func-> OriginalBytes 保留原始函数字节,因为它们出现在原始dll文件中

基本上,我们使用VirtualAllocEx分配内存,复制我们的代码和原始返回地址,将返回地址替换为堆栈上的内容,然后进入无限循环,因此我们可以再次对函数进行修补。这种方法应该适用于单线程挂钩(我不需要处理多个线程)。

但是,有时,当我们“跳过”功能时,应用程序只是崩溃了,我不明白为什么会这样。您能说些什么?怎么了谢谢。

0 个答案:

没有答案