如何从注入的 DLL 获取程序窗口
How do I get a programs windows from an injected DLL?
我已经将DLL注入到程序中,以在应用程序主窗口上实现聊天UI。我想我可以获取应用程序主窗口句柄,然后获取它的 DC,并绘制到它上面。该窗口具有可预测的标题,这意味着我可以使用FindWindow
来获取句柄。唯一的问题是,DLL 是在进程启动时注入的。此时,尚未创建窗口。这意味着FindWindow
什么也找不到!
对此有哪些解决方案?我可以在 DLL 中创建一个线程并休睡一段时间,直到我知道窗口已创建?这似乎很不稳定,所以我宁愿不这样做。
我尝试做的是使用 DLL 中的SetWindowsHookEx
来挂接全局 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
而不是日志来查看它是否有效,结果证明这是一个糟糕的主意。所有程序都冻结了,因为它们在等待我单击"确定",我不得不进行硬重置......当我重新打开计算机并用 log 命令替换MessageBox
时,它不起作用。不过,我知道我的日志有效,因为它在其他任何地方都有效。我对这发生了什么感到非常困惑。
是否有其他方法可以获取主窗口(最好是在创建主窗口时)?还是我的钩子方法很好,但只是执行错误?感谢您的任何反馈。
您始终可以在应用程序已启动时注入 DLL。由于Windows Vista/7中的ASLR,现在它非常复杂,但并非不可能。您必须编写一个简短的应用程序,该应用程序将使用给定的 PID 将选定的 DLL 注入到进程中。以下是将 DLL 注入正在运行的进程应执行的操作:
编写一个外壳代码,该代码将查找kernel32.dll
库的地址。这是我在 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
- 将编译的外壳代码从文件加载到内存中。
- 作为调试器附加到目标进程。停止应用程序中的所有线程。分配一些内存并设置"读取,写入,执行"权限并在那里注入shellcode。
- 获取主线程句柄。打开线程,创建线程上下文备份,然后设置修改 EIP 寄存器的新上下文(设置为分配的内存 - 外壳代码 - 地址)。
- 恢复线程一段时间(例如 5 秒)。确保该过程已激活,并且我们的shellcode有机会执行。
- 再次作为调试器附加到目标进程。读取 EAX 寄存器,该寄存器现在应该在目标进程中存储
kernel32.dll
基址(多亏了 ASLR,它可能与注入器进程中的地址不同)。 - 检查
LoadLibraryA
函数在kernel32.dll
与过程的偏移量。 - 目标进程中的偏移量应相同,因此您必须将远程
kernel32.dll
基址添加到偏移量中,以便计算远程进程中LoadLibraryA
函数的基址。 - 调用
CreateRemoteThread
函数,将LoadLibraryA
的计算地址作为要调用的函数,将 DLL 路径作为其参数。
前段时间我不得不自己弄清楚这一切(我找不到任何描述),但最近我发现了类似的东西:http://syprog.blogspot.com/2012/05/createremotethread-bypass-windows.html
快乐黑客!
- 使用C++获取程序的 ASM
- 在集成终端上运行vscode lldb调试器时,如何获取程序的输出?
- 如何在 ubuntu 上的 php 脚本中获取程序(c,c++,java,python,php)的执行时间和内存使用量?
- 在 Linux 上获取程序的目录
- 无法获取程序来处理WM_PowerBroadcast消息
- PIN从指令地址获取程序集操作码
- 我如何在 Linux 中获取程序版本
- 全屏获取c ++程序的输出.它是控制台输出窗口的目标代码
- 获取程序在C/C++/Oj-C中编译的时间
- 如何获取程序分配的内存大小
- 从我的 C/C++ 代码 - x86 和 ARM 获取程序集等效代码
- 获取程序中的当前优化级别
- 为什么我无法使用 C# 中的 Process 获取C++程序的输出?
- C++获取程序文件目录,附加额外路径并执行
- 如何从注入的 DLL 获取程序窗口
- 如何获取程序崩溃的行
- 从自己的程序获取程序元数据
- C++获取程序的基本属性
- 在GDB中调试程序时如何获取程序的环境
- 如何使用Clang获取C/ c++程序的所有全局声明列表