0

我已将 DLL 注入到程序中,以在应用程序主窗口上实现聊天 UI。我想我可以获取应用程序主窗口句柄,然后获取它的 DC,然后在上面绘制。该窗口有一个可预测的标题,这意味着我可以使用它FindWindow来获取句柄。唯一的问题是,DLL 是在进程启动时注入的。那时,该窗口尚未创建。这意味着FindWindow什么也没找到!

对此有什么解决方案?我可以在 DLL 中创建一个线程并休眠一段时间,直到我知道创建了窗口吗?这似乎很不稳定,所以我宁愿不这样做。

我试图做的是SetWindowsHookEx在 DLL 中使用来挂钩全局 WndProc。我可以扫描这些消息,直到从我的窗口中找到一条消息(这意味着它已被创建)。然后我可以保存句柄并继续我的程序。我不太担心当时有多个同名的窗口。唯一的问题是我的钩子永远不会被调用。

我像这样创建钩子:

m_hWndProcHook = SetWindowsHookEx(WH_CALLWNDPROC, (HOOKPROC)WndProc, m_hModule, 0);
if(!m_hWndProcHook)
{
    oss << "Failed to set wndproc hook. Error code: " << GetLastError();
    Log(oss.str().c_str());
    return false;
} 

它返回一个有效的钩子。WndProc 如下所示:

LRESULT CALLBACK CChatLibrary::WndProc(int code, WPARAM wParam, LPARAM lParam)
{
    CWPSTRUCT* pData;
    ostringstream oss;
    char wndName[256];

    gChatLib->Log("WNDPROC");

    if(code < 0)
        return CallNextHookEx(gChatLib->GetWndProcHookHandle(), code, wParam, lParam);
    else
    {
        //Get the data for the wndproc
        pData = (CWPSTRUCT*)lParam;

        //Log the message
        GetWindowText(pData->hwnd, wndName, 256);
        oss << "Message from window \"" << wndName << "\"";
        gChatLib->Log(oss.str().c_str());

        return CallNextHookEx(gChatLib->GetWndProcHookHandle(), code, wParam, lParam);
    }
}

但是没有“WNDPROC”消息记录到我的日志文件中......早些时候,我有一个MessageBox而不是日志来查看它是否有效,结果证明这是一个糟糕的主意。所有程序都冻结了,因为它们在等待我单击“确定”,而我不得不进行硬重置...当我重新打开计算机并MessageBox用日志命令替换时,它不起作用。不过,我知道我的日志有效,因为它在其他任何地方都有效。我对发生的事情感到非常困惑。

是否有其他获取主窗口的方法(最好是在创建时)?还是我的钩子方法很好,但只是执行错误?感谢您的任何反馈。

4

1 回答 1

1

当应用程序已经启动时,您始终可以注入 DLL。由于 Windows Vista/7 中的 ASLR,现在它相当复杂,但并非不可能。您必须编写一个简短的应用程序,将选定的 DLL 注入到具有给定 PID 的进程中。为了将 DLL 注入正在运行的进程中,应该执行以下操作:

编写一个可以找到kernel32.dll库地址的 shellcode。这是我在 NASM 中的旧代码:

[BITS 32]

_main:
    xor     eax,    eax
    mov     esi,    [FS:eax+0x30]   ; ESI points at PEB
    mov     esi,    [esi+0x0C]  ; ESI points at PEB->Ldr
    mov     esi,    [esi+0x1C]  ; ESI points at PEB->Ldr.InInitOrder
    mov     edx,    -1          ; EDX is now the current letter pointer

check_dll:
    mov     ebp,    [esi+0x08]  ; EBP points at base address InInitOrder[i]
    mov     edi,    [esi+0x20]  ; EDI points at InInitOrder[X] name
    mov     esi,    [esi]       ; ESI points at flink
    mov     edx,    -1      ; set letter pointer at InInitOrder name
    mov     ebx,    0       ; set pattern letter pointer to null

check_small_name:
    inc     edx             ; go to the next letter in InInitOrder name
    cmp     ebx,    0x7     ; check if we have checked all letters
    je      library_found       ; if so and no error kernel32.dll found
    mov     al, BYTE[edi+edx]   ; load byte to EAX from InInitOrder name
    cmp     al,     0x0 ; check if unicode complement
    je      check_small_name    ; ignore if so
    jmp     s_kernel32

back1:
    pop     ecx
    cmp     BYTE[ecx+ebx],  al  ; compare characters
    jne     check_big_name      ; if not equal check upper size
    inc     ebx         ; if equal then go to the next letter in pattern
    jmp     check_small_name    ; loop  

check_big_name:
    jmp     b_kernel32

back2:
    pop     ecx
    cmp     BYTE[ecx+ebx],  al  ; check characters
    jne     check_dll       ; if not equal then go to the next module
    inc     ebx         ; if equal go increment the pattern pointer
    jmp     check_small_name    ; loop

library_found:
    mov     eax,    ebp         ; move kernel32 base address into ECX

loop:
    jmp loop    

s_kernel32:
    call    back1
    db      "kernel32",10,0 

b_kernel32:
    call    back2
    db      "KERNEL32",10,0
  1. 将编译好的 shellcode 从文件加载到内存中。
  2. 作为调试器附加到目标进程。停止应用程序中的所有线程。分配一些内存并设置“读、写、执行”权限并在那里注入 shellcode。
  3. 获取主线程句柄。打开线程,创建线程上下文备份,然后设置新的上下文并修改 EIP 寄存器(设置为分配的内存 - shellcode - 地址)。
  4. 恢复线程一段时间(例如 5 秒)。确保进程被激活并且我们的 shellcode 有机会执行。
  5. 再次作为调试器附加到目标进程。读取现在应该kernel32.dll在目标进程中存储基地址的 EAX 寄存器(感谢 ASLR,它可能与注入器进程中的不同)。
  6. 从您的过程中检查LoadLibraryA函数的偏移量。kernel32.dll
  7. 目标进程中的偏移量应该相同,因此您必须将远程kernel32.dll基地址添加到偏移量才能计算LoadLibraryA远程进程中函数的基地址。
  8. 调用CreateRemoteThread函数,将计算地址LoadLibraryA作为要调用的函数,并将 DLL 路径作为参数。

前段时间我不得不自己解决这一切(我找不到任何描述),但最近我发现了类似的东西:http: //syprog.blogspot.com/2012/05/createremotethread-bypass-windows.html

快乐黑客!

于 2012-06-20T18:33:24.667 回答