【问题标题】:Crashes after Injecting std functions in a process在进程中注入 std 函数后崩溃
【发布时间】:2017-04-30 14:33:10
【问题描述】:

我目前正在尝试 PE 注入,并注意到一旦我使用 std::cout 或 std::string 之类的东西,我在崩溃中注入的目标进程。 消息框甚至 printf() 都可以正常工作。代码编译没有错误,我读到导入表不在注入过程中的同一位置可能导致它崩溃,但我不知道该怎么做才能修复它(重新加载导入表)。在此先感谢,这里是注入示例:

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

void ThreadProc(PVOID p)
{
    MessageBox(NULL,"Message from injected code!","Message",MB_ICONINFORMATION); //funktioniert einwandfrei
    RedirectOutput();
    std::cout << "hi"; //crashed
}

int main(int argc,char* argv[])
{
    PIMAGE_DOS_HEADER pIDH;
    PIMAGE_NT_HEADERS pINH;
    PIMAGE_BASE_RELOCATION pIBR;

    HANDLE hProcess,hThread;
    PUSHORT TypeOffset;

    PVOID ImageBase,Buffer,mem;
    ULONG i,Count,Delta,*p;

    printf("\nOpening target process\n");

    hProcess=OpenProcess(
        PROCESS_CREATE_THREAD|PROCESS_QUERY_INFORMATION|PROCESS_VM_OPERATION|PROCESS_VM_READ|PROCESS_VM_WRITE,
        FALSE,
       13371337);

    if(!hProcess)
    {
        printf("\nError: Unable to open target process (%u)\n",GetLastError());
        return -1;
    }

    ImageBase=GetModuleHandle(NULL);
    printf("\nImage base in current process: %#x\n",ImageBase);

    pIDH=(PIMAGE_DOS_HEADER)ImageBase;
    pINH=(PIMAGE_NT_HEADERS)((PUCHAR)ImageBase+pIDH->e_lfanew);

    printf("\nAllocating memory in target process\n");
    mem=VirtualAllocEx(hProcess,NULL,pINH->OptionalHeader.SizeOfImage,MEM_COMMIT|MEM_RESERVE,PAGE_EXECUTE_READWRITE);

    if(!mem)
    {
        printf("\nError: Unable to allocate memory in target process (%u)\n",GetLastError());

        CloseHandle(hProcess);
        return 0;
    }

    printf("\nMemory allocated at %#x\n",mem);

    Buffer=VirtualAlloc(NULL,pINH->OptionalHeader.SizeOfImage,MEM_COMMIT|MEM_RESERVE,PAGE_READWRITE);
    memcpy(Buffer,ImageBase,pINH->OptionalHeader.SizeOfImage);

    printf("\nRelocating image\n");

    pIBR=(PIMAGE_BASE_RELOCATION)((PUCHAR)Buffer+pINH->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress);
    Delta=(ULONG)mem-(ULONG)ImageBase;

    printf("\nDelta: %#x\n",Delta);

    while(pIBR->VirtualAddress)
    {
        if(pIBR->SizeOfBlock>=sizeof(IMAGE_BASE_RELOCATION))
        {
            Count=(pIBR->SizeOfBlock-sizeof(IMAGE_BASE_RELOCATION))/sizeof(USHORT);
            TypeOffset=(PUSHORT)(pIBR+1);

            for(i=0;i<Count;i++)
            {
                if(TypeOffset[i])
                {
                    p=(PULONG)((PUCHAR)Buffer+pIBR->VirtualAddress+(TypeOffset[i] & 0xFFF));
                    *p+=Delta;
                }
            }
        }

        pIBR=(PIMAGE_BASE_RELOCATION)((PUCHAR)pIBR+pIBR->SizeOfBlock);
    }

    printf("\nWriting relocated image into target process\n");

    if(!WriteProcessMemory(hProcess,mem,Buffer,pINH->OptionalHeader.SizeOfImage,NULL))
    {
        printf("\nError: Unable to write process memory (%u)\n",GetLastError());

        VirtualFreeEx(hProcess,mem,0,MEM_RELEASE);
        CloseHandle(hProcess);

        return -1;
    }

    VirtualFree(Buffer,0,MEM_RELEASE);

    printf("\nCreating thread in target process\n");
    hThread=CreateRemoteThread(hProcess,NULL,0,(LPTHREAD_START_ROUTINE)((PUCHAR)ThreadProc+Delta),NULL,0,NULL);

    if(!hThread)
    {
        printf("\nError: Unable to create thread in target process (%u)\n",GetLastError());

        VirtualFreeEx(hProcess,mem,0,MEM_RELEASE);
        CloseHandle(hProcess);

        return -1;
    }

    printf("\nWaiting for the thread to terminate\n");
    WaitForSingleObject(hThread,INFINITE);

    printf("\nThread terminated\n\nFreeing allocated memory\n");

    VirtualFreeEx(hProcess,mem,0,MEM_RELEASE);
    CloseHandle(hProcess);

    return 0;
}

【问题讨论】:

  • 复制代码并应用重定位还不够。您的代码可能已经有一些初始化的全局数据,您可以按原样复制这些数据。例如一些在原始进程中正确且有意义的全局指针,但在远程进程中将指向垃圾。或者一些全局句柄打开..所有这些你复制到远程进程。所以 c/c++ 运行时和远程失败 - 非常等待

标签: c++ c code-injection portable-executable import-table


【解决方案1】:

我认为答案很简单——STL 库请求对全局数据进行一些初始化。例如,通过全局对象的构造函数。但是您只需将代码复制到目标进程即可。它不调用任何初始化,通常在调用 main 函数之前执行。只需尝试 DLL 注入。

【讨论】:

  • 问题是我真的不想拥有一个 dll 和注入器,我认为没有办法将它们合并在一起..
  • 然后,您可以编写自己的分配器并将 std::string 替换为 std::basic_string,如果分配器不使用任何全局数据,它应该可以工作。至少对于字符串、映射、向量和列表。我不确定你能不能这么简单地改变 cin 和 cout。
【解决方案2】:

您似乎没有在目标进程中加载​​ CRT dll,所以我假设当您尝试调用 cout 函数时,您正在跳转到未分配的内存。

如果 DLL 实际上是在目标进程中加载​​的,请确保它与在您自己的进程中加载​​的地址相同。否则,您必须修补导入表以匹配目标进程的导入表。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-10-14
    • 1970-01-01
    • 2016-08-02
    • 1970-01-01
    • 2014-05-09
    • 2013-05-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多