是否可以“复制"?一个函数进入另一个进程并在一个线程中执行它而不使用 LoadLibrary? [英] Is it possible to "copy" a function into another process and execute it in a thread without using LoadLibrary?

查看:23
本文介绍了是否可以“复制"?一个函数进入另一个进程并在一个线程中执行它而不使用 LoadLibrary?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写和执行单个函数:

I'm trying to write and execute a single function function:

int thread(void) {
    WCHAR boxTitle = L"testing...";
    WCHAR message = L"hello?";
    int (*MessageBoxW)(HWND, LPCWSTR, LPCWSTR, UINT);
    MessageBoxW = (LPVOID)0x7FFCA28E2750; // address of MessageBoxW function in user32.dll on my machine
    MessageBoxW(NULL, message, boxTitle, MB_OK);
    return 0;
}

在另一个使用 VirtualAllocExWriteProcessMemoryCreateRemoteThread 的进程中:

In another process using VirtualAllocEx, WriteProcessMemory, and CreateRemoteThread:

int main(void) {

    HANDLE hProc;
    LPVOID baseAddr;
    int funcSize;

    funcSize = (int)main - (int)thread;
    hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, 10724); // notepad.exe PID on my machine
    baseAddr = VirtualAllocEx(hProc, NULL, funcSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);

    WriteProcessMemory(hProc, baseAddr, &thread, funcSize, NULL);
    CreateRemoteThread(hProc, NULL, 0, (LPTHREAD_START_ROUTINE)baseAddr, NULL, 0, NULL);
    CloseHandle(hProc);

    return 0;
}

问题是消息框没有正确显示我通过函数指针提供给 MessageBoxW 函数的 LPCWSTR 参数.消息框出现,但框标题和消息正文为空.

The problem is that the message box doesn't properly display the LPCWSTR arguments that I provide to the MessageBoxW function through my function pointer. The message box appears, but the box title and message body are blank.

这是显示此问题的图像的链接:

Here is a link to an image displaying this issue:

我有一种感觉,这个问题与字符编码以及我将函数复制到远程进程的虚拟地址空间的方式有关,但我真的不知道出了什么问题.

I have a feeling that this issue involves something with character encoding and the way that I have copied my function into the virtual address space of the remote process, but I really can't figure out what's wrong.

推荐答案

您无法按照自己的方式计算函数的大小.无法保证mainthread 会按顺序存储在内存中,或者main 会在thread 之后存储>.

You can't calculate the size of a function the way you are. There is no guarantee that main and thread will be stored sequentially in memory, or that main will be stored after thread.

您也没有将字符串文字的实际字符复制到远程进程中,您只是将指针复制到字符串文字中.您不能跨进程边界共享指针,每个进程都有不同的虚拟地址空间,并且给定进程地址空间内的指针仅在该进程内有效.您需要在远程进程中分配额外的内存以将字符复制到其中,然后让远程线程将指向该内存的指针传递给 MessageBoxW().

You are also not copying the actual characters of the string literals into the remote process, you are only copying the pointers to the string literals. You can't share pointers across process boundaries, each process has a different virtual address space, and a pointer within a given process' address space is only valid within that process. You need to allocate additional memory in the remote process to copy the characters into, and then make the remote thread pass pointers to that memory to MessageBoxW().

更不用说,您根本没有执行任何清理,因此您正在泄漏在远程进程中分配的内存和系统资源,让它们在远程线程完成运行后闲置不用.

Not to mention, you are not performing any cleanup at all, so you are leaking memory and system resources that are allocated in the remote process, letting them just sit unused once the remote thread is finished running.

您将不得不执行以下类似操作(这仅适用于 x86,对于 x64 来说有点复杂.如果我的操作码有点错误,请原谅我,我的 x86 有点生疏):

You will have to do something more like the following (this is for x86 only, it gets a bit more complicated for x64. Forgive me if I get the opcodes wrong a little, my x86 is a bit rusty):

static const WCHAR *boxTitle = L"testing...";
static const WCHAR *message = L"hello?";

#pragma pack(push, 1)
struct myThreadOpCodes
{
    BYTE push_uType;
    DWORD uType;
    BYTE push_lpCaption;
    DWORD lpCaption;
    BYTE push_lpText;
    DWORD lpText;
    BYTE push_hWnd;
    DWORD hWnd;
    BYTE call_MessageBoxW;
    LONG offset_MessageBoxW;
    BYTE xor_EAX[2];
    BYTE ret;
    WORD numBytes;
};
#pragma pack(pop)

int main(void)
{
    HANDLE hProc, hThread;
    LPVOID baseAddr;
    myThreadOpCodes code;

    hProc = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | PROCESS_VM_OPERATION | PROCESS_VM_WRITE | PROCESS_VM_READ, FALSE, 10724);
    if (!hProc)
        return 0;

    // TODO: if ASLR is enabled, to get the real address of MessageBoxW within the 
    // target process, you will have to first enumerate the loaded modules in the
    // process looking for the actual base address of kernel32.dll (see
    // http://bytepointer.com/articles/locating_kernel32_in_aslr_memory.htm)
    // then enumerate its exports table looking for the real address of
    // MessageBoxW...
    void *lpMessageBox = GetProcAddress(GetModuleHandle(TEXT("kernel32")), "MessageBoxW");

    code.push_uType = 0x68;
    code.uType = MB_OK;
    code.push_lpCaption = 0x68;
    code.lpCaption = 0;
    code.push_lpText = 0x68;
    code.lpText = 0;
    code.push_hWnd = 0x68;
    code.hWnd = 0;
    code.call_MessageBoxW = 0xE8;
    code.offset_MessageBoxW = 0;
    code.xor_EAX[0] = 0x33;
    code.xor_EAX[1] = 0xC0;
    code.ret = 0xCA;
    code.numBytes = sizeof(LPVOID);

    int TitleLen = (lstrlenW(lpTitle) + 1) * sizeof(WCHAR);
    int TextLen = (lstrlenW(message) + 1) * sizeof(WCHAR);

    baseAddr = VirtualAllocEx(hProc, NULL, sizeof(code) + TitleLen + TextLen, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
    if (baseAddr)
    {
        code.lpCaption = DWORD_PTR(baseAddr) + sizeof(code);
        code.lpText = code.lpCaption + TitleLen;
        code.offset_MessageBoxW = LONG_PTR(lpMessageBox) - (LONG_PTR(baseAddr) + offsetof(myThreadOpCodes, xor_EAX));

        if (WriteProcessMemory(hProc, baseAddr, &code, sizeof(code) + TitleLen + TextLen, NULL))
        {
            DWORD oldProtection;
            if (VirtualProtectEx(hProc, baseAddr, sizeof(code), PAGE_EXECUTE, &oldProtection))
            {
                FlushInstructionCache(hProc, baseAddr, sizeof(code));

                hThread = CreateRemoteThread(hProc, NULL, 0, (LPTHREAD_START_ROUTINE)baseAddr, NULL, 0, NULL);
                if (hThread)
                {
                    WaitForSingleObject(hThread, INFINITE);
                    CloseHandle(hThread);
                }
            }
        }

        VirtualFreeEx(hProc, baseAddr, 0, MEM_RELEASE);
    }

    CloseHandle(hProc);

    return 0;
}

话虽如此,将整个函数注入另一个进程的更简单的方法是在 DLL 中实现该函数,以便您可以正常为该函数编写代码,然后注入对 LoadLibrary() 的简单调用 进入目标进程加载DLL,然后DLL可以根据需要调用该函数.但是您似乎想避免这条路线,因为您的问题是关于避免 LoadLibrary().

That being said, a much simpler way to inject a whole function into another process is to implement the function in a DLL so you can write code for the function normally, and then inject a simple call to LoadLibrary() into the target process to load the DLL, and then the DLL can call the function as needed. But you seem to want to avoid this route, since your question is about avoiding LoadLibrary().

这篇关于是否可以“复制"?一个函数进入另一个进程并在一个线程中执行它而不使用 LoadLibrary?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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