Exetools  

Go Back   Exetools > General > General Discussion

Notices

Reply
 
Thread Tools Display Modes
  #1  
Old 01-19-2005, 09:06
FEARHQ FEARHQ is offline
Friend
 
Join Date: Mar 2002
Posts: 73
Rept. Given: 0
Rept. Rcvd 0 Times in 0 Posts
Thanks Given: 0
Thanks Rcvd at 1 Time in 1 Post
FEARHQ Reputation: 0
Reading process memory

While writing a tiny library to read/write process memory I came across a rather unusual problem. While I can write to the process memory without a hitch, I have discovered a wierd bug that would crash the process of which you are reading the memory and I'm not sure why this happens. What I have actually done is use the ToolHelp32 library to traverse the module list and wait until a certain module is loaded (sleeping 10 milliseconds if not found), get it's base address and base size and then proceed to read it's memory with what I have written below. The problem is that the module fails in really odd manners after I try to read it with the code below. My write routine is very similar and produces no faults.

Code:
;GetProcessMemory proc uses ecx dwProcessId:DWORD, lpAddress:DWORD, dwSize:DWORD, lpBuffer:DWORD
;	LOCAL hProcess:DWORD
;	LOCAL oldProt:DWORD
;	LOCAL dummyProt:DWORD
;	
;	; Attempt to open the process for write operations
;	invoke OpenProcess, PROCESS_VM_OPERATION+ PROCESS_VM_READ, FALSE, dwProcessId
;	.IF eax == 0
;		ret
;	.endif
;	mov hProcess, eax
;	
;	; Set the page protection to allow read, write and execute status
;	invoke VirtualProtectEx, hProcess, lpAddress, dwSize, PAGE_EXECUTE_READWRITE, addr oldProt
;	or eax, eax
;	jz Failed
;	
;	; Read the target process's memory
;	invoke ReadProcessMemory, hProcess, lpAddress, lpBuffer, dwSize, NULL
;	or eax, eax
;	jz Failed
;	
;	; Restore the old page protection
;	invoke VirtualProtectEx, hProcess, lpAddress, dwSize, oldProt, addr dummyProt
;	or eax, eax
;	jz Failed
;	
;	invoke CloseHandle, hProcess
;	ret
;	
;Failed:
;	invoke CloseHandle, hProcess
;	xor eax, eax
;	ret
;GetProcessMemory endp
Reply With Quote
  #2  
Old 01-19-2005, 14:36
Innocent
 
Posts: n/a
Hmmm. I would suggest using OllyDbg on your program to see where the problem is. Watch the registers as you step through your code. Pay attention to the LastErr flag. My guess is one of your invoke statements is producing an error. Use Olly to find which one and troubleshoot.
Reply With Quote
  #3  
Old 01-19-2005, 20:10
JuneMouse
 
Posts: n/a
you must have read access to entire area that you trying to read
that means if a byte is straddling on other page than you need Read access
to both the pages

use IsBadReadPtr() and also intersperse your Calls with GetLastError()
or set a seh to trap failures that way you can easily pinpoint the failures to certain areas rathere than looking from scratch
Reply With Quote
  #4  
Old 01-20-2005, 16:20
upb's Avatar
upb upb is offline
Friend
 
Join Date: Apr 2002
Location: Elbonia
Posts: 63
Rept. Given: 5
Rept. Rcvd 0 Times in 0 Posts
Thanks Given: 3
Thanks Rcvd at 0 Times in 0 Posts
upb Reputation: 0
umm but isnt he setting read access on the entire area of pages covered by the buf?!
Reply With Quote
  #5  
Old 01-20-2005, 21:43
Shub-Nigurrath's Avatar
Shub-Nigurrath Shub-Nigurrath is offline
VIP
 
Join Date: Mar 2004
Location: Obscure Kadath
Posts: 919
Rept. Given: 60
Rept. Rcvd 419 Times in 94 Posts
Thanks Given: 68
Thanks Rcvd at 330 Times in 100 Posts
Shub-Nigurrath Reputation: 400-499 Shub-Nigurrath Reputation: 400-499 Shub-Nigurrath Reputation: 400-499 Shub-Nigurrath Reputation: 400-499 Shub-Nigurrath Reputation: 400-499
here's a code snippet form a tool I'm writing. it's in C++ but might help.
The concept is to wrap the real ReadProcessMemory and use the new one. The code I wrote in C++ is useful because for classes derived from the one here attached there's nothing to change, and you might write the code as before.

I hope it helps: despite you are programming in ASM the concepts are the same and also the code structure doesn't change that much.

AccessMemory.h
Code:
#include <windows.h>

typedef BOOL (__stdcall *ACCESS_PROCESS_MEMORY_FCN)(HANDLE, LPVOID, LPVOID, DWORD, LPDWORD );

class CAccessMemory  
{
public:
	CAccessMemory();
	virtual ~CAccessMemory();

