[Tutorial] Update memory hacking plugins
#1

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
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)
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.

pawn Code:
*(_DWORD *)a2 = *(_DWORD *)(v3 + 10529);
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.
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:

pawn Code:
pNetGame->pPlayerPool->pPlayer[playerid]->fHealth;
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:
pawn Code:
virtual void RegisterAsRemoteProcedureCall( int* uniqueID, void ( *functionPointer ) ( RPCParameters *rpcParms ) );
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.
Reply
#2

Incredible tutorial, great work, +REP
Reply
#3

Nice tutorial, but you missed out signature finding/obtaining.
Reply
#4

I'll continue it soon. The basics are here. Try to find armour and vehicleid from CPlayer based on this.

E: Added tutorial how to find RPC. If it's not clear, then I'll make screenshots.
Reply
#5

Amazing tutorial , shouldn't this be posted on "Tutorials" section? Thank you for this kurta
Reply
#6

I think this topic should be pinned.
Reply
#7

Nice work, will help lots of people
Reply
#8

Thanks!, you teach me how plugin developer hack memory.
Reply
#9

I do not know but I should make a copy of this tutorial now and keep it in a safe place!
Thank you and good job!
Reply
#10

O.o Muito bom!
Reply
#11

thank you, buddy)
Reply
#12

Everyone behaving like they understood this tutorial .
Reply
#13

Quote:
Originally Posted by Mellnik
View Post
Everyone behaving like they understood this tutorial .
Most other tutorials on that topic are even harder to understand. Memory hacking is heavy stuff, it cant be explained in a tutorial that every 10-year-old could understand

Nice post though, I didnt know of IDA yet.
Reply
#14

AMAZING! Thank you
Reply
#15

Finally I have a good reason to come back to samp development, thank you so much Mr.Atila

I've been waiting for something like this since I wanted to update the FCNPC plugin and nobody could help me at that time, I really do believe that this topic should be pinned, thanks for sharing.

+6
Reply
#16

Very usefull this!

Thanks
Reply
#17

thanks, useful tutorial. so great for that.

(apperantly saying only "nice" gets ur post removed. fk nazi mods)
Reply
#18

Great tutorial !!

I have a problem with the structures in that use structures to store data but if I put "-fpack-struct = 1" run time errors occur. Example:

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
};

CNetGame *pNetGame = (CNetGame*)0x4F6CC8;

struct _Player // How do I not pack this structure in linux?
{
int a;
bool c;
};
Windows fix:

pawn Code:
#pragma pack(push, 1)
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
};

CNetGame *pNetGame = (CNetGame*)0x4F6CC8;
#pragma pack(pop)

struct _Player
{
int a;
bool c;
};
As I can fix this in linux?
Reply
#19

I'm wondering if memory hacking could be used to attach basically every element to each other ? So like a vehicle to another vehicle or a vehicle to an object.

I thought somehow finding the internal function for attaching (if there is one) and then using it for other stuff than object to object for example. But like I said I don't know if that's possible that's why I'm asking here.
Reply
#20

Quote:
Originally Posted by FSAOskar
View Post
I'm wondering if memory hacking could be used to attach basically every element to each other ? So like a vehicle to another vehicle or a vehicle to an object.

I thought somehow finding the internal function for attaching (if there is one) and then using it for other stuff than object to object for example. But like I said I don't know if that's possible that's why I'm asking here.
No, this can be done in client, it must be impossible to Kalcor make something that attaches every element types on another, if he does it he create a function for that (or RPC to call this function in client), but there's nothing for this.

Hope you don't create a tutorial to reverse SA:MP client kurta999, i'm wondering how Kalcor doesn't get mad with this tutorial but i'm sure when you put a idb from samp.dll Kalcor will come front of your house door ( or maybe he release 0.4a =) with extra Anti RE and debugging ), but funny tutorial ever! How to reverse SA:MP Server on SA:MP Forums, lol!
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)