Contribute  :  Web Resources  :  Past Polls  :  Site Statistics  :  Downloads  :  Forum  
    BiW ReversingThe challenge is yours    
 Welcome to BiW Reversing
 Tuesday, March 31 2020 @ 09:06 PM CEST

How to code a loader

   

CodingLevel : beginner

OS : windows
Language : ASM

How to code a basic loader that pauses a process, alters some process memory and continues execution.



TARGET = attachment
TOOLS USED = Assembler : MASM 7.0

What is a loader, and why do we need it?
A loader is a little standalone program that is used to load another program. Of course we will only use a loader if we want to change something in the program after it is loaded in the memory. (patching in memory)
A well known example of a loader is a trainer used to cheat in games.
The reasons why we choose for a loader instead of a regular patch can be various. We might only want to change something after the CRC is done, or we might want to change something and later in the program restore the original bytes,...
I'm sure you can find some use for it :)

How does a loader work?
Ok, grab your win32.hlp and fasten your seatbelt :)
First of all, the loader has to create a new process and start the target. We will use the CreateProcess API for that (pretty obvious ;) When the target is loaded in memory we want to pause the process, so we can change the things we want.
Let's check out what win32.hlp can tell us about this API :
BOOL CreateProcess(

    LPCTSTR lpApplicationName,		// pointer to name of executable module
    LPTSTR lpCommandLine,		// pointer to command line string
    LPSECURITY_ATTRIBUTES lpProcessAttributes,	// pointer to process security attributes
    LPSECURITY_ATTRIBUTES lpThreadAttributes,	// pointer to thread security attributes
    BOOL bInheritHandles,		// handle inheritance flag
    DWORD dwCreationFlags,		// creation flags
    LPVOID lpEnvironment,		// pointer to new environment block
    LPCTSTR lpCurrentDirectory,		// pointer to current directory name
    LPSTARTUPINFO lpStartupInfo,	// pointer to STARTUPINFO
    LPPROCESS_INFORMATION lpProcessInformation 	// pointer to PROCESS_INFORMATION
   );

Check all the API's I mention here in your win32.hlp document, because I will only discuss the things that are important for our loader.

lpApplicationName is the path + name of our target program. (eg c:somedircrackme.exe)
lpCommandLine can be used if you want to add some commandline parameters to the target.

dwCreationFlags is important for us, because we want to pause the process as soon as it is loaded.
To accomplish that, we use CREATE_SUSPENDED here.

lpStartupInfo points to a struct with startup information (again check win32.hlp for more info)

lpProcessInformation points to an empty struct that will be filled when the target is loaded in memory.
This struct contains the process handle, thread handle and process/thread ID.
NOTE : The advantage of using the process handle instead of the thread handle, is that when using the process handle you have PROCESS_ALL_ACCESS access to the process object. Meaning that you have read/write access for the entire process. When using the thread handle, you will need to enable write access manualy.

Ok, now that the target is loaded, we can easily let the thread run/pause with the following API's :
DWORD ResumeThread(

    HANDLE hThread 	// identifies thread to restart
   );
to let it run, and
DWORD SuspendThread(

    HANDLE hThread 	// handle to the thread
   );
to pause it again.
The hThread handle can be found in the LPPROCESS_INFORMATION struct.

Finally we can read and write from/to the process using these API's :
BOOL WriteProcessMemory(

    HANDLE hProcess,	// handle to process whose memory is written to
    LPVOID lpBaseAddress,	// address to start writing to
    LPVOID lpBuffer,	// pointer to buffer to write data to
    DWORD nSize,	// number of bytes to write
    LPDWORD lpNumberOfBytesWritten 	// actual number of bytes written
   );
This is pretty self-explanatory. The hProcess handle is the one from the LPPROCESS_INFORMATION struct.
To read from the process :
BOOL ReadProcessMemory(

    HANDLE hProcess,	// handle of the process whose memory is read
    LPCVOID lpBaseAddress,	// address to start reading
    LPVOID lpBuffer,	// address of buffer to place read data
    DWORD nSize,	// number of bytes to read
    LPDWORD lpNumberOfBytesRead 	// address of number of bytes read
   );


This information should be enough to understand the following example.

A loader example
In the example below I will open a crackme (in target.zip) and change the caption text to "Detten's Caption".
I will show the process for 5 seconds, and then terminate the process.
So here we patch a simple string, but with the same method we can also patch code bytes or dwords of course ;) As preparation for the loader we need to know the address where the caption string is saved in the target. So fire up your favorite disassembler, and find this address : 004050FCh

	.386
.model flat,stdcall
option casemap:none

include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\includekernel32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib


.data
FileName db "C:\somedircrackme.exe",0
notloaded db "It did not work :-(",0
Letsgo db "The process is started",13,10,
	  "Let's change smthg and run it now :-)",0
