Win32的,我怎么能挂接函数中使用C ++编写的程序? [英] Win32, How can i hook functions in compiled programs with C++?

查看:248
本文介绍了Win32的,我怎么能挂接函数中使用C ++编写的程序?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

就拿这个功能(在Ollydbg的调试器查看)

Take for instance this function (viewed in Ollydbg debugger)

第一个PUSH EBP指令是一个void * F(int32_t N)开始(IDK它返回什么,只是猜测无效*),我知道,输入参数n是堆栈,以及EBP + 8一个指针变量,我想它会像
INT * N =(INT *)(uint32_t的(EBP)+ 0×08); / *假设EBP是一个void *和sizeof(EBP)==的sizeof(uint32_t的)==的sizeof(void *的),而数学+8是相同c ++ uint32_t的和x86汇编.. * /

The first PUSH EBP instruction is the start for a void* f(int32_t n) (idk what it returns, just guessing void*), I know that the input parameter n is at the stack, and that EBP+8 is a pointer to that variable, i guess it would be like int* n=(int*)(uint32_t(EBP)+0x08); /*assuming EBP is a void* and sizeof(EBP)==sizeof(uint32_t)==sizeof(void*) and that the +8 math is the same in c++ uint32_t and x86 assembly..*/

我想打一个勾,将检查是否n是高于7或低于0,如果是的话,将其更改为1. OllyDbg的,写装配code直接,我可以这样做:
修补第一个MOV EBP,ESP指令JMP短,其背后的INT3指令(我需要7个字节),然后改变(未使用)INT3对
MOV EBP,ESP
JMP LONG 0068BCCD
哪里0068BCCD是将未使用的0x000000000000的在该文件的末尾
 

I want to make a hook, that will check if n is above 7, or below 0, and if it is, then change it to 1. With ollydbg, writing the assembly code directly, i can do: patch the first MOV EBP,ESP instruction to JMP SHORT to the INT3 instructions behind it (I'll need 7 bytes), then change the (unused) INT3's to MOV EBP,ESP JMP LONG 0068BCCD where 0068BCCD is to the unused 0x000000000000's at the end of the file

,然后在0068BCCD,我可以写汇编codeS检查INT指向由EBP + 8,并在必要时进行修改:

, then at the 0068BCCD , i can write the assembly codes to check the int pointed at by EBP+8 , and modify it if necessary:

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

这(如果我没有陷入困境)基本上相当于

which (if i didn't mess up) is basically the equivalent of

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 ++? (我看到了一个源$ C ​​$ C回来的路上,一个MMORPG作弊程序,钩住客户,做到这一点,但code是输给我)

Finally, here is the question: How can i make this hook, not with Ollydbg, but with C++ ? (I saw a source code way back, a MMORPG cheat program, hooking the client, do this, but the code is lost to me )

推荐答案

首先,你将要注入的目标进程中的DLL。要做到这一点,你可以用这个code:

First, you will want to inject a dll in the target process. To do so, you can use this code:

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, sizeof(szLibPath), NULL);

    // 3. Force remote process to load dll
    hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE) GetProcAddress(hKernel32,"LoadLibraryA"), pLibRemote, 0, 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。这是它变得有点复杂。首先,一些包括:

Then you have to make your dll. This is where it gets a little more complicated. First some includes:

injected.dll

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

然后,我们需要将绕行右位置的功能:

Then we need to make a function that will detour the right location:

void DetourAddress(void* funcPtr, void* hook, BYTE* mem)
{
    BYTE cmd[5] = { 0xE9, 0x00, 0x00, 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], 5, 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(), (LPVOID)RVAaddr, cmd, 5, 0); // write jmp

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

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

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

如果您需要在某一时刻删除您的DLL,您将需要恢复code:

If you need to remove your dll at some point, you will need to restore the code:

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, 5, PAGE_EXECUTE_READWRITE, &dwProtect);

    WriteProcessMemory(GetCurrentProcess(), (LPVOID)RVAaddr, &mem[2], 5, NULL); // write jmp

    VirtualProtect(RVAaddr, 5, dwProtect, NULL);
}

接下来,我们需要使一个函数出迂回字节,以便使程序执行它们,因此,它不会受到我们的弯路。全球空间补充一点:

Next, we need to make a function out of the detoured bytes in order for the program to execute them, so that it isn't affected by our detour. Add this in global space:

// memory (0x5E = pop esi, 0x68 = push DWORD, 0xC3 = RETN)
BYTE detourMem[13] = { 0x5E, 0x5E, 0x0, 0x0, 0x0, 0x0, 0x0, 0x68, 0x00, 0x00, 0x00, 0x00, 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;

在这之后,你需要你的迂回功能:

After that, you need your detouring function:

_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
    }
}

Finaly,这里是你的DLLMain会是什么样子:

Finaly, here is how your DLLMain would look like:

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;
}

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

I understand this is a lot all at once, so if you have any questions don't hesitate!

这篇关于Win32的,我怎么能挂接函数中使用C ++编写的程序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