cr4n5/XiaoYuanKouSuan

响应体加密算法破解

ZQBCWG opened this issue · 37 comments

写错标题了,应该写解密hook的
Hook结果:
时间:2024-10-12 10:09:23
类名:com.fenbi.android.leo.imgsearch.sdk.utils.e
日志名称:c([B)
参数1
参数类型:[B
参数值:已自动编码字节集数据Base64:
y7KptyngpGugGo8zFqqJgI4JeauTmFnwn4mQw5c5V+x1i3OSrMjoFvQN4NZJwt+AdtBmdY5Mm02nNgpSLyUAHzrxuJdnOvvW9gjK3zCnbYXzxIsuuyal9+Iv5tkhKlOj/Vp4ADoeYazFJ5H0oT1acGGKMMS5xfK76RGykkQ+DVg3/DQOqh9Hn9B2pRzJCehkx64cqg+rhT4WV1iOhJjnjlbXnpp0Xq36IGW6XB/h8mUPliC+HKugTpBlyKnqKwcte9RBFQ96LwFhx3oqRWlxIb7Fu9HCKsPd0ZrHLGYRQCbWwnocdd7PGxtUzGoHxlFXXG28BjetiLmW4L0tDBlB9l+cNkN12LylDIxOgfs/eKwF5XLJgGNX3SprtY875g8ThxQ8SJkOx2jRUlqLBsIv4G7ZziXzvIiUXS8hqvncwfMiIkNJy/G1unZ5FN2Bxnw1zJnS3pHh923iqHLsiIXL1FlDelT+jwgq5kHPhQqoOWqM9orAmJQ32Lb1Q1tO2k9EWZyl8H6bBiAXJme7onQX6pDOjlbRA9YEYwTujZUC9l/+6qX8S+GNalGUd458Lzwr5gCYdMvCkI1nH1OywJhTeAEkt3BxkwykZjTaVpvq4HkKbAGJfqlrgfYz+783pViGGPhdWbFl2Q+dKVXMejBfucL9BzIJ6iiuObNRN48r4tFm4yTKaw==
返回结果类型:[B
返回结果值:已自动编码字节集数据Base64:
H4sIAAAAAAAAAMWVTWvUQBjHv8uc425eJ5NQhBI89KAtttWD9TAms9vodCbOTKxl2ZsVrGApWBCl4MHicXsXv02z+jGcTJOtRaFBpDmF/Od5+T3/PEwmoHi2kq0rAWIA7QiiKPSh60I38JCHgAW42iZiUxIdMAGlfq5kIPYCB/lehHzLSPfwDtH51dHBz9mb8++fq5OT6vh0/mFWvXtbHXzSVfALrLDYFFSHbStVyHg4pITf4ozmjAxGT1LOFGFqkDKjjzGlROwNncgNHRh4eGRj6KLB02IMLnquEZZhpkxJVlI6bVAf5izhJVMgdiwgCR1dCrYFNMSYqIRLtZHXzAjatpbJS7zzYLWe8Bo3Cp4zVTsA/ealmd21z7+dVq/3f3x8NT8+m8/eV1++VmeHOkWUlGzsFcT0f14SqXLOEgOohZQLQVKVNHzpguy3YAniRxOQZ0asUQ3AH3h1tjFR4zju1laai5QSu3afyd36A4LbjXnLjVAb1x7XXXTAY+2awqqUpptMRV6oNnBXcDZevyJdTgeS1btry/fvgKl1Aet0hYUtq9sbq9uVNWxZnSvGLl0Hu/QfYb3OW4AWtL056/8DbNAbbdCZ9q87e6NrADuz+i2s15uxYVdYv/+LC3VlXVyyjt/bFkRdYaMWNrx5Y3WJssiwIlnzc5tOfwFAWv+reQgAAA==
调用堆栈:
at qN.pu.ka.wOMKBb.TY.rwM.XposedBridge$LegacyApiSupport.handleBefore(Unknown Source:24)
at J.callback(Unknown Source:179)
at com.fenbi.android.leo.utils.r2.c(SourceFile:1)
at com.fenbi.android.leo.utils.r2.a(SourceFile:13)
at com.fenbi.android.leo.webapp.secure.commands.DataDecryptCommand$execute$1$decryptData$1.invokeSuspend(SourceFile:24)
at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(SourceFile:12)
at kotlinx.coroutines.u0.run(SourceFile:129)
at kotlinx.coroutines.internal.n$a.run(SourceFile:4)
at c50.j.run(SourceFile:3)
at kotlinx.coroutines.scheduling.CoroutineScheduler.P(SourceFile:1)
at kotlinx.coroutines.scheduling.CoroutineScheduler$c.d(SourceFile:15)
at kotlinx.coroutines.scheduling.CoroutineScheduler$c.p(SourceFile:29)
at kotlinx.coroutines.scheduling.CoroutineScheduler$c.run(SourceFile:1)
解密后对应JSON:{"pkIdStr":"609689746226253838","otherUser":{"userId":351843984,"userName":"告诉你坝啥是压力","avatarUrl":"https://leo-online.fbcontent.cn/leo-gallery/19271653af0a628.jpg","userPendantUrl":null},"otherWinCount":1,"selfWinCount":0,"targetCostTime":86000,"examVO":{"pkIdStr":"609689746226253838","pointId":64,"pointName":"20以内的数比大小","ruleType":0,"questionCnt":10,"correctCnt":0,"costTime":0,"questions":[{"id":0,"examId":609689746226253838,"content":"12\\circle0","answer":">","userAnswer":null,"answers":[">"],"status":0,"script":null,"wrongScript":null,"ruleType":"COMPARE"},{"id":1,"examId":609689746226253838,"content":"6\\circle2","answer":">","userAnswer":null,"answers":[">"],"status":0,"script":null,"wrongScript":null,"ruleType":"COMPARE"},{"id":2,"examId":609689746226253838,"content":"7\\circle10","answer":"<","userAnswer":null,"answers":["<"],"status":0,"script":null,"wrongScript":null,"ruleType":"COMPARE"},{"id":3,"examId":609689746226253838,"content":"18\\circle1","answer":">","userAnswer":null,"answers":[">"],"status":0,"script":null,"wrongScript":null,"ruleType":"COMPARE"},{"id":4,"examId":609689746226253838,"content":"18\\circle15","answer":">","userAnswer":null,"answers":[">"],"status":0,"script":null,"wrongScript":null,"ruleType":"COMPARE"},{"id":5,"examId":609689746226253838,"content":"1\\circle2","answer":"<","userAnswer":null,"answers":["<"],"status":0,"script":null,"wrongScript":null,"ruleType":"COMPARE"},{"id":6,"examId":609689746226253838,"content":"14\\circle3","answer":">","userAnswer":null,"answers":[">"],"status":0,"script":null,"wrongScript":null,"ruleType":"COMPARE"},{"id":7,"examId":609689746226253838,"content":"4\\circle0","answer":">","userAnswer":null,"answers":[">"],"status":0,"script":null,"wrongScript":null,"ruleType":"COMPARE"},{"id":8,"examId":609689746226253838,"content":"2\\circle14","answer":"<","userAnswer":null,"answers":["<"],"status":0,"script":null,"wrongScript":null,"ruleType":"COMPARE"},{"id":9,"examId":609689746226253838,"content":"9\\circle7","answer":">","userAnswer":null,"answers":[">"],"status":0,"script":null,"wrongScript":null,"ruleType":"COMPARE"}],"updatedTime":0}}
最终数据以gzip解码,目前思路是反射调用方法解密在模拟输入答案或重新加密后直接发包
相较于xmexg/xyks#9的重新处理,hook这个传出的值我个人觉得更好

ios
+[DataEncryptor translateData:]

一个非常恶心的亦或算法

@ZQBCWG 能分享一下你的脚本吗?

@ZQBCWG 能分享一下你的脚本吗?

@xmexg
重新做了新的,直接调用libContentEncoder.so解密
编译成dex即可直接食用
这回是真破解了
纯root机MT管理器+Termux连电脑都不用碰
完美薄纱,部分思路来源于ChatGPT

package com.fenbi.android.leo.imgsearch.sdk.utils;
import java.util.Base64;
import java.util.zip.GZIPInputStream;
import java.io.ByteArrayInputStream;
public class e {
    static {
        System.loadLibrary("ContentEncoder");
    }
    public static native byte[] c(byte[] data);
    public static byte[] a(byte[] data) throws Exception {
        if (data == null || data.length == 0) {
            return null;
        }
        byte[] decodedData = b(data);
        try (ByteArrayInputStream bais = new ByteArrayInputStream(decodedData);
             GZIPInputStream gzipIn = new GZIPInputStream(bais)) {
            return gzipIn.readAllBytes(); 
        }
    }
    public static byte[] b(byte[] data) {
        return c(data);  // 调用 native 库
    }
    public static void main(String[] args) {
        if (args.length == 0) {
            System.out.println("传入命令行参数");
            return;
        }
        try {
            byte[] input = Base64.getDecoder().decode(args[0]);
            byte[] output = a(input);
            if (output != null) {
                System.out.println(new String(output));
            } else {
                System.out.println("解密失败");
            }
        } catch (Exception e) {
            System.out.println("发生错误: " + e.getMessage());
            e.printStackTrace();
        }
    }
}
export LD_LIBRARY_PATH=[放libContentEncoder.so的文件夹路径]:$LD_LIBRARY_PATH
dalvikvm -cp [编译的dex] com.fenbi.android.leo.imgsearch.sdk.utils.e [加密的Base64]

还是要hook拿到解密后的数据才行吗?

还是要hook拿到解密后的数据才行吗?

抓包拿到的那些乱码base64编码就行了

还是要hook拿到解密后的数据才行吗?

抓包拿到的那些乱码base64编码就行了

libContentEncoder.so是Linux的库吧?有没有Windows版本的?

还是要hook拿到解密后的数据才行吗?

抓包拿到的那些乱码base64编码就行了

libContentEncoder.so是Linux的库吧?有没有Windows版本的?

这个so解包就有了啊

还是要hook拿到解密后的数据才行吗?

抓包拿到的那些乱码base64编码就行了

libContentEncoder.so是Linux的库吧?有没有Windows版本的?

在小猿口算的apk里,dalvikvm要在Android上运行
我用手机搞的,没有想过其他平台

还是要hook拿到解密后的数据才行吗?

抓包拿到的那些乱码base64编码就行了

libContentEncoder.so是Linux的库吧?有没有Windows版本的?

这个so解包就有了啊

可以的,虽然说没有反编译APK,但是当压缩包开居然有这好东西
屏幕截图 2024-10-12 142843

还是要hook拿到解密后的数据才行吗?

抓包拿到的那些乱码base64编码就行了

libContentEncoder.so是Linux的库吧?有没有Windows版本的?

这个so解包就有了啊

可以的,虽然说没有反编译APK,但是当压缩包开居然有这好东西 屏幕截图 2024-10-12 142843

因为apk没加壳(

你们能用这个修改试题答案吗?
我hook了调用ContentEncoder的协程(com.fenbi.android.leo.webapp.secure.commands.DataDecryptCommand$execute$1$decryptData$1)内的invokeSuspend方法, 还是不能修改答案
https://github.com/xmexg/xyks/tree/master/frida/matchV2_byDataDecryptCommand

你们能用这个修改试题答案吗? 我hook了调用ContentEncoder的协程(com.fenbi.android.leo.webapp.secure.commands.DataDecryptCommand$execute$1$decryptData$1)内的invokeSuspend方法, 还是不能修改答案 https://github.com/xmexg/xyks/tree/master/frida/matchV2_byDataDecryptCommand

抓包改在加密回去不就可以了

谢谢提供!!

你们能用这个修改试题答案吗? 我hook了调用ContentEncoder的协程(com.fenbi.android.leo.webapp.secure.commands.DataDecryptCommand$execute$1$decryptData$1)内的invokeSuspend方法, 还是不能修改答案 https://github.com/xmexg/xyks/tree/master/frida/matchV2_byDataDecryptCommand

抓包改在加密回去不就可以了

佬,libContentEncoder.so 中是否有加密方法呢?

你们能用这个修改试题答案吗? 我hook了调用ContentEncoder的协程(com.fenbi.android.leo.webapp.secure.commands.DataDecryptCommand$execute$1$decryptData$1)内的invokeSuspend方法, 还是不能修改答案 https://github.com/xmexg/xyks/tree/master/frida/matchV2_byDataDecryptCommand

抓包改在加密回去不就可以了

佬,libContentEncoder.so 中是否有加密方法呢?

有加密方法, 目前还解不开so层的加密
隔壁有解libRequestEncoder.so的讨论xmexg/xyks#5

你们能用这个修改试题答案吗? 我hook了调用ContentEncoder的协程(com.fenbi.android.leo.webapp.secure.commands.DataDecryptCommand$execute$1$decryptData$1)内的invokeSuspend方法, 还是不能修改答案 https://github.com/xmexg/xyks/tree/master/frida/matchV2_byDataDecryptCommand

抓包改在加密回去不就可以了

佬,libContentEncoder.so 中是否有加密方法呢?

有加密方法, 目前还解不开so层的加密

隔壁有解libRequestEncoder.so的讨论xmexg/xyks#5

那看来目前最好的做法就是获得解密后的答案adb模拟输入了

你们能用这个修改试题答案吗? 我hook了调用ContentEncoder的协程(com.fenbi.android.leo.webapp.secure.commands.DataDecryptCommand$execute$1$decryptData$1)内的invokeSuspend方法, 还是不能修改答案 https://github.com/xmexg/xyks/tree/master/frida/matchV2_byDataDecryptCommand

抓包改在加密回去不就可以了

佬,libContentEncoder.so 中是否有加密方法呢?

有加密方法, 目前还解不开so层的加密

隔壁有解libRequestEncoder.so的讨论xmexg/xyks#5

那看来目前最好的做法就是获得解密后的答案adb模拟输入了

最好的是修改判断逻辑的js文件

你们能用这个修改试题答案吗? 我hook了调用ContentEncoder的协程(com.fenbi.android.leo.webapp.secure.commands.DataDecryptCommand$execute$1$decryptData$1)内的invokeSuspend方法, 还是不能修改答案 https://github.com/xmexg/xyks/tree/master/frida/matchV2_byDataDecryptCommand

抓包改在加密回去不就可以了

佬,libContentEncoder.so 中是否有加密方法呢?

有加密方法, 目前还解不开so层的加密 隔壁有解libRequestEncoder.so的讨论xmexg/xyks#5

这个方法不是用来加密的吗
改一下我那个java的逻辑和调用函数不就行了

invoke-virtual {v0, v1}, Lcom/fenbi/android/leo/utils/r2;->b([B)[B
move-result-object v0

你们能用这个修改试题答案吗? 我hook了调用ContentEncoder的协程(com.fenbi.android.leo.webapp.secure.commands.DataDecryptCommand$execute$1$decryptData$1)内的invokeSuspend方法, 还是不能修改答案 https://github.com/xmexg/xyks/tree/master/frida/matchV2_byDataDecryptCommand

抓包改在加密回去不就可以了

佬,libContentEncoder.so 中是否有加密方法呢?

用这个加密回去完全可以

package com.fenbi.android.leo.imgsearch.sdk.utils;

import java.util.Base64;
import java.util.zip.GZIPOutputStream;
import java.io.ByteArrayOutputStream;

public class e {
    static {
        System.loadLibrary("ContentEncoder");
    }
    public static native byte[] c(byte[] data);
    public static byte[] a(byte[] data) throws Exception {
        if (data == null || data.length == 0) {
            return null;
        }
        byte[] compressedData = compress(data);
        return b(compressedData);
    }
    public static byte[] compress(byte[] data) throws Exception {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try (GZIPOutputStream gzipOut = new GZIPOutputStream(baos)) {
            gzipOut.write(data);
        }
        return baos.toByteArray();
    }
    public static byte[] b(byte[] data) {
        return c(data);  // 调用 native 库
    }
    public static void main(String[] args) {
    if (args.length == 0) {
        System.out.println("传入命令行参数");
        return;
    }
    try {
        byte[] output = a(args[0].getBytes());
        if (output != null) {
            StringBuilder result = new StringBuilder();
            result.append(Base64.getEncoder().encodeToString(output));
            System.out.println(result.toString());
        } else {
            System.out.println("加密失败");
        }
    } catch (Exception e) {
        System.out.println("发生错误: " + e.getMessage());
        e.printStackTrace();
    }
}
}
# leo export LD_LIBRARY_PATH=/cust/leo/lib:$LD_LIBRARY_PATH
# leo dalvikvm -cp /cust/leo/enc/Z.dex com.fenbi.android.leo.imgsearch.sdk.utils.e EncryptTestABC
y7KptyngpGugGjlrEO/37L7Hj00hCkPcvhqR8hhHrUxYPQ==
# leo dalvikvm -cp /cust/leo/Z.dex com.fenbi.android.leo.imgsearch.sdk.utils.e y7KptyngpGugGjlrEO/37L7Hj00hCkPcvhqR8hhHrUxYPQ==
EncryptTestABC

找到问题了, 无法修改是因为异步导致js还没收到py传来的新值就return了, 已在 https://github.com/xmexg/xyks/tree/master/frida/matchV2_byDataDecryptCommand 修复

你们能用这个修改试题答案吗? 我hook了调用ContentEncoder的协程(com.fenbi.android.leo.webapp.secure.commands.DataDecryptCommand$execute$1$decryptData$1)内的invokeSuspend方法, 还是不能修改答案 https://github.com/xmexg/xyks/tree/master/frida/matchV2_byDataDecryptCommand

抓包改在加密回去不就可以了

佬,libContentEncoder.so 中是否有加密方法呢?

用这个加密回去完全可以

package com.fenbi.android.leo.imgsearch.sdk.utils;



import java.util.Base64;

import java.util.zip.GZIPOutputStream;

import java.io.ByteArrayOutputStream;



public class e {

    static {

        System.loadLibrary("ContentEncoder");

    }

    public static native byte[] c(byte[] data);

    public static byte[] a(byte[] data) throws Exception {

        if (data == null || data.length == 0) {

            return null;

        }

        byte[] compressedData = compress(data);

        return b(compressedData);

    }

    public static byte[] compress(byte[] data) throws Exception {

        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        try (GZIPOutputStream gzipOut = new GZIPOutputStream(baos)) {

            gzipOut.write(data);

        }

        return baos.toByteArray();

    }

    public static byte[] b(byte[] data) {

        return c(data);  // 调用 native 库

    }

    public static void main(String[] args) {

    if (args.length == 0) {

        System.out.println("传入命令行参数");

        return;

    }

    try {

        byte[] output = a(args[0].getBytes());

        if (output != null) {

            StringBuilder result = new StringBuilder();

            result.append(Base64.getEncoder().encodeToString(output));

            System.out.println(result.toString());

        } else {

            System.out.println("加密失败");

        }

    } catch (Exception e) {

        System.out.println("发生错误: " + e.getMessage());

        e.printStackTrace();

    }

}

}
# leo export LD_LIBRARY_PATH=/cust/leo/lib:$LD_LIBRARY_PATH

# leo dalvikvm -cp /cust/leo/enc/Z.dex com.fenbi.android.leo.imgsearch.sdk.utils.e EncryptTestABC

y7KptyngpGugGjlrEO/37L7Hj00hCkPcvhqR8hhHrUxYPQ==

# leo dalvikvm -cp /cust/leo/Z.dex com.fenbi.android.leo.imgsearch.sdk.utils.e y7KptyngpGugGjlrEO/37L7Hj00hCkPcvhqR8hhHrUxYPQ==

EncryptTestABC

谢谢分享,因为没有系统学过安卓,目前还在慢慢折腾

sample.zip
chmod 755 xykscpp ; ./xykscpp sampledata

sample.zip chmod 755 xykscpp ; ./xykscpp sampledata

佬 你的源码可不可以发一下
我在mac上跑不了层主提供的java代码

brew install openjdk-21-jdk

brew install openjdk-21-jdk

macOS下没有dalvikvm

brew install openjdk-21-jdk

macOS下没有dalvikvm

javac编译成class一样可以运行

brew install openjdk-21-jdk

macOS下没有dalvikvm

javac编译成class一样可以运行

可以写的详细一些吗 实在没有接触过这些 不是很了解

brew install openjdk-21-jdk

macOS下没有dalvikvm

javac编译成class一样可以运行

可以写的详细一些吗 实在没有接触过这些 不是很了解

javac Java源代码的文件

然后把文件根据包名移到对应目录在

export LD_LIBRARY_PATH=[放libContentEncoder.so的文件夹路径]:$LD_LIBRARY_PATH
java com.fenbi.android.leo.imgsearch.sdk.utils.e [加密的Base64]

或者不想搞来搞去就用手机termux吧

brew install openjdk-21-jdk

macOS下没有dalvikvm

javac编译成class一样可以运行

可以写的详细一些吗 实在没有接触过这些 不是很了解

javac Java源代码的文件

然后把文件根据包名移到对应目录在

export LD_LIBRARY_PATH=[放libContentEncoder.so的文件夹路径]:$LD_LIBRARY_PATH
java com.fenbi.android.leo.imgsearch.sdk.utils.e [加密的Base64]

或者不想搞来搞去就用手机termux吧

第一步javac报错 没有class e

brew install openjdk-21-jdk

macOS下没有dalvikvm

javac编译成class一样可以运行

可以写的详细一些吗 实在没有接触过这些 不是很了解

javac Java源代码的文件

然后把文件根据包名移到对应目录在

export LD_LIBRARY_PATH=[放libContentEncoder.so的文件夹路径]:$LD_LIBRARY_PATH
java com.fenbi.android.leo.imgsearch.sdk.utils.e [加密的Base64]

或者不想搞来搞去就用手机termux吧

第一步javac报错 没有class e

javac e.java
把文件名改成e

brew install openjdk-21-jdk

macOS下没有dalvikvm

javac编译成class一样可以运行

可以写的详细一些吗 实在没有接触过这些 不是很了解

javac Java源代码的文件

然后把文件根据包名移到对应目录在

export LD_LIBRARY_PATH=[放libContentEncoder.so的文件夹路径]:$LD_LIBRARY_PATH
java com.fenbi.android.leo.imgsearch.sdk.utils.e [加密的Base64]

或者不想搞来搞去就用手机termux吧

第一步javac报错 没有class e

javac e.java 把文件名改成e

那个第一行的package我这里没有
话说不能把整个过程抽象出来吗 目前是不是还要hook
其实可以直接抓包 然后用上面xxzzddxzd的成果解密出结果 跳过hook
主要还是ios上面不好调试

sample.zip chmod 755 xykscpp ; ./xykscpp sampledata

brew install openjdk-21-jdk

macOS下没有dalvikvm

javac编译成class一样可以运行

可以写的详细一些吗 实在没有接触过这些 不是很了解

javac Java源代码的文件

然后把文件根据包名移到对应目录在

export LD_LIBRARY_PATH=[放libContentEncoder.so的文件夹路径]:$LD_LIBRARY_PATH
java com.fenbi.android.leo.imgsearch.sdk.utils.e [加密的Base64]

或者不想搞来搞去就用手机termux吧

第一步javac报错 没有class e

javac e.java 把文件名改成e

那个第一行的package我这里没有 话说不能把整个过程抽象出来吗 目前是不是还要hook 其实可以直接抓包 然后用上面xxzzddxzd的成果解密出结果 跳过hook 主要还是ios上面不好调试

sample.zip chmod 755 xykscpp ; ./xykscpp sampledata

那就用sample.zip这个,你mac可以用吧

可以用
如果有源代码 我写起来会舒服很多
现在只有一个可执行文件
本来想看层主代码可否移植的

可以用 如果有源代码 我写起来会舒服很多 现在只有一个可执行文件 本来想看层主代码可否移植的

那就问他要代码吧
我这个是基于抽离java方法和so执行的,so只有arm64和arm架构

现在只有一个可执行文件

如果你是mac可以使用IDEA 使用springboot自行搭建服务端测试 目前是关于sign的,可以自行根据上面的方法替换
参考这里

可以用 如果有源代码 我写起来会舒服很多 现在只有一个可执行文件 本来想看层主代码可否移植的

@imofelrj 如果你只需要获得抓包后的解码,只需要参考
xmexg/xyks