27.01.2016, 18:18
(
Last edited by kurta999; 12/02/2016 at 08:15 AM.
)
This tutorial is about how to find structure addresses in samp server. I'm not really going to say why to do that, I will just say how to do. I do not have a big assembly skill, you do not need too if you just want to update structures or memory offsets. It's fucking easy, just time consuming. Use your head, and think every time.
SA-MP needs more people, who know how to update memory hacking plugins. Lot of them die because it's boring to update them after every version realease, and author just give a fuck for them and almost nobody can update, casue don't know how to do that.
First of all, you need to download IDA Pro, use ******. I recommend 6.8 version, I won't post it here since warez not allowed. Older version will be good too.
Findig memory offsets:
Open IDA, and you'll see this window:
Click on "Go - Work on your own"
Nice, if you see this then you're not retard. Click on File -> Open and open "samp-server.exe"
Click on OK, and wait a bit. Processing the .exe is done, when you see something similar to image below:
Click with Right mouse, select Text view.
If you did everything good, you'll see something similar to image below:
Nice! Now we are going to find player health variable, which memory location is used in samp server to store player health.
Press SHIFT + 12, it will show a new toolbar, called "Strings". Navigate here and press ALT + T. Search for GetPlayerHealth
Double click on GetPlayerHealth string. If you did everything well, then you will see something like image below:
Press F5. IDA now will create pseudocode from assembly code, which is SO MUCH easyer to read.
Now you have info to get these 5 things:
pNetGame
CPlayerPool *pPlayerPool pointer location inside CNetGame class
CPlayer *pPlayer pointer location inside CPlayerPool class
fHealth in CPlayer class
amx_GetAddr (sub_403100)
Click on dword_4F6CC8, press N - type pNetGame. This is the pNetGame pointer, now you renamed this "address name" to readable name, it will appear as pNetGame next time. Address of pointer is: 0x4F6CC8. You'll have DIFFERENT ADDRESS, SINCE MY TEST SERVER IS 0.3.7 R1 not R2-1.
----------------------------------------------------
(_DWORD *)pNetGame + 2) is the location of pPlayerPool pointer. (_DWORD *)pNetGame + 2) equal to (char*)pNetGame + .
Go here and figure out from answers to why: http://stackoverflow.com/questions/2...ter-and-offset
---------------
Now we have pPlayerPool! Nice! Wee need to find pPlayer inside pPlayerPool which is a pointer array, every index stores data about one player.
Now look at first line, where we get pNetGame address.
154012 - this is the address of pPlayer pointer inside CPlayerPool class.
Nice! Now we have pPlayer pointer. Now we have to find fHealth location inside CPlayer class.
v3 + 10529
DONE!
If you want to test this example, then don't forget to do the following thing in Visual Studio; You have to set struct alignment to 1 byte, insted of default 4. If you skip this option, you code won't work.
In Visual Studio: Project File -> Properties -> C/C++ -> Code Generation -> Sturct member Alignment -> 1Byte (Zp1)
In GCC: -fpack-struct=1
Now we have everything. If you want to get player health, then now you can do:
If you want to access every classes which are in CNetGame, check YSF: https://github.com/kurta999/YSF/blob...Structs.h#L734
Findig RPCs:
For functions
For findig SetGravity RPC:
1.) Find for "SetGravity" in strings windows, then do same what I said before how to navigate to the function
2.) Check assembly/pseudo code, there only one function call and nothing more. ( call sub_48E260 )
3.) Navigate into this function, press F5 - check the code in pseudocode how it looks - now you see that's there are more code, we are at good place - go back to assembly view.
4.) RPC can be a BYTE ( 0 - 255 ), there only one character, which is one byte.
.text:0048E2FA push offset aT ; "ĺ"
5.) Double click on aT, you'll see:
.rdata:004B592C aT db 'ĺ',0
6). Select ĺ, switch to hex view at toolbar menu, and which is selected, that's your RPC ID.
0x92 for SetGravity.
For callbacks
1.) Search for "OnPlayerSpawn" in strings menu, then do same what I said before how to navigate to the function
2.) You have to go back, where FROM this function will be called:
This is the basic function, which will call pawn callbacks when player spawn. Rename it to PAWN_OnPlayerSpawn.
.text:0046ADF0 sub_46ADF0 proc near ; CODE XREF: sub_48EA70+118p
Double click at memory address after CODE XREF. You've jumped to function, which is the function of RPC. Rename it to INTERNAL_OnPlayerSpawn This function will be called when server receives RPC with OnPlayerSpawn RPC ID and then call PAWN_OnPlayerSpawn, which will call OnPlayerSpawn in pawn scripts
So let's go back, we have function which called by RPC. Click on DATA XREF address, press F5.
You'll see something like:
(*(void (__thiscall **)(int, void *, char **(__cdecl *)(int)))(*(_DWORD *)v1 + 116))(
v1,
&unk_4B5E18,
INTERNAL_OnPlayerSpawn);
Now you went back to RakServer::RegisterAsRemoteProcedureCall-s. This function has two parameters:
You know the last one - this is OnPlayerSpawn. You have to click on first parameter (unk_4B5E1, select it, switch to hex view and copy the rpc id. This is 0x34.
https://github.com/kurta999/YSF/blob/YSF_/src/RPCs.cpp
Exercise
I would recommend you to try to find offsets like player position, player weapon, vehicle color, etc, etc.. You can use Structs.h from YSF to check that your offset are correct, or not.
SA-MP needs more people, who know how to update memory hacking plugins. Lot of them die because it's boring to update them after every version realease, and author just give a fuck for them and almost nobody can update, casue don't know how to do that.
First of all, you need to download IDA Pro, use ******. I recommend 6.8 version, I won't post it here since warez not allowed. Older version will be good too.
Findig memory offsets:
Open IDA, and you'll see this window:
Click on "Go - Work on your own"
Nice, if you see this then you're not retard. Click on File -> Open and open "samp-server.exe"
Click on OK, and wait a bit. Processing the .exe is done, when you see something similar to image below:
Click with Right mouse, select Text view.
If you did everything good, you'll see something similar to image below:
Nice! Now we are going to find player health variable, which memory location is used in samp server to store player health.
Press SHIFT + 12, it will show a new toolbar, called "Strings". Navigate here and press ALT + T. Search for GetPlayerHealth
Double click on GetPlayerHealth string. If you did everything well, then you will see something like image below:
Press F5. IDA now will create pseudocode from assembly code, which is SO MUCH easyer to read.
Now you have info to get these 5 things:
pNetGame
CPlayerPool *pPlayerPool pointer location inside CNetGame class
CPlayer *pPlayer pointer location inside CPlayerPool class
fHealth in CPlayer class
amx_GetAddr (sub_403100)
Click on dword_4F6CC8, press N - type pNetGame. This is the pNetGame pointer, now you renamed this "address name" to readable name, it will appear as pNetGame next time. Address of pointer is: 0x4F6CC8. You'll have DIFFERENT ADDRESS, SINCE MY TEST SERVER IS 0.3.7 R1 not R2-1.
----------------------------------------------------
(_DWORD *)pNetGame + 2) is the location of pPlayerPool pointer. (_DWORD *)pNetGame + 2) equal to (char*)pNetGame + .
Go here and figure out from answers to why: http://stackoverflow.com/questions/2...ter-and-offset
pawn Code:
(char*)pNetGame +8). // 8 is the offset of pPlayerPool pointer INSIDE CNetGame class
Now we have pPlayerPool! Nice! Wee need to find pPlayer inside pPlayerPool which is a pointer array, every index stores data about one player.
Now look at first line, where we get pNetGame address.
pawn Code:
((_DWORD *)pNetGame + 2) + 4 * playerid + 154012)
Nice! Now we have pPlayer pointer. Now we have to find fHealth location inside CPlayer class.
pawn Code:
*(_DWORD *)a2 = *(_DWORD *)(v3 + 10529);
DONE!
pawn Code:
struct CPlayer
{
BYTE padding[10529];
float fHealth;
};
struct CPlayerPool
{
BYTE padding[154012];
CPlayer *pPlayer[MAX_PLAYERS];
};
struct CNetGame
{
BYTE padding[8]; // offsets starts from 0
CPlayerPool *pPlayerPool; // stars from 8, ends at 12
};
// Initializing pNetGame
CNetGame* pNetGame = NULL;
PLUGIN_EXPORT int PLUGIN_CALL AmxLoad(AMX *amx)
{
if (pNetGame == NULL)
pNetGame = ((CNetGame*)(*(void**)0x4F6CC8));
return amx_Register(amx, projectNatives, -1);
}
// Or you can check YSF how to init pNetGame from ppData, since it's stored here and you not need to find it every time.
In Visual Studio: Project File -> Properties -> C/C++ -> Code Generation -> Sturct member Alignment -> 1Byte (Zp1)
In GCC: -fpack-struct=1
Now we have everything. If you want to get player health, then now you can do:
pawn Code:
pNetGame->pPlayerPool->pPlayer[playerid]->fHealth;
Findig RPCs:
For functions
For findig SetGravity RPC:
1.) Find for "SetGravity" in strings windows, then do same what I said before how to navigate to the function
2.) Check assembly/pseudo code, there only one function call and nothing more. ( call sub_48E260 )
3.) Navigate into this function, press F5 - check the code in pseudocode how it looks - now you see that's there are more code, we are at good place - go back to assembly view.
4.) RPC can be a BYTE ( 0 - 255 ), there only one character, which is one byte.
.text:0048E2FA push offset aT ; "ĺ"
5.) Double click on aT, you'll see:
.rdata:004B592C aT db 'ĺ',0
6). Select ĺ, switch to hex view at toolbar menu, and which is selected, that's your RPC ID.
0x92 for SetGravity.
For callbacks
1.) Search for "OnPlayerSpawn" in strings menu, then do same what I said before how to navigate to the function
2.) You have to go back, where FROM this function will be called:
This is the basic function, which will call pawn callbacks when player spawn. Rename it to PAWN_OnPlayerSpawn.
.text:0046ADF0 sub_46ADF0 proc near ; CODE XREF: sub_48EA70+118p
Double click at memory address after CODE XREF. You've jumped to function, which is the function of RPC. Rename it to INTERNAL_OnPlayerSpawn This function will be called when server receives RPC with OnPlayerSpawn RPC ID and then call PAWN_OnPlayerSpawn, which will call OnPlayerSpawn in pawn scripts
So let's go back, we have function which called by RPC. Click on DATA XREF address, press F5.
You'll see something like:
(*(void (__thiscall **)(int, void *, char **(__cdecl *)(int)))(*(_DWORD *)v1 + 116))(
v1,
&unk_4B5E18,
INTERNAL_OnPlayerSpawn);
Now you went back to RakServer::RegisterAsRemoteProcedureCall-s. This function has two parameters:
pawn Code:
virtual void RegisterAsRemoteProcedureCall( int* uniqueID, void ( *functionPointer ) ( RPCParameters *rpcParms ) );
https://github.com/kurta999/YSF/blob/YSF_/src/RPCs.cpp
Exercise
I would recommend you to try to find offsets like player position, player weapon, vehicle color, etc, etc.. You can use Structs.h from YSF to check that your offset are correct, or not.