窃取程序的内存






4.79/5 (70投票s)
2003年12月3日
2分钟阅读

368426

3991
一篇关于使用 Win32 API 在另一个进程中分配和使用内存的高级文章。
引言
我最近试图从另一个程序的 listview
控件中窃取 string
。你需要传递一个指针,以便它知道将 string
放在哪里。通常,这不会是一个问题,但由于 Windows 使用虚拟内存,因此指针在程序之间无效。
虚拟内存是 Windows 将内存分配给其所有程序的方式。它使程序认为它们有 2 Gb 的内存可以使用。它还可以保护程序免于使用彼此的内存,因此如果一个程序崩溃,它不会导致整个系统崩溃。
所以在编写了一些代码后,我意识到我的指针都是无效的,并且它不起作用。在 MSDN 中挖掘了几个小时,我找到了函数 VirtualAllocEx()
、VirtualFreeEx()
、WriteProcessMemory()
和 ReadProcessMemory()
。 掌握了这些新信息,我开始修改我的代码。 这是我目前的代码
#define WIN32_LEAN_AND_MEAN #include <stdio.h> #include <windows.h> #include <commctrl.h> int main(void) { /* Run through the windows until we find our listview. */ HWND hwnd=FindWindow(NULL, "Stealing Program's Memory: ListView"); HWND listview=FindWindowEx(hwnd, NULL, "SysListView32", NULL); int count=(int)SendMessage(listview, LVM_GETITEMCOUNT, 0, 0); int i; char item[512], subitem[512]; /* Shove all items of listview into item and subitem and print out one by one. */ LVITEM lvi; lvi.cchTextMax=512; for(i=0; i<count; i++) { lvi.iSubItem=0; lvi.pszText=item; SendMessage(listview, LVM_GETITEMTEXT, (WPARAM)i, (LPARAM)&lvi); lvi.iSubItem=1; lvi.pszText=subitem; SendMessage(listview, LVM_GETITEMTEXT, (WPARAM)i, (LPARAM)&lvi); printf("%s - %s\n", item, subitem); } return 0; }
正如我之前所说,这不起作用。 当它们跨进程时,指向 lvi
、item
和 subitem
的指针都会搞砸。 解决方案? 使用 WriteProcessMemory()
和 ReadProcessMemory()
来使用其他程序的内存,对其执行 LVM_GETITEMTEXT
,然后将其读回。 确实很黑,但再次从另一个程序的 listview
控件中读取项目是一个巨大的黑客行为。
首先,我们像这样获得 listview
的进程
unsigned long pid; HANDLE process; GetWindowThreadProcessId(listview, &pid); process=OpenProcess(PROCESS_VM_OPERATION|PROCESS_VM_READ| PROCESS_VM_WRITE|PROCESS_QUERY_INFORMATION, FALSE, pid);
接下来,我们创建三个指针,LVITEM *_lvi
、char *_item
和 char *_subitem
,并使用 VirtualAllocEx()
在另一个程序的虚拟内存空间中分配它们
LVITEM *_lvi=(LVITEM*)VirtualAllocEx(process, NULL, sizeof(LVITEM), MEM_COMMIT, PAGE_READWRITE); char *_item=(char*)VirtualAllocEx(process, NULL, 512, MEM_COMMIT, PAGE_READWRITE); char *_subitem=(char*)VirtualAllocEx(process, NULL, 512, MEM_COMMIT, PAGE_READWRITE);
现在,我们将 lvi.pszText
指向 _item
,并使用 WriteMemoryProcess()
将其内存复制到 _lvi
lvi.pszText=_item; WriteProcessMemory(process, _lvi, &lvi, sizeof(LVITEM), NULL);
现在我们有一个在其他程序虚拟内存中有效的 LVITEM
指针,我们可以将 LVM_GETITEMTEXT
发送到 listview
,并将 _item
的文本复制到 item 中,以便我们可以在我们的程序中读取它
SendMessage(hwnd, LVM_GETITEMTEXT, (WPARAM)i, (LPARAM)_lvi); ReadProcessMemory(process, _item, item, max, NULL);
对 subitem 重复该操作,然后释放我们在其他程序的内存中使用的内存
VirtualFreeEx(process, _lvi, 0, MEM_RELEASE); VirtualFreeEx(process, _item, 0, MEM_RELEASE); VirtualFreeEx(process, _subitem, 0, MEM_RELEASE);
好耶,全部完成。 如果这对你来说没有太大意义,这是我们的新代码,全部修复了
#define WIN32_LEAN_AND_MEAN #include <stdio.h> #include <windows.h> #include <commctrl.h> int main(void) { HWND hwnd=FindWindow(NULL, "Stealing Program's Memory: ListView"); HWND listview=FindWindowEx(hwnd, NULL, "SysListView32", NULL); int count=(int)SendMessage(listview, LVM_GETITEMCOUNT, 0, 0); int i; LVITEM lvi, *_lvi; char item[512], subitem[512]; char *_item, *_subitem; unsigned long pid; HANDLE process; GetWindowThreadProcessId(listview, &pid); process=OpenProcess(PROCESS_VM_OPERATION|PROCESS_VM_READ| PROCESS_VM_WRITE|PROCESS_QUERY_INFORMATION, FALSE, pid); _lvi=(LVITEM*)VirtualAllocEx(process, NULL, sizeof(LVITEM), MEM_COMMIT, PAGE_READWRITE); _item=(char*)VirtualAllocEx(process, NULL, 512, MEM_COMMIT, PAGE_READWRITE); _subitem=(char*)VirtualAllocEx(process, NULL, 512, MEM_COMMIT, PAGE_READWRITE); lvi.cchTextMax=512; for(i=0; i<count; i++) { lvi.iSubItem=0; lvi.pszText=_item; WriteProcessMemory(process, _lvi, &lvi, sizeof(LVITEM), NULL); SendMessage(listview, LVM_GETITEMTEXT, (WPARAM)i, (LPARAM)_lvi); lvi.iSubItem=1; lvi.pszText=_subitem; WriteProcessMemory(process, _lvi, &lvi, sizeof(LVITEM), NULL); SendMessage(listview, LVM_GETITEMTEXT, (WPARAM)i, (LPARAM)_lvi); ReadProcessMemory(process, _item, item, 512, NULL); ReadProcessMemory(process, _subitem, subitem, 512, NULL); printf("%s - %s\n", item, subitem); } VirtualFreeEx(process, _lvi, 0, MEM_RELEASE); VirtualFreeEx(process, _item, 0, MEM_RELEASE); VirtualFreeEx(process, _subitem, 0, MEM_RELEASE); return 0; }
如果您希望将程序的内存用于其他原因,或者遇到与我类似的问题,那么适应这种情况应该相当容易。
本文最初是为 int64.org 编写的。
许可证
本文没有附加明确的许可,但可能在文章文本或下载文件中包含使用条款。 如果有疑问,请通过下面的讨论区联系作者。 可以在此处找到作者可能使用的许可证列表。