I haven’t written a blog for a long time, and I’ve been focusing on the reverse lately. Just scratching the surface so far. The reverse of Android Java layer is relatively simple, mainly is to peel, decompile source code, hook through Xposed. Next, introduce how to debug the source code of hook Native layer, namely the hook SO file.
Application Environment Preparation
First of all, in order to facilitate learning, it is very difficult to hook the third-party app at the beginning, so we create a native project and hook our own project as a learning practice point.
Create the default Native Application
Open as and choose File -> new project -> naive c++ to create a native project that includes c++.
The default Native project helps us implement stringFromJNI, so let’s explore how to hook stringFromJNI and modify its value.
Modify the stringFromJNI method for debugging purposes
As’s default stringFromJNI is only called when the Activity onCreate. For debugging purposes, we add a click event, which is called again after each click and returns a random value.
Java code adds the following method:
binding.sampleText.setOnClickListener {
Log.e("MainActivity", "stringFromJNI")
binding.sampleText.text = stringFromJNI()
}
Copy the code
Modify the native-lib. CPP code:
#include <jni.h> #include <string> using namespace std; int max1(int num1, int num2); #define random(x) rand()%(x) extern "C" JNIEXPORT jstring JNICALL Java_com_noober_naticeapplication_MainActivity_stringFromJNI( JNIEnv* env, jobject /* this */) { int result = max1(random(100), random(100)); string hello = "Hello from C++"; string hello2 = hello.append(to_string(result)); return env->NewStringUTF(hello2.c_str()); } int max1(int num1, int num2) {// local variable declare int result; if (num1 > num2) result = num1; else result = num2; return result; }Copy the code
The code is very simple, I believe not c++ students can understand, is random input two numbers, take the small bit of the concatenation after “Hello from c++”, and return. The main purpose is to make the return content dynamic every time we click.
Modify the androidManifest file
Add the following two lines of code to the Application:
android:extractNativeLibs="true"
android:debuggable="true"
Copy the code
Android :debuggable: enables us to debug apK, if it is a third party has packaged the app, we need to modify its manifest file, add this line of code, and then repackage, otherwise can not debug so.
Android: extractNativeLibs: a lot of people at the time of debugging found IDA pro everything is normal, but it hasn’t been loaded our libnative – lib. So, because of the lack of this line of code. If it is not added, so may directly load its own base.apk, resulting in IDA Pro unable to recognize.
Modify CMakeLists. TXT
Add the following code in cMakelists. So file generation path, so that after compilation, you can find the produced SO file in the main-cp-jnilibs directory.
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/jniLibs/${ANDROID_ABI})
Copy the code
Compile and run, get so
After the above work is done, it will be compiled and run directly, and 4 SO files will be generated at the same time. We will get the corresponding SO used when the mobile phone is running for hook. I’m using libnative lib.so in the arm64-v8a directory.
Hook environment preparation
- System: Windows 10 64-bit
- Tools IDA Pro 7.5
- Java8 environment
- Android SDK tools and ADB tools
- Libnative -lib.so in arm64-v8a
- The android:
Hook using IDA Pro
Adb with mobile ready
- First, find IDA Pro’s DBGSRV folder, which contains many server files
64 stands for 64 bits, otherwise it is 32 bits, and we choose according to the instruction set of so that we need to debug. Since I’m debugging arm64-v8A, I’m going to select android_server64. After connecting to the real machine, open CMD and enter the following command:
Adb push "\\Mac\Home\Desktop\IDA PRO 7.5 (x86, x64, ARM, ARM64)\ DBGSRV \android_server64" /data/local/ TMPCopy the code
-
If it is a real machine, su is required, emulator does not
Su # machineCopy the code
-
Modify the permissions
chmod 777 /data/local/tmp/android_server64 Copy the code
-
run
/data/local/tmp/android_server64 Copy the code
-
Open a new CMD and perform ADB locally for port forwarding
adb forward tcp:23946 tcp:23946 Copy the code
IDA Pro work preparation
-
Open IDA Pro, because our SO is 64-bit, so open ida64.exe. Click New and select libnative-lib.so.
-
Select the debugger – select the debugger
- Select Remote ARM Linux/Android Debugger
- Click on the debugger – the debugger options
Check Suspend on Process Entry point, suspending at breakpoint
- Click on the debugger – Process options
Set hostname to localhost
- Find the exports label, CTRL + F, search for the Java keyword and find the function we want to hook.
- Double-click to open and press F5 to disassemble. So you can see the C ++ code after disassembly. Then we can add any breakpoints to debug.
-
Run adb to enter the debug state, that is, to open the launch activity of the app we want to debug.
adb shell am start -D -n com.noober.naticeapplication/com.noober.naticeapplication.MainActivity Copy the code
-
Click debugger-Attach to Process
Select the process we want to debug.
-
Adb executes the following command to associate the running so with the local SO to be debugged.
JDB - connect com. Sun. Jdi. SocketAttach: hostname = 127.0.0.1 port = 8700Copy the code
-
At this time, IDA card is in the position of LIBc. so, click “Continue”, and the following interface will pop up. Associate SO to the local and select same. If it doesn’t pop up, open all the loaded SO by pressing CTRL + S and find our libnative-lib.so
- The breakpoint is automatically entered.
Use IDA Pro for debugging
IDA Pro common debugging shortcut keys
- F2 the breakpoint
- F7 Step in
- F8 single step past
- F9 executes to the next breakpoint
- G to the function address
- Debugger- Debugger windows-locals looks at variables
debug
- A brief analysis of the disassembly code shows that the return value is V5, passed f8, and executed on the line before return. Open locals to get the values of all variables.
- Copy the bytes address 0x7FFE2CDEB9LL, switch to the code interface, and enter the shortcut key G to jump to the address. So we get the data from memory, and you can see that the value returned is “Hello from c++89.”
- Of course, we can also modify the value directly in locals, so that we can hook so to dynamically modify the data.
The end of the
The above is all the content of the article, mainly for students who have not been exposed to SO debugging to learn, as well as their own records. As for how to further so hook, I will continue to share after the later research.