65.9K
CodeProject 正在变化。 阅读更多。
Home

窃取程序的内存

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.79/5 (70投票s)

2003年12月3日

2分钟阅读

viewsIcon

368426

downloadIcon

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;
}

正如我之前所说,这不起作用。 当它们跨进程时,指向 lviitemsubitem 的指针都会搞砸。 解决方案? 使用 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 *_lvichar *_itemchar *_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 编写的。

许可证

本文没有附加明确的许可,但可能在文章文本或下载文件中包含使用条款。 如果有疑问,请通过下面的讨论区联系作者。 可以在此处找到作者可能使用的许可证列表。

© . All rights reserved.