Experienced Elementalist
- Joined
- Sep 4, 2009
- Messages
- 248
- Reaction score
- 69
ollydbg:
PDB Dumps: http://forum.ragezone.com/f311/matchserver-functions-575273/#post5027927
GunZOld + test.txt: http://forum.ragezone.com/f245/release-gunzold-test-txt-219398/
I used Microsoft Visual C++ 2008. You can use a different compiler, you'd just have to change the assemblys syntax.
This "tutorial" is not intended to be used to "attack" or "make hacks" for other servers. It is intended to help other server developers/owners.
Don't ask me "what is an int?" or whatnot. If you want to understand this, go learn C++.
Note: I won't explain everything, I will not go into detail on a lot, and will be wrong. Just enough for you to get a kick-start on C++ developing for GunZ.
I may not be correct on everything, and my explanations are rather horrid.
@Phail and Guy, I know you will criticize me a lot what I typed. But try to keep it to a minimum please.![Big grin :D :D](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)
I've been up for 3 Ducking days, but I'm positive you don't care. lol.
Most basic GunZ function; ZChatOutput
typedef: a keyword used to define another type. In this case, void.
__cdecl: __cdecl is a calling convention. (More information later)
*: is used as a pointer in this case, not to multiply.![Stick out tongue :p :p](data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7)
The arguments:
const char*: The message to display
int: Where to place it
int: The type of color
DWORD: The color of the message
Usage of ZChatOutput:
You might be asking, "How do I find the addresses?"
Using ollydbg, test.txt, and GunZOld.exe.
Fire up ollydbg, open GunZOld.exe in ollydbg.
Open test.txt, and find ZChatOutput: 427A40: ZChatOutput
The "427A40" is the address in GunZOld.exe. Copy that address, open the ollydbg window, and hit "CTRL + G" paste it in the text box, and hit OK.
It should be something like this:
Since the addresses have changed, we can NOT copy "Calls", "MOV + [address]", or anything with an address.
Open up a new ollydbg window, and open "theduel.exe"
Highlight from: "MOV ECX, DWORD PTR SS:[ESP+10]" - to "PUSH EDX"
right click -> binary -> binary copy
Open the "theduel.exe" ollydbg, press "CTRL + B" and paste it in the "HEX + 00" box.
NOTE: It may not look exactly like eachother, so search underneath/above it and compare between each runnable in ollydbg.
This is what I have in "theduel.exe":
It appears to look alike, but to make sure, compare GunZOld & theduel's block underneath it:
GunZOld:
Theduel:
They appear to be the same, so scroll back up to 0042A230 - And we have ZChatOutput's address!!
(Their are more ways to find addresses, but I like this way.)
"Now what?"
Here is the complete source code:
^Thanks again Phail.
... And Brandon XD
Compile, inject, fix any errors (if any) and test.
Congratulations.
Let's take a bigger step, using assembly's syntax inside of C++. ZGameClient::OnAnnounce
Looks different, that's because ZGameClient::OnAnnounce is used as a class, not a function.
So attempting to use the "__cdecl" will not work, we will need to use "__asm" keyword to call this.
How did I know the parameters? The GunZ PDB Dump, searching for the functions name.
Copy this: ZGameClient::OnAnnounce - and open GunZ PDB Dump.txt in wordpad.
Press "CTRL + F" and paste that, and search.
First, you will find something like this:
Gives us all we need, but hit F3 two more times.
You should see something like this:
Ok, we have a better view on what we should use as parameters for this function.
(Remember, my explanations are rather horrid. And I may not be correct on everything.)
^ Thanks Phail.
=====
I'm done. Took me an hour or so to write this.
Enjoy what you i gave, please correct me if I am wrong. (I like critisizm, but keep it to a minimum please.)
You must be registered to see links
PDB Dumps: http://forum.ragezone.com/f311/matchserver-functions-575273/#post5027927
GunZOld + test.txt: http://forum.ragezone.com/f245/release-gunzold-test-txt-219398/
I used Microsoft Visual C++ 2008. You can use a different compiler, you'd just have to change the assemblys syntax.
This "tutorial" is not intended to be used to "attack" or "make hacks" for other servers. It is intended to help other server developers/owners.
Don't ask me "what is an int?" or whatnot. If you want to understand this, go learn C++.
Note: I won't explain everything, I will not go into detail on a lot, and will be wrong. Just enough for you to get a kick-start on C++ developing for GunZ.
I may not be correct on everything, and my explanations are rather horrid.
@Phail and Guy, I know you will criticize me a lot what I typed. But try to keep it to a minimum please.
I've been up for 3 Ducking days, but I'm positive you don't care. lol.
Most basic GunZ function; ZChatOutput
Code:
typedef void(__cdecl *ZChatOutputType) (const char*, int, int, DWORD);
ZChatOutputType ZChatOutput = (ZChatOutputType)0x0042BAE0; //FAKE Address *points to jjang*
typedef: a keyword used to define another type. In this case, void.
__cdecl: __cdecl is a calling convention. (More information later)
*: is used as a pointer in this case, not to multiply.
The arguments:
const char*: The message to display
int: Where to place it
int: The type of color
DWORD: The color of the message
Usage of ZChatOutput:
Code:
ZChatOutput("Hello world!", 2, 0, 0xFFFFFF);
You might be asking, "How do I find the addresses?"
Using ollydbg, test.txt, and GunZOld.exe.
Fire up ollydbg, open GunZOld.exe in ollydbg.
Open test.txt, and find ZChatOutput: 427A40: ZChatOutput
The "427A40" is the address in GunZOld.exe. Copy that address, open the ollydbg window, and hit "CTRL + G" paste it in the text box, and hit OK.
It should be something like this:
Code:
00427A40 /$ E8 9B3D0700 CALL GunzOld.0049B7E0
00427A45 |. 8B4C24 10 MOV ECX,DWORD PTR SS:[ESP+10]
00427A49 |. 8B5424 0C MOV EDX,DWORD PTR SS:[ESP+C]
00427A4D |. 51 PUSH ECX ; /Arg4
00427A4E |. 8B4C24 0C MOV ECX,DWORD PTR SS:[ESP+C] ; |
00427A52 |. 52 PUSH EDX ; |Arg3
00427A53 |. 8B5424 0C MOV EDX,DWORD PTR SS:[ESP+C] ; |
00427A57 |. 51 PUSH ECX ; |Arg2
00427A58 |. 52 PUSH EDX ; |Arg1
00427A59 |. 8D88 80030000 LEA ECX,DWORD PTR DS:[EAX+380] ; |
00427A5F |. E8 8CFBFFFF CALL GunzOld.004275F0 ; \GunzOld.004275F0
00427A64 \. C3 RETN
Since the addresses have changed, we can NOT copy "Calls", "MOV + [address]", or anything with an address.
Open up a new ollydbg window, and open "theduel.exe"
Highlight from: "MOV ECX, DWORD PTR SS:[ESP+10]" - to "PUSH EDX"
right click -> binary -> binary copy
Open the "theduel.exe" ollydbg, press "CTRL + B" and paste it in the "HEX + 00" box.
NOTE: It may not look exactly like eachother, so search underneath/above it and compare between each runnable in ollydbg.
This is what I have in "theduel.exe":
Code:
0042A230 /$ E8 AB1A0800 CALL theduel.004ABCE0
0042A235 |. 8B4C24 10 MOV ECX,DWORD PTR SS:[ESP+10]
0042A239 |. 8B5424 0C MOV EDX,DWORD PTR SS:[ESP+C]
0042A23D |. 51 PUSH ECX ; /Arg4
0042A23E |. 8B4C24 0C MOV ECX,DWORD PTR SS:[ESP+C] ; |
0042A242 |. 52 PUSH EDX ; |Arg3
0042A243 |. 8B5424 0C MOV EDX,DWORD PTR SS:[ESP+C] ; |
0042A247 |. 51 PUSH ECX ; |Arg2
0042A248 |. 52 PUSH EDX ; |Arg1
0042A249 |. 8D88 80030000 LEA ECX,DWORD PTR DS:[EAX+380] ; |
0042A24F |. E8 9CFBFFFF CALL theduel.00429DF0 ; \theduel.00429DF0
0042A254 \. C3 RETN
It appears to look alike, but to make sure, compare GunZOld & theduel's block underneath it:
GunZOld:
Code:
00427A70 /$ 53 PUSH EBX
00427A71 |. 55 PUSH EBP
00427A72 |. 56 PUSH ESI
00427A73 |. 57 PUSH EDI
00427A74 |. 8B7C24 14 MOV EDI,DWORD PTR SS:[ESP+14]
00427A78 |. 8BF1 MOV ESI,ECX
00427A7A |. 8D6E 28 LEA EBP,DWORD PTR DS:[ESI+28]
00427A7D |. 57 PUSH EDI
00427A7E |. 55 PUSH EBP
00427A7F |. E8 9AD81200 CALL GunzOld.0055531E
00427A84 |. 83C4 08 ADD ESP,8
00427A87 |. 33DB XOR EBX,EBX
00427A89 |. 85C0 TEST EAX,EAX
Theduel:
Code:
0042A260 /$ 53 PUSH EBX
0042A261 |. 55 PUSH EBP
0042A262 |. 56 PUSH ESI
0042A263 |. 57 PUSH EDI
0042A264 |. 8B7C24 14 MOV EDI,DWORD PTR SS:[ESP+14]
0042A268 |. 8BF1 MOV ESI,ECX
0042A26A |. 8D6E 28 LEA EBP,DWORD PTR DS:[ESI+28]
0042A26D |. 57 PUSH EDI
0042A26E |. 55 PUSH EBP
0042A26F |. E8 AA681500 CALL theduel.00580B1E
0042A274 |. 83C4 08 ADD ESP,8
0042A277 |. 33DB XOR EBX,EBX
0042A279 |. 85C0 TEST EAX,EAX
They appear to be the same, so scroll back up to 0042A230 - And we have ZChatOutput's address!!
(Their are more ways to find addresses, but I like this way.)
"Now what?"
Here is the complete source code:
Code:
#include <windows.h>
typedef void(__cdecl *ZChatType) (const char*, int, int, DWORD);
ZChatType ZChat = (ZChatType)0x0042A230;
void MyThread()
{
for(;;Sleep(20)) //Infinite Loop
{
if(GetAsyncKeyState (VK_MENU) && GetAsyncKeyState ('L'))
// IF THE KEY ALT (was pressed) AND THE KEY L (was pressed)
{
ZChatOutput("Hello World!", 2, 0, 0xFFFFFF);
Sleep(250); //To make sure it doesn't run while them keys were pressed.
}
}
}
extern "C"
{
__declspec(dllexport) BOOL __stdcall DllMain(HINSTANCE hInst,DWORD reason,LPVOID lpv)
{
DisableThreadLibraryCalls(hInst);
if (reason == DLL_PROCESS_ATTACH)
{
MessageBox(NULL, L"Injected", L"HI", MB_OK);
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&MyThread, NULL, 0, NULL); //Remember our void? "MyThread" ??
}
return true;
}
}
Compile, inject, fix any errors (if any) and test.
Congratulations.
Let's take a bigger step, using assembly's syntax inside of C++. ZGameClient::OnAnnounce
Looks different, that's because ZGameClient::OnAnnounce is used as a class, not a function.
So attempting to use the "__cdecl" will not work, we will need to use "__asm" keyword to call this.
Code:
DWORD OnAnnounceAdd = 0x0042BAE0;
DWORD ZGetGameClientAdd = 0x0042BAE0;
void OnAnnounce(unsigned int nType, char* szMsg)
{
__asm
{
MOV ECX, ZGetGameClientAdd
MOV EAX, OnAnnounceAdd
PUSH szMsg
PUSH nType
CALL EAX
}
}
/*
MOV ECX, ZGetGameClientAdd - COPY ZGetGameClientAdd into the ECX register
MOV EAX, OnAnnounceAdd - COPY OnAnnounceAdd into the EAX register
PUSH szMsg - PUSH'ing szMsg into the stack
PUSH nType - PUSH'ing nType into the stack
CALL EAX - CALL what's in the EAX register
So, when we call EAX, we also call what we push'd. (Learn ASM)
*/
How did I know the parameters? The GunZ PDB Dump, searching for the functions name.
Copy this: ZGameClient::OnAnnounce - and open GunZ PDB Dump.txt in wordpad.
Press "CTRL + F" and paste that, and search.
First, you will find something like this:
Code:
?OnAnnounce@ZGameClient@@IAEXIPAD@Z(protected: void __thiscall ZGameClient::OnAnnounce(unsigned int,char *))
Gives us all we need, but hit F3 two more times.
You should see something like this:
Code:
Function : static, [0x000afd70][0x0001:0x000aed70], len = 00000030, protected: void __thiscall ZGameClient::OnAnnounce(unsigned int,char *)
FuncDebugStart : static, [0x000afd71][0x0001:0x000aed71]
FuncDebugEnd : static, [0x000afd9a][0x0001:0x000aed9a]
Data : enregistered edx, Object Ptr, Type: class ZGameClient * const, this
Data : ebp Relative, [0x00000004], Param, Type: unsigned int, nType
Data : ebp Relative, [0x00000008], Param, Type: char *, szMsg
Ok, we have a better view on what we should use as parameters for this function.
(Remember, my explanations are rather horrid. And I may not be correct on everything.)
Your definitions for calling conventions are incorrect my good sir.
The "__cdecl" - we can call, when the function is NOT apart in a class.
The "__thiscall" - we can call using ASM.
The "__stdcall" - used for calling functions that apart of graphics/winapi/directx/etc.
__cdecl -> Arguments are pushed from right to left, and the calling function cleans it up.
__thiscall -> Arguments are pushed from right to left, and the called function cleans the stack up. ECX = "this" aka class pointer.
__stdcall -> Arguments are pushed from right to left, and the called function cleans the stack up.
^ Thanks Phail.
=====
I'm done. Took me an hour or so to write this.
Enjoy what you i gave, please correct me if I am wrong. (I like critisizm, but keep it to a minimum please.)
Last edited: