Coming to you with another tutorial, i'm not saying i will be right on every part of it everyone makes mistake, but this should give a brief explanation of how it works and how to program it.
What you will need to understand this tutorial.
- C++ (any version)
- A debugger (preferably IDA Pro)
- Some experience in programming (c++ and assembly)
- Cheat engine (optional)
Note: if you wish to follow the exact steps i do you need to use Call Of Duty - Modern Warfare.
Mid functions in general.
So why use mid functions? Simply because it's useful!
Sometimes you want to modify a code, or check if a code has been run and you can do this using mid functions.
The code i'm about to show involves the same problem.
If my hack is running before we enter the game the whole game bugs and gets black.
So i made a small check using a mid function to see if we have entered the game or not.
So how do we start with this?
First of all i went and started to look for an address that only runs when you join the game.
I could do this in several ways, i decided to go with a mid function.
And if you think about it, ammo and health get set in game, so if we could find where the ammo is first set to a value we can place a mid function here.
So here is how it works.
short: Game loads stuff > Game loaded? Yes > Set Ammo to value > Set health to max > Other stuff...
So now we will go look for the place where Ammo is set.
What i first did was shoot my gun until i have a little bit of ammo left.
As you see i have 4 bullets left, which makes it easier to search this value in Cheat Engine.
Time to attach Cheat Engine!
After attaching Cheat Engine you can do your first scan!
Remember the amount of bullets you had left? Enter that in Cheat Engine!
After you scanned you should have a list of results that looks like this:
Shoot a couple of times and scan again (with the value of bullets you have left of course).
Do this until your result looks like this one (as less possible addresses as possible).
Now which one is it? Hard to tell huh?
What i like to do is save them all in the box below like this.
To change the value of one of those addresses simply double click the value and enter 0 to set it to 0.
To find the correct one do as following: Start from the top one and try set the value of it to 0.
If the other addresses don't change it's not the correct address, if the others change it's correct.
Not correct? Try the next one!
You will know it when you found it.
Now to find out where this addresses is being accessed from right click "Find out what writes to this address".
Now that it's scanning shoot a couple of times.
After you did that you should get a result that looks like this one.
Click it and then "Show Dissembler".
You should get a window looking like this.
Code:
iw3sp.exe + 1BF5D9 - 89 84 8F 34030000 - mov[edi + ecx * 4 + 00000334], eax
This code sets our ammo, if we shoot we substract 1 from eax, then set the ammo value to eax.
So now we are going to make our midfunction with the following code.
Code:
iw3sp.exe + 1BF5D5 - 8B D0 - mov edx, eax
iw3sp.exe + 1BF5D7 - 2B C2 - sub eax, edx
iw3sp.exe + 1BF5D9 - 89 84 8F 34030000 - mov[edi + ecx * 4 + 00000334], eax
iw3sp.exe + 1BF5E0 - 5B - pop ebx
Now it's time to explain what a mid function is.
A mid function is simply jumping from a piece of code to your function and then eventually jumping back to the original code.
To place a jump you need at least 5 bytes, that's just how it is.
The code looks like following.
Code:
void PlaceJMP(BYTE * address, DWORD jumpTo, DWORD length)
{
//Credits to whoever made this! <3
DWORD oldProtect, newProtect, relativeAddress;
VirtualProtect(address, length, PAGE_EXECUTE_READWRITE, &oldProtect);
relativeAddress = (DWORD)(jumpTo - (DWORD)address) - 5;
*address = 0xE9;
*((DWORD *)(address + 0x1)) = relativeAddress;
for (DWORD x = 0x5; x < length; x++)
{
*(address + x) = 0x90;
}
VirtualProtect(address, length, oldProtect, &newProtect);
}
So what does this code do? It simply replaced the bytes of the original code with our jump (jmp) to our function.
Ex:
Orig: 8B 89 30 03 00 00
Ours: E9 90 90 90 90 90
Len or size = 6, because our jmp is 6 bytes long.
Enter the wrong size and you will experience things you don't like!
Back to the mid function!
We had the following code:
Code:
iw3sp.exe + 1BF5D5 - 8B D0 - mov edx, eax
iw3sp.exe + 1BF5D7 - 2B C2 - sub eax, edx
iw3sp.exe + 1BF5D9 - 89 84 8F 34030000 - mov[edi + ecx * 4 + 00000334], eax
iw3sp.exe + 1BF5E0 - 5B - pop ebx
Remember we need at least 5 bytes for our jmp!
In this case i'm going to go with 1BF5D9 - 89 84 8F 34 03 00 00.
In this case our size is 7, so we got more then our 5 bytes (minimum) which is good!
Remember if we make a mid function we have to rewrite the original instruction or it may result in a crash.
Our function will look look this.
Code:
//Addresses= Addresses + 400000 (Start address)
DWORD CoDJmpStart = 0x5BF5D9; //iw3sp.exe + 1BF5D9 - 89 84 8F 34030000 - mov[edi + ecx * 4 + 00000334], eax
DWORD CoDJmpBack = 0x5BF5E0; //iw3sp.exe + 1BF5E0 - 5B - pop ebx
__declspec(naked)void CallOfDuty_Check(void)
{
//Our code will be placed here shortly!
}
As you can see we defined some addresses above, we do this because you cannot define addresses inside the mid function.
So now we have to rewrite the original code (mov[edi + ecx * 4 + 00000334], eax) which we placed our jmp over.
No we simply write this instruction inside our function and jmp back to the following address (iw3sp.exe + 1BF5E0 - 5B - pop ebx / CoDJmpBack).
Code:
//Addresses= Addresses + 400000 (Start address)
DWORD CoDJmpStart = 0x5BF5D9; //iw3sp.exe + 1BF5D9 - 89 84 8F 34030000 - mov[edi + ecx * 4 + 00000334], eax
DWORD CoDJmpBack = 0x5BF5E0; //iw3sp.exe + 1BF5E0 - 5B - pop ebx
__declspec(naked)void CallOfDuty_Check(void)
{
//We replace the original code here because we simply make a check in this tutorial.
//Replacing the eax with your val (mov eax, 10) could set your to 10 instead of dropping.
__asm mov[edi + ecx * 0x4 + 0x334], eax //Original code (set ammo)
__asm pushad //Push to stack
__asm mov Check, 1 //We set our check to 1, (Check = Defenition => We entered game!)
__asm popad //Stack to register
__asm jmp[CoDJmpBack] //Jmp back to our original code
}
I did it in endscene as following:
Code:
HRESULT WINAPI myEndScene(LPDIRECT3DDEVICE9 pDev)
{
if (Check){ //If we entered the game (which the midfunction will tell us.
//We execute this code:
CFont.MenuRender(pDev, 13, 600, (TCHAR*)Decrypt(STRING_FONT));
pMenu->DrawCrosshair(WHITE, 36, pDev);
return pEndScene(pDev);
}
}
As you see i only start drawing once our mid function has done it's job and we know we have entered the game!
Now we need to place the jmp inside our DllMain.
Simply add the following code:
Code:
PlaceJMP((BYTE*)CoDJmpStart, (DWORD)CallOfDuty_Check, 7);
This will place the jmp from the original function to our function.
You have successfully done it!
If you did everything right it should work now, go on and test it!
What actually happens.
We place our jump at the address specified above(CoDJmpStart).
This function jumps to our function
Here we rewrite the original code and add our code, function, etc.
And we jump back right after our jump.
I did the same for health (COD MW!):
Code:
DWORD COD_MW_JMP_SIZE = 6;
DWORD COD_MW_START_HOOK = 0;
DWORD COD_MW_JMP_START = 0x5BF5C2; //iw3sp.exe+1BF5C2 - 8B 89 30030000 - mov ecx,[ecx+00000330]
DWORD COD_MW_JMP_END = 0x5BF5C8; //iw3sp.exe+1BF5C8 - 8B 84 8F 34030000 - mov eax,[edi+ecx*4+00000334]
__declspec(naked)void COD_Start_Hook()
{
__asm mov ecx, [ecx + 0x330]
__asm pushad
__asm mov COD_MW_START_HOOK, 1
__asm popad
__asm jmp[COD_MW_JMP_END]
}
And to prevent GameGuard from detecting he dll in WarRock ph, needs some extra work done!
Don't just copy and paste it and then comment it doesn't work!
Code:
DWORD PH_GameGuard_Start = 0x40E1C6;
DWORD PH_GameGuard_jmpback = 0x40E1CC; //PH_EndSceneStart+Size
__declspec(naked)void HideHackFromGameGuard(void)
{
__asm
{
mov eax, 0x3F8
mov dwReg, eax
pushad
}
__asm
{
popad
jmp[PH_GameGuard_jmpback]
}
}
Now you know how it works, give me feedback and enjoy making it!
It takes time and patience to understand it fully!
Feel free to leave a like since i worked over 2 hours to do this!