绕过更新

image-20221015230013403![

frida-ps -Ua  查看包名com.aikucun.akapp
objection -g com.aikucun.akapp explore -P ~/.objection/plugins
android hooking list activities  查看所有Activity
android intent launch_activity com.aikucun.akapp.activity.LoginActivity  跳到登录Activity不过被更新弹窗盖住

image-20221015230116924

jadx反编译搜索"立即更新",直接hook掉show方法

image-20221015225748211

function hook_sig(){
    Java.perform(function(){
        console.log("Entering hook")
		// 干掉弹窗
        Java.use("com.aikucun.akapp.widget.dialog.ConfirmDialog").show.implementation = function(){
            console.log("hook show ")
        }
    })
}
setImmediate(hook_sig)

frida -U -f com.aikucun.akapp -l hook_sig.js --no-pause

image-20221015230152996

抓包

https://zuul.aikucun.com/aggregation-center-facade/api/app/search/product/image/switch

appid 38741001
did 24c29bc14b5e3ddec1bf571c844a7e78
noncestr ae5a5c
timestamp 1665846444
zuul 1
sig c5a0da1284344f608043722f45c85dfd934c0ce7

反编译搜索"sig"

image-20221015230944548

image-20221015231027003

上frida打印参数和返回值

var MXSecurity = Java.use('com.mengxiang.arch.security.MXSecurity')

MXSecurity.signV1.implementation = function (a, b, c) {
    console.log('a: ', a); // url
    console.log('b: ', b); // noncestr
    console.log('c: ', c); // timestamp

    var res = this.signV1(a, b, c);  // 加密返回
    console.log('res: ', res);

    return res
}

image-20221015231154659

IDA打开libmx.so,搜索java发现signV1是静态注册函数

image-20221015231525351

image-20221015231823764

拼接了appid,noncestr,timestamp,secret,url等参数后调用digest函数进行加密,参数分别是JNIEnv,SHA1加密函数,加密内容的bytearray

image-20221015232105626

如果需要还原算法,那么前提得拿到secret盐,可以通过jnitrace或者frida hook native都可以,或者直接使用unidbg黑盒调用。

Jnitrace

pip install jnitrace==3.0.8
jnitrace -l libmx.so -m spawn com.aikucun.akapp --ignore-vm > akc.log

image-20221015235243061

Unidbg

初始化

public class AkuMx1 extends AbstractJni {
    // 初始化一些 apk 常量
    private final AndroidEmulator emulator;
    private final VM vm;
    private final Module module;
    private final DvmClass mxSecurity;

    // APK 路径
    public String apkPath = "C:\\Users\\Administrator\\Downloads\\爱库存5.7.8.apk";
    // so 文件路径
    public String soPath = "unidbg-android/src/test/resources/demo/akc/libmx.so";

    // 加载指定版本的系统库
    private static LibraryResolver createLibraryResolver() {
        return new AndroidResolver(23);
    }

    // 创建 android 模拟器,这里是 32 位的
    private static AndroidEmulator createARMEmulator() {
        return AndroidEmulatorBuilder.for32Bit().build();
    }

    AkuMx1() {
        emulator = createARMEmulator();
        final Memory memory = emulator.getMemory();
        // 设置 sdk版本 23
        memory.setLibraryResolver(createLibraryResolver());

        //创建DalvikVM,可以载入apk,也可以为null
        vm = emulator.createDalvikVM(new File(apkPath));
        // 设置可以调用 jni 函数
        vm.setJni(this);
        // 打印 jni 函数调用具体的 log
        vm.setVerbose(true);

        // 加载 so 文件
        DalvikModule dm = vm.loadLibrary(new File(soPath), true);
        module = dm.getModule();
        // 加载 java 加密函数所在 类
        mxSecurity = vm.resolveClass("com/mengxiang/arch/security/MXSecurity");
    }

    // 关闭模拟器
    private void destroy() throws IOException {
        emulator.close();
        System.out.println("destroy");
    }

    public static void main(String[] args) throws IOException {
        AkuMx1 aku = new AkuMx1();
        aku.run();
        aku.destroy();
    }

    public void run() {
        
    }
}

主动调用

    public void run() {
        String a = "https://zuul.aikucun.com/aggregation-center-facade/api/app/search/product/image/switch?appid=38741001&did=24c29bc14b5e3ddec1bf571c844a7e78&noncestr=af7aff&timestamp=1665849838&zuul=1";
        String b = "af7aff";
        String c = "1665849838";

        DvmObject<?> strRc = mxSecurity.callStaticJniMethodObject(
                emulator,
                "signV1(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
                vm.addLocalObject(new StringObject(vm, a)),
                vm.addLocalObject(new StringObject(vm, b)),
                vm.addLocalObject(new StringObject(vm, c))
        );
        System.out.println("strRc: " + strRc.getValue());
    }

image-20221016000642683

返回值确实空的,使用frida主动调用正常返回

function invoke_sig() {
    Java.perform(function () {
        var MXSecurity = Java.use('com.mengxiang.arch.security.MXSecurity');
        var a = "https://zuul.aikucun.com/aggregation-center-facade/api/app/search/product/image/switch?appid=38741001&did=24c29bc14b5e3ddec1bf571c844a7e78&noncestr=af7aff&timestamp=1665849838&zuul=1";
        var b = "af7aff";
        var c = "1665849838";
        console.log(MXSecurity.signV1(a, b, c));
    })
}

image-20221016004530356

通过jnitrace查看libmx.so的执行流可知需要先执行Java_com_mengxiang_arch_security_MXSecurity_init,即public static final native int init(Context context, boolean z);

    public void run() {
        // 加载 context 上下文对象
        DvmClass Context = vm.resolveClass("android/content/Context");
        DvmObject<?> strRc1 = mxSecurity.callStaticJniMethodObject(
                emulator, "init(Landroid/content/Context;Z;)I;",
                // Context.newObject(null) 初始化对象,参数直接 null
                vm.addLocalObject(Context.newObject(null)),
                // frida hook打印入参为  false
                vm.addLocalObject(DvmBoolean.valueOf(vm,false))
        );
        System.out.println("strRc1: " + strRc1);

        String a = "https://zuul.aikucun.com/aggregation-center-facade/api/app/search/product/image/switch?appid=38741001&did=24c29bc14b5e3ddec1bf571c844a7e78&noncestr=af7aff&timestamp=1665849838&zuul=1";
        String b = "af7aff";
        String c = "1665849838";

        DvmObject<?> strRc2 = mxSecurity.callStaticJniMethodObject(
                emulator,
                "signV1(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
                vm.addLocalObject(new StringObject(vm, a)),
                vm.addLocalObject(new StringObject(vm, b)),
                vm.addLocalObject(new StringObject(vm, c))
        );
        System.out.println("strRc2: " + strRc2.getValue());
    }

image-20221016005619011

SHA256 是 android里的,java 里是 SHA-256,我们需要重写该函数

    @Override
    public DvmObject<?> callStaticObjectMethodV(BaseVM vm, DvmClass dvmClass, String signature, VaList vaList) {
        switch (signature) {
            case "java/security/MessageDigest->getInstance(Ljava/lang/String;)Ljava/security/MessageDigest;":
                StringObject type = vaList.getObjectArg(0);

                String name = "";
                if ("\"SHA256\"".equals(type.toString())) {
                    name = "SHA-256";
                } else {
                    name = type.toString();
                    System.out.println("else name: " + name);
                }

                try {
                    return vm.resolveClass("java/security/MessageDigest").newObject(MessageDigest.getInstance(name));
                } catch (NoSuchAlgorithmException e) {
                    throw new IllegalStateException(e);
                }
        }

        return super.callStaticObjectMethodV(vm, dvmClass, signature, vaList);
    }

image-20221016005800985

                if ("\"SHA256\"".equals(type.toString())) {
                    name = "SHA-256";
                } else if ("\"SHA1\"".equals(type.toString())) {
                    name = "SHA-1";
                } else {
                    name = type.toString();
                    System.out.println("else name: " + name);
                }

image-20221016010003383