手动DLL注入

时间:2019-04-19 21:59:41

标签: c++ windows dll dll-injection

我正在尝试学习一些手动dll注入,但是似乎无法使dlls代码执行正常工作。我是Windows C ++的新手,因此感谢您提供任何改进我的代码的技巧。我也只发布了相关代码。

进样器程序:

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

DWORD gotDLL = GetFullPathName(DLL_NAME, MAX_PATH, dllPath, NULL);

hFile = CreateFile(dllPath, GENERIC_READ, NULL, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

dllFileSize = GetFileSize(hFile, NULL);
memAddrForDLL = VirtualAllocEx(hProcess, NULL, dllFileSize, MEM_RESERVE | MEM_COMMIT, PAGE_EXECUTE_READWRITE);

loadedDLL = HeapAlloc(GetProcessHeap(), NULL, dllFileSize);

// Load dll into allocated memory in current process
ReadFile(hFile, loadedDLL, dllFileSize, &bytesRead, NULL))

// Find offset of dll entry point
IMAGE_NT_HEADERS* pOldNtHeader = reinterpret_cast<IMAGE_NT_HEADERS*>(reinterpret_cast<BYTE*>(loadedDLL) + reinterpret_cast<IMAGE_DOS_HEADER*>(loadedDLL)->e_lfanew);
IMAGE_OPTIONAL_HEADER* pOldOptHeader = &pOldNtHeader->OptionalHeader;

entryPointOffset = pOldOptHeader->AddressOfEntryPoint;

// Load dll into allocated memory in target process
WriteProcessMemory(hProcess, memAddrForDLL, loadedDLL, bytesRead, NULL)

LPTHREAD_START_ROUTINE entryPoint = (LPTHREAD_START_ROUTINE)((unsigned __int64)memAddrForDLL + entryPointOffset);

CreateRemoteThread(hProcess, NULL, NULL, (LPTHREAD_START_ROUTINE)LoadLibrary, entryPoint, NULL, NULL)

DLL:

DWORD WINAPI OnDllAttach(LPVOID base){
    typedef void func(void);
    func* f = (func*)0x00007FF605EC5835;
    f();
    FreeLibraryAndExitThread(static_cast<HMODULE>(base),1);
}

BOOL WINAPI OnDllDetach(){
    return TRUE;
}

BOOL WINAPI DllMain(_In_ HINSTANCE hinstDll,
                    _In_ DWORD fdwReason,
                    _In_opt_ LPVOID lpvReserved){
    typedef void func(void);
    func* f = (func*)0x00007FF605EC5835;
    f();
    switch(fdwReason) {
        case DLL_PROCESS_ATTACH:
            DisableThreadLibraryCalls(hinstDll);
            CreateThread(nullptr, 0, OnDllAttach, hinstDll, 0, nullptr);
            return TRUE;
        case DLL_PROCESS_DETACH:
            if(lpvReserved == nullptr)
                return OnDllDetach();
            return TRUE;
        default:
            return TRUE;
    }
}

目标程序包含此功能:

void printer(){
    cout << "test" << endl;
}

我的注射器产生以下输出

1. Attempting to attatch to process target.exe
--- Got target.exe PID: 14640
--- Got target.exe Handle: 0x0000000000000084
2. Attempting to allocate memory
--- Found dll: D:\projects\injector\hack.dll
--- Got hack.dll Handle: 0x0000000000000088
--- Allocated memory in target.exe at 0x0000017BEB690000
3. Attempting to copy dll to target.exe
--- Allocated memory at 0x00000226A060FFE0
--- Loaded hack.dll in current process at 0x00000226A060FFE0
--- hack.dll is a valid DLL
--- Loaded hack.dll into target.exe at 0x0000017BEB690000
4. Attempting to execute dll
--- Offset from start of file to entrypoint: 0x3cf6
--- Began execution of hack.dll in target.exe at 0x0000017BEB693CF6

使用Ghidra,我可以确认这是dll入口点的正确偏移量。但是,当运行我的注射器时,目标进程中没有任何反应,我也尝试使用cout从dll中打印一条消息,但是却什么也没得到(我不认为它甚至可以工作,因为什么都没有被重新定位)

我正在使用

CreateRemoteThread(hProcess, NULL, NULL, entryPoint, memAddrForDLL, NULL, NULL)

在第四个参数称为lpStartAddress之前,我认为这应该是入口点,但这导致目标进程崩溃,我看到的每个示例都使用了当前在代码中使用的方式。

在我的dll中,我正在通过地址在目标进程中调用该函数。

编辑:我正在自己的控制台应用程序上对此进行测试。

2 个答案:

答案 0 :(得分:0)

加载到内存中的.DLL与磁盘上的.DLL文件不同。部分的布局不同,您需要处理重定位,导入表和PEB加载的模块列表。您基本上必须重新实现NTDLL!Ldr*

CreateRemoteThread上调用LoadLibrary是另一种技术,执行此操作时,线程参数需要指向远程进程中的.DLLs路径,而不是入口点。

答案 1 :(得分:0)

DLL注入的最基本形式是:

  • 使用VirtualAllocEx()在目标进程中分配内存
  • 使用WriteProcessMemory将DLL的路径写入该内存位置
  • 在目标进程中通过CreateRemoteThread()调用LoadLibrary()
  • 传递将DLL路径写入该调用的内存位置

您已经有了这个,但是,您的目标是手动映射DLL,并避免使用LoadLibrary()。您提供的代码无法解决,大约还有5个步骤。您需要模拟LoadLibrary()通常执行的所有操作:

  • 加载原始二进制数据
  • 将部分映射到目标流程
  • 注入加载程序shellcode
  • 进行搬迁
  • 修复进口问题
  • 执行TLS回调
  • 致电DllMain
  • 清理

手动映射的好处是,您将在ToolHelp32Snapshot()中隐藏,并在PEB和NtQueryVirtualMemory中浏览模块链接列表。

如果您想做正确的事,并通过体面的错误检查,大约需要350行代码,而且会变得很复杂。所有这些都是通过解析PE标头完成的。

  1. 获取目标的进程ID
  2. 读取DLL文件
  3. 在目标进程中从PE标头分配与ImageBase相同大小的内存
  4. 解析PE标头后,遍历PE部分
  5. 将段以正确的相对地址写入内存
  6. 将shellcode写入目标进程
  7. 调用CreateRemoteThread并将您的shellcode设置为执行
  8. 您的shellcode可以修复导入并进行重定位
  9. 您的Shellcode执行TLS回调
  10. 以上2个步骤已完成,分析了可选标头中的DataDirectory
  11. 使用DLL_PROCESS_ATTACH参数调用DllMain()

现在,您的DLL已加载,并且DLL_PROCESS_ATTACH开关的情况正在执行。显然,这要复杂得多,但这就是想法。

没有我的朋友Broihon教给我,我将一无所知,所以我想将此答案归功于他。祝你好运