	BOOL ReadProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress, LPVOID lpBuffer,
		DWORD nSize, LPDWORD lpNumberOfBytesRead);
	BOOL WriteProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress, LPVOID lpBuffer,
		DWORD nSize, LPDWORD lpNumberOfBytesWritten);

private:
	BOOL _accessProcessMemory(
		ACCESS_PROCESS_MEMORY_FCN fcn, 
		HANDLE hProcess, 
		LPVOID lpBaseAddress, LPVOID lpBuffer,
		DWORD nSize, LPDWORD lpNumberOfBytesWritten);

};
AccessMemory.cpp
Code:
CAccessMemory::CAccessMemory()
{

}

CAccessMemory::~CAccessMemory()
{

}

//A wrapper for the ::ReadProcessMemory which set also the memory 
//access right properly
BOOL CAccessMemory::ReadProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress, LPVOID lpBuffer,
		DWORD nSize, LPDWORD lpNumberOfBytesRead) {
	
	ACCESS_PROCESS_MEMORY_FCN fcn;
	
	//There's a little difference between the two function pointers or 
	//::ReadProcessMemory and ::WriteProcessMemory, because the two prototypes are different
	//This trick cast the pointer of the function pointer of ::ReadProcessMemory to a 
	//void* then cast it back to an ACCESS_PROCESS_MEMORY_FCN function pointer. 
	//The differences between these two prototypes are not important and 
	//everything works excellently.
	fcn=(ACCESS_PROCESS_MEMORY_FCN)((void*)&(::ReadProcessMemory));
	
	return _accessProcessMemory(fcn, hProcess, lpBaseAddress, lpBuffer,
		nSize, lpNumberOfBytesRead);
}

//A wrapper for the ::WriteProcessMemory which set also the memory 
//access right properly
BOOL CAccessMemory::WriteProcessMemory(HANDLE hProcess, LPVOID lpBaseAddress, LPVOID lpBuffer,
		DWORD nSize, LPDWORD lpNumberOfBytesWritten)
{
	ACCESS_PROCESS_MEMORY_FCN fcn;

	//Assign the function pointer, this time there are no problems, 
	//because ACCESS_PROCESS_MEMORY_FCN is the prototype of ::WriteProcessMemory
	fcn=::WriteProcessMemory; 
	
	return _accessProcessMemory(fcn, hProcess, lpBaseAddress, lpBuffer,
		nSize, lpNumberOfBytesWritten);
}

//It is used by the WriteProcessMemory and ReadProcessMemory methods. 
//It worry to grant access to memory.
BOOL CAccessMemory::_accessProcessMemory(
		ACCESS_PROCESS_MEMORY_FCN fcn, 
		HANDLE hProcess, 
		LPVOID lpBaseAddress, LPVOID lpBuffer,
		DWORD nSize, LPDWORD lpNumberOfBytes)
{
	DWORD OldProtection=0;
	//It is not really used because the VirtualProtectEx function always requires a valid
	//variable to hold the old page protection values, otherwise fails. When restoring the 
	//protection values of the page, on the existing of this program, the old values are not
	//important of course.
	DWORD dummyProtection=0;

	BOOL bVal=FALSE;

	int tries=0;
	
	//Do 3 tries loop, so as not the block forever..
	while(tries<3) {
		__try {
			tries++;
			bVal=fcn(hProcess, lpBaseAddress, lpBuffer,nSize, lpNumberOfBytes);
			if(!bVal) 
				//The RaiseException function raises an exception in the calling thread.
				RaiseException(1, // exception code 
                0,                // continuable exception (non death exception)
                0, NULL);         // no arguments 
		}
		__except(TRUE) {
			if(IsBadReadPtr(lpBaseAddress, nSize) || IsBadWritePtr(lpBaseAddress, nSize))
				VirtualProtectEx(hProcess, lpBaseAddress, nSize, 
					PAGE_EXECUTE_READWRITE, &OldProtection);
			continue;
		}
		break;
	}
	
	//Restore the previous protections of the patched address.
	//OlProtection is !=0 if the previous VirtualProtectEx has been done.
	if(OldProtection!=0)
		VirtualProtectEx(hProcess, lpBaseAddress, nSize, 
			OldProtection, &dummyProtection);

	return bVal;

}
__________________
Ŝħůb-Ňìĝùŕřaŧħ ₪)
There are only 10 types of people in the world: Those who understand binary, and those who don't
http://www.accessroot.com
Reply With Quote
  #6  
Old 01-21-2005, 15:42
FEARHQ FEARHQ is offline
Friend
 
Join Date: Mar 2002
Posts: 73
Rept. Given: 0
Rept. Rcvd 0 Times in 0 Posts
Thanks Given: 0
Thanks Rcvd at 1 Time in 1 Post
FEARHQ Reputation: 0
Thanks for all the replies guys

My function does succeed in reading the entire block and copying it, that's not really the problem. The problem is the module not playing so nicely with me afterwards :/ I did set the protection to read/write/execute in any case to allow all acces... Perhaps this is deadly when code is actually executing in there, heh.

Shub-Nigurrath, I love the idea to use IsBadReadPtr/IsBadWritePtr to check the memory range for desired access, but wouldn't this simply give you the access rights for YOUR process's pages in that range? I don't see those functions taking in a handle to the target process, but then again I never used them before.

Innocent: Olly is MY debugger of choice, for all debugging and 'other' tasks. There is no direct problem with my code, but aparently the target code doesn't like to be read, or have it's protections changed (haven't really looked at that). The point is that this generic write routine fails by all means with my current target, and so would Shub-Nigurrath's. My workaround was to map the target file to memory and get whatever info I need for there.

On a side note, is there any way to pause execution of the target process? I would probably need to stop all of it's threads, then later resume them... Best would be to save the thread's run state (some may be paused and if they were, they should be paused when I'm done)
Reply With Quote
  #7  
Old 01-21-2005, 16:38
Shub-Nigurrath's Avatar
Shub-Nigurrath Shub-Nigurrath is offline
VIP
 
Join Date: Mar 2004
Location: Obscure Kadath
Posts: 919
Rept. Given: 60
Rept. Rcvd 419 Times in 94 Posts
Thanks Given: 68
Thanks Rcvd at 330 Times in 100 Posts
Shub-Nigurrath Reputation: 400-499 Shub-Nigurrath Reputation: 400-499 Shub-Nigurrath Reputation: 400-499 Shub-Nigurrath Reputation: 400-499 Shub-Nigurrath Reputation: 400-499
2 FEARHQ

not really using that permissions you can gain access right for any process, even external processes: I used it for a loader which launches an external program and everything works fine.
__________________
Ŝħůb-Ňìĝùŕřaŧħ ₪)
There are only 10 types of people in the world: Those who understand binary, and those who don't
http://www.accessroot.com
Reply With Quote
  #8  
Old 01-21-2005, 19:04
TQN TQN is offline
VIP
 
Join Date: Apr 2003
Location: Vietnam
Posts: 343
Rept. Given: 142
Rept. Rcvd 20 Times in 12 Posts
Thanks Given: 169
Thanks Rcvd at 130 Times in 43 Posts
TQN Reputation: 20
Hi Shub-Nigurrath !
Sorry first if I have a wrong idea. I think the IsBadReadPtr and IsBadWritePtr can not be used to check memory access right for a memory range of another process. In your code, you really call them to check read/write right for a memory range in your virtual memory process with the addess value is same as lpAddress (of beging loaded process).
FEARHQ, if one of a call to ReadProcessMemory failed, the protection flag of those memory pages will be not restored to original flag (je Failed). Some coders/programs uses PAGE_NOACCESS to allocate memory when need.
Regards,
TQN
Reply With Quote
  #9  
Old 01-22-2005, 08:29
Shub-Nigurrath's Avatar
Shub-Nigurrath Shub-Nigurrath is offline
VIP
 
Join Date: Mar 2004
Location: Obscure Kadath
Posts: 919
Rept. Given: 60
Rept. Rcvd 419 Times in 94 Posts
Thanks Given: 68
Thanks Rcvd at 330 Times in 100 Posts
Shub-Nigurrath Reputation: 400-499 Shub-Nigurrath Reputation: 400-499 Shub-Nigurrath Reputation: 400-499 Shub-Nigurrath Reputation: 400-499 Shub-Nigurrath Reputation: 400-499
humm. You are right: I got the wrong point because I used since now it for loaders, so the target process, even if external, is launched by my loader, a "child", works also for protected memory sections of the target..but a process of this type is different than an external already running process.

Effectively for opened processes it doesn't work, or better, works the reading but not the writing: it returns a casual value (negative also) and do not write anything.
__________________
Ŝħůb-Ňìĝùŕřaŧħ ₪)
There are only 10 types of people in the world: Those who understand binary, and those who don't
http://www.accessroot.com
Reply With Quote
  #10  
Old 01-22-2005, 15:57
JuneMouse
 
Posts: n/a
TQN so if isBadReadPtr() wont work for processes opened by OpenProcess
then what do we use is it VirtualQuery() ??
how does one ascertain if one really has access to that process for read write etc
without getting the code in debugger and looking for every return values
Reply With Quote
  #11  
Old 01-22-2005, 21:24
TQN TQN is offline
VIP
 
Join Date: Apr 2003
Location: Vietnam
Posts: 343
Rept. Given: 142
Rept. Rcvd 20 Times in 12 Posts
Thanks Given: 169
Thanks Rcvd at 130 Times in 43 Posts
TQN Reputation: 20
Hi JuneMouse !
Sorry if I wrong. In my experience, the safe way is call VirtualQueryEx to detect read/write right of a virtual memory page of a external process. Call GetSystemInfo to get page size, scan one page one.
Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Reading File Version from Memory phroyt Source Code 7 05-01-2020 04:18
Game and in-process memory hacking redbull General Discussion 1 01-26-2005 01:28


All times are GMT +8. The time now is 01:34.


Always Your Best Friend: Aaron, JMI, ahmadmansoor, ZeNiX, chessgod101
( 1998 - 2024 )