Featured image of post 某音app模拟生成7神参数

某音app模拟生成7神参数

样本地址: aHR0cHM6Ly93d3cud2FuZG91amlhLmNvbS9hcHBzLzc0NjE5NDg=

ssl pinning 绕过

首先抓包直接打开是没有网络的,我用算法助手的升级版 trustMe 也不行,说明普通的 ssl pinning 是没用的,说明可能是在 so 层做的防护,hook 一下 dlopen,看一下哪些 so 在最前面进行加载的,也不说最前面吧,相对靠前

大名鼎鼎的六神,网上一搜就知道是 libsscronet.so 中对 so 进行的 ssl pinning 校验的,拖到 ida 中分析一下
问一下 ai,对于这种 so,我应该关注哪些函数

进去之后在导入函数中搜一下
SSL_CTX_set_custom_verify 这个函数就很像啊,跟刚才 gpt 跟我说的不能说有点类似,只能说一模一样了,进去看一下

1
2
3
4
5
// attributes: thunk
__int64 SSL_CTX_set_custom_verify()
{
  return __imp_SSL_CTX_set_custom_verify();
}

发现就是个跳板函数,会跳转到 __imp_SSL_CTX_set_custom_verify 这个函数,这个函数继续往下跟发现跟不到个啥了,导入函数,C 语言中应该有相应的代码实现,直接问下 gpt 有没有相关的原型函数

1
2
3
4
5
void SSL_CTX_set_custom_verify(
    SSL_CTX *ctx,
    int mode,
    enum ssl_verify_result_t (*callback)(SSL *ssl, uint8_t *out_alert)
);

其中的这个 mode 一般有以下取值

1
2
3
4
5
SSL_VERIFY_NONE                 // 0x00
SSL_VERIFY_PEER                 // 0x01
SSL_VERIFY_FAIL_IF_NO_PEER_CERT // 0x02
SSL_VERIFY_PEER_IF_NO_OBC       // 0x04
SSL_VERIFY_CLIENT_ONCE          // 0x08

其他的都不重要,知道 mode 为 0 是不进行强校验就够了,也就是说我可以直接 hook 这个函数,返回 0 就可以了,可以使用 frida 脚本,进行 hook 就能够抓包了

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
function hook_dlopen(module_name, fun) {
    var android_dlopen_ext = Module.findExportByName(null, "android_dlopen_ext");
    if (android_dlopen_ext) {
        Interceptor.attach(android_dlopen_ext, {
            onEnter: function (args) {
                var pathptr = args[0];
                if (pathptr) {
                    this.path = (pathptr).readCString();
                    if (this.path.indexOf(module_name) >= 0) {
                        this.canhook = true;
                    }
                }
            },
            onLeave: function (retval) {
                if (this.canhook) {
                    let verifyadd = Module.getExportByName("libsscronet.so","SSL_CTX_set_custom_verify");
                    Interceptor.attach(verifyadd,{
                        onEnter(args){
                            Interceptor.attach(args[2],{
                                onLeave(retval){
                                    console.log("Hook成功!强制verify返回 0x0");
                                    retval.replace(0x0);
                                }
                            })
                        }
                    })
                }
            }
        });
    }
}

hook_dlopen("libsscronet.so");

接着,我是直接抓的登录包,毕竟抓这个包最明显

参数也确实挺多的,这就是大名鼎鼎的六神吗
这种大型的 app,这种关键参数涉及到的算法不太可能是在 Java 层生成的(因为我刚才搜索字段,直接给 jadx 卡死了,占22G 内存,总共才 32G 啊),那就只能是在 native 层生成的,像请求头这种东西,一般是在发包请求之前进行构造的吧,还是继续分析 libsscronet.so 这个库,那它是在哪儿添加的请求头呢?
参考了一下大佬的文章,发现是在 http_request_headers.cc 这个文件中进行添加的

跳转过去,对这个函数进行 hook,应该就是在这儿添加的请求头

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
const soName = "libsscronet.so";
const base = Module.findBaseAddress(soName);

if (base === null) {
    console.log("[-] module not found");
} else {
    const idaBase = 0x0;          
    const funcOffset = 0x37ED64;  
    const target = base.add(funcOffset - idaBase);
    Interceptor.attach(target, {
        onEnter(args) {
            var key = args[1].readPointer().readCString();
            var value = args[2].readPointer().readCString();

            // console.log("\n==== sub_37ED64 called ====");
            // console.log("key = " + key);
            // console.log("value = " + value);
            if(key == "X-Gorgon"){
                console.log("X-Gorgon堆栈信息如下")
                console.log(key,'==>',value);
                console.log('SetHeaders called from:\n' + Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n') + '\n');
            }

        },

        onLeave(retval) {
            // console.log("ret = " + retval);
        }
    });
}

得到的信息如下:

跳转到偏移 0x47abc8 处,看一下

这里的 v153 代表 key,v157 代表 value,从这里看不太可能是在这个网络库中进行生成的,继续往上进行溯源

而当我看到 v73 的时候,直接给我引向了 X23 寄存器

在之前的 frida 代码中继续看一下这个寄存器指向的值是在哪儿,找 gpt 给我写了一份 frida hook 的代码,hook 结果如下(不得不多,ai 真是太好用了):

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
[Pixel 2::抖音 ]->
========== BLR X23 ==========
[target ] 0x79a67f3e38
[module ] `libmetasec_ml`.so
[offset ] 0x2a6e38
[symbol ] 0x79a67f3e38 libmetasec_ml.so!0x2a6e38
[x0/v74] 0x7a7a468e40 -> https://log0-misc-lf.amemv.com/service/2/app_log/?version_code=380000&device_platform=android&device_id=4285258443570425&aid=1128&iid=4285258442771721&tt_data=a
[x1/v75] 0x787c223d00 -> cookie
passport_csrf_token=43311270ac30c95568130c5db23a83e8; passport_csrf_token_default=43311270ac30c95568130c5db23a83e8; store-region=cn-yn; store-region-src=did; install_id=4285258442771721; ttreq=1$3b3ffd2e9bc05d9f58d58ec2561b0f25fdd413ad; odin_tt=87d6142c75744770c2aaf6011f3cf458125cc74125923869cf45448563276f68a5a773584bb305de007f5969b3438c1990a2abf706b965e1cbb08f7c8d61ac37c433ecd67ea7464b5c0d52815eade962
log-encode-type
zstd
log-encode-token
0
x-tt-dt
AAATEBUCNJWPC5KV7FWGOTXDPYJ2DVUKD6KCB5EDEEPLX3HZ4C76BU46M2VJYG2YUF2T45VSXEBAN37FBI2UI54KJBCLRTPUHJF3AT63PL4ITCVG555LCHHJVVTU7FGX3G7E277OXE364WWTTKSMN3Y
activity_now_client
1773932331119
x-ss-req-ticket
1773932379205
x-vc-bdturing-sdk-version
4.1.1.cn
sdk-version
2
passport-sdk-settings
device_transfer_s_0,device_transfer_ab_0
passport-sdk-version
601581
content-type
application/octet-stream;tt-data=a
x-ss-stub
86245E39DA5BFEC362A9DD92634D85C1
content-length
7942
x-tt-store-region
cn-yn
x-tt-store-region-src
did
x-tt-request-tag
s=-1;p=0
x-ss-dp
1128
x-tt-trace-id
01-069bfdeb0df396b7b4cbcf95f2e10468-069bfdeb0df396b7-00
user-agent
com.ss.android.ugc.aweme/380001 (Linux; U; Android 10; zh_CN_#Hans; Pixel 2; Build/QQ3A.200805.001; Cronet/TTNetVersion:6f1e308d 2025-12-08 QuicVersion:21ac1950 2025-11-18)
accept-encoding
gzip, deflate, br

---- target enter ----
[arg0] 0x7a7a468e40 -> https://log0-misc-lf.amemv.com/service/2/app_log/?version_code=380000&device_platform=android&device_id=4285258443570425&aid=1128&iid=4285258442771721&tt_data=a
[arg1] 0x787c223d00 -> cookie
passport_csrf_token=43311270ac30c95568130c5db23a83e8; passport_csrf_token_default=43311270ac30c95568130c5db23a83e8; store-region=cn-yn; store-region-src=did; install_id=4285258442771721; ttreq=1$3b3ffd2e9bc05d9f58d58ec2561b0f25fdd413ad; odin_tt=87d6142c75744770c2aaf6011f3cf458125cc74125923869cf45448563276f68a5a773584bb305de007f5969b3438c1990a2abf706b965e1cbb08f7c8d61ac37c433ecd67ea7464b5c0d52815eade962
log-encode-type
zstd
log-encode-token
0
x-tt-dt
AAATEBUCNJWPC5KV7FWGOTXDPYJ2DVUKD6KCB5EDEEPLX3HZ4C76BU46M2VJYG2YUF2T45VSXEBAN37FBI2UI54KJBCLRTPUHJF3AT63PL4ITCVG555LCHHJVVTU7FGX3G7E277OXE364WWTTKSMN3Y
activity_now_client
1773932331119
x-ss-req-ticket
1773932379205
x-vc-bdturing-sdk-version
4.1.1.cn
sdk-version
2
passport-sdk-settings
device_transfer_s_0,device_transfer_ab_0
passport-sdk-version
601581
content-type
application/octet-stream;tt-data=a
x-ss-stub
86245E39DA5BFEC362A9DD92634D85C1
content-length
7942
x-tt-store-region
cn-yn
x-tt-store-region-src
did
x-tt-request-tag
s=-1;p=0
x-ss-dp
1128
x-tt-trace-id
01-069bfdeb0df396b7b4cbcf95f2e10468-069bfdeb0df396b7-00
user-agent
com.ss.android.ugc.aweme/380001 (Linux; U; Android 10; zh_CN_#Hans; Pixel 2; Build/QQ3A.200805.001; Cronet/TTNetVersion:6f1e308d 2025-12-08 QuicVersion:21ac1950 2025-11-18)
accept-encoding
gzip, deflate, br
[ret ] 0x7962937600 -> X-Perseus  # 1
eaeee5ynOZskw1llR2hm8+lJKhgcJPtKXM6OkB1vcOil+HVeDQiP+Ut/EXHY4DxpD9rXqytpWqczMCvDv2roCE/eRlLg1x6GgYLRp2JjHNQv4jOyzqnsRn1XRkvrtg9OTpjtCU0TGZtC52v3EPZLc4k4FQH7qvWdvuf62n8T3bgbSPEHLFeOqzdXvB56iNpYrAzV8u5tHbWvq4q/+0BFFrQSZ0iW8HXX3SeSQL0nvv9/pji4hRtoWZwg8prIAakJykHIPDggP+d+z7uw9cWQ4Nyy+ZhK1EShp9D3oBpZBpcPK4N+ywV2ddocGXewx2gpNz5DLOymxyd6Jg1xhn6/ePdmp0UHLlPWslMJ2+D5QS51M6MsWgNs0TEzlPUzmeYR6vt1bnGVix6tYxSSziobNrThnSLpeiy1EFruU9dGEScCMkZu72ihet8y5WctEXcbylIwjBhWLD6bEKV4fpIDF3hYDfGSDqvEQTroPWhNudoVaajZlw0nEz/TLmj7hLcW89l2lfZWynQgxTnBvdBOzqGCgN9vyEopBG8RInm4+I28sxATas9B5sojhectRbSCzSLWCIYOHboPxPLSjdeMOoVoVWoXbRc8WP4UKuUg+YVrBW31X4R1v9tvyGjzsWxWTK5iQdCVyOWmXrBtPKUDHI9mTZnHfXeTsRtsZKjwySV0B40BMN9GOaoA2l4ltGXO1eNB9nOobbBrP73sFCZzFXLrgnAo/KDxCRcUGE+/dhwlAoGs0FgtvORo5mHDY8v7x1Dv5vXax8uqW+bYFuFh3vu6OSp/rIJYa+KzYnRSRXbe+Zu9MzMxSi9NIFuQB1cCPAdBTjlaJhlQAZHB+HCGh7f8fG6bcpock9/wXeQFDoibFWR1lNiGIDnNMYtHBdTM6CnRHYtlKpW+0C+BhA/u+Q==
X-Medusa  # 2
jA+8aeCVl0PJlBP4CsW+A0k5GJdG4AAN7JZxNnkc3L4Auhy097W94A0oAJIHmIQSzh4JlOFbEmCqNTjyPiNUlDX+Go/Aev2LLy3Wbb4LuRMXtUiaZ5riW7/gE4JPovQqf71xz8hEVCHavVVSZBCzb+ModMO6eToxM3wTPQA6+D8fS4KZQphjENUVIVb4nHDq+MLLUtAJ+t5nCyZqQX54bJd57z9mOF07JJbd0x+Hx9JBlSYNHl2tGtVDixKKOtS5zgnYQvwcRmmLkTu+IbhUANZk2mH+uljhw3l7Wri8HZ8+VOHBdcnK6oSSK093U9JEppDDdMrdcSesnhOhMaUSjXcsM3aYY8L9p6z//aep+0sa
X-Argus # 3
iw+8aQ==
X-Helios # 4
mzldD91aKzfTcF8SCMCCGn4tdFZJxImB4NNpRlikIYB7Kvtb
X-Ladon # 5
r3kMdQ==
X-Khronos # 6 
1773932427
X-Gorgon # 7
8404a00c0405a19810f52af5ffa35cc68fa1f92bebe2762947e0

对上了,这里请求参数中也正好是 \r\n 作为分割的,最后的返回值就是七神
跳转到 libmetasec_ml.so 中的偏移地址0x2a6e38

发现处在 sub_2A6E38,这个应该就是外部加密参数生成的 so 中的加密函数了,接着就可以 hook 一下这个函数,看一下参数是什么,接着好去到 unidbg 中进行模拟加密参数的生成,写一下 frida 代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18

const base = Module.findBaseAddress("libmetasec_ml.so");
var func_addr = base.add(0x2A6E38);
console.log("baseAddr from hook", base);
Interceptor.attach(func_addr, {
    onEnter: function (args) {
        console.log("=============入参开始==================")
        var arg0 = args[0].readUtf8String();
        var arg1 = args[1].readUtf8String();
        console.log("参数1" + arg0);
        console.log("参数2" + arg1);
    },
    onLeave: function (retval) {
        console.log("返回值地址:: " + retval);
        console.log("返回值:: " + retval.readUtf8String());
        console.log("=============返回值结束==================")
    }
});

hook 结果如下: 参数 1 就是请求的 url+一堆参数拼接起来的结果,这一点跟 web 有点像,参数 2 就是一堆的请求参数,用 \r\n 进行分割

unidbg 模拟执行

先弄个架子在这儿,这个用 ai 改造了一下

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
package com.douyin;

import com.github.unidbg.AndroidEmulator;
import com.github.unidbg.Emulator;
import com.github.unidbg.Module;
import com.github.unidbg.arm.backend.Unicorn2Factory;
import com.github.unidbg.file.FileResult;
import com.github.unidbg.file.IOResolver;
import com.github.unidbg.linux.android.AndroidEmulatorBuilder;
import com.github.unidbg.linux.android.AndroidResolver;
import com.github.unidbg.linux.android.dvm.AbstractJni;
import com.github.unidbg.linux.android.dvm.BaseVM;
import com.github.unidbg.linux.android.dvm.DalvikModule;
import com.github.unidbg.linux.android.dvm.DvmClass;
import com.github.unidbg.linux.android.dvm.VaList;
import com.github.unidbg.linux.android.dvm.VM;
import com.github.unidbg.memory.Memory;
import com.github.unidbg.hook.hookzz.HookZz;
import com.github.unidbg.hook.hookzz.IHookZz;
import com.github.unidbg.hook.hookzz.HookEntryInfo;
import com.github.unidbg.arm.context.RegisterContext;
import com.github.unidbg.virtualmodule.android.AndroidModule;

import java.io.File;

public class DouYin extends AbstractJni implements IOResolver {

    // ========== 每次新项目只改这里 ==========

    // 模拟器位数:so在armeabi-v7a目录下填false,arm64-v8a目录下填true
    private static final boolean IS_64BIT         = true;

    // app包名(随意,一般填真实包名)
    private static final String  PROCESS_NAME     = "com.ss.android.ugc.aweme";

    // apk路径,不需要apk时填null(填null时LOAD_BY_NAME必须为false)
    private static final String  APK_PATH         = "apks/douyin/douyin.apk";

    // so加载方式:
    //   false = 传文件路径(用SO_PATH),不依赖apk,最常用
    //   true  = 传库名(用SO_NAME),unidbg自动去apk内查找,必须提供APK_PATH
    private static final boolean LOAD_BY_NAME     = true;
    private static final String  SO_PATH          = ""; // LOAD_BY_NAME=false时生效
    private static final String  SO_NAME          = "metasec_ml";                // LOAD_BY_NAME=true时生效,不带lib前缀和.so后缀


    // 是否打印JNI调用细节,调试时改true
    private static final boolean VERBOSE          = true;


    // ========================================

    public static AndroidEmulator emulator;
    public static Memory memory;
    public static VM vm;
    public static Module module;

    // 1. 构造方法 —— 初始化模拟器
    public DouYin() {

        // 1. 创建模拟器(32/64位由IS_64BIT控制)
        emulator = IS_64BIT
                ? AndroidEmulatorBuilder.for64Bit().setProcessName(PROCESS_NAME).addBackendFactory(new Unicorn2Factory(true)).build()
                : AndroidEmulatorBuilder.for32Bit().setProcessName(PROCESS_NAME).addBackendFactory(new Unicorn2Factory(true)).build();

        // 2. 获取内存对象
        memory = emulator.getMemory();

        // 3. 设置安卓SDK版本(只支持19、23)
        memory.setLibraryResolver(new AndroidResolver(23));

        // 4. 创建虚拟机
        vm = APK_PATH != null
                ? emulator.createDalvikVM(new File(APK_PATH))
                : emulator.createDalvikVM();
        vm.setJni(this);
        vm.setVerbose(VERBOSE);

        // 5. 加载so文件(两种方式由LOAD_BY_NAME控制)
        DalvikModule dm = LOAD_BY_NAME
                ? vm.loadLibrary(SO_NAME, false)
                : vm.loadLibrary(new File(SO_PATH), false);

        // 6. 动态注册才需要执行JNI_OnLoad
        dm.callJNI_OnLoad(emulator);

        // 7. 获取module对象(后续拿基址、偏移等)
        module = dm.getModule();

    }





    // 5. main方法 —— 右键直接运行
    public static void main(String[] args) {
        DouYin douYin = new DouYin();
    }

    @Override
    public FileResult resolve(Emulator emulator, String pathname, int oflags) {
        System.out.println("pathname:" + pathname);
        return null;
    }
}

运行,发现报错

这个一般就是当前的这个 so 文件依赖于 android.so 文件,这个 unidbg 为我们实现了相关的虚拟模块

1
new AndroidModule(emulator,vm).register(memory);

接着又发现 Jni 层在寻找 MS 这个类,但是我在 unidbg 中并没有引用这个类啊,你肯定是找不到的啊

去 jadx 看了一下这个类,发现继承 i2 这个类,i2 又继承 y2 这个类

在 JNI_Onload 调用之前声明这个类就可以了

1
MS = vm.resolveClass("com.bytedance.mobsec.metasec.ml.MS",vm.resolveClass("ms.bd.c.i2",vm.resolveClass("ms.bd.c.y2")));

继续,发生报错

1
2
3
4
5
java.lang.UnsupportedOperationException: com/bytedance/mobsec/metasec/ml/MS->b(IIJLjava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;
        at com.github.unidbg.linux.android.dvm.AbstractJni.callStaticObjectMethodV(AbstractJni.java:504)   
        at com.github.unidbg.linux.android.dvm.AbstractJni.callStaticObjectMethodV(AbstractJni.java:438)   
        at com.github.unidbg.linux.android.dvm.DvmMethod.callStaticObjectMethodV(DvmMethod.java:59)        
        at com.github.unidbg.linux.android.dvm.DalvikVM64$112.handle(DalvikVM64.java:1836)

往上找,就找到了下面的这个地方

先看一下参数是什么

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
@Override
public DvmObject<?> callStaticObjectMethodV(BaseVM vm, DvmClass dvmClass, String signature, VaList vaList) {
	switch(signature){
		case "com/bytedance/mobsec/metasec/ml/MS->b(IIJLjava/lang/String;Ljava/lang/Object;)Ljava/lang/Object;":{
			int arg = vaList.getIntArg(0);
			System.out.println("参数==>"+arg);
		}
	}
	return super.callStaticObjectMethodV(vm, dvmClass, signature, vaList);
}

得到的结果是:

然后就可以直接补了,去 jadx 中看一下这个分支,可以发现返回值就是 2,补上

ok,继续,然后又报错了

1
2
3
4
java.lang.UnsupportedOperationException: java/lang/Long->longValue()J
	at com.github.unidbg.linux.android.dvm.AbstractJni.callLongMethodV(AbstractJni.java:236)
	at com.github.unidbg.linux.android.dvm.AbstractJni.callLongMethodV(AbstractJni.java:231)
	at com.github.unidbg.linux.android.dvm.DvmMethod.callLongMethodV(DvmMethod.java:84)

补上

1
2
3
4
5
6
7
8
9
@Override
public long callLongMethodV(BaseVM vm, DvmObject<?> dvmObject, String signature, VaList vaList) {
	switch (signature){
		case "java/lang/Long->longValue()J":{
			return (Long)dvmObject.getValue();
		}
	}
	return super.callLongMethodV(vm, dvmObject, signature, vaList);
}

然后,然后这儿就结束了,接着就需要进行主动调用了

它的这个参数太多了,干脆就直接写成一个文件的形式然后读取吧

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
public void metaSec() throws IOException {
        byte[] urlBytes = Files.readAllBytes(Paths.get("apks/douyin/url.txt"));
        byte[] headerBytes = Files.readAllBytes(Paths.get("apks/douyin/headers.txt"));

        MemoryBlock urlBlock = memory.malloc(urlBytes.length + 1, true);
        UnidbgPointer urlPtr = urlBlock.getPointer();
        urlPtr.write(0, urlBytes, 0, urlBytes.length);

        MemoryBlock headerBlock = memory.malloc(headerBytes.length + 1, true);
        UnidbgPointer headerPtr = headerBlock.getPointer();
        headerPtr.write(0, headerBytes, 0, headerBytes.length);

        Number result = module.callFunction(emulator, 0x2A6E38, urlPtr, headerPtr);

        UnidbgPointer resultPtr = memory.pointer(result.longValue());
        System.out.println(resultPtr.getString(0));

    }

接着又报错

这个还是跟上面一样,去 jadx 中进行查看
然后报错

1
2
3
java.lang.UnsupportedOperationException: java/lang/Integer->getBytes(Ljava/lang/String;)[B
	at com.github.unidbg.linux.android.dvm.AbstractJni.callObjectMethodV(AbstractJni.java:417)
	at com.github.unidbg.linux.android.dvm.AbstractJni.callObjectMethodV(AbstractJni.java:262)

直接补就行

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
@Override
public DvmObject<?> callObjectMethodV(BaseVM vm, DvmObject<?> dvmObject, String signature, VaList vaList) {
	switch (signature) {
		case "java/lang/Integer->getBytes(Ljava/lang/String;)[B": {
			String str = dvmObject.getValue().toString();
			String charset = vaList.getObjectArg(0).getValue().toString();
			System.out.println("getBytes str=" + str + " charset=" + charset);
			try {
				return new ByteArray(vm, str.getBytes(charset));
			} catch (Exception e) {
				return new ByteArray(vm, str.getBytes());
			}
		}
	}
	return super.callObjectMethodV(vm, dvmObject, signature, vaList);
}

接着又出现了

1
2
参数==>33554433
参数==>33554434

去 jadx 找就行
接着,又报错

1
2
3
4
5
6
java.lang.UnsupportedOperationException: java/lang/Thread->getStackTrace()[Ljava/lang/StackTraceElement;
	at com.github.unidbg.linux.android.dvm.AbstractJni.callObjectMethodV(AbstractJni.java:417)
	at com.douyin.DouYin.callObjectMethodV(DouYin.java:161)
	at com.github.unidbg.linux.android.dvm.AbstractJni.callObjectMethodV(AbstractJni.java:262)
	at com.github.unidbg.linux.android.dvm.DvmMethod.callObjectMethodV(DvmMethod.java:89)
	at com.github.unidbg.linux.android.dvm.DalvikVM64$32.handle(DalvikVM64.java:559)

直接补

1
2
3
4
5
6
7
8
case "java/lang/Thread->getStackTrace()[Ljava/lang/StackTraceElement;":{
	StackTraceElement[] elements = Thread.currentThread().getStackTrace();
	DvmObject[] objs = new DvmObject[elements.length];
	for (int i = 0; i < elements.length; i++) {
		objs[i] = vm.resolveClass("java/lang/StackTraceElement").newObject(elements[i]);
	}
	return new ArrayObject(objs);
}

继续报错

1
2
3
4
5
java.lang.UnsupportedOperationException: java/lang/StackTraceElement->getClassName()Ljava/lang/String;
	at com.github.unidbg.linux.android.dvm.AbstractJni.callObjectMethodV(AbstractJni.java:417)
	at com.douyin.DouYin.callObjectMethodV(DouYin.java:170)
	at com.github.unidbg.linux.android.dvm.AbstractJni.callObjectMethodV(AbstractJni.java:262)
	at com.github.unidbg.linux.android.dvm.DvmMethod.callObjectMethodV(DvmMethod.java:89)

直接补

1
2
3
4
case "java/lang/StackTraceElement->getClassName()Ljava/lang/String;":{
	StackTraceElement stackTraceElement = (StackTraceElement)dvmObject.getValue();
	return new StringObject(vm,stackTraceElement.getClassName());
}

继续报错

1
2
3
4
5
java.lang.UnsupportedOperationException: java/lang/StackTraceElement->getMethodName()Ljava/lang/String;
	at com.github.unidbg.linux.android.dvm.AbstractJni.callObjectMethodV(AbstractJni.java:417)
	at com.douyin.DouYin.callObjectMethodV(DouYin.java:167)
	at com.github.unidbg.linux.android.dvm.AbstractJni.callObjectMethodV(AbstractJni.java:262)
	at com.github.unidbg.linux.android.dvm.DvmMethod.callObjectMethodV(DvmMethod.java:89)

直接补

1
2
3
4
case "java/lang/StackTraceElement->getMethodName()Ljava/lang/String;":{
	StackTraceElement stackTraceElement = (StackTraceElement)dvmObject.getValue();
	return new StringObject(vm,stackTraceElement.getMethodName());
}

仍在报错

1
2
3
4
5
java.lang.UnsupportedOperationException: java/lang/Thread->getBytes(Ljava/lang/String;)[B
	at com.github.unidbg.linux.android.dvm.AbstractJni.callObjectMethodV(AbstractJni.java:417)
	at com.douyin.DouYin.callObjectMethodV(DouYin.java:171)
	at com.github.unidbg.linux.android.dvm.AbstractJni.callObjectMethodV(AbstractJni.java:262)
	at com.github.unidbg.linux.android.dvm.DvmMethod.callObjectMethodV(DvmMethod.java:89)

在补之前还需要补一下这个分支的数据

1
参数==>16777233

返回个版本号 继续补

1
2
3
4
case "java/lang/Thread->getBytes(Ljava/lang/String;)[B":{
   String arg = vaList.getObjectArg(0).getValue().toString();
   return new ByteArray(vm,arg.getBytes(StandardCharsets.UTF_8));
}

接着,就能够出值了

能不能用,不知道,算法分析后面再写吧,参数太多了,一篇文章不一定能写完