Click here to Skip to main content
11,478,896 members (63,280 online)
Click here to Skip to main content

Stealing Program's Memory

, 2 Dec 2003 241.2K 3.2K 107
Rate this:
Please Sign up or sign in to vote.
An advanced article on allocating and using memory in another process using the Win32 API.

Introduction

I was recently trying to steal strings from another program's listview control. You need to pass a pointer so it knows where to put the string. Normally this wouldn't be a problem, but because Windows uses virtual memory pointers are not valid across programs.

Virtual memory is how Windows deals out memory to all it's programs. It makes programs think they have 2 Gb of memory to use. It also protects programs from using each other's memory so if one program crashes it doesn't take down the whole system with it.

So after coding a fair bit, I realized my pointers were all invalid and it wouldn't work. A few hours of digging through MSDN brought me to the functions VirtualAllocEx(), VirtualFreeEx(), WriteProcessMemory() and ReadProcessMemory(). Armed with this new information, I set out to modify my code. Here is what I had so far:

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

As I said before, this won't work. The pointers to lvi, item, and subitem all get screwed when they go across process. The solution? Use WriteProcessMemory() and ReadProcessMemory() to use the other programs memory, perform LVM_GETITEMTEXT on it, and read it back. Hackish yes, but then again reading items from another program's listview control is one giant hack.

First, we get the process of the listview like this:

unsigned long pid;
HANDLE process;
GetWindowThreadProcessId(listview, &pid);
process=OpenProcess(PROCESS_VM_OPERATION|PROCESS_VM_READ|
                    PROCESS_VM_WRITE|PROCESS_QUERY_INFORMATION, FALSE, pid);

Next We create three pointers, LVITEM *_lvi, char *_item, and char *_subitem and allocate them in the other program's virtual memory space with 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);

Now we point lvi.pszText to _item, and copy it's memory to _lvi using WriteMemoryProcess():

lvi.pszText=_item;
WriteProcessMemory(process, _lvi, &lvi, sizeof(LVITEM), NULL);

Now that we have an LVITEM pointer that is valid in the other programs virtual memory, we can shoot off LVM_GETITEMTEXT to listview and copy _item's text into item so we can read it in our program:

SendMessage(hwnd, LVM_GETITEMTEXT, (WPARAM)i, (LPARAM)_lvi);
ReadProcessMemory(process, _item, item, max, NULL);

Repeat that for subitem, then free the memory we used in the other program's memory:

VirtualFreeEx(process, _lvi, 0, MEM_RELEASE);
VirtualFreeEx(process, _item, 0, MEM_RELEASE);
VirtualFreeEx(process, _subitem, 0, MEM_RELEASE);

Yay, all done. In case that didn't make too much sense to you, here is our new code, all fixed up:

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

If you're looking to use a program's memory for another reason, or have had a similar problem to mine, adapting this should be fairly easy.

This article was originally written for int64.org

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Cory Nelson
Web Developer
United States United States
No Biography provided

Comments and Discussions

 
QuestionI tried to read Header control? using HDITEM . Pin
SathishMask29-Sep-14 6:36
memberSathishMask29-Sep-14 6:36 
Questionthanks Pin
Imbue16-Mar-13 11:37
memberImbue16-Mar-13 11:37 
QuestionLVM_GETITEMRECT Pin
Zockerman™22-May-12 8:08
memberZockerman™22-May-12 8:08 
GeneralMy vote of 5 Pin
Synetech2-Mar-12 15:08
memberSynetech2-Mar-12 15:08 
QuestionBut GetWindowText() works. :-? Pin
Synetech2-Mar-12 12:51
memberSynetech2-Mar-12 12:51 
QuestionRemove Item Pin
Mustafa Chelik11-Dec-11 3:38
memberMustafa Chelik11-Dec-11 3:38 
QuestionC# Code Version Pin
Nilesh bhope8-Aug-11 3:57
memberNilesh bhope8-Aug-11 3:57 
AnswerRe: C# Code Version Pin
taylorza21-Aug-11 2:23
membertaylorza21-Aug-11 2:23 
GeneralRe: C# Code Version Pin
Nilesh bhope29-Aug-11 3:01
memberNilesh bhope29-Aug-11 3:01 
GeneralRe: C# Code Version Pin
Nilesh bhope29-Aug-11 6:04
memberNilesh bhope29-Aug-11 6:04 
GeneralThank you very much - it is exactly what I needed. Pin
__stas__15-Nov-10 23:37
member__stas__15-Nov-10 23:37 
GeneralExcellent article though requires a little addition Pin
Member 373653224-Jul-09 5:22
memberMember 373653224-Jul-09 5:22 
GeneralRe: Excellent article though requires a little addition Pin
Member 71363228-Apr-10 6:49
memberMember 71363228-Apr-10 6:49 
Generala problem about List Control Pin
dyj682213-Jul-09 19:01
memberdyj682213-Jul-09 19:01 
GeneralDoes the job Pin
software_chotmail13-Jun-09 14:42
membersoftware_chotmail13-Jun-09 14:42 
GeneralAPI is returning blank for LVM_GETITEMTEXT message in 64 bit system (Win2003). Pin
rushijoshi6-Apr-09 1:50
memberrushijoshi6-Apr-09 1:50 
QuestionRe: API is returning blank for LVM_GETITEMTEXT message in 64 bit system (Win2003). Pin
anadipsia12-Aug-09 4:21
memberanadipsia12-Aug-09 4:21 
AnswerRe: API is returning blank for LVM_GETITEMTEXT message in 64 bit system (Win2003). Pin
ChewsHumans11-Mar-10 15:36
memberChewsHumans11-Mar-10 15:36 
Questioncode returns blanks when tried on listview which seems to be with window style LVS_OWNERDRAWFIXED Pin
Member 436362620-Jan-09 1:05
memberMember 436362620-Jan-09 1:05 
AnswerRe: code returns blanks when tried on listview which seems to be with window style LVS_OWNERDRAWFIXED Pin
Member 17143758-Sep-10 19:00
memberMember 17143758-Sep-10 19:00 
GeneralRidiculous... Pin
kilt6-Nov-08 4:11
memberkilt6-Nov-08 4:11 
GeneralRe: Ridiculous... Pin
damnedyankee7-Nov-08 1:35
memberdamnedyankee7-Nov-08 1:35 
GeneralRe: Ridiculous... Pin
zameb10-Aug-10 8:01
memberzameb10-Aug-10 8:01 
GeneralRe: Ridiculous... Pin
Synetech2-Mar-12 12:38
memberSynetech2-Mar-12 12:38 
QuestionHow to steal TStringGrid's Memory? Pin
white88815-Aug-08 18:31
memberwhite88815-Aug-08 18:31 
GeneralVery good!!! Pin
Klaus Hattinger12-Aug-08 7:59
memberKlaus Hattinger12-Aug-08 7:59 
GeneralRe: Very good!!! Pin
Portatofe2-Oct-08 9:44
memberPortatofe2-Oct-08 9:44 
GeneralDoesn't work in Vista 64 Pin
blurmotion17-May-08 3:18
memberblurmotion17-May-08 3:18 
AnswerRe: Doesn't work in Vista 64 Pin
blurmotion18-May-08 0:03
memberblurmotion18-May-08 0:03 
GeneralRe: Doesn't work in Vista 64 Pin
anadipsia12-Aug-09 4:24
memberanadipsia12-Aug-09 4:24 
QuestionRe: Doesn't work in Vista 64 Pin
anadipsia12-Aug-09 4:48
memberanadipsia12-Aug-09 4:48 
AnswerRe: Doesn't work in Vista 64 [modified] Pin
derek_penguin6-Nov-09 22:30
memberderek_penguin6-Nov-09 22:30 
GeneralRe: Doesn't work in Vista 64 Pin
Zockerman™22-May-12 8:04
memberZockerman™22-May-12 8:04 
GeneralVirtualAllocEx problems Pin
Cedar8217-Nov-07 5:45
memberCedar8217-Nov-07 5:45 
GeneralStatic Text Pin
josip cagalj23-Aug-07 2:14
memberjosip cagalj23-Aug-07 2:14 
QuestionGetting list vew Data with sendmessage(xxxxx) Pin
Xzion28-Mar-07 22:40
memberXzion28-Mar-07 22:40 
Questionwhat if not window default control Pin
9999kkk25-Nov-06 1:04
member9999kkk25-Nov-06 1:04 
GeneralA Clever Utility, and an Explanation of Cross-Process Copying of Data Pin
Mike O'Neill6-Sep-06 17:14
memberMike O'Neill6-Sep-06 17:14 
GeneralC# Version Pin
Marco225028-Aug-06 16:57
memberMarco225028-Aug-06 16:57 
Hi. I'm trying to convert to C# but I got a null buffer (all items are \0).

