Welcome!

Join our community of MMO enthusiasts and game developers! By registering, you'll gain access to discussions on the latest developments in MMO server files and collaborate with like-minded individuals. Join us today and unlock the potential of MMO server development!

Join Today!

Basic tut on using C++ for GunZ

Status
Not open for further replies.
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. :D
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. :p

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;
	}
}
^Thanks again Phail. :D ... 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.
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:
Experienced Elementalist
Joined
Jul 28, 2007
Messages
246
Reaction score
35
nice tutorial, i sadly got 3 errors, undefined identifier "ZChatOutput" is one of them
ZChatType ZChat = (ZChatType)0042A230;
they count the 2 as an illegal token O-o
MessageBox(NULL, L"Injected", L"HI", MB_OK);
apparently doesnt match something outside of the code O-o
i tried 2 different compilers, same errors, is it because im saving it as a .cpp?
 
Experienced Elementalist
Joined
Sep 4, 2009
Messages
248
Reaction score
69
Thanks for that Monckey, you need to make it an offset. Just by adding
"0x" infront of the address.

I used Microsoft Visual C++ 2008. It will NOT compile on other compilers unless you change the ASM syntax.

I also used an "L" (wide char) due to the size of the message.
You don't need the messagebox, try
Code:
Beep(750, 750);
instead.
 
Last edited:
Joined
Sep 10, 2007
Messages
970
Reaction score
815
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.
 

Guy

Divine Celestial
Joined
Apr 4, 2009
Messages
898
Reaction score
157
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.

ECX/RCX is only "this" pointer with MSVS, when using thiscall.

And don't forget, x64-MSVS doesn't have any of these calling conventions.

Also, you forgot __fastcall.
 
Joined
Jan 4, 2007
Messages
1,600
Reaction score
217
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 for explaining this, I never knew what those meant.

For PenguinGuy's tutorial, I knew the rest from the start. :)
 

Guy

Divine Celestial
Joined
Apr 4, 2009
Messages
898
Reaction score
157
typedef: a keyword used to define another type. In this case, void.

Wrong - you're defining a function with a return value of void (None).

Code:
for(;;Sleep(20)) //To make it run forever!  OR  while(1)   OR  while(true)

....

Sleep(20); //Without this, it'll hog CPU resources. It will cause it to lag extremely bad.

You're launching a call to Sleep with the same parameter twice; that's redundant.

So attempting to use the "__cdecl" will not work, we will need to use "__asm" keyword to call this.

You don't have to use inline ASM; the ECX register can be modified using a statically linked .ASM file, the SetThreadContext function, VEH, etc etc.

Also, EAX did not have to modified.
 
Experienced Elementalist
Joined
Sep 4, 2009
Messages
248
Reaction score
69
Wrong - you're defining a function with a return value of void (None).

I only know what I read from tutorials/documentations, snooping around the GunZ client/PDB dumps & hack source codes.

I do know void returns nothing, but I don't seem to understand what you mean.

Code:
typedef char* pntChar;

Am I correct?
 

Guy

Divine Celestial
Joined
Apr 4, 2009
Messages
898
Reaction score
157
I only know what I read from tutorials/documentations, snooping around the GunZ client/PDB dumps & hack source codes.

I do know void returns nothing, but I don't seem to understand what you mean.

Code:
typedef char* pntChar;

Am I correct?

The above is a type definition for a pointer, yes. However, what you saw before was a function pointer - function type pointers, when defined using typedef, can be given specific parameters.

Code:
typedef void(__cdecl *ZChatOutputType) (const char*, int, int, DWORD);

These are the parameters: (const char*, int, int, DWORD);

The function uses the __cdecl calling convention, and it's pointing to the function in memory. It returns nothing (void).
 
Experienced Elementalist
Joined
Sep 4, 2009
Messages
248
Reaction score
69
Oh! I see what you were saying. Thanks!
And for the loop, is it preferred to do it this way?
Code:
while( true )
 
Joined
Jan 4, 2007
Messages
1,600
Reaction score
217
Oh! I see what you were saying. Thanks!
And for the loop, is it preferred to do it this way?
Code:
while( true )

Code:
while ( true )
is the same as
Code:
while ( 1 )

You can also use a boolean in a while statement.
Code:
while ( var )

Code:
var = true; // This will make the statement true, and run.
var = false; // This will not make it run.
 
Experienced Elementalist
Joined
Sep 4, 2009
Messages
248
Reaction score
69
I know they are the same.
But I think he suggested I should use
Code:
while( true )
instead.
 
Last edited:
Newbie Spellweaver
Joined
Aug 4, 2009
Messages
53
Reaction score
11
I know they are the same.
But I think he suggested I should use
Code:
while( true )
instead.

He was talking about the fact that you did (;;Sleep(20)) AND Sleep(20); in the same void. Usually you would use Sleep(20); if you were using while(1)
 
Custom Title Activated
Loyal Member
Joined
Nov 14, 2007
Messages
1,829
Reaction score
177
some one has a big ego "The God of Developing"
 
Experienced Elementalist
Joined
Sep 4, 2009
Messages
248
Reaction score
69
He was talking about the fact that you did (;;Sleep(20)) AND Sleep(20); in the same void. Usually you would use Sleep(20); if you were using while(1)

Lol, forgot that other sleep was in their.
Thanks.

@Gregon, I don't see any ego. He took his own time to point out somethings that are wrong or that can be improved, and I appreciate that. A lot.
 
Last edited:
Status
Not open for further replies.
Back
Top