Hello sexy cheaters :D
I decided to make a little “tutorial” to explain you how to do some hacks like greyb1t’s last hack for Insanity which can be found here:
[Only registered and activated users can see links. Click Here To Register...]
1. Introduction :cool:
The first thing i want to say, I am not a teacher as I am not enough skilled in coding and I usually do not produce proper code. But I will try to comment my code so you can understand it.
This “tutorial” can be used to make other hacks in flyff if you understand it correctly and can do more powerful things, I let you imagine what can be done :D
This is only for education purpose so please do not do it against the rules or make sure to have permission to do it..
This hack will be patched soon as it is easy to fix but as I said, you can do it for other hacks if the game server does not check your calls.
We will do this test in
[Krona Flyff] client.
Quote:
|
Note that I will not release any code that kills many mobs at the same time just to not see nabs aoeing the hole spawn. If you know how to find the mobs in the camera view then you can code it by yourself but I do not recommend it xD
|
2. How does it work? :confused:
What we will do is to call a function inside the game client (Neuz.exe). This function is:
Quote:
|
void CDPClient::SendMeleeAttack( OBJMSG dwAtkMsg, OBJID objid, int nParam2, int nParam3, FLOAT fVal )
|
As you can see, it is member of the
CDPClient class which means that it can be called by our game client.
So, we will need to find in "Neuz.exe" the following few things:
- The “SendMeleeAttack()” method address
- The parameters values to pass to our function
Different ways can be used to get these addresses but a fast method is to search for “Referenced strings” with CE or with your preferred debugger.
Quote:
|
Note that Krona has an anti-debugger protection and I only succeeded to bypass it with CE “VEH” debugger. x32dbg and olly are detected and close immediately when a software breakpoint is reached.
|
After CE finishes the processing, search for the string “
DoAttackMelee” => you will find an unique address, then click it and you will get somewhere here:
Scroll down a little bit and you will be here:
As you can see:
- The client address is at : Neuz.exe+9FDA70
- The SendMeleeAttackaddress is at: Neuz.exe+4197B0
You have to set up a break point at the function start in order to find the list of the parameters:
- Put a breakpoint at the start of the SedMeleeAttack function (or press F5 in CE)
- Hit a mob with a melee attack
- Your CE should break! Then go to CE and right click the Stack frame and select "Full Stack"
- Remove the break point and Press F9 to continue
- Check the Stack Frame and you will see all the parameters of the function
- The ECX register holds the "Client" address which is the class pointer
Example for "Insanity FlyFF"
At the end, we will see that:
- OBJMSG dwAtkMsg: this is an integer and it has the value 29 (or 0x1D in hexadecimals)
- OBJID objid: this is the mob ID (i.e session ID and not to be confused with the fixed constant player_id). This can be found by selecting different mobs in the game and using the Dissect Data/Structure feature of CE => See below to know how to find this value...
- int nParam2: always equal to 0
- int nParam3: always equal to 0x10000 (or 65536 in decimals)
- FLOAT fVal: this is the equipped weapon attack speed. This value can be found by calling another method called GetActiveHandItemProp() which applies to the class CMover. => Let’s do not do it for the moment and just use a hardcoded value. The values can be found using your debugger:
- For the sword: the attack speed is 0.08500000089f
- For the knux: 0.0700000003f
If you can find a pointer to the current Equipped Weapon structure then you can get the attack speed which is at offset 0x130.
You also can get this value on the fly using "thread context and debug registers" method by setting a hardware breakpoint in your code at a certain position:
Neuz.exe+14F21E - F3 0F10 82 30010000 - movss xmm0,[edx+00000130]
and get the EAX value but this will be for advanced users only.
3. How to find the target ID address? :confused:
If you have no idea how to find the target ID I will explain it to you using CE but of course you can find it using another way in CE or even using other tools (for example if you have a packet editor, which can be done using my tutorial by the way ;) , you can read the target ID by hooking the send() function that sends a packet to the server when you select a target...)
1 - Put a breakpoint at the function start (Press F5)
2 - Hit a mob using a melee attack
3 - Go back to CE and check the Stack frame and save the target ID value in notepad
Example for "Insanity FlyFF", target ID =
0x015767F5 (hexadecimal)
4 - In CE: New Scan, check "Hex" button and write down
0x015767F5
5 - In most cases, the first address is the correct one but
be sure the address is not static (not green). Here it is
0x035976D0
6 - Add the address
0x035976D0 to the list and right-click "Find out what accesses this address"
7 - Select the same mob 2 or 3 times and you will see that the accessor is
0x035973E0 with offset
0x2F0
This means that the session ID of the selected target is at offset 0x2F0 and the "entity" address representing our mob is at address
0x035973E0
8 - Now we need to find a
static pointer (green address) for our target
0x035973E0 so we can find it every time we run Neuz...
9 -
Select the same mob and Scan for
0x035973E0, hex button checked of course.
10 -
Unselect the mob and you will see 2 values changing to
00000000
11 - The second address is the correct one (or you can test both to find the correct one). Add the address
0x278EBBB0 to the list and do "Find out what writes to this address"
12 - Select the mob and you will see that the offset for the target is
0x20 and the base is
0x278EBB90
13 - We now must find a static pointer that points to
0x278EBB90
Scan for
0x278EBB90, "Hex" button checked -> bingo , we found 2 static pointers
14 - The second pointer
0x015EAF90 is the correct one!
15 - To test it, add a pointer manually in CE:
Address =
"Neuz.exe" + B6AF90 (it is eaqual to 0x015EAF90 for me but this changes all the time
so always use relative address starting from "Neuz.exe")
Offset 1 = 0x20
Offset 2 = 0x2F0
That’s all for the parameters so let’s start the boring part :o
4. Code :bandit:
When you want to call a function in your Neuz module, you can use a pointer to your function like this:
Quote:
typedef void (__thiscall * SendMeleeAttack_t)(void * client, unsigned int dwAtkMsg, unsigned int objid, int nParam2, int nParam3, float fVal);
SendMeleeAttack_t pSendMeleeAttack = (SendMeleeAttack_t)((DWORD)g_hExeModule+0x4197B0);
|
__thiscall : this is the used calling convention => very important
All you need later is to call the function inside Neuz by just writing:
Quote:
|
pSendMeleeAttack((void*)g_DPlay, dwAtkMsg , SelectedID , nParam2 , nParam3,fItemAttakSpeed);
|
Quote:
Note that g_DPlay is the pointer to our client: (void*) means a pointer to anything.
This means that the function we are going to call is called by a pointer to our client so you will need to add the parameter “(void*)client” when you call it.
|
The other parts of the code are easy to understand so there is nothing special to explain here (I am tired of writing :rolleyes:)
[Only registered and activated users can see links. Click Here To Register...]
Source code
PHP Code:
#pragma once
#define win32_lean_and_mean
#include <windows.h>
#include <stdio.h>
#include <fcntl.h> // for the console stuff
#include <io.h> //
#include <TlHelp32.h> // for the module operations
// Note that the __thiscall calling is **very important**
typedef void (__thiscall * SendMeleeAttack_t)(void * client, unsigned int dwAtkMsg, unsigned int objid, int nParam2, int nParam3, float fVal);
SendMeleeAttack_t pSendMeleeAttack ; // pointer to our main function
HANDLE CreateConsole(); // for logging
DWORD g_threadID; // Thread ID
HMODULE g_hModule; // Instance of the current injected DLL module
HMODULE g_hExeModule; // Entry point of "Neuz.exe" module
HMODULE g_hCrashReport ;// evil module to get rid of => this is loaded in Krona FlyFF, not in all other Flyff versions!!
DWORD g_DPlay = 0x0; // Pointer to our client (for Krona, it is Neuz.exe+9FDA70) => it can be found at ECX register at the function start
DWORD SelectedBase = 0x0 ;// target base address
unsigned int dwAtkMsg = 0x1D; // 29 (1D in hexa)
unsigned int SelectedID = 0x0; // will be computed everytime the hack is called
int nParam2 = 0; // 0x0
int nParam3 = 0x10000; // 0x10000
float fItemAttakSpeed = 0.0f; // currently equipped weapon attack speed
boolean bExecuted = false; // was the hack executed?
DWORD WINAPI MyThread(LPVOID); // The thread that executes the hack
void printLastExecution(); // used for printing some crap
unsigned long get_module(unsigned long pid, char *module_name, unsigned long *size) ;// used only to remove the CrashRpt.dll module
// used to find Dma Addy with multi level pointers (found somewhere in the dark net)
DWORD FindDmaAddy(int PointerLevel, DWORD Offsets[], DWORD BaseAddress);
// Entry point of our DLL module
INT APIENTRY DllMain(HMODULE hDLL, DWORD Reason, LPVOID Reserved)
{
switch (Reason)
{
case DLL_PROCESS_ATTACH:
g_hModule = hDLL;
DisableThreadLibraryCalls(hDLL);
CreateConsole();
g_hExeModule = GetModuleHandle("Neuz.exe"); // get the module base address of Neuz.exe
printf_s("[INFO]: g_hExeModule address: 0x%x\n", g_hExeModule); // print it :)
// The base address of the target object => can be found easily with CE or with any other debugger
SelectedBase = (DWORD)g_hExeModule + 0x9CC37C; //Neuz.exe+9CC37C
printf_s("[INFO]: SelectedBase address: 0x%x\n", SelectedBase);
g_DPlay = (DWORD)g_hExeModule+0x9FDA70; // pointer to Neuz.g_DPlay
printf_s("[INFO]: g_DPlay address: 0x%x\n", g_DPlay);
pSendMeleeAttack = (SendMeleeAttack_t)((DWORD)g_hExeModule+0x4197B0); // Neuz.exe+14F273 - E8 38A52C00 - call Neuz.exe+4197B0
printf_s("[INFO]: pSendMeleeAttack address: 0x%x\n", pSendMeleeAttack);
// Create the main thread that will execute the hack
CreateThread(NULL, NULL, &MyThread, NULL, NULL, &g_threadID);
break;
case DLL_THREAD_ATTACH:
case DLL_PROCESS_DETACH:
case DLL_THREAD_DETACH:
break;
}
return TRUE;
}
// Main Thread
DWORD WINAPI MyThread(LPVOID)
{
// remove evil tool to hide our hacks from being sent to the game server in case of a crash
while (g_hCrashReport == NULL)
{
unsigned long size;
g_hCrashReport = (HMODULE)get_module(GetCurrentProcessId(), "CrashRpt1402.dll", &size);
if (g_hCrashReport != NULL) // we found it xD
{
printf_s("[INFO]: CrashRpt1402.dll found at Handle: 0x%x\n", g_hCrashReport);
break;
}
}
DWORD hackOffsetsTargetID[] = {0x20, 0x2f4}; // Offsets of the mob ID
BOOL unloaded = false;
// Loop
while (true)
{
//Sleep(200);
//system("cls"); // Remove the console logging
//printf("...::[Krona FlyFF] Send Melee Attack hack (made by cookie69)::...\n");
//printf("1. Select a mob in the game\n");
//printf("2. Press F2 to hit the mob 1 time\n");
//bExecuted? printLastExecution() : printf("");
if (GetAsyncKeyState(VK_F2) & 0x8000) // Press F2
{
// unload the evil module
if(!unloaded)
{
unloaded = FreeLibrary(g_hCrashReport);// go to hell mofo spy tool
unloaded ? printf_s("[INFO]: CrashRpt1402.dll was unloaded successfully xD\n") : printf_s("[ERROR]: Unable to unload the DLL CrashRpt1402.dll!!\n");
// => unloading a module like this one is very bad => you may crash your client!
}
bExecuted? printLastExecution() : printf("");
bExecuted = true;
Beep(0x0FFF,1000); // Beeps to tell us that the hack was called. (frequency is 0x25 through 0x7FFF).
// Find the Targeted Mob ID
if(DWORD addy = FindDmaAddy(2, hackOffsetsTargetID, SelectedBase))
{
SelectedID = *(unsigned int*)addy;
}
// hard coded values => I didnt find a pointer to the current weapon attack speed so I used a hardcoded value
// there is also another way to do it: set a break point at Neuz.exe+14F21 and read "EDX +130" value, follow in dump and transform it to float type.
//Neuz.exe+14F21E - F3 0F10 82 30010000 - movss xmm0,[edx+00000130]
float fSwordAtkSpeed = 0.08500000089f;
float fKnuxAtkSpeed = 0.0700000003f;
fItemAttakSpeed = fSwordAtkSpeed;
// Only send attack if there is a selected mob to avoid crash
if(SelectedID != NULL)
{
pSendMeleeAttack((void*)g_DPlay, dwAtkMsg , SelectedID , nParam2 , nParam3,fItemAttakSpeed);
}else{
printf_s("[ERROR]: You must select a mob before calling the function!\n");
}
}
else if (GetAsyncKeyState(VK_F3) & 0x8000)
{
printf_s("__Hack DLL was unloaded from Neuz__\n");
MessageBox(0, "DLL unloaded!", "", 0);
break;
}
Sleep(100);
}
FreeLibraryAndExitThread(g_hModule, 0);
return 0;
}
// It does some printing
void printLastExecution()
{
printf("-----------------------Results ---------------------\n");
printf("[INFO]: g_DPlay: 0x%x\n", g_DPlay);
printf("[INFO]: dwAtkMsg: 0x%x\n", dwAtkMsg);
SelectedID == NULL? printf("[ERROR]: No selected mob in the game!\n") : printf("[INFO]: SelectedID: 0x%x\n", SelectedID);
printf("[INFO]: nParam2: 0x%x\n", nParam2);
printf("[INFO]: nParam3: 0x%x\n", nParam3);
printf("[INFO]: fItemAttakSpeed: %f\n", fItemAttakSpeed);
printf("----------------------------------------------------\n");
}
// Not mine, it was found in the internet
DWORD FindDmaAddy(int PointerLevel, DWORD Offsets[], DWORD BaseAddress)
{
//DEFINES OUR ADDRESS to write to
//if statements are crucial to make sure that the address is valid to write
//otherwise we crash. Address will not be valid when things like map changes or game loads are happening
DWORD Ptr = *(DWORD*)(BaseAddress); //Base Address
if(Ptr == 0) return NULL;//prevent crash
//this is done to allow us to have pointers up to many levels e.g.10
for(int i = 0; i < PointerLevel; i ++)
{
//if it = PointerLevel-1 then it reached the last element of the array
//therefore check if that address plus the offset is valid and leave the loop
if(i == PointerLevel-1)
{
//!!make sure the last address doesnt have the asterisk on DWORD otherwise incoming crash
Ptr = (DWORD)(Ptr+Offsets[i]); //Add the final offset to the pointer
if(Ptr == 0) return NULL;//prevent crash
//we here return early because when it hits the last element
//we want to leave the loop, specially adapted for offsets of 1
return Ptr;
}
else
{
//if its just a normal offset then add it to the address
Ptr = *(DWORD*)(Ptr+Offsets[i]); //Add the offsets
if(Ptr == 0) return NULL;//prevent crash
}
}
return Ptr;
}
// From xsh detour hack
HANDLE CreateConsole()
{
int hConHandle = 0;
HANDLE lStdHandle = 0;
FILE *fp = 0;
// Allocate a console
AllocConsole();
// redirect unbuffered STDOUT to the console
lStdHandle = GetStdHandle(STD_OUTPUT_HANDLE);
hConHandle = _open_osfhandle(PtrToUlong(lStdHandle), _O_TEXT);
fp = _fdopen(hConHandle, "w");
*stdout = *fp;
setvbuf(stdout, NULL, _IONBF, 0);
return lStdHandle;
}
// It returns the module handle loaded in the specified process
unsigned long get_module(unsigned long pid, char *module_name, unsigned long *size) {
void *snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pid);
MODULEENTRY32 me32;
me32.dwSize = sizeof(MODULEENTRY32);
while (Module32Next(snapshot, &me32)) {
if (strcmp(me32.szModule, module_name) == 0) {
if (size != 0) *size = me32.modBaseSize;
return (unsigned long)me32.modBaseAddr;
}
} return NULL;
}
VirusTotal :confused:
[Only registered and activated users can see links. Click Here To Register...]
The full solution was made with
Visual Studio 2012 and is attached to this thread. You have all the permissions to use or modify it…
If you need any help and if I can then I will reply to you otherwise please don't blame me.
If this helped someone then please push the thanks button.
Regards