hanan
hanan

Reputation: 632

Is this native code possible for further static analysis?

I was trying to reverse engineer a native lib code in an android app. the .so contains many functions. But the function sUQWWyTBEs() was referred in the Java code. I was curious how this function works.

This function returns a string like this 47fjlkj843h9asjklj94kljfsad93j4l2715943hasd... but what I wanted is that how this value was generated or returned.

the code of the function sUQWWyTBEs() decompiled with Ghidra:

*************************************************************
                             *                           FUNCTION                          
                             *************************************************************
                             undefined  __cdecl  Myapp_sUQWWyTBEs()
             undefined         w0:1           <RETURN>
             longlong *        x0:8           param_1
                             Myapp_sUQWWyTBEs XREF[2]:     Entry Point (*) , 00101350   
        00100e44 08  00  40  f9    ldr        x8, [param_1 ]
        00100e48 01  00  00  b0    adrp       x1, s_c7a584936712f32773d3d0a_00101000           ; = "c7a584936712f32773d3d0a"
        00100e4c 21  60  08  91    add        x1, x1, #0x218
        00100e50 02  9d  42  f9    ldr        x2, [x8, #0x538 ]
        00100e54 40  00  1f  d6    br         x2

in my understanding, I have made the static analysis as like following:

00100e44 08 00 40 f9 ldr x8, [param_1 ]

load the value at memory address param_1 into register x8.

0100e48 01 00 00 b0 adrp x1, s_c7a584936712f32773d3d0a_00101000

sets register x1 to 0x101000.

00100e4c 21 60 08 91 add x1, x1, #0x218

adds 0x218 to x1, so it sets x1 to 0x101218.

00100e50 02 9d 42 f9 ldr x2, [x8, #0x538 ]

loads the value at x8 + 0x538 into x2.

00100e54 40 00 1f d6 br x2

and finally branches to the address stored in x2.

with that being said, Here I don't know the memory at address at x2, obviously it initially depends on the value param_1 holds. is there way or how can I refer where param_1 was initialized? I don't know very much about usage of Ghidra or other reverse engineering tools. any one might help would be appreciated.

Upvotes: 0

Views: 450

Answers (1)

Botje
Botje

Reputation: 30840

Assuming this function is declared on the Java side as a native function, param_1 is a JNIEnv*. The Android JNI documentation states:

JNI defines two key data structures, "JavaVM" and "JNIEnv". Both of these are essentially pointers to pointers to function tables.

The code you show thus basically calls the function in the function table at offset 0x538. Assuming you're showing a 64-bit Android program, function pointers are 8 bytes so you need to figure out the 167th function pointer (starting from 0).

Take your copy of jni.h and extract the members of struct JNINativeInterface, number them starting from 0:

0:     void*       reserved0;
1:     void*       reserved1;
2:     void*       reserved2;
3:     void*       reserved3;
4:     jint        (*GetVersion)(JNIEnv *);
...
167:     jstring     (*NewStringUTF)(JNIEnv*, const char*);

So, assuming I did not make any mistakes, the code you are showing calls env->NewStringUTF with s_c7a584936712f32773d3d0a_00101000+0x218 as argument.

I think you can let Ghidra parse jni.h to make those types available. If you then change the type of param_1, that might be sufficient to let Ghidra do this mapping for you and produce a sensible decompilation to C/C++.

Upvotes: 4

Related Questions