A new method to write CModule in Frida for hacking Android applications
Why a new method
I introduced how to use official CModule in Frida at last post. But I think it have some weaknesses to improve.
- It can use C, this make us need to use ugly mangled function name when we want to call C++ functions
- We need to embed C code in to Typescript code. So we can not find the error line quickly when C code does not pass compilation.
New method
In here, I will introduce a new method to write a CModule in Frida. Please note, this method only work with Android platform, and I only tested on Arm32 archtecture. In theory, Arm64 archtecture should work either. This method has the following stage:
- Write a .so using Android NDK
- Convert .so to a typescript module to hold all informations we needs when we want to load the .so
- Load .so in Frida and call one function in it.
I tried to load .so using Module.load(), but this method always failed on Android platform. I think it because the restrictions of new versions Android, I used Android 10.
Write a .so using Android NDK
First, we write a .so in C++, the following is the code in file main.cpp
1 | ////////////////////////////////////////////////// |
Line 3-4, declares functions in Frida. And we need to add a options in our Android.mk
LOCAL_ALLOW_UNDEFINED_SYMBOLS := true
Without this options, we can not pass the link because the compiler can not find these functions.
Line 8-13, declares functions in libMyGame.so. We can use C++ syntax here, and make our code more readable. And we need to declare entire C++ class in libMyGame.so, just declare the functions we want to call.
Line 16-23, defines a function for Typescript code to call. It just does the same thing as we did in previous post, print out cocos2d application version string.
And we need to set correct options in Application.mk.
APP_STL := gnustl_static
APP_ABI=armeabi-v7a
If these options is not compatible with libMyGame.so, our function will crush. Frankly, I tried all APP_STL
variables, and finally find only gnustl_static
is compatible with this game.
Generate a Typescript file hold all information when loading
I wrote a python script. This python scripts use lief to parse .so file to get the following informations.
- name, machine type
- segments
Only care about segments with load type, discard other segments - export symbols
- relocations
- ctors
This is a list of functions, and we need to call these functions after loading. - dtors
These functions should be called when unload the .so file, and I have not write code for it now.
This script generates final Typescript file using jinja2. The name of the template file is so2tsmodule.jinja
Load .so file
I wrote a method, named loadSo
, in file soutils.ts. Method prototype as follows
1 | export function loadSo(info:SoInfoType, syms?:{[key:string]:NativePointer}, libs?:string[]):LoadSoInfoType |
- info is a object we defined in the Typescript file we generated in the last stage.
- syms is a list of symbols we pass to the load modules
- libs is a list of library names. This method try to find symbols in these libraries.
We need to accomplish the following stages when load .so file:
- Allocate buffer, and set the permission to
rwx
- Write all segments need to load to the buffer
- Create a variable to hold all export symbols in the .so file
- Handle relocations
This stage is a little complicated. We need to find symbol addresses, and write correct number in the correct address accord to different recolcaion type. - Call ctors
Run the function in the .so file
The following is the Typescript code to do this. And it’s in file sotest.ts
1 | let soname ="libMyGame.so" |
Line 3-12, loads the .so file.
We need to import generated Typescript file as a module using the following code
1 | import * as mysoinfo from './mysoinfo' |
Line 6-7 lists all functions defined in Frida and will be called in C++ code
Line 10 lists all libraries contained the functions will be called in C++ code
Line 16-17 calls function fun
in the C++ code.
Compile & run
I wrote a makefile for compilation.
We can use the following command to compile.
1 | $ make build_sotest |
And use the following command to run.
1 | $ make run |
If everything is OK, we can see the output as follows
Hello World from so
cocos2d application version:
1.8.12
Conclusion
All code is in my github.