An overview of the

After updating a business hall APP (version 7.4.0), it is found that loading the Xposed module will cause the APP crash.

By analyzing the Tombstone log to find the detection point, write Xposed module to bypass stack detection.

Log analysis

The following information is obtained when logs of the Error level are filtered:

A/libc: Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x78c in tid 20120 (c10086.activity), pid 20120 (c10086.activity)
A/DEBUG: pid: 20120, tid: 20120, name: c10086.activity  >>> com.greenpoint.android.mc10086.activity <<<
A/DEBUG: uid: 10480
A/DEBUG: signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x78c
A/DEBUG: Cause: null pointer dereference
A/DEBUG:     r0  00000000  r1  ffb273e6  r2  0000078c  r3  b6a287de
A/DEBUG:     r4  c6049d88  r5  00000000  r6  00000000  r7  c6049d88
A/DEBUG:     r8  b6a287de  r9  0000078c  r10 f72255a0  r11 ffb284d0
A/DEBUG:     ip  f4c7d0a4  sp  00000000  lr  00000000  pc  0000078c
A/DEBUG: backtrace:
A/DEBUG:       #00 pc 0000078c  <unknown>
A/DEBUG:       #01 pc 00000000  <unknown>
E/tombstoned: Tombstone written to: /data/tombstones/tombstone_18
Copy the code

Export/data/tombstones/tombstone_18 to the computer, check the memory stack (method) :

memory near r1 ([stack]): ffb273c4 00000305 00000017 000002f1 00000581 ................ ffb273d4 f4c8125c 00000000 00000000 736f7078 \........... xpos ffb273e4 1d006465 00000000 43746567 7373616c ed...... getClass ffb273f4 656d614e 0000e400 72727563 54746e65 Name.... currentT ffb27404 61657268 00f00064 53746567 6b636174 hread... getStack ffb27414 63617254 00000065 6176616a 6e616c2f Trace... java/lan ffb27424 68542f67 64616572 0000f200 6a4c2928 g/Thread.... ()Lj ffb27434 2f617661 676e616c 7268542f 3b646165 ava/lang/Thread; ffb27444 00009d00 6a4c2928 2f617661 676e616c .... ()Ljava/lang ffb27454 7274532f 3b676e69 00004100 6176616a /String; .A.. java ffb27464 6e616c2f 74532f67 546b6361 65636172 /lang/StackTrace ffb27474 6d656c45 00746e65 000000ef 4c5b2928 Element..... ()[L ffb27484 6176616a 6e616c2f 74532f67 546b6361 java/lang/StackT ffb27494 65636172 6d656c45 3b746e65 00005100 raceElement; .Q.. ffb274a4 14765802 00000000 c6049d88 f4c8125c .Xv.........\... ffb274b4 00000000 f72255a0 c6001aa5 31362f64 .....U".....d/61Copy the code

First by Java. Lang. Thread. CurrentThread object for the current Thread, and then call the getStackTrace obtain an array of StackTraceElement, iterate through the array, call getClassName, determine whether include xposed

positioning

XposedHookThread getStackTrace, print the call stack (function return value) :

findAndHookMethod(Thread.class, "getStackTrace".new XC_MethodHook() {
    @Override
    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
        StackTraceElement[] st = (StackTraceElement[]) param.getResult();
        String sts = "";
        for (StackTraceElement ste : st) {
            sts += ste.toString() + "\n";
        }
        Log.e("StackTrace", sts);
        super.afterHookedMethod(param); }});Copy the code

(if you want to HookStackTraceElement. GetClassName, print the return value)

The log is as follows:

dalvik.system.VMStack.getThreadStackTrace(Native Method)
java.lang.Thread.getStackTrace(Thread.java:1736)
java.lang.reflect.Method.invoke(Native Method)
de.robv.android.xposed.LspHooker.handleHookedMethod(Unknown Source:107)
LspHooker_.getStackTrace(Unknown Source:8)
java.lang.Runtime.nativeLoad(Native Method)
java.lang.Runtime.nativeLoad(Runtime.java:1131)
java.lang.Runtime.loadLibrary0(Runtime.java:1085)
java.lang.Runtime.loadLibrary0(Runtime.java:1008)
java.lang.System.loadLibrary(System.java:1664)
com.secneo.apkwrapper.AW.attachBaseContext(Unknown Source:17)
Copy the code

Can see the caller is Java. Lang. Runtime. NativeLoad, namely so loading when the getStackTrace (in Native layer through JNI invocation)

Analysis of the

Use JEB decompiled classes. Dex, positioning to com. The secneo. Apkwrapper. AW. AttachBaseContext:

@Override  // android.content.ContextWrapper
protected void attachBaseContext(Context context) {
    // ...
    AW.mC = context;
    System.loadLibrary("DexHelper"); H.i(); AW. ᵢ =this;
    super.attachBaseContext(context);
    // ...
}
Copy the code

You can see that libdexhelper. so is loaded (the old version loaded so at

, now attachBaseContext)

As you can see from the load flow of so, the check function is called either in the JNI_OnLoad or in the.init or.init_array segment

Using IDA debugging, it is found that this hardening is done by calling the detection function in JNI_OnLoad, which can be bypassed by Patch or Hook (not the focus of this article, I will not go into details).

Due to the final call Java layer getClassName method, considering the versatility, decided to write Xposed module, bypass stack detection

bypass

XposedHookStackTraceElement getClassName method, to determine whether contains xposed, if include the replacement of the return value is the android OS. The Handler

Note: You need to Hook DexHelper before loading

findAndHookMethod(StackTraceElement.class, "getClassName".new XC_MethodHook() {
    @Override
    protected void afterHookedMethod(MethodHookParam param) throws Throwable {
        String className = (String) param.getResult();
        if(className ! =null && className.contains("xposed")) {
            param.setResult("android.os.Handler");
        }
        super.afterHookedMethod(param); }});Copy the code