Please, can someone help me?

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WindowsApplication3
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{
IntPtr mainWindowHwnd;
IntPtr lvwHwnd = (IntPtr)0;

try
{
mainWindowHwnd = FindWindow(null, "Stealing Program's memory: ListView");
lvwHwnd = FindWindowEx(mainWindowHwnd, IntPtr.Zero, "SysListView32", IntPtr.Zero);

if (lvwHwnd == (IntPtr)0)
throw new Win32Exception();
}
catch(Exception ex)
{
MessageBox.Show("[" + Marshal.GetLastWin32Error().ToString() + "] - Não foi possível obter o handle do controle filho.\n\n" + ex.ToString(), "Atenção", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
return;
}

int lvwItem = 0;

IntPtr pid = (IntPtr)0;
GetWindowThreadProcessId(lvwHwnd, ref pid);

IntPtr _lvi;
IntPtr _subitem = IntPtr.Zero;

IntPtr process = OpenProcess(PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_QUERY_INFORMATION, false, pid.ToInt32());

LVITEM lvi = new LVITEM();

//process = (IntPtr)(process.ToInt32() - 1);
_lvi = VirtualAllocEx(process, IntPtr.Zero, Marshal.SizeOf(typeof(LVITEM)), MEM_COMMIT, PAGE_READWRITE);
_subitem = VirtualAllocEx(process, IntPtr.Zero, 512, MEM_COMMIT, PAGE_READWRITE);

if(_lvi == IntPtr.Zero)
throw new SystemException("Failed to allocate memory in remote process");

bool bsuccess;

lvi.cchTextMax = 512;
lvi.iSubItem = 1;
lvi.pszText = _subitem;
bsuccess = WriteProcessMemory(process, _lvi, ref lvi, Marshal.SizeOf(typeof(LVITEM)), IntPtr.Zero);
SendMessage(lvwHwnd, LVM_GETITEMTEXT, lvwItem, _lvi);

IntPtr lpBuffer;
lpBuffer = Marshal.AllocHGlobal(512);
string sRet;
IntPtr bytesReaded;
byte[] buffer = new byte[512];
ReadProcessMemory(process, _subitem, buffer, 512, out bytesReaded);
//sRet = Marshal.PtrToStringAnsi(lpBuffer, 512);

VirtualFreeEx(process, _lvi, 0, MEM_RELEASE);
VirtualFreeEx(process, _subitem, 0, MEM_RELEASE);
}

[DllImport("user32.dll",
CharSet = System.Runtime.InteropServices.CharSet.Auto)]
public static extern IntPtr FindWindow(string lpClassName,
string lpWindowName);

[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr FindWindowEx(IntPtr parent /*HWND*/,
IntPtr next /*HWND*/,
string sClassName,
IntPtr sWindowTitle);

//'''''''''''''''''''''''''''''''''''''''''''''''
//' Used by the OpenProcess API call

private const long STANDARD_RIGHTS_REQUIRED = 0xF0000;
private const long SYNCHRONIZE = 0x100000;

private const int PROCESS_TERMINATE = 0x1;
private const int PROCESS_CREATE_THREAD = 0x2;
private const int PROCESS_SET_SESSIONID = 0x4;
private const int PROCESS_VM_OPERATION = 0x8;
private const int PROCESS_VM_READ = 0x10;
private const int PROCESS_VM_WRITE = 0x20;
private const long PROCESS_DUP_HANDLE = 0x40;
private const long PROCESS_CREATE_PROCESS = 0x80;
private const long PROCESS_SET_QUOTA = 0x100;
private const long PROCESS_SET_INFORMATION = 0x200;
private const int PROCESS_QUERY_INFORMATION = 0x400;
private const long PROCESS_SUSPEND_RESUME = 0x800;
private const long PROCESS_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFF;

[DllImport("kernel32")]
public static extern IntPtr OpenProcess(int dwDesiredAccess,
bool bInheritHandle,
int dwProcessID);
//'''''''''''''''''''''''''''''''''''''''''''''''

const uint MEM_COMMIT = 0x1000;
const uint MEM_RELEASE = 0x8000;
const uint PAGE_READWRITE = 0x4;

[DllImport("kernel32")]
static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress,
int dwSize, uint flAllocationType, uint flProtect);


[DllImport("kernel32")]
static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress,
ref LVITEM buffer, int dwSize, IntPtr lpNumberOfBytesWritten);

//Private Declare Function SendMessage Lib "user32.dll" Alias "SendMessageA" (ByVal hWnd As IntPtr, ByVal msg As Int32, ByVal wParam As IntPtr, ByRef lParam As IntPtr) As Boolean
[DllImport("user32.dll")]
static extern bool SendMessage(IntPtr hWnd, int msg, int wParam, IntPtr lParam);

private const int LVM_FIRST = 0x1000;
private const long LVM_GETSELECTEDCOUNT = (LVM_FIRST + 50);
private const long LVM_GETITEMSTATE = (LVM_FIRST + 44);
public const int LVM_GETITEMTEXT = (LVM_FIRST + 45);
public const long LVM_GETITEMCOUNT = LVM_FIRST + 4;
private const long LVIF_TEXT = 0x1;

//'Public Const LVM_GETITEMA = (LVM_FIRST + 5)
//'Public Const LVM_GETITEMW = (LVM_FIRST + 75)
public const long LVM_GETITEM = (LVM_FIRST + 5);


[StructLayout(LayoutKind.Sequential)]
private struct LVITEM
{
public Int16 mask;
public Int16 iItem;
public Int16 iSubItem;
public Int16 state;
public Int16 stateMask;
public IntPtr pszText;
public Int16 cchTextMax;
public Int16 iImage;
}

[DllImport("kernel32.dll")]
public static extern bool ReadProcessMemory(
IntPtr hProcess,
IntPtr lpBaseAddress,
//[In, Out] byte[] buffer,
IntPtr buffer,
UInt32 size,
out IntPtr lpNumberOfBytesRead
);

[DllImport("kernel32.dll")]
public static extern Int32 ReadProcessMemory(
IntPtr hProcess,
IntPtr lpBaseAddress,
[In, Out] byte[] buffer,
UInt32 size,
out IntPtr lpNumberOfBytesRead
);

[DllImport("kernel32")]
static extern bool VirtualFreeEx(IntPtr hProcess, IntPtr lpAddress, int dwSize,
uint dwFreeType);

[DllImport("user32")]
private static extern IntPtr GetWindowThreadProcessId(IntPtr hWnd,
ref IntPtr lpdwProcessId);
}
}
GeneralRe: C# Version Pin
Karlheinz Godo15-Feb-07 9:40
memberKarlheinz Godo15-Feb-07 9:40 
GeneralCleaner C# Function Pin
dfhgesart7-Jul-07 17:10
memberdfhgesart7-Jul-07 17:10 
JokeThanks a lot! This is exactly what I'm looking for. Pin
songkiet9-Aug-06 9:58
membersongkiet9-Aug-06 9:58 
Questionretrieve text on statusbar Pin
doenoe31-Jul-06 23:22
memberdoenoe31-Jul-06 23:22 
AnswerRe: retrieve text on statusbar Pin
andy66611-Nov-06 5:19
memberandy66611-Nov-06 5:19 
QuestionGet strings from Microsoft Outlook SUPERGRID Pin
kopyt19-Jul-06 3:13
memberkopyt19-Jul-06 3:13 
QuestionPossible to do same for delphi TStringGrid? Pin
Absorbant Pad13-Jun-06 1:10
memberAbsorbant Pad13-Jun-06 1:10 
Questioncan we write text? Pin
aldo hexosa4-Mar-06 3:47
memberaldo hexosa4-Mar-06 3:47 
AnswerRe: can we write text? Pin
shazzababs12-Oct-09 6:25
membershazzababs12-Oct-09 6:25 
Questionleak? Pin
[cs2]27-Jan-06 8:11
member[cs2]27-Jan-06 8:11 
GeneralProblem with one App Pin
clivet18-Sep-05 1:50
memberclivet18-Sep-05 1:50 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.150520.1 | Last Updated 3 Dec 2003
Article Copyright 2003 by Cory Nelson
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid