Tutorial Android Function Hooking Tutorial

MORGAN666

Platinian
Original poster
May 11, 2022
18
131
28
21
Hell
Things you need to follow this Android Function Hooking Tutorial:

• Knowledge of C++

• Basic Knowledge on making mod menus for android.
• Must already know how to patch functions with hex codes. If you don't, come back when you can.
DnSpy
Android Studio

Octowolves template
Or
LGLS TEMPLATE

(if you prefer another template that's also fine of course)

• A brain


Assuming you have these, you can keep on reading. If not, this tutorial is too advanced for you to understand and be able to apply the principles to other games.

I will be doing a cumulative open source cheat project for bullet force, and the download for the project will be available at the end of each tutorial. This series is going to be quite out of order, but it is what it is.

Please don't ask me questions unrelated to this tutorial in the comments. If you want to learn about making menus for android, read the other threads in this section or get the f*ck out.

I will provide a finished copy of the hooking tutorial with Octowolves template. It is your responsibility to update the offsets when needed, as I provide the function names already in this tutorial.

In this Android function hooking tutorial I will be using Octowolves template to demonstrate.

So, you know how to patch, but you want to take things to the next level. But what's the next level? Where do you begin?

Well, this tutorial IS the next level.

What is it?

Hooking.

What is hooking?


Hooking is a more efficient and better way of modding functions.

It allows us to return anything we want to a function, by creating a function and hooking it, by calling it in our main thread with the offset.

Why should I use it instead of patching?

• More efficient

• Can return anything you want

• Can set up functions to call pointers in update

• Any patching used in menus is easy to get leeched, and your offsets are at risk when patching.

• Hooking is harder to leech than patches and less likely to in the first place.


Now, that you know what hooking is and why you should use it, lets get on with the tutorial.

I will split this thread into 5 sections, one for each basic datatype you can hook, as well as an extra section.

Section 1: Android Hooking Basics

So, Hooking goes a little as follows:

First, we make a function and return what we want on it following the template below:
Function

C++:
(datatype) (*old_function)(void *instance);
(datatype) function(void *instance) {
    if (instance != NULL) {
        if (boolean) {
            return (whatever suitable for datatype);
        }
    }
    return old_function(instance);
}
Then, we need to call it in our hack_thread with the offset like this:

Hook
C++:
octo_hook((void*)getAbsoluteAddress(0xOFFSET), (void*)Function, (void**)&old_Function);
Your full hack_thread would look something like this:

Code:
void* hack_thread(void*) {
    LOGI("I have been loaded. Mwuahahahaha");
    do {
        sleep(1);
    } while (!isLibraryLoaded(libName));
    LOGI("I found the il2cpp lib. Address is: %p", (void*)findLibrary(libName));
    octo_hook((void*)getAbsoluteAddress(0xOFFSET), (void*)Function, (void**)&old_Function);
    return NULL;
}
Your full hack_thread would look something like this:

C++:
void* hack_thread(void*) {
    LOGI("I have been loaded. Mwuahahahaha");
    do {
        sleep(1);
    } while (!isLibraryLoaded(libName));
    LOGI("I found the il2cpp lib. Address is: %p", (void*)findLibrary(libName));
    octo_hook((void*)getAbsoluteAddress(0xOFFSET), (void*)Function, (void**)&old_Function);
    return NULL;
}
Thats it!

Section 2: Hooking Boolean functions.

In Bullet Force, there is an interesting function that we can find pretty easily.

If we search in dnspy for CanShoot, we can see that it is a function in class PlayerScript, which I mentioned in previous tutorials that it is your player class. All the good stuff is in it.

Function

C++:
private bool CanShoot(bool checkRPM = true)
This function seems to check if we can shoot or not.

We could easily patch this to true and move on, but we are here for hooking right?

You can only return the datatype of the functions datatype. (duh), So we can only return true or false.

All we need to do is to return true, and it will allow us to shoot, even if we are out of ammo or reloading.

Strangely enough, when you modify this function, it also stops the bullet delay, making you able to shoot more bullets, so this function is also a firerate cheat.

Following the template I mentioned in section 1 above, we can create our hooking function and return true.

Function

C++:
bool (*old_CanShoot)(void *instance);
bool CanShoot(void *instance) {
    if (instance != NULL) {
        if (isAmmoandFirerate) {
            return true;
        }
    }
    return old_CanShoot(instance);
}
Now, we need to call it in your hack thread and input an offset with getabsoluteaddress.

Hook in thread.

C++:
octo_hook((void*)getAbsoluteAddress(0x4ED460), (void*)CanShoot, (void**)&old_CanShoot);
Your hack thread should look like this now:

Hack Thread
C++:
void* hack_thread(void*) {
    LOGI("I have been loaded. Mwuahahahaha");
    do {
        sleep(1);
    } while (!isLibraryLoaded(libName));
    LOGI("I found the il2cpp lib. Address is: %p", (void*)findLibrary(libName));
    octo_hook((void*)getAbsoluteAddress(0x4ED460), (void*)CanShoot, (void**)&old_CanShoot);
    return NULL;
}
Now, we need to make a new toggle for the feature. Find the const char *features in the jobject array getListFT.

Once you've found it Remove everything inside the { };

Your feature list should now look like this:

Feature List

C++:
const char *features[]= {};
Then, add " " and put your feature name of your toggle inside of it. We are doing fire rate and unlimited ammo, So call the toggle what you want. Im going to call it "Firerate and Unlimited Ammo".

Your features list should now look like this:

Feature List
C++:
const char *features[]= {"Unlimited Ammo And Firerate"};
Then, go to the changeSeekBar, changeSpinner, changeEditText functions, and remove the cases in there, as we don't need them, because we are only using toggles.

The functions should now look like this:

C++:
void changeSeekBar(JNIEnv *env, jclass clazz, jint i, jint seekbarValue) {
    int li = (int) i;
    switch (li) {
        default:
            break;
    }
    return;
}

void changeSpinner(JNIEnv *env, jclass clazz, jint i, jstring value) {
    int li = (int) i;
    switch (li) {
        default:
            break;
    }
}

void changeEditText(JNIEnv *env, jclass clazz, jint i, jstring value){
    int li = (int) i;
    switch (li){
        default:
            break;
    }
    return;
}
In your changetoggles function, delete the cases, and add case 0: and then break; at the end. (make sure to break after every case you make)

After that, do, isAmmoandFirerate = ! isAmmoandFirerate; inside of your case.

This is what it should look like now:

ChangeToggle Function
C++:
void changeToggle(JNIEnv *env, jclass thisObj, jint number) {
    int i = (int) number;
    switch (i) {
        case 0:
            isAmmoandFirerate = ! isAmmoandFirerate;
            break;
        default:
            break;
    }
    return;
}
We count from case 0 as the first feature, our second feature will be case 1, and so on.

That's it, you're done!

You just successfully hooked your first function! Give yourself a pat on the back.

Lets not get too cocky, we still don't know how to hook other basic datatypes.

Section 3: Hooking Android Integer Functions.

So, I've found a very interesting integer function.

Function
C++:
public int getGrenadesLeft()
First, make a boolean.

Boolean
C++:
bool isUnlimitedGrenades = false;
To hook this, we need to return an integer back. Following the template in section one, lets make our function.

Function
C++:
int (*old_getGrenadesLeft)(void *instance);
int getGrenadesLeft(void *instance) {
    if(instance!=NULL) {
        if (isUnlimitedGrenades) {
            return 3;
        }
    }
    return old_getGrenadesLeft(instance);
}
Why did you only return 3? Don't we want more grenades than that, like 999?

Simple enough. When I first attempted using this function, the game checks if your grenades exceed the max number of grenades.

Instead of looking for the check and disabling it, we can just hook it to a low number. It will always stay at 3 grenades, giving us unlimited grenades.


Tip: If you are still getting kicked from the game, hook function GetMaxGrenades to 3 as well.

Now, call our hook in our hack thread with the offset.

Hook
C++:
octo_hook((void*)getAbsoluteAddress(0x8FD818), (void*)getGrenadesLeft, (void**)&old_getGrenadesLeft);

Your hack_thread should now look like this:

Hack Thread
C++:
void* hack_thread(void*) {
    LOGI("I have been loaded. Mwuahahahaha");
    // loop until our target library is found
    do {
        sleep(1);
    } while (!isLibraryLoaded(libName));
    LOGI("I found the il2cpp lib. Address is: %p", (void*)findLibrary(libName));

    octo_hook((void*)getAbsoluteAddress(0x8FD818), (void*)getGrenadesLeft, (void**)&old_getGrenadesLeft);
    octo_hook((void*)getAbsoluteAddress(0x4ED460), (void*)CanShoot, (void**)&old_CanShoot);
    return NULL;
}
Then, add "Unlimited Grenades" as a feature in your feature list.

Add this inside ChangeToggles after case 0:

Case
C++:
case 1:
   isUnlimitedGrenades = ! isUnlimitedGrenades;
break;
Done! You just successfully hooked your first int function.

Section 4: Hooking Float Functions.

So, Once again, we see another function that stands out.

This one comes from my Android Il2cpp Breakdown

Function
C++:
public extern float get_fieldOfView();
This function controls your in-game Field Of View (fov).

We should return 100 to it, as we want a high fov right?

First, lets make our boolean.

Boolean
C++:
bool isFov = false;
Then, lets make our function.

Hook Function
C++:
float (*old_get_fieldOfView)(void *instance);
float get_fieldOfView(void *instance) {
    if(instance!=NULL) {
        if (isFov) {
            return 100.0f;
        }
    }
    return old_get_fieldOfView(instance);
}
}
Why did we return 100.0f instead of just 100.0?

Since we are dealing with float functions, we need to return a float (duh) right?

Well, if we return 100.0, the game thinks its a double, which may or may not cause crash or feature issues.

When we put f at the end, it lets the game know its a float.

Better be safe than sorry!


Now, we can call our function in our hack thread with the offset.

Hook in thread.
C++:
octo_hook((void*)getAbsoluteAddress(0x1133710), (void*)get_fieldOfView, (void**)&old_get_fieldOfView);
Your finalized hack thread should look like something similar to this:

Hack Thread
C++:
void* hack_thread(void*) {
    LOGI("I have been loaded. Mwuahahahaha");
    // loop until our target library is found
    do {
        sleep(1);
    } while (!isLibraryLoaded(libName));
    LOGI("I found the il2cpp lib. Address is: %p", (void*)findLibrary(libName));

    octo_hook((void*)getAbsoluteAddress(0x8FD818), (void*)getGrenadesLeft, (void**)&old_getGrenadesLeft);
    octo_hook((void*)getAbsoluteAddress(0x4ED460), (void*)CanShoot, (void**)&old_CanShoot);
    octo_hook((void*)getAbsoluteAddress(0x8FD818), (void*)get_fieldOfView, (void**)&old_get_fieldOfView);
    return NULL;
}
Then, go to your features, and add "Fov" as a feature.

