Results 1 to 12 of 12

Thread: DLL code patching at runtime ...

  1. #1

    Question DLL code patching at runtime ...

    Hi,

    I have one process that load one dll. I need to change the code of a routine, but only after the program has started. I have absolute address of code that I want to patching.

    I start writing simple code with use of :

    CreateToolhelp32Snapshot - for list of process/module
    Process32First and Process32Next - for find primary process that load dll
    Module32First and Module32Next - for find dll that i want patching
    OpenProcess - to get handle of process that load dll

    But now, for testing, I want read address of code that i want patch.

    how do I go ?

    Thanks.

    Kappasm.

  2. #2
    After OpenProcess you need to do a ReadProcessMemory or WriteProcessMemory to patch.
    I promise that I have read the FAQ and tried to use the Search to answer my question.

  3. #3
    Hi tazBRC,

    thanks for your replay.

    Quote Originally Posted by tazBRC View Post
    After OpenProcess you need to do a ReadProcessMemory or WriteProcessMemory to patch.
    I tried these instructions but to no avail. There is definitely something that escapes me.

    This is my code :

    Code:
    #include <stdio.h>
    #include <windows.h>
    #include <tlhelp32.h> 
    
    // Process Name
    char process_name[] = "Process.exe";
    
    // Module Name
    char module_name[] = "Module.dll";
    
    //
    // Error Message
    //
    void MessageError(TCHAR * msg)
    {
    	// Local variable
            DWORD eNum;
    	TCHAR Message[256];
    	TCHAR sysMsg[256];
    	TCHAR * p;
    
    	// Last Error
    	eNum = GetLastError( );
    
    	// Formatting error message
    	FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, eNum, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), sysMsg, 256, NULL);
    
    	// Trim the end of the line and terminate it with a null
    	p = sysMsg;
    	while( ( *p > 31 ) || ( *p == 9 ) ) ++p;
    	do { *p-- = 0; } while( ( p >= sysMsg ) && ( ( *p == '.' ) || ( *p < 33 ) ) );
    
    	// Display the message
    	sprintf(Message, TEXT("\nWARNING: %s failed with error %d (%s)"), msg, eNum, sysMsg );
    
    	// Print message
    	MessageBox(NULL, Message, "Error !!!", MB_OK);
    }
    
    //
    // Main Program
    //
    int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
    {
    	// Local variable
    	DWORD Process;
    	DWORD ModuleAddress;
    	DWORD ModuleSize;
    	DWORD OldProtect;
    	PROCESSENTRY32 process;
    	MODULEENTRY32 module;
    	HANDLE snapshot;
    	BOOL gotime;
    	HANDLE phandle;
    	HANDLE hToken;
    	TOKEN_PRIVILEGES token;
    	PBYTE pMem;
    	DWORD Read;
    
    	// Get Full privilegies
    	if(OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
    	{
    		LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &token.Privileges[0].Luid);
    		token.PrivilegeCount = 1;
    		token.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
    		AdjustTokenPrivileges(hToken, 0, &token, sizeof(token), NULL, NULL);
    	}
    
    	// Init Process / Module size
    	process.dwSize = sizeof(process);
    	module.dwSize = sizeof(module);
    
    	// Init Search state
    	gotime = FALSE;
    
    	/*
    	 * TH32CS_SNAPALL-> Includes all processes and threads in the system,
    	 * plus the heaps and modules of the process specified in th32ProcessID.
    	 */
    	snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0); 
    
    	// Search first process
    	Process32First(snapshot, &process); 
    
    	// Search "Process.exe"
    	do
    	{
    		// Check found ...
    		if(strcmp(process.szExeFile, process_name) == 0) 
    		{
    			// Save Process ID
    			Process = process.th32ProcessID;			
    
    			// Find !!!
    			gotime = TRUE;
    
    			// End.
    			break;
    		}
    
    	} while (Process32Next(snapshot, &process));
    
    	// Close Search Process
    	CloseHandle(snapshot);
    
    	// Check found process
    	if (!gotime)
    	{
    		// Error
    		MessageError("Process not found");
    
    		// Exit
    		return(-1);
    	}
    
    	// Init Find Module
    	gotime = FALSE;
    
    	/*
    	 * TH32CS_SNAPALL-> Includes all processes and threads in the system,
    	 * plus the heaps and modules of the process specified in th32ProcessID.
    	 */
    	snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, Process); 
    
    	// Search first module on process
    	Module32First(snapshot, &module); 
    
    	// Search "Module.dll"
    	do
    	{
    		// Check found ...		
    		if(strcmp(module.szModule, module_name) == 0) 
    		{
    			// Save Module ID and Size
    			ModuleAddress = (DWORD)module.modBaseAddr;
    			ModuleSize = (DWORD)module.modBaseSize;
    
    			// Find !!!
    			gotime = TRUE;
    
    			// End.
    			break;
    		}
    
    	} while (Module32Next(snapshot, &module));
    
    	// Close Search Process
    	CloseHandle(snapshot);
    
    	// Check found process
    	if (!gotime)
    	{
    		// Error
    		MessageError("Module not found");		
    
    		// Exit
    		return(-1);
    	}
    		
    	// Get handle of "Process.exe"
    	phandle = OpenProcess(PROCESS_ALL_ACCESS, 0, Process); 
        
    	// Check Open
    	if (phandle != 0)
    	{
    		// Allocate memory for Dump
    		pMem = (PBYTE)malloc(ModuleSize);
    
    		// Read Memory
    		ReadProcessMemory(phandle, (LPVOID)ModuleAddress, pMem, ModuleSize, &Read);
    
    		// Free Memory Dump
    		free(pMem);
    
    		// Close process
    		CloseHandle(phandle);
            }
    	else
    	{	
    		// Error
    		MessageError("Error Dump memory");		
    
    		// Exit
    		return(-1);
    	}
    
    	// End
    	return (0);
    }
    During debugging the ReadProcessMemory do not work, any byte is read from "Module.dll".

    I am not a professional programmer, I'm sorry if you do not like

    Kappasm.

  4. #4
    <script>alert(0)</script> disavowed's Avatar
    Join Date
    Apr 2002
    Posts
    1,281
    First of all, you don't need SE_DEBUG_NAME privilege.

    Secondly, are both your process and the target process 32-bits? If not, you'll have problems (you'll always fail if one's 32-bit and the other's 64-bit, and if they're both 64-bits then your code will fail because you're truncating the module's base address to 32-bits).

    Also, checking the return value of GetLastError() after ReadProcessMemory(...) helps with debugging.

  5. #5
    Hi disavowed,

    Quote Originally Posted by disavowed View Post
    First of all, you don't need SE_DEBUG_NAME privilege.
    I thought it was necessary ... I try to remove it.


    Quote Originally Posted by disavowed View Post
    Secondly, are both your process and the target process 32-bits? If not, you'll have problems (you'll always fail if one's 32-bit and the other's 64-bit, and if they're both 64-bits then your code will fail because you're truncating the module's base address to 32-bits).
    Both process are 32-bit.

    Quote Originally Posted by disavowed View Post
    Also, checking the return value of GetLastError() after ReadProcessMemory(...) helps with debugging.
    GetLastError() return :

    "ReadProcessMemory failed with error 299"

    I am still confused .

    Maybe someone has a code that already works ?

    Thanks.

    Kappasm.

  6. #6
    error 299 returned from ReadProcessMemory means you still have parts of memory that are not readable. Did you have a look at your memory regions while debugging? Maybe you can identify the affected part this way. Or try to read-in your memory in pieces, to determine which part is not readable.

    Regards

  7. #7
    <script>alert(0)</script> disavowed's Avatar
    Join Date
    Apr 2002
    Posts
    1,281
    I'd recommend using VirtualQueryEx(...) to find each region of memory in the loaded module, and use ReadProcessMemory(...) once per region.

  8. #8
    Hi disavowed,

    thanks for suggestions ...

    Quote Originally Posted by disavowed View Post
    I'd recommend using VirtualQueryEx(...) to find each region of memory in the loaded module
    What do you mean by region of memory ? The loaded module is not fully accessible ? The module is divided into blocks ? How to find the block with absolute address ?

    Many questions to which I have no answer ...

    An example perhaps would be appreciated ...

    Kappasm.

  9. #9
    <script>alert(0)</script> disavowed's Avatar
    Join Date
    Apr 2002
    Posts
    1,281
    Yes, the memory of the loaded module is divided into multiple regions. Read the documentation on VirtualQueryEx(...) to learn how to query these regions (start at the base of the module, then find the next region based on the size of the previous region).

  10. #10
    I prefer the examples, I'm still reading. One last thing ...

    Quote Originally Posted by disavowed View Post
    start at the base of the module, then find the next region based on the size of the previous region
    I call first time VirtualQueryEx with destination this type structure and start address previously found with research of "module.dll" :

    Code:
    typedef struct _MEMORY_BASIC_INFORMATION 
    {
      PVOID  BaseAddress;
      PVOID  AllocationBase;
      DWORD  AllocationProtect;
      SIZE_T RegionSize;
      DWORD  State;
      DWORD  Protect;
      DWORD  Type;
    } MEMORY_BASIC_INFORMATION, *PMEMORY_BASIC_INFORMATION;
    and i obtain "RegionSize". First region is PE header, I want code, I call again VirtualQueryEx with start address "BaseAddress + RegionSize". And so for the next region to obtain "RegionSize = 0" ... right ?

    I understand you correctly ?

    Thanks very much.

    Kappasm.

  11. #11
    since you prefer examples...

    Code:
    #define MakePtr( cast, ptr, addValue )   (cast)( (DWORD)(ptr) + (DWORD)(addValue))
    
    BOOL __stdcall DumpProcessRange( IN DWORD dwProcessId, IN void* pStartAddr, IN DWORD dwcBytes, OUT void* pDumpedBytes, OUT char* szErrorStr)
    {
    	BOOL                       bRet;
    	HANDLE                     hProc;
    	DWORD                      cb, cbFailure = 0, cb2Do, dwBlockSize;
    	MEMORY_BASIC_INFORMATION   minfo;
    	char                       cBuff[100];
    
    	// get process handle
    	hProc = OpenProcess( PROCESS_VM_READ, FALSE, dwProcessId );
    	if ( !hProc )
    	{
    		lstrcpy( szErrorStr, "Error while querying process handle !" );
    		return FALSE; // ERR
    	}
    
    	//
    	// first let's try 2 dump the whole block directly
    	//
    	bRet = ReadProcessMemory( hProc, pStartAddr, pDumpedBytes, dwcBytes, &cb );
    	CloseHandle( hProc );
    	if ( bRet )
    		goto TidyUp;
    
    	//
    	// scan the memory information
    	//
    	hProc = OpenProcess( PROCESS_VM_READ | PROCESS_QUERY_INFORMATION, FALSE, dwProcessId );
    	if ( !hProc )
    	{
    		lstrcpy( szErrorStr, "Error while querying process handle !" );
    		return FALSE; // ERR
    	}
    
    	cb2Do              = dwcBytes;
    	minfo.BaseAddress  = pStartAddr;
    	while ( cb2Do )
    	{
    		// get memory info
    		bRet = VirtualQueryEx(
    			hProc,
    			minfo.BaseAddress,
    			&minfo, sizeof(minfo));
    		if ( !bRet )
    		{
    			lstrcpy( szErrorStr, "VirtualQueryEx() failed !" );
    			goto TidyUp; // ERR
    		}
    
    		#define f  minfo.Protect
    
    		dwBlockSize = min( minfo.RegionSize, cb2Do );
    		if ( pStartAddr ) // first region dump ?
    			dwBlockSize -= (DWORD)pStartAddr - (DWORD)minfo.BaseAddress;
    
    		if ( ((f & PAGE_GUARD)     != 0) || // do we have access there ?
    			 ((f & PAGE_NOACCESS)  != 0) )
    		{
    			//
    			// don't try 2 dump this memory part
    			//
    
    			// zero not dumped part in output buffer
    			memset(
    				MakePtr( PVOID, pDumpedBytes, dwcBytes - cb2Do ),
    				0,
    				dwBlockSize);
    			cbFailure += dwBlockSize;
    		}
    		else
    		{
    			//
    			// dump normally
    			//
    
    			bRet = ReadProcessMemory(
    				hProc,
    				pStartAddr ? pStartAddr : minfo.BaseAddress,
    				MakePtr( PVOID, pDumpedBytes, dwcBytes - cb2Do ),
    				dwBlockSize,
    				&cb);
    			if ( pStartAddr ) // only non-zero  on first region dump
    				pStartAddr = NULL;
    			if ( !bRet )
    			{
    				// OK,no...zero not dumped part in output buffer
    				memset(
    					MakePtr( PVOID, pDumpedBytes, dwcBytes - cb2Do ),
    					0,
    					dwBlockSize);
    				cbFailure += dwBlockSize;				
    			}
    		}
    
    		// adjust vars
    		minfo.BaseAddress   = MakePtr( PVOID, minfo.BaseAddress, minfo.RegionSize );
    		cb2Do              -= dwBlockSize;
    	}
    
    	bRet = TRUE; // ret an OK
    
    	if ( cbFailure ) // were any bytes not dumpable ?
    	{
    		wsprintf(
    			cBuff,
    			"0x%X of 0x%X bytes could not be dumped\nand were padded with zeros.",
    			cbFailure, dwcBytes);
    		MessageBox( GetActiveWindow(), cBuff, "IntelliDump", MB_ICONWARNING );
    	}
    
    	//
    	// tidy up
    	//
    TidyUp:
    	CloseHandle( hProc );
    
    	return bRet;
    }
    taken from yoda's intellidump.

  12. #12

    Talking

    With your very useful information I managed to do the patching of the DLL.

    Thanks very much Darkelf and disavowed.

    Best Regards.

    Kappasm.

Similar Threads

  1. extract runtime assembly code ?
    By mansourweb in forum Malware Analysis and Unpacking Forum
    Replies: 0
    Last Post: May 13th, 2010, 04:48
  2. Vista x64 SP1 tcpip.sys runtime patching
    By LordByte in forum Advanced Reversing and Programming
    Replies: 3
    Last Post: March 17th, 2008, 19:26
  3. EPROM code patching
    By philkin in forum The Newbie Forum
    Replies: 12
    Last Post: November 24th, 2004, 00:15
  4. patching dll functions at runtime?
    By ramin_rad2000 in forum Malware Analysis and Unpacking Forum
    Replies: 6
    Last Post: May 23rd, 2004, 07:54
  5. vb p-code patching
    By NikDH in forum Advanced Reversing and Programming
    Replies: 1
    Last Post: January 25th, 2001, 19:28

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •