Virtual memory problem
- From: d_purple_devil@xxxxxxxxxxx
- Date: 26 Jan 2007 10:13:06 -0800
Hi all, I have a program that needs to pick up the contents of a
SysListView in another process. As you are all aware this requires me
allocating memory for my strings and the LVITEM structure in the other
process, then writing to them and sending the message and then reading
from them.
My code works, this might seem like a strange post but wait the plot
thickens.I tested this program on the task manager, It has four of
these SysListViews hanging around so It seemed as good a candidate as
any for my experiment. I watch the process locate the window (the title
changes so I had to do an enumwindows to find it) then I did an
enumchildwindows in order to find all the SyslistViews. Now I getting
somewhere I think to my self. I call my home-grown C dll with my window
handles and I get the thread and process responsible for these
critters.
I set my debug priveleges and and ask for my window handle "all
access". I allocate my memory watch my lil pointers come back and send
my message and readprocessmemory back into my address space, and
gleefully see the pointers filled with strings from the task manager.
This is where it gets interesting. I change my window title to the name
of the the title to the part of the name of the MDI window that I am
interested in. I get my handles, my process handle, and allocate my
memory, The first call works great, then the problems start ;( The
second call to virtualallocex succeeds but the pointes now have the
"bad ptr" following the address that was allocated, "that wasn't there
on the other window" I think to myself, and sure enough the strings
come back empty.
So I decide to google this one. Two days of googling and no cigar.
While googling I also decided that virtualallocex wasn't to be trusted
to find the base address in the other process, so I decided to walk the
vad and find my own address, this worked as well, and I locate memory
locations large enough to hold my memory , but still no cigar. It works
for the task manager but not the target program ;(
By this time I have almost read anything I could find on virtualallocex
and by passing most of the other virtual memory functions, I fiddled
with virtualqueryex and virtualprotectex, trying to find the problem.
FormatMessage came to mind pretty quickly but "The operation completed
successfully" isn't much help when trying to debug code that is
anything but successful.
At this point let me try to give you a description of my environment:
Window XP PRO SP2 latest updates.
VS.NET 2003, latest updates Enterprise Architect.
An old, P III 500 that if I could get the project to work would provide
me with some cash to buy one of the latest beasts available.
256 Mb of ram (always a drag that swapping ;()
The program I am trying to infiltrate is
EFX Navigator on www.efxgroup.com
For my info tell me what you need, I can get back to you.
Here is my soucre code, This C Win32 dll (hence why I posted here)
This code is anything but tidy but with all the debuging I'm doing
cleaning up old code (that works on the taskmanager and other programs)
doesn't seem like a good approach
Any way here it is:
---------------------------------------------------------------------------------------------------------------------------------------------
C DLL CODE
// Extract Data Library.cpp : Defines the entry point for the DLL
application.
//Defines
#define WIN32_LEAN_AND_MEAN
//Includes
#include "stdafx.h"
#include <stdio.h>
#include <windows.h>
#include <commctrl.h>
#define My_EXPORTS //Define in order to
export functions
#include "Extract Data Library.h"
#include <string>
#include <cstdlib>
#include "stdlib.h"
//Declares Exported Functions
//Delcares Internal Functions
DWORD DoFormatMessage();
DWORD DoDebugFormatMessage();
int SetDebugPrivileges(void);
MEMORY_BASIC_INFORMATION WalKingTheVAD(HANDLE hProcess, DWORD
RequiredSpace);
//Exported Variables
//Global Variables
//DLL ENTRRY POINT
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
//Code Starts here
My_API_Export int __stdcall CopyListViewToListBox(HWND SourceHwnd, HWND
TargetHwnd, BOOL Append)
{
SetDebugPrivileges();
HWND listview= SourceHwnd;
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;
MEMORY_BASIC_INFORMATION mbi;
LPVOID BaseAddress = 0;
GetWindowThreadProcessId(listview, &pid);
//process=OpenProcess(PROCESS_VM_OPERATION|PROCESS_VM_READ|
//
PROCESS_VM_WRITE|PROCESS_QUERY_INFORMATION, FALSE, pid);
process=OpenProcess(PROCESS_ALL_ACCESS,false, pid);
//DoFormatMessage();
mbi = WalKingTheVAD(process, (DWORD)(sizeof(LVITEM)) );
if (mbi.BaseAddress ==NULL)
{
MessageBox(NULL, "Insufficient Memory in Target Process
to Extract
Data","Fatal Error", MB_ICONERROR);
return -1;
}
BaseAddress = mbi.AllocationBase;
_lvi=(LVITEM*)VirtualAllocEx(process, BaseAddress,
sizeof(LVITEM),
MEM_COMMIT, PAGE_READWRITE);
if (_lvi == NULL) DoFormatMessage();
mbi = WalKingTheVAD(process, (DWORD)(100) );
if (mbi.BaseAddress ==NULL)
{
MessageBox(NULL, "Insufficient Memory in Target Process
to Extract
Data","Fatal Error", MB_ICONERROR);
return -1;
}
BaseAddress = mbi.AllocationBase;
_item=(char*)VirtualAllocEx(process, BaseAddress, 100,
MEM_COMMIT,
PAGE_READWRITE);
DoFormatMessage();
_subitem=(char*)VirtualAllocEx(process,NULL, 100, MEM_COMMIT,
PAGE_READWRITE);
DoFormatMessage();
/*
_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;//0
lvi.pszText=_item;
WriteProcessMemory(process, _lvi, &lvi, sizeof(LVITEM),
NULL);
SendMessage(listview, LVM_GETITEMTEXT, (WPARAM)i,
(LPARAM)_lvi);
lvi.iSubItem=1;//1
lvi.pszText=_subitem;
WriteProcessMemory(process, _lvi, &lvi, sizeof(LVITEM),
NULL);
SendMessage(listview, LVM_GETITEMTEXT, (WPARAM)i,
(LPARAM)_lvi);
ReadProcessMemory(process, _item, item, 100, NULL);
ReadProcessMemory(process, _subitem, subitem, 100,
NULL);
//printf("%s - %s\n", item, subitem);
//MessageBox(NULL, item, subitem,MB_OK);
}
VirtualFreeEx(process, _lvi, 0, MEM_RELEASE);
VirtualFreeEx(process, _item, 0, MEM_RELEASE);
VirtualFreeEx(process, _subitem, 0, MEM_RELEASE);
VirtualProtectEx(process, mbi.BaseAddress,
mbi.RegionSize,mbi.Protect,
&mbi.Protect); //restore Old
Protection stored in .Protect
CloseHandle(process);
return 0;
}
My_API_Export int __stdcall FillListBox(HWND targetHwnd, char *item,
char *subitem, BOOL Append)
{
if (Append) LockWindowUpdate(targetHwnd);
SendMessage(targetHwnd, LB_ADDSTRING, NULL, (LPARAM)item);
SendMessage(targetHwnd, LB_ADDSTRING, NULL, (LPARAM)subitem);
if (Append) LockWindowUpdate(NULL);
return 0;
}
DWORD DoFormatMessage()
{
//Implement as Class later
void *m_szErrMsg = NULL;
DWORD err = GetLastError();
int nLen = FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
err,
MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
(LPTSTR)&m_szErrMsg,
1,
NULL );
MessageBox(NULL, (LPCSTR)m_szErrMsg, "Extract Data", MB_OK |
MB_ICONEXCLAMATION);
LocalFree(m_szErrMsg); /*free memory*/
return err;
}
DWORD DoDebugFormatMessage()
{
//Implement as Class later
void *m_szErrMsg = NULL;
DWORD err = GetLastError();
int nLen = FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
err,
MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
(LPTSTR)&m_szErrMsg,
1,
NULL );
OutputDebugString("Msg From System:\n");
OutputDebugString((LPCSTR)m_szErrMsg);
LocalFree(m_szErrMsg); /*free memory*/
return err;
}
//No PISSY PROGRAM IS GOING TO DENY US A PROCESS HANDLE
int SetDebugPrivileges(void)
{
DWORD err = 0; // define error holder, used to store the error
code in
case of failure
TOKEN_PRIVILEGES Debug_Privileges;
//STEP 1
if (!LookupPrivilegeValue (NULL, // Privieleges for the local
system
SE_DEBUG_NAME, // define the name of the privilege
&Debug_Privileges.Privileges[0].Luid))
// will get the LUID value into this variable
{ //if function failed, cannot proceed to the next step
err = DoFormatMessage();
return err; //terminate the outer function
}
//STEP 2
HANDLE hToken = 0; // instantiate a token handle
if (!OpenProcessToken (GetCurrentProcess (), // current process
ID
handle
TOKEN_ADJUST_PRIVILEGES| TOKEN_QUERY, //set
the desired access
&hToken)) // handle to the token will be
held here
{ // if function failed, cannot proceed to the next step
err = DoFormatMessage();
if (hToken) // if handle is still valid
CloseHandle (hToken); // destroy it
return err; //terminate the outer function
}
//STEP3
Debug_Privileges.Privileges[0].Attributes =
SE_PRIVILEGE_ENABLED; //
set to enable privilege
Debug_Privileges.PrivilegeCount = 1; // working with only one
privilege
if (!AdjustTokenPrivileges (hToken, // access token handle
FALSE,
// do not disable privileges
&Debug_Privileges, // pointer to the token structure
0, //
no need for a buffer
NULL,
// previous state not set
NULL))
// no need for a buffer
{
err = DoFormatMessage();
if (hToken) // if handle is still valid
CloseHandle (hToken); // destroy it
return err; //terminate the outer function
}
return err;
}
MEMORY_BASIC_INFORMATION WalKingTheVAD(HANDLE hProcess, DWORD
RequiredSpace)
{
SYSTEM_INFO si;
MEMORY_BASIC_INFORMATION mbi;
LPVOID lpMem;
TCHAR szFile[MAX_PATH];
char szNumber[20];
char *State;
char *Type;
char istr[65];
char RegionSizeStr[65];
int tmp = 0;
DWORD dwPageSize;
/* Get maximum address range from system info */
GetSystemInfo(&si);
/* walk process addresses */
lpMem = si.lpMinimumApplicationAddress;
dwPageSize = si.dwPageSize;
while (lpMem < si.lpMaximumApplicationAddress)
{
OutputDebugString("Testing New Block: \n");
mbi.RegionSize = 0;
VirtualQueryEx(hProcess, lpMem, &mbi,
sizeof(MEMORY_BASIC_INFORMATION));
//DoFormatMessage();
OutputDebugString("RegionStart: ");
itoa((int)lpMem,istr,16);
OutputDebugString(istr);
OutputDebugString("\nRegionSize: ");
itoa(mbi.RegionSize,RegionSizeStr,16);
OutputDebugString(RegionSizeStr);
OutputDebugString("\nState: ");
tmp = mbi.State;
State = (char *)((mbi.State == MEM_FREE ? "MEM_FREE"
:
(mbi.State == MEM_COMMIT) ?
"MEM_COMMIT" :
(mbi.State == MEM_RESERVE) ?
"MEM_RESERVE" :
itoa(tmp, &szNumber[0], 16) ));
OutputDebugString(State);
OutputDebugString("\nType: ");
tmp = mbi.Type;
Type = (char *)((mbi.Type == MEM_MAPPED ?
"MEM_MAPPED" :
mbi.Type == MEM_PRIVATE ? "MEM_PRIVATE"
:
mbi.Type == MEM_IMAGE ? "MEM_IMAGE"
:
mbi.Type == 0 ? "N/A (0)"
:
itoa(tmp, &szNumber[0], 16)));
OutputDebugString(Type);
OutputDebugString("\nProtection on Region : ");
OutputDebugString(istr);
OutputDebugString("\n");
if (mbi.Protect & PAGE_NOCACHE)
OutputDebugString("NoCache ");
if (mbi.Protect & PAGE_GUARD) OutputDebugString("Guard
");
switch (mbi.Protect & ~(PAGE_NOCACHE|PAGE_GUARD))
{
case 0: OutputDebugString("none\n"); break;
case PAGE_NOACCESS:
OutputDebugString("NoAccess\n"); break;
case PAGE_WRITECOMBINE:
OutputDebugString("WriteCombine\n"); break;
case PAGE_READONLY:
OutputDebugString("Read\n"); break;
case PAGE_READWRITE:
OutputDebugString("ReadWrite\n"); break;
case PAGE_WRITECOPY:
OutputDebugString("WriteCopy\n"); break;
case PAGE_EXECUTE:
OutputDebugString("Execute\n"); break;
case PAGE_EXECUTE_READ:
OutputDebugString("Execute Read\n"); break;
case PAGE_EXECUTE_READWRITE:
OutputDebugString("Execute Read
Write\n"); break;
case PAGE_EXECUTE_WRITECOPY:
OutputDebugString("Execute Read
WriteCopy\n"); break;
default: OutputDebugString("none\n");
}
/*if (mbi.Type == MEM_MAPPED &&
GetMappedFileName(GetCurrentProcess(),
(LPVOID) i, szFile,
MAX_PATH))
{
printf("File Name: %s\n", szFile);
}
*/
OutputDebugString("\n");
if (mbi.RegionSize == 0) mbi.RegionSize = 1;
//increment in order to
avoid infinte loops
//shouldn't happen but right now it is
necessary remove
later
lpMem = (LPVOID)((DWORD)mbi.BaseAddress +
(DWORD)mbi.RegionSize);
//Test Allocation
if (mbi.State == MEM_FREE) //Hopefully Free
{
if (RequiredSpace < mbi.RegionSize)
{
LPVOID tmp =
VirtualAllocEx(hProcess,mbi.AllocationBase,mbi.RegionSize,
MEM_RESERVE,PAGE_NOACCESS);
if (DoDebugFormatMessage() == 0)
{ //Success found a slot return
info to validate
mbi.BaseAddress = tmp;
mbi.AllocationBase = tmp;
return mbi;
}
//VirtualFreeEx(hProcess,tmp,0,
MEM_RELEASE);
}
}
}
mbi.BaseAddress = NULL;
mbi.AllocationBase = NULL;
return mbi;
}
In CopyListViewToListBox(...) is where the fun starts. Now as I said
this code works on the TaskManager and a demo program, so smart alecs
can refrain from flameing me please, This problem is a problem only on
the target application that I wish to infiltrate.
In need of Win32 guru assistance,
Charles
.
- Prev by Date: Re: Bytecode documentation?
- Next by Date: Re: complex arithmetic in lcc-Win32
- Previous by thread: Bytecode documentation?
- Index(es):