Win32,如何用C挂钩编译程序中的函数?

前端之家收集整理的这篇文章主要介绍了Win32,如何用C挂钩编译程序中的函数?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
以此为例(在Ollydbg调试器中查看)

第一个PUSH EBP指令是void * f(int32_t n)的开始(idk它返回的内容,只是猜测void *),我知道输入参数n在堆栈中,而EBP 8是指向它的指针变量,我想它会是这样的
int * n =(int *)(uint32_t(EBP)0x08); / *假设EBP是void *和sizeof(EBP)== sizeof(uint32_t)== sizeof(void *),并且8数学在c uint32_t和x86程序集中是相同的.* /

我想制作一个钩子,它将检查n是否高于7或低于0,如果是,则将其更改为1.使用ollydbg,直接编写汇编代码,我可以这样做:
修补第一个MOV EBP,ESP指令到JMP SHORT到它后面的INT3指令(我需要7个字节),然后将(未使用的)INT3改为
MOV EBP,ESP
JMP LONG 0068BCCD
其中0068BCCD是文件末尾未使用的0x000000000000

,然后在0068BCCD,我可以编写汇编代码来检查EBP 8指向的int,并在必要时修改它:

PUSHAD
CMP DWORD PTR SS:[EBP+8],7
JA SHORT Error
CMP DWORD PTR SS:[EBP+8],0
JL SHORT Error
JMP SHORT Finished
Error:
PUSHAD
PUSH OFFSET TheString
CALL Onlink-x86.App::Output
ADD ESP,4
POPAD
MOV DWORD PTR SS:[EBP+8],1
Finished:
POPAD
JMP LONG 00447493
TheString:
"Warning: label assertion Failed,but (pretending its 1 and) trying to ignore.."+0x00

哪个(如果我没有搞砸)基本上相当于

void FilterIntAtEBP_8(){
int i=*(int*)(uint32_t(EBP)+8);
if(i>7 || i<0){
Output("Warning: label assertion Failed,but (pretending its 1 and) trying to ignore..");
*(int*)(uint32_t(EBP)+8)=1;
}
return;
}

最后,问题是:如何使用Ollydbg,而不是使用C? (我看到了一个源代码回来,一个MMORPG作弊程序,挂钩客户端,执行此操作,但代码丢失给我)

首先,您需要在目标进程中注入一个dll.为此,您可以使用以下代码

Injector.h

#ifndef INJECTOR_H_INCLUDED
#define INJECTOR_H_INCLUDED

#include <Windows.h>
#include <string>

class Injector
{
public:
    /**
     * Loads a DLL into the remote process
     * @Return true on sucess,false on failure
    */
    bool InjectDll(DWORD processId,std::string dllPath);
private:
};

#endif // INJECTOR_H_INCLUDED

Injector.cpp

#include "Injector.h"

bool Injector::InjectDll(DWORD processId,std::string dllPath)
{
    HANDLE hThread,hProcess;
    void*  pLibRemote = 0;  // the address (in the remote process) where szLibPath will be copied to;

    HMODULE hKernel32 = GetModuleHandle("Kernel32");
    HINSTANCE hInst = GetModuleHandle(NULL);

    char DllFullPathName[_MAX_PATH];
    GetFullPathName(dllPath.c_str(),_MAX_PATH,DllFullPathName,NULL);

    // Get process handle
    hProcess = OpenProcess(PROCESS_ALL_ACCESS,FALSE,processId);

    // copy file path in szLibPath
    char szLibPath[_MAX_PATH];
    strcpy_s(szLibPath,DllFullPathName);

    // 1. Allocate memory in the remote process for szLibPath
    pLibRemote = VirtualAllocEx( hProcess,NULL,sizeof(szLibPath),MEM_COMMIT,PAGE_READWRITE );

    if (pLibRemote == NULL)
    {
        // probably because you don't have administrator's right
        return false;
    }

    // 2. Write szLibPath to the allocated memory
    WriteProcessMemory(hProcess,pLibRemote,(void*)szLibPath,NULL);

    // 3. Force remote process to load dll
    hThread = CreateRemoteThread(hProcess,(LPTHREAD_START_ROUTINE) GetProcAddress(hKernel32,"LoadLibraryA"),NULL);

    if (hThread == NULL)
    {
        return false;
    }

    return true;
}

main.cpp中

#include "Injector.h"
int main()
{
    Injector injector;
    DWORD processId = 1653; // change the process id here. 

    if (injector.InjectDll(processId,"injected.dll"))
    {
        printf("Good job,you injected the dll\n");
    }
    else
    {
        printf("Something wrong happened\n");
    }

    while (true);
}

然后你必须做你的DLL.这是它变得更复杂的地方.首先一些包括

injected.dll

#include <Windows.h>
#include <stdio.h>

然后我们需要创建一个绕过正确位置的函数

void DetourAddress(void* funcPtr,void* hook,BYTE* mem)
{
    BYTE cmd[5] = { 0xE9,0x00,0x00 }; // jump place holder
    void* RVAaddr = (void*)((DWORD)funcPtr + (DWORD)GetModuleHandle(NULL)); // base + relative address

    // make memory readable/writable
    DWORD dwProtect;
    VirtualProtect(RVAaddr,5,PAGE_EXECUTE_READWRITE,&dwProtect);

    // read memory
    ReadProcessMemory(GetCurrentProcess(),(LPVOID)RVAaddr,&mem[2],NULL);

    // write jmp in cmd
    DWORD offset = ((DWORD)hook - (DWORD)RVAaddr - 5);  // (dest address) - (source address) - (jmp size)
    memcpy(&cmd[1],&offset,4); // write address into jmp
    WriteProcessMemory(GetCurrentProcess(),cmd,0); // write jmp

    // write mem
    VirtualProtect(mem,13,&dwProtect);

    void* returnAdress = (void*)((DWORD)RVAaddr + 5);
    memcpy(&mem[8],&returnAdress,4); // write return address into mem

    // reprotect
    VirtualProtect(RVAaddr,dwProtect,NULL);
}

如果您需要在某个时候删除您的DLL,则需要恢复代码

void PatchAddress(void* funcPtr,BYTE* mem)
{
    void* RVAaddr = (void*)((DWORD)funcPtr + (DWORD)GetModuleHandle(NULL)); // base + relative address

    // make memory readable/writable
    DWORD dwProtect;
    VirtualProtect(funcPtr,&dwProtect);

    WriteProcessMemory(GetCurrentProcess(),NULL); // write jmp

    VirtualProtect(RVAaddr,NULL);
}

接下来,我们需要从绕行的字节中创建一个函数,以便程序执行它们,这样它就不会受到绕行的影响.在全球空间中添加

// memory (0x5E = pop esi,0x68 = push DWORD,0xC3 = RETN)
BYTE detourMem[13] = { 0x5E,0x5E,0x0,0x68,0xC3 };

// Convert bytes array to function
typedef void ( * pFunc)();
pFunc funcMem = (pFunc) &detourMem;

// I also added a variable as an example of what you can do with it.
DWORD var = 0;

之后,您需要绕行功能

_declspec(naked) void DetourFunction()
{
    // we need to push all flag and registers on the stack so we don't modify them by accident
    __asm
    {
        PUSHFD
        PUSHAD

        // You can do "whatever" you want here in assembly code
        // ex,put eax value into var:
        mov var,eax
    }

    printf("this code is executed everytime the detoured function is called\n");
    // Do whatever you want in c++ here
    if (var < 7)
    {
        // eax was smaller than 7
    }

    // We pop every flags and registers we first pushed so that the program continue as it was supposed to
    __asm
    {
        // we set everything back to normal
        POPAD
        POPFD
        push esi

        // we call our funcMem
        mov edx,funcMem;
        call edx
    }
}

最后,这是你的DLLMain的样子:

BOOL APIENTRY DllMain( HMODULE hModule,DWORD  ul_reason_for_call,LPVOID lpReserved  )
{
    DWORD detouredAddress = 0x689B; // add the RELATIVE ADDRESS of the location you want to detour
    FILE *stream;
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        // Only add this if you want a console to appears when you inject your dll (don't forget FreeConsole when you remove the dll)
        AllocConsole();
        freopen_s(&stream,"CONOUT$","w",stdout);

        // If you need to know the base address of the process your injected:   
        printf("base address: 0x%X\n",(DWORD)GetModuleHandle(NULL));

        // Our detour function
        DetourAddress((void*)detouredAddress,(void*)&DetourFunction,detourMem);
        break;
    case DLL_PROCESS_DETACH:
        // We restore the process to have what it was before it was injected
        PatchAddress((void*)detouredAddress,detourMem);

        FreeConsole();
        break;
    }

    return true;
}

我明白这一切都很多,所以如果你有任何问题请不要犹豫!

猜你在找的Windows相关文章