Your final Features should look something like this:

Feature List
C++:
const char *features[]= {"Ammo And Firerate", "Unlimited Grenades", "Fov Changer"};
Go to your changetoggles function and add:

Case
C++:
case 2:
   isFov = ! isFov;
   break;
Your final changetoggle function should look like this:

ChangeToggle Function
C++:
void changeToggle(JNIEnv *env, jclass thisObj, jint number) {
    int i = (int) number;
    switch (i) {
        case 0:
            isAmmoandFirerate = ! isAmmoandFirerate;
            break;
        case 1:
            isUnlimitedGrenades = ! isUnlimitedGrenades;
            break;
        case 2:
            isFov = ! isFov;
            break;
        default:
            break;
    }
    return;
}
And that's it! Those are the 3 datatypes you will mostly see, and now you know how to hook all of them! Give yourself a pat on the back (again).

Section 5: Hooking update to use function pointers and other stuff

I've kind of already gone over this in many of my other tutorials, but ill recap it here for educational purposes.

What is update?

A short recap:

Update is called 60 times a second and is needed if you are using things like function pointers. It is useful for things like getting players positions, as you want the most current position of the player.

Right?

The best way is just hooking update.


So, lets make an update function.

Update Function
C++:
void(*old_PlayerScript_UpdateFast)(void *player);
void PlayerScript_UpdateFast(void *player) {
    if(player != nullptr){
        //your stuff goes here
    }
    old_PlayerScript_UpdateFast(player);
}
Now, just hook it in our hack thread.

Hook in thread.
C++:
octo_hook((void*)getAbsoluteAddress(0x507AE8), (void*)PlayerScript_UpdateFast, (void**)&old_PlayerScript_UpdateFast);
That's it! You can now call whatever you desire in your update function. Have Fun! (ill leave the update function in the source code I provide, just in case anyone is going to use it).

Section 6: Using Headers for Offsets and Hook Android Functions (optional)

Using headers for things such as offsets or hook functions is mainly just for maintaining clean code in your main.cpp.

Lets make an offset header. It generally makes it easier to update offsets if they are in one file only in order.

Offsets Header
C++:
#ifndef OFFSETS_H
#define OFFSETS_H

namespace Offsets {
    enum Offsets {
  
        CanShootOffset = 0x4ED460,
        getGrenadesLeftOffset = 0x8FD818,
        get_fieldOfViewOffset = 0x8FD818,
        PlayerScriptUpdateFastOffset = 0x507AE8

    };
}