NewText db "Dettens Caption",0

Startup STARTUPINFO <>
processinfo PROCESS_INFORMATION <>

.data?
hInstance HINSTANCE ?
byteswritten dd ?
uExitCode dd ?

.code
start:

	invoke GetModuleHandleA, NULL
	mov    hInstance,eax 

	; Create a process and load the crackme in it, and
	; immediatly suspend the thread (pause it)
	invoke CreateProcess, ADDR FileName, NULL, NULL, NULL, NULL, CREATE_SUSPENDED,
			      NULL, NULL, ADDR Startup, ADDR processinfo
	.IF eax == NULL ; Creation of new process failed?
		invoke MessageBox, NULL, ADDR notloaded, NULL, MB_ICONEXCLAMATION
	.ELSE
	        invoke MessageBox, NULL, ADDR Letsgo, NULL, MB_OK ; Display Message
	        ; I will change the text string in the crackme used in
	        ; the captionbar (004050FCh)
                invoke WriteProcessMemory, processinfo.hProcess, 004050FCh, ADDR NewText,
                			   13, byteswritten
	        ; Let the process run happily ;)

	        invoke ResumeThread, processinfo.hThread
	        ;Let the process run for 5 sec. and then terminate it
	        invoke Sleep, 5000
	        invoke TerminateProcess, processinfo.hProcess, uExitCode
	.ENDIF
	invoke ExitProcess,eax
end start
	
That's all it takes to create a loader ;)
In the next loader tutorial I will discuss some more advanced loader techniques, like reading and changing the process context (all registers and flags).

If you have questions, remarks, or suggestions contact me at detten(at)reversing(dot)be

Detten




What's Related

Story Options

How to code a loader | 6 comments | Create New Account
The following comments are owned by whomever posted them. This site is not responsible for what they say.
How to code a loader
Authored by: KiTo on Sunday, March 06 2005 @ 08:37 PM CET
Here is the same code but in c++:

	char lpApp[16] = "crackme.exe";
	char lpNew[10] = "KiTo r0x!";
	char lpWritten;
	unsigned long lAdress = 0x004050FC;
	STARTUPINFO si;
	PROCESS_INFORMATION pi;

	ZeroMemory(&si, sizeof(si));
	ZeroMemory(&pi, sizeof(pi));
	si.cb = sizeof(si);

	bool hResult = CreateProcess(lpApp, NULL, NULL, NULL, NULL, CREATE_SUSPENDED, NULL, NULL, &si, &pi);
	if(hResult == NULL)
	{
		SetDlgItemText(hwnd, IDC_STATUS, "Couldn't create the process, aborting...");
		DWORD bajs = GetLastError();
	}
	else
	{

	hResult = WriteProcessMemory(pi.hProcess, &lAdress, lpNew, 12, NULL);
	if(hResult == NULL)
	{
		SetDlgItemText(hwnd, IDC_STATUS, "Couldn't write to memory, aborting...");
	}
	else
	{


	ResumeThread(pi.hThread);
	Sleep(5000);
	TerminateProcess(pi.hProcess, 0);

	}}
How to code a loader
Authored by: TDC on Thursday, August 11 2005 @ 03:23 PM CEST
Quote detten: [quote]In the next loader tutorial I will discuss some more advanced loader techniques, like reading and changing the process context (all registers and flags).[/quote] Wheres the next tut :)?

---
[img]http://www35.tok2.com/home/jellard23/sig-reverse.jpg[/img]
:: The world is yours! ::

How to code a loader
Authored by: eraser on Monday, April 09 2007 @ 02:28 PM CEST

Take a look at the byteswritten variable.

byteswritten dd ?

invoke WriteProcessMemory, processinfo.hProcess, 004050FCh, ADDR NewText, 13, byteswritten

pNumberOfBytesWritten
[out] A pointer to a variable that receives the number of bytes transferred into the specified process. This parameter is optional. If lpNumberOfBytesWritten is NULL, the parameter is ignored.

At the beginning the byteswritten variable is 0 (NULL) therefor the call of the WriteProcessMemory() function doesn't fail.

There are two different solutions how to correct this implicit issue.

1.)

byteswritten dd ?

invoke WriteProcessMemory, processinfo.hProcess, 004050FCh, ADDR NewText, 13, ADDR byteswritten

; - we want to use the byteswritten variable, e.g. to provide additional testing of WriteProcessMemory()

2.)

invoke WriteProcessMemory, processinfo.hProcess, 004050FCh, ADDR NewText, 13, NULL

---
the real failure is when you don't learn anything from any given situation

 Copyright © 2020 BiW Reversing
 All trademarks and copyrights on this page are owned by their respective owners.
Powered By Geeklog 
Created this page in 0.72 seconds