使用Xposed绕过某加固的Xposed堆栈检测

查看 147|回复 10
作者:XhyEax   
概述
更新某营业厅app(版本号7.4.0)后,发现加载Xposed模块会导致app crash。
通过分析Tombstone日志找到检测点,编写Xposed模块绕过堆栈检测。
日志分析
过滤Error级别的日志,得到以下信息:
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
导出/data/tombstones/tombstone_18到电脑,查看内存(方法栈):
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/61
首先通过java.lang.Thread.currentThread获得当前线程对象,然后调用getStackTrace获得StackTraceElement数组,遍历该数组,调用getClassName,判断是否包含xposed
定位
XposedHookThread.getStackTrace,打印调用栈(函数返回值):
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);
    }
});
(如果要HookStackTraceElement.getClassName,打印返回值即可)
日志如下:
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)
可以看到调用者是java.lang.Runtime.nativeLoad,即so加载时调用(在Native层通过JNI调用getStackTrace)
分析
使用JEB反编译classes.dex,定位到com.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);
    // ...
}
可以看到加载的是libDexHelper.so(旧版本是在加载,现在改到attachBaseContext了)
由so的加载流程可知,检测函数的调用要么是在JNI_OnLoad,要么是在.init或.init_array段
使用IDA动态调试,发现该加固是在JNI_OnLoad中调用检测函数(并非本文重点,就不详细介绍了)
由于最终还是要调用Java层的getClassName方法,考虑到通用性,决定编写Xposed模块,绕过堆栈检测
绕过
XposedHookStackTraceElement.getClassName方法,判断是否包含xposed,如果包含则替换返回值为android.os.Handler
注意:需要在DexHelper加载前Hook
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);
    }
});

是在, 堆栈

无闻无问   


无闻无问 发表于 2021-10-8 07:04
dalvik.system.VMStack.getThreadStackTrace(Native Method)
java.lang.Thread.getStackTrace(Thread.java ...

这个是堆栈打印,as的logcat能输出,另外xposed、frida都可以打印堆栈
MT的注入能打印指定类指定方法的输出,但是没办法输出堆栈调用
我记得酷安有个logcat的软件,你可以试试
vipiu   

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)
大神,这些日志是怎么打印的,工具还是什么?求指教,求分享!
我用mt注入,没这种函数执行流程…
delta314   

厉害了,感谢分享!
delta314   

电信营业厅也打不开,xp冲突,不知道是不是手机问题
木子小每文   

确实是好帖子,不过对于小白来说还有点难啊,目前所知,好些个银行类的装了xp也是进不去
咔c君   

大老牛逼了~~~~~~
asdfliuchen   

不错学习了
goda   

大神,嘀嗒出行也检测了,能不能帮忙出个防嘀嗒检测的工具。
凛冬已至   

谢谢分享,学习了
您需要登录后才可以回帖 登录 | 立即注册

返回顶部