Home of Gamehacking - Archiv

Normale Version: [C++]Funktion um dynamisch eine CodeCave zu schreiben
Sie sehen gerade eine vereinfachte Darstellung unserer Inhalte. Normale Ansicht mit richtiger Formatierung.
Hey,
hier mal meine Funktion zum Schreiben einer CodeCave (inklusive Jump hin und zurück), wobei der Speicher dafür per VirtualAllocEx dynamisch alloziiert wird.
Dies ist wohl die komplexeste und wichtigste Funktion meiner Base.

C Code
//////////////////////////////////////////////////////////////////////////
//WriteAllocCave
//This function will write a codecave to an allocated memory address. Then it will write a jump to the cave at a specified address.
//Furthermore you need to pass the offset relative to your base address to the function.
//Function will return 1 if everything went correctly. If not it will show you an error and return 0.
//////////////////////////////////////////////////////////////////////////
int WriteAllocCave(LPCWSTR szProcessName, LPCWSTR szModuleName, DWORD dwOffset, BYTE szOrigCode[], int nOrigCode, BYTE szCaveCode[], int nCaveCode)
{
	HANDLE hProcess; //Process handle.
	DWORD BaseAddress, lpAddress, dwOldProtect, nNops, lpBackAddress;
	LPVOID lpCaveAddress;//BaseAddress of the module and the real address we want to know.
	char* BytesRead[255]; //Buffer
	DWORD szJumpBytes[9] = {0x0E9, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90};
	BYTE szJumpBack[5] = {0x0E9, 0x90, 0x90, 0x90, 0x90};

	hProcess = GetProcessHandle(szProcessName); //Get the process handle for WPM/RPM.
	if (hProcess == 0)
	{
		MessageBox(NULL, _T("Couldn't get process handle!"), szErrorTitle, NULL);
		return 0;
	}
	BaseAddress = GetModuleBaseAddress(szProcessName, szModuleName); //Get the base address of the specific module.
	if (BaseAddress == 0)
	{
		MessageBox(NULL, _T("Couldn't get module base address!"), szErrorTitle, NULL);
		return 0;
	}

	lpAddress = (DWORD)BaseAddress + dwOffset; //Calculate real address.

	//First we need to allocate memory. Calculate the size of the needed cave
	int iCaveSize = nCaveCode + 5; //+5 because a 5 Bytes jump back after the cave
	//Allocate memory.
	if((lpCaveAddress = VirtualAllocEx(hProcess, 0, iCaveSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE)) == 0)
	{
		//Function failed.
		MessageBox(NULL, _T("Failed to allocate memory!"), szErrorTitle, NULL);
		return 0;
	}
	//Calculate Bytes for the jump to the code cave.
	void* var = &szJumpBytes; //Variable to store the address of the szJumpBytes variable
	__asm //Credits to Specid from DVT for the general idea
	{
		pushad
			mov ebx, lpCaveAddress
			mov ecx, lpAddress
			add ecx, 5
			sub ebx, ecx ;//Calculate the distance.
			mov edx, ebx ;//Store the distance
			shr edx, 16
			mov eax, var
			mov byte ptr [eax+1], bl ;//Write the calculated bytes into the variable.
			mov byte ptr [eax+2], bh
			mov byte ptr [eax+3], dl
			mov byte ptr [eax+4], dh 
			;//Now we have to calculate the needed NOPs (0x90).
			mov ebx, nOrigCode ;//Number of bytes the original code has.
			sub ebx, 5 ;//Decrease this number by 5, because that's the bytes for the jump.
			mov nNops, ebx ;//Number of NOPs we have to write.
			mov edx, 4
			xor ebx, ebx
		start:
			cmp nNops, ebx
			je End
				INC edx
				INC ebx
				mov byte ptr [eax+edx], 144 ;//144d == 90h == NOP
			jmp start

		End:
		popad
	}
	//Read code and compare it. If it's szOrigCode, then we need to write our jump to the cave + the cave code. If it's the jump to the 
	//cave, we need to write the original code (user deactivated trainer).
	//If it's neither one of these two, then the user has probably a wrong version.
	//First VirtualProtectEx to make the code read/writeable.
	if (VirtualProtectEx(hProcess, (LPVOID)lpAddress, nOrigCode, PAGE_EXECUTE_READWRITE, &dwOldProtect) == 0)
	{
		MessageBox(NULL, _T("VirtualProtectEx failed!"), szErrorTitle, NULL);
		return 0;
	}
	//Now ReadProcessMemory and the byte comparison.
	if(ReadProcessMemory(hProcess, (LPVOID)lpAddress, (LPVOID)BytesRead, nOrigCode, 0) == 0)
	{
		MessageBox(NULL, _T("ReadProcessMemory failed!"), szErrorTitle, NULL);
		return 0;
	}

	//Compare original bytes with those standing in memory.
	if(memcmp((const void*)BytesRead, szOrigCode, nOrigCode) == 0) //Bytes match.
	{
		//We got the original bytes standing in memory, so we write the cave code now.
		if((WriteProcessMemory(hProcess, (LPVOID)lpCaveAddress, (LPCVOID)szCaveCode, nCaveCode, 0)) == 0)
		{
			//Oh noes, WPM error.
			MessageBox(NULL, _T("Failed to write to process memory.."), szErrorTitle, NULL);				return 0;
		}
		else
		{	//Now we write the jump back to the original code. (after the cave code)
			lpBackAddress = (DWORD)lpCaveAddress + nCaveCode;
			//Calculate bytes for the jump back to the original code.
			var = &szJumpBack;
			__asm
			{
				pushad ;//Save register
					mov ebx, lpAddress
					add ebx, 5 ;//Add 5 to lpAddress since there are standing our bytes for the jump to the cave
					mov ecx, lpBackAddress
				    add ecx, 5
					sub ebx, ecx
					mov edx, ebx ;//Store the distance
					shr edx, 16
					mov eax, var
					mov byte ptr [eax+1], bl ;//Write the calculated bytes into the variable.
					mov byte ptr [eax+2], bh
					mov byte ptr [eax+3], dl
					mov byte ptr [eax+4], dh 
				popad ;//Restore register
			}
			//Write jump to the original code
			if((WriteProcessMemory(hProcess, (LPVOID)lpBackAddress, (LPCVOID)szJumpBack, sizeof szJumpBack, 0)) == 0)
			{
				//Oh noes, WPM error.
				MessageBox(NULL, _T("Failed to write to process memory.."), szErrorTitle, NULL);
				return 0;
			}
			else
			{
				//Write jump to our cave == finish cheat.
				if((WriteProcessMemory(hProcess, (LPVOID)lpAddress, (LPCVOID)szJumpBytes, nOrigCode, 0)) == 0)
				{
					//Oh noes, WPM error.
					MessageBox(NULL, _T("Failed to write to process memory.."), szErrorTitle, NULL);
					return 0;
				}
				else //Everything went fine.
				{
					Beep(0x1000,200); //Activated sound.
					return 1;
				}
			}
		}
	}
	//First compare (original bytes) didn't succeed, so we check now for modified bytes (jump to cave).
	//Compare just the first Byte (weather there is 0E9h or not).
	else if (memcmp((const void*)BytesRead, szJumpBytes, 1) == 0) //Bytes match.
	{
		//We got the jump bytes(to the cave)standing in memory. So the user wants to deactivate the option now. Therefore we need to write
		//the original bytes.
		if ((WriteProcessMemory(hProcess, (LPVOID)lpAddress, (LPCVOID)szOrigCode, nOrigCode, 0)) == 0)
		{ 
			//Oh noes, WPM error.
			MessageBox(NULL, _T("Failed to write to process memory.."), szErrorTitle, NULL);
			return 0;
		}
		else //Everything went fine.
		{
			Beep(0x500,200); //Deactivated sound.
			return 1;
		}
	}
	else
	{
		//Neither modified bytes nor original bytes found. So the user has a wrong/currupted version.
		MessageBox(NULL, _T("You have the wrong gameversion!"), szErrorTitle, NULL);
		return 0;
	}

	return 0;
}

Warum schreibst du

Code:
if ((WriteProcessMemory(hProcess, (LPVOID)lpAddress, (LPCVOID)szOrigCode, nOrigCode, 0)) == 0)

und nicht gleich

Code:
if (WriteProcessMemory(hProcess, (LPVOID)lpAddress, (LPCVOID)szOrigCode, nOrigCode, 0) == 0)

?

Hey,
da hab ich wohl zwei Klammern zuviel geschrieben :blush: Du hast Recht, man kanns auch mit nur einer Klammer schreiben. Sollte aber nicht weiter stören.
(26.02.2012, 17:37)Acubra schrieb: [ -> ]Hey,
da hab ich wohl zwei Klammern zuviel geschrieben :blush: Du hast Recht, man kanns auch mit nur einer Klammer schreiben. Sollte aber nicht weiter stören.

Eigentlich sollte man auch statt den C-Casts C++-Casts verwenden.
Naja Haarspalterei Wink