Prev: Problem with CSocket
Next: size of Picture Control
From: d_purple_devil on 26 Jan 2007 08:32 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, The first part is a VB.net module the second part is as VC++ 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: VB.net Code First ----------------------------------------------------------------------------------------------------------------------------------------------------- Imports System Imports System.Runtime.InteropServices Imports System.Text Module MainModule 'FormatMessage <DllImport("kernel32.dll", EntryPoint:="FormatMessageA", _ CharSet:=CharSet.Ansi, _ ExactSpelling:=True, _ CallingConvention:=CallingConvention.StdCall)> _ Private Function FormatMessage( _ ByVal dwFlags As Int32, ByVal lpSource As Int32, _ ByVal dwMessageId As Int32, ByVal dwLanguageId As Int32, _ ByVal lpBuffer As StringBuilder, _ ByVal nSize As Int32, ByVal Arguments As Int32) As Int32 End Function Private Const FORMAT_MESSAGE_ALLOCATE_BUFFER As Long = &H100 Private Const FORMAT_MESSAGE_FROM_SYSTEM As Long = &H1000 Private Const FORMAT_MESSAGE_IGNORE_INSERTS As Long = &H200 Private Declare Function GetLastError Lib "kernel32.dll" () As Integer 'declare API functions Private Delegate Function EnumChildProcDelegate _ (ByVal hWnd As IntPtr, _ ByVal lParam As Integer) As Boolean Private Declare Function EnumChildWindows Lib "user32" _ (ByVal hWndParent As IntPtr, _ ByVal lpEnumFunc As EnumChildProcDelegate, _ ByVal lParam As Integer) As Boolean Declare Function GetClassName Lib "user32.dll" Alias "GetClassNameA" _ (ByVal hwnd As IntPtr, _ ByVal lpClassName As StringBuilder, _ ByVal nMaxCount As Long) As Long Private Declare Ansi Function FindWindow Lib "user32" Alias "FindWindowA" _ (ByVal lpClassName As StringBuilder, ByVal lpWindowName As StringBuilder) As IntPtr Public Declare Sub GetWindowText Lib "user32.dll" _ Alias "GetWindowTextA" (ByVal hWnd As IntPtr, _ ByVal lpString As StringBuilder, _ ByVal nMaxCount As Integer) Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" _ (ByVal hwnd As IntPtr, ByVal wMsg As Integer, _ ByVal wParam As Integer, _ ByVal lParam As String) As Integer Public Declare Function GetWindow Lib "user32.dll" _ Alias "GetWindow" (ByVal hwnd As Integer, _ ByVal wCmd As Integer) As Integer 'Top Level enumeration Public Delegate Function EnumWindowsCallback(ByVal hWnd As IntPtr, _ ByVal lParam As Integer) As Boolean Public Declare Function EnumWindows Lib "user32.dll" _ Alias "EnumWindows" (ByVal callback As EnumWindowsCallback, _ ByVal lParam As Integer) As Integer <DllImport("user32.dll", EntryPoint:="EnumWindows", SetLastError:=True, _ CharSet:=CharSet.Ansi, ExactSpelling:=True, _ CallingConvention:=CallingConvention.StdCall)> _ Public Function EnumWindowsDllImport(ByVal callback As EnumWindowsCallback, _ ByVal lParam As Integer) As Integer End Function 'My DLL Declares Private Declare Function CopyListViewToListBox Lib "Extract Data Library.dll" _ Alias "CopyListViewToListBox" (ByVal SourceHwnd As IntPtr, ByVal TargetHwnd As IntPtr, _ ByVal Append As Boolean) As Integer Private Declare Function FillListBox Lib "Extract Data Library.dll" _ Alias "FillListBox" (ByVal targetHwnd As IntPtr, ByVal item As String, _ ByVal subitem As String, ByVal Append As String) As Integer 'Variables Dim iFound As Int32 Dim aihWnds As ArrayList Private Const WM_GETTEXT = &HD 'Listbox Functions Private Declare Function LockWindowUpdate Lib "user32" (ByVal hwndLock As IntPtr) _ As Long 'Listbox Constants Const LB_RESETCONTENT = &H184 Const LB_GETCOUNT = &H18B Const LB_GETTEXT = &H189 Const LB_ADDSTRING = &H180 Const LB_GETITEMDATA = &H199 Const LB_SETITEMDATA = &H19A Function GetGlass(ByVal hwnd) As String 'classe de la fenetre Dim sClassName = New StringBuilder(256) GetClassName(hwnd, sClassName, 256) sClassName = Left$(sClassName, InStr(sClassName, Chr(0)) - 1) Return sClassName End Function Function GetCaption(ByVal hwnd As IntPtr) As String 'titre du document Dim sCaption = New StringBuilder(256) GetWindowText(hwnd, sCaption, 256) sCaption = sCaption.ToString If Len(sCaption) > 1 Then Debug.WriteLine(sCaption) If (InStr(sCaption, Chr(0)) - 1) > 0 Then 'trim null sCaption = Left$(sCaption, InStr(sCaption, Chr(0)) - 1) End If End If Return sCaption End Function Function GetCaptionFromMessage(ByVal hwnd) As String 'texte titre fenetre Dim sCaption = New String(Chr(0), 100) Dim retval = SendMessage(hwnd, WM_GETTEXT, 100, sCaption) sCaption = Left$(sCaption, InStr(sCaption, Chr(0)) - 1) Return sCaption End Function Function EnumChildrenProc(ByVal hwnd As IntPtr, ByVal lParam As Integer) As Boolean Dim retval As Long 'error handling goes here good old formatmessage from system Dim ClassName As New StringBuilder(256) retval = GetClassName(hwnd, ClassName, 256) If ClassName.ToString = "SysListView32" Then 'found listbox Debug.WriteLine(hwnd) 'FillListbox(hwnd) MainModule.aihWnds.Insert(iFound, hwnd) iFound = iFound + 1 End If 'If iFound = 1 Then 'Return False 'Found Both of the Listbox Stop enumeration 'Else Return True 'Still haven't got them both 'End If End Function Sub GetListBoxes() 'need to loop through all windows to get the first characters and compare to level II ... 'Dim sWindowCaption = "Windows Task Manager" 'Dim hwnd = FindWindow(vbNullString, sWindowCaption) Dim proc As New EnumWindowsCallback(AddressOf MainModule.EnumWindowProc) EnumWindows(proc, 0) 'DuplicateListBox(MainForm.Listboxes(0).Handle, MainForm.Listboxes(1)) End Sub Private Function EnumWindowProc(ByVal hwnd As IntPtr, ByVal lParam As Integer) As Boolean If InStr(GetCaption(hwnd).ToString, "Level II") Then ProcessEFXChildren(hwnd) Return False End If Return True End Function Private Function ProcessEFXChildren(ByVal hwnd As IntPtr) iFound = 0 aihWnds = New ArrayList Dim i As Integer Dim proc As New EnumChildProcDelegate(AddressOf MainModule.EnumChildrenProc) Dim retval = EnumChildWindows(hwnd, proc, 0&) For i = 0 To iFound - 1 CopyListViewToListBox(aihWnds(i), MainForm.Listboxes(0).Handle, False) Next End Function End Module --------------------------------------------------------------------------------------------------------------------------------------------- VC++.NET 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; } The Vb is pretty standard so CopyListViewToListBox(aihWnds(i), MainForm.Listboxes(0).Handle, False) is where I depart from VB into C and it is just there to avoid there being anything missing. 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
|
Pages: 1 Prev: Problem with CSocket Next: size of Picture Control |