papers
Back to the HCU Papers

			Tweaking with memory in Window95
			      - An API approach -

						by Iceman


	
Intro
------

	I decided to write this after I read NaTzGUL's tutorial called "How to 
access memory of another process".This time want to take you deeper inside 
Windows95 ,revealing some useful tricks.The basic fact is that if we want
to write good tools for reverse engineering on WIN32 hosted platforms we have
to take full control over the OS.That means system level programming
techniques such: virtual memory management,Debug API functions,Ring 0 programming
using VxD or Call gates,Image Manipulation functions.

So let's learn how this OS work!

	My future projects are based on Ring 0 programing.I am especially 
interested in Call gates and WIN32 debug API.Two of the most powerful
functions of WIN32 API are contained in debug API.They are GetThreadContext & 
SetThreadContext.You can do amazing things using them,such as injecting
code and executing code in another process adress space.
	I want to thank to Matt Pietrek for his articles about WIN32 
platforms.Reading those was a pleasure and very instructive.In fact 90% of
my knowledge regarding system level programming in Windows was gained reading
his work.In my humble opinion Matt is one of the best official "reverse 
engineer".Thank you,Matt,thank you for sharing knowledge with us!
	Next,let's give Reverser the credit he deserves.His WEB site is a treasure
for knowledge seekers.Is the best page in reverse engineering business I ever
seen.
	I know , I know my english is very bad.Please forgive me.
	This essay is structured as below:

Chapter1:Short Introduction to Windows95 memory management
Chapter2:Tweaking with virtual memory functions
Chapter3.Short intro to Toolhelp32 functions
Chapter4.How do I:
		4.1.Write self-modifiable code.
		4.2.Modify the code pages of another process. 
		4.3.Modify functions inside system Dll's.
		
========================================================================

Short Introduction to Windows95 memory management
--------------------------------------------------

	I assume that the reader is familiar with process and threads functions 
and have a basic knowledge on how Windows95,using the paging mechanism on
386+ processors,manage memory.Let's remember some facts:
		1.Windows 95 implements a page based virtual memory system. It 
uses a 32 bit linear addressing system.Internaly,all memory is managed in
4096 bytes segments called pages.The entire memory that CPU can address
in theory is called "address space".That's 4Gb.
		2. In Windows95 each 32 bit application is provided with an 
independent 4 Gb address space,regardless of how match phisycal memory is 
installed in your computer.This address space is structured as below:



	4Gb		------------------------         
			|                      |
			|                      |
			|          VxD	       |
	3Gb		------------------------
			|     System DLLs      |
			|  	   MMF	       |
			|  Top W16 Global Heap |
	2Gb		------------------------
			|		       |
			|		       |
			|    User process      |
			|        area	       |		
			|		       |
			|		       |	
	4Mb		------------------------
			|  Base W16 Global Heap|
	0		------------------------		
			
	The portion 0 to 4Mb is shared between processes.It usually contain
16 bit system dll's.The next region begin at 4Mb and ends at 2Gb.This is
the user process area.Each process have code ,data ,resources loaded in
this region.
The region is not shared! The third region begin at 2Gb and ends at
3 Gb.This region is shared between processes.Usualy the system load here
The system dll's .This region is also used to map Memory Mapped Files.The
MMF must be in a shared region because they are utilized to share data 
between processes.Finaly , the last region begin at 3Gb and ends at 4Gb		
Here the system loads Ring0 components (VxD).
	When a executable image is loaded,the system loader maps the file 
in the user process area starting with address 0x0040000 (4Mb).
This is the base address of the most PE files.
Of course ,an executable image can be rebased,so don't relay blindly on this 
address.(Microsoft provides a set of functions for image manipulation.
This functions reside inside imagehlp.dll. Some of them can be
quite useful ,so don't miss them.

============================================================================

Tweaking with virtual memory functions
--------------------------------------

	Following functions are used for Virtual Memory Managemnt.They are part 
of WIN32 API:
		VirtualAlloc
		VirtualFree
		VirtualLock
		VirtualUnlock
		VirtualProtect
		VirtualProtectEx
		VirtualQuery
		VirtualQueryEx

	VirtualAlloc is used to allocate virtual memory in process address space.
	VirtualFree  is used to free virtual memory.
	VirtualLock and VirtualUnlock are used for locking/unlocking pages in memory.
	VirtualProtect and VirtualProtectEx are used to change protection
attributes of virtual memory pages.
	VirtualQuery and VirtualQueryEx are used to query virtual memory pages. 
Using this function you can retrieve all information you need about a memory
region.
	VirtualProtectEx & VirtualQueryEx are extended versions of 
VirtualProtect & VirtualQuery functions.They can be used to query and
modify protection attributes of memory pages in another processes address space.
	Why bother with this functions? The answer is very simple.If you try to 
write to a code page using WriteProcessMemory the function will fail. This
is because the OS always write-protect the code pages,protecting them from
being modified.Any attempt to write to a write protected page will generate a
Access Violation exception.

So , if I want to modify something inside a write-protected 
page I must change it's protection attributes. Here is the step where
virtual memory functions can help.All you have to do is to change page 
protection attributes with VirtualProtect or VirtualProtectEx.You have 
to use VirtualProtect if you want to modify protection our own process 
memory pages and VirtualProtectEx to work on another process.
Those function also saves old protection attribs., so then you finish 
your work restore them.
	You can use this method to:
		1.Write self-modifiable code.
		2.Modify the code pages of another process. 
		3.Modify functions inside system Dll's.
		4.Read from read-protected areas.
		5.Injecting and executing code into another process
		  address space.
	This is not a limitative list.Just use your imagination!
	Let's see now how you can modify protection attributes with 
VirtualProtectEx:

	BOOL VirtualProtectEx(

		    HANDLE hProcess,
		    LPVOID lpAddress,	
		    DWORD dwSize,
		    DWORD flNewProtect,	
		    PDWORD lpflOldProtect 	
   			     );

We need:
	1.HANDLE hProcess: A handle to target process.The handle must have 
PROCESS_VM_OPERATION access.See OpenProcess for further reference.(I
usually use OpenProcess with PROCESS_ALL_ACCESS to get all possible access rights)
	2. LPVOID lpAddress: A pointer to the base address of the region of 
pages whose access protection attributes are to be changed.(I usually use a
DWORD with a type cast)
	3.DWORD dwSize: A dword that specify the size in bytes of region whose 
protection attributes are to be modificated.If dwSize excedes a page
boundary both pages will change protection attributes.
	4.DWORD flNewProtect:A dword that specify new protection atributes.This 
can be a one of following flags:

	PAGE_READONLY		Enables read access to the committed region of pages. 
				An attempt to write to the committed region results in 
				an access violation. If the system differentiates between
				read-only access and execute access, an attempt to execute
				code in the committed region results in an access 
				violation.
	PAGE_READWRITE		Enables both read and write access to the committed region

				of pages.
	PAGE_WRITECOPY		Gives copy-on-write access to the committed region of pages.
	PAGE_EXECUTE		Enables execute access to the committed region of pages. 
				An attempt to read or write to the committed region results 
				in an access violation.
	PAGE_EXECUTE_READ	Enables execute and read access to the committed region
                                of pages.
			        An attempt to write to the committed region results in an access
				violation.
	PAGE_EXECUTE_READWRITE	Enables execute, read, and write access to the
                                committed region of pages.
	PAGE_EXECUTE_WRITECOPY	Enables execute, read, and write access to the
				committed region of pages. The pages are shared 
				read-on-write and copy-on-write.
	PAGE_GUARD		Pages in the region become guard pages. Any attempt to read 
				from or write to a guard page causes the operating system 
				to raise a STATUS_GUARD_PAGE exception, and turn off the guard
				page status. Guard pages thus act as a one-shot access alarm.
				The PAGE_GUARD flag is a page protection modifier. 
				An application uses it with one of the other page protection 
			        flags, with one exception: it cannot be used with PAGE_NOACCESS.
			        When an access attempt leads the operating system to turn off 
				guard page status, the underlying page protection takes over.
				If a guard page exception occurs during a system service, 
				the service typically returns a failure status indicator.
	PAGE_NOACCESS		Disables all access to the committed region of pages. 
				An attempt to read from, write to, or execute in the 
				committed region results in an access violation exception,
			        called a general protection (GP) fault.
	PAGE_NOCACHE		Allows no caching of the committed regions of pages. 
				The hardware attributes for the physical memory should be set 
				to "no cache." This is not recommended for general usage. 
				It is useful for device drivers; for example, mapping a video 
				frame buffer with no caching. This flag is a page protection 
				modifier, only valid when used with one of the page protections
			        other than PAGE_NOACCESS.

	5.PDWORD lpflOldProtect: A pointer to a DWORD to save old protection
attributes.


	A handle to another process is easy to obtain.You can use several methods
for this:
	1.Use CreateProcess to create target process.Then retrieve the handler
from PROCESS_INFORMATION structure.(basically you use the loader method here).
	2.Use of ToolHelp32 functions.This method is more elegant than previous
one. The first step here is to retrieve a PID of target process.
	Use CreateToolhelp32Snapshoot,Process32First and Process32Next functions.
After you have the PID use OpenProcess to obtain a handle to target
process.(Be sure to set access flags to PROCESS_ALL_ACCESS).Warning: Toolhelp32 functions
are not portable!
	3.The methods described by NaTzGUL in his essay "How to access memory of
another process".
	The rest of parameters are self-explanatory.Now let's modify the
protection attributes of first code page of target process.


		HANDLE hTarget;              	// Handle to target process 
		DWORD  codebase = 0x0040000;  	// Assuming image is based at 0x0040000
		DWORD  oldattr;			// Here we will store old prot. attribs	
		VirtualProtectEx( hTarget , 
				LPVOID(codebase),                //Change attribs of 
				4096,                            // first code page to 
				PAGE_EXECUTE_READWRITE,		 // enable read , write
				&oldattr);			 // and execute access.
		
		//
		// Do something useful here
		// 
		//
		 VirtualProtectEx( hTarget , 
				LPVOID(codebase),                //Restore old attr.
				4096,                            // 
				oldattr,		         // 
				&oldattr);

	Querying the virtual address space is another important thing.By use of
VirtualQuery and VirtualQueryEx you can get various info about memory regions in a
process address space.
 Fire up Soft-Ice and type Query.Do you like the screen now? What you can
see is a map virtual address space of target process.Every memory region 
is listed there with some additional info.Not only Soft-Ice can do this.
You can too!By the way: A memory region from Virtual memory API point of view 
is a region whose protection attributes , type and base allocations are the same.
Let's the API: 

	DWORD VirtualQueryEx(
				HANDLE hProcess,	// handle of process 
			        LPCVOID lpAddress,	// address of region 
			        PMEMORY_BASIC_INFORMATION lpBuffer,	// address of 
									// information buffer 
				DWORD dwLength 	// size of buffer 
   			     );	
 
The parameters:
		1.HANDLE hProcess: Handle to target process.Must have
PROCESS_QUERY_INFORMATION
access flag set.
		2.LPCVOID lpAddress: Pointer to se address of the region of pages to be
queried.
This value is rounded down to the next page boundary.
		3.PMEMORY_BASIC_INFORMATION lpBuffer pointer to a
MEMORY_BASIC_INFORMATION structure to receive region info.

		typedef struct _MEMORY_BASIC_INFORMATION { // mbi  
    			PVOID BaseAddress;            // base address of region 
		        PVOID AllocationBase;         // allocation base address 
		        DWORD AllocationProtect;      // initial access protection 
		        DWORD RegionSize;             // size, in bytes, of region 
		        DWORD State;                  // committed, reserved, free 
		        DWORD Protect;                // current access protection 
		        DWORD Type;                   // type of pages 

		} MEMORY_BASIC_INFORMATION; 
		typedef MEMORY_BASIC_INFORMATION *PMEMORY_BASIC_INFORMATION; 

     BaseAddress	Points to the base address of the region of pages. 
     AllocationBase	Points to the base address of a range of pages
			allocated by the VirtualAlloc function. The page pointed 
			to by the BaseAddress member 
			is contained within this allocation range. 
     AllocationProtect  Specifies the access protection given when the
			region was initially 
			allocated. One of the following flags can be present, along with the 
			PAGE_GUARD and PAGE_NOCACHE protection modifier flags. 	
     RegionSize		Specifies the size, in bytes, of the region beginning at
			the base 
			address in which all pages have identical attributes. 		 
     State		Specifies the state of the pages in the region. 
			One of the following states is indicated:
			MEM_COMMIT	Indicates committed pages for which physical storage 
					has been allocated, either in memory or in the paging 
					file on disk.
			MEM_FREE	Indicates free pages not accessible to the calling 
					process and available to be allocated. For free pages, 
					the information in the AllocationBase, AllocationProtect,
					Protect, and Type members is undefined.
			MEM_RESERVE	Indicates reserved pages where a range of the process's 
					virtual address space is reserved without allocating any
				        physical storage. For reserved pages, the information in
				        the Protect member is undefined.
 

     Protect 		Specifies the access protection of the pages in the region.
			One of the 
			flags listed for the AllocationProtect member is specified.
     Type		Specifies the type of pages in the region. The following types
			are defined: 	  	
			MEM_IMAGE	Indicates that the memory pages within the region are 
					mapped into the view of an image section.
			MEM_MAPPED	Indicates that the memory pages within the region are 
					mapped into the view of a section.
			MEM_PRIVATE	Indicates that the memory pages within the region are 
					private (not shared by other processes).
	4.DWORD dwLength: Specifies the size, in bytes, of the buffer pointed to
			by the lpBuffer parameter. 
			  Usually set to sizeof(MEMORY_BASIC_INFORMATION).
 	
	Now let's retrieve this information for the code section of target
process:

		HANDLE Hare;              	// Handle to target process 
		DWORD  codebase = 0x0040000;  	// Assuming image is based at 0x0040000
		MEMORY_BASIC_INFORMATION mbi;   // 
		VirtualQueryEx(hTarget,
LPCVOID(codebase),&mbi,sizeof(MEMORY_BASIC_INFORMATION);

        After VirtualQueryEx returns you have in mbi all information you
need about code	memory region  of target process.
	To retrieve info about all memory regions of a process address space all
you have to do is to start enumerate all memory regions from 0 to 4Gb.Initially call
VirtualProcessEx with
LPCVOID lpAddress set to 0 .After the function returns start iterate  calls
to VirtualProcessEx with LPCVOID lpAddress incremented by the size of region
it queried previously.
Be sure to save away contents of MEMORY_BASIC_INFORMATION structure before
next call.Usualy I use a do - while  loop.
=============================================================================
		
	3.Short intro to Toolhelp32 functions
	-------------------------------------
	
	Nice set of functions!Unfortunately they are NOT portable to other
implementations
of WIN32 such as WIN32s or WINDOWS NT.Those functions are designed to
retrieve info about
processes and threads running in your system.They are very useful to design
debuggers for
WIN95 environment.
	The keyword  is "snapshot".A snapshot is an object in OS memory that lists
all 
possible information about processes and thread runing.Snapshoots are
created with
CreateToolhelp32Snapshoot functions.This function returns a handle that you
can use for 
future access to snapshot object.Destroying the snapshot object is very
simple.All
you have to do is to call CloseHandle function.The snapshot objects are
continue updated
by OS to reflect the real state of system,so you don't have to worry that
the information
is outdated.
	They also provide an easy method to create an "Attach to process"
function.A good 
tool must provide a way to dynamically attach to other processes.Using this
functions is 
very easy to do it.
	Those functions resides in Kernel32.dll,but they are not exported through
kernel32.lib
I think that in Visual C they are exported through tlh32.lib.You must also
locate the 
appropriate header file.The linker does not link implicitly with
tlh32.lib!You have to add
the lib to your project.
	The API:
		CreateToolhelp32Snapshoot
		Heap32First
		Heap32Next
		Heap32ListFirst
		Heap32ListNext
		Module32First
		Module32Next
		Process32First
		Process32Next
		Thread32First
		Thread32Next
		Toolhelp32ReadProcessMemory

	After you use CreateToolhelp32Snapshoot to create system snapshot you can
use
other functions to retrieve the info.
	Process32First & Process32Next are used to walk the process list in
snapshoot.They
return process information in a PROCESSENTRY32  structure.Use
Process32First to get info
about the first process,then Process32Next to retrieve info about
subsequent processes.
Use GetLastError to retrieve the error status.
	This functions are the subject of one of my future essays,so I don't
present them in 
details here.They are very simple to use.I put this short section here only
to provide you
an idea how to retrieve some really cool info.
============================================================================
====================


	How do I....
	------------



		1.Write self modifiable code?

			A. Call VirtualProtect on code pages you want to modify.
			   DWORD flNewProtect must be PAGE_WRITECOPY.
			B. Write to code pages.
			C.Call VirtualProtect on code pages you want to modify to
			   restore old attribs.(PAGE_EXECUTE)
			D.Call FlushInstructionCache to empty the invalidate instruction cache.
			  This step is required because this portion of code may be already
			  in cache memory.		


		2.Modify the code pages of another process(single thread).
			A.Get a handle to target process 
			B.Get handle of target process main thread.
			C.Stop thread using SuspendThread.
			D.Call VirtualProtectEx on code pages you want to modify.
			  DWORD flNewProtect must be PAGE_READWRITE.
			E.Save away the code pages (not required. may you don't need
			  them anymore.Use ReadProcessMemory
			F.Use WriteProcessMemory to write to target pages.
			G.Call VirtualProtectEx on code pages you want to modify to
			   restore old attribs.(PAGE_EXECUTE)
			H.Resume thread using ResumeThread.

			
		3.Modify functions inside system Dll's

			This is can be very dangerous.Write something wrong inside kernell32.dll
		,for  example,and BYE-BYE Windows.But,sometimes it may be very useful
that a
		WIN API function to return without doing nothing,to return faked
values,or to
		do anything but not what was supposed to do.Please take a look at
Madmax's essay
		"Cracking using KERNEL32.DLL??" in Reverser's pages of reverse engineering
to get 
		the point. He chose to patch the file kernel32.dll itself.I don't like
this
		method.I want as far as possible my system files unmodified.So I have to
tweak
		with memory.Let's see how:

			A. Use GetModuleHandle to get a handle to Kernel32.dll
			B. Use GetProcessAdress to get the address of the function we
			   want to patch.
			C.Call VirtualProtect on code pages you want to modify.
			  Use value returned by GetProcessAdress as  LPVOID lpAddress
			  parameter.DWORD flNewProtect must be PAGE_EXECUTE_READWRITE.
			D.Modify (patch the function). Write some code there.Anything
			  you want.I keep hoping that you know what are you doing! 
			E.Call VirtualProtect to restore previous protection attributes.
	      Enjoy your new kernel!
	      Let's see some code.We want to patch
			
		HANDLE hKernel32;
		DWORD oldprot;
		hKernel32=GetModuleHandle("kernel32.dll");
		VirtualProtect(GetProcessAdress( hKernel32,"GetDriveTypeA"),4096,
						PAGE_EXECUTE_READWRITE, &oldprot);
		//
		//
		//Write new code
		// 
		VirtualProtect(GetProcessAdress( hKernel32,"GetDriveTypeA"),4096,
						oldprot, &oldprot);	
			
		As an exercise,try to make this function to say that your HDD is a
			ramdisk.
		Note that the small code snippet presented above does not perform ANY
			error checking.This is bad.This is very bad!I suggest an 
			extensive error checking and or exception handling when you
			play with memory.For example if somehow the first call to
			VirtualProtect fails then trying to access that memory range
			to write will generate a superb AccessViolation Exception.It
			will crash into pieces.I also make intensive use of 
			IsBadWritePtr,IsBadCodePtr,IsBadReadPtr API functions.
			So please, do always !at least! a basic error checking!
============================================================================
===================

Final Notes
-----------

	1.Any corrections and additions are wellcomed.Please append them at the
end of
this document and also include your name (or your nickname ).Slightly
editing minor mistakes
and typos is admitted in-place and without notice.
	2.You can contact me at folowing e-mail adress ice_man81@hotmail.com

You are deep inside reverser's page of reverse engineering, choose your way out:

papers
Back to the HCU Papers



redhomepage redlinks redsearch_forms red+ORC redstudents' essays redacademy database
redreality cracking redhow to search redjavascript wars
redtools redanonymity academy redcocktails redantismut CGI-scripts redmail_reverser
redIs reverse engineering legal?