#endif
Now, we can include our header, and replace our hook offsets with those in the header.

Your hooks should now look like this:

Hooks
C++:
octo_hook((void*)getAbsoluteAddress(Offsets::getGrenadesLeftOffset), (void*)getGrenadesLeft, (void**)&old_getGrenadesLeft);
octo_hook((void*)getAbsoluteAddress(Offsets::CanShootOffset), (void*)CanShoot, (void**)&old_CanShoot);
octo_hook((void*)getAbsoluteAddress(Offsets::get_fieldOfViewOffset), (void*)get_fieldOfView, (void**)&old_get_fieldOfView);
octo_hook((void*)getAbsoluteAddress(Offsets::PlayerScriptUpdateFastOffset), (void*)PlayerScript_UpdateFast, (void**)&old_PlayerScript_UpdateFast);
Now, lets put our hook functions in a different header to make our main.cpp a bit cleaner.

We can put our booleans, hook functions, and more into the header.

We can also make a function that calls all of our hooks into the hack thread from the header, cleaning up the main.cpp even further.

This is what your hook header should look like:

Hook Header
C++:
bool isAmmoandFirerate = false;
bool isUnlimitedGrenades = false;
bool isFov = false;


bool (*old_CanShoot)(void *instance);
bool CanShoot(void *instance) {
    if (instance != NULL) {
        if (isAmmoandFirerate) {
            return true;
        }
    }
    return old_CanShoot(instance);
}

int (*old_getGrenadesLeft)(void *instance);
int getGrenadesLeft(void *instance) {
    if(instance!=NULL) {
        if (isUnlimitedGrenades) {
            return 3;
        }
    }
    return old_getGrenadesLeft(instance);
}

float (*old_get_fieldOfView)(void *instance);
float get_fieldOfView(void *instance) {
    if (instance != NULL) {
        if (isFov) {
            return 100.0f;
        }
    }
    return old_get_fieldOfView(instance);
}

void(*old_PlayerScript_UpdateFast)(void *player);
void PlayerScript_UpdateFast(void *player) {
    if(player != nullptr){
        //your stuff goes here
    }
    old_PlayerScript_UpdateFast(player);
}

void CallHooks() {
    octo_hook((void*)getAbsoluteAddress(Offsets::getGrenadesLeftOffset), (void*)getGrenadesLeft, (void**)&old_getGrenadesLeft);
    octo_hook((void*)getAbsoluteAddress(Offsets::CanShootOffset), (void*)CanShoot, (void**)&old_CanShoot);
    octo_hook((void*)getAbsoluteAddress(Offsets::get_fieldOfViewOffset), (void*)get_fieldOfView, (void**)&old_get_fieldOfView);
    octo_hook((void*)getAbsoluteAddress(Offsets::PlayerScriptUpdateFastOffset), (void*)PlayerScript_UpdateFast, (void**)&old_PlayerScript_UpdateFast);
}
Dont forget to call CallHooks(); in your hack_thread, otherwise it wont work.

Well, thats pretty much all the basics of hooking, and its quite simple once you get the hang of it. You shouldnt have to patch anything every again! (except maybe nopping anticheat functions).

Sorry for the delay on the tutorials, I was sick, and also was busy with some irl stuff. But im back!

More posts coming soon!



This Tutorial by Octowolve
 
Last edited:

ZixMatrix

Inactive Approved Modder
Aug 27, 2017
111
1,660
193
27
null
thanks for the clean thread
even until now, i still dont know how to do hooking
 

Biteytmods

Platinian
Apr 23, 2022
11
11
3
21
India
LGL modmenu doesn't work with the offsets.h header, I tried with hooks and with hex patching, nothing working, I tried many things but nothing works yet, can anyone help me with this
 
  • Like
Reactions: Slushball

lterronus

Solid & Active Platinian
Oct 27, 2017
77
30
18
30
and for Field Ammo 0xE2 - 0x0001 void Update

bool is Ammo = false;


int (*old_lifeUpdate)(void *instance);
int lifeUpdateMod(void *instance) {
if (instance != NULL) {
if (isLife) {
*(float *) ((uint??****_t) instance + 0xA0) = 9999;
}
}
return old_lifeUpdate(instance);
}


what difference between uint32, uint64 and uintptr

I'm using MSHookfunction but it has no effect on the game



Game Zumbi Fire LIB only arm64
 

Sami1980

Solid & Active Platinian
May 15, 2021
64
11
8
43
Europe
You mentioned Android Studio as one of the requirements but you didn't comment about using it anywhere in the tutorial. When/why would we use it?