首页
社区
课程
招聘
React Native Hermes 逆向实践
发表于: 2022-7-4 21:31 30201

React Native Hermes 逆向实践

2022-7-4 21:31
30201

Android 应用gl,使用了加固i,老版本的应用gl是js源码,新版本更新后,刚开始以为是加密了源码,分析后才知道是使用了Hermes优化引擎。

Hermes是Facebook为React Native开源的一款javascript优化引擎。

原来的index.android.bundle是javascript的,被Hermes优化后变成了Bytecode。

Hermes优化的优化效果如下:

优化前:

优化后:

应用gl使用了加固i,在被root 的手机上运行,闪退。

绕过方法也很简单,在magisk的设置中,开启遵守排除列表,然后在配置排除列表中选择应用gl

应用被添加到排除列表后,将没办法使用lspoed,只能使用frida

抓包可以看到登录接口有个signcode加密参数,69e34d747c5757236142a19f4595d313 是32位字符串,猜测跟md5相关

由于我分析过应用gl前面版本,所以知道它是React Native开发的

但当你们拿到新app的时候,需要先对apk文件,app数据目录进行一次搜索

解压 apk, 使用命令 grep -r "signcode" *,搜索一下apk下有没有signcode,第一次没搜到(备注:应用gl把代码打包到assets/android-rn.zip里了)

在app的数据目录下,使用命令 grep -r "signcode" *,搜索一下,在文件./files/RN/rnbundle/index.android.bundle下搜索到了signcode

把./files/RN/rnbundle/index.android.bundle拿出来

使用010editor打开后,就看到如下图的内容:

刚打开index.android.bundle, 我就猜测这个文件难道被加密了?(备注:在这之前我没有分析过被Hermes优化的应用)。

因为应用gl有加固i,我并没有研究加固,于是只能研究React Native的源码,看不能找到最终加载源码的地方

下载源码 https://github.com/facebook/react-native.git

在源码中搜索 LoadScript,找到2个可疑的函数

这2个函数是native,使用https://github.com/lasting-yang/frida_hook_libart/blob/master/hook_RegisterNatives.js,可以找到函数对应的so

对jniLoadScriptFromAssets和jniLoadScriptFromFile进行hook,需要配合hook_dlopen一起使用,因为frida注入的时候,libreactnativejni.so还没有加载。

jniLoadScriptFromFile被加载,传入参数为index.android.bundle文件路径

继续阅读源码,jniLoadScriptFromFile中会调用loadScriptFromString

loadScriptFromString

hook loadScriptFromString后,可以知道loadSynchronously为0, 继续分析loadBundle

runOnExecutorQueue的参数是一个Lambda表达式,它的回调函数里面调用了loadBundle,在源码中搜索loadBundle,找到了很多处实现代码,这时候我们酒不知道loadBundle具体实现在哪里,继续写hook代码hook_loadBundle

facebook::react::JSIExecutor::loadBundle函数中调用了evaluateJavaScript

hook "*evaluateJavaScript*",

evaluateJavaScriptWithSourceMap函数 在React Native源码中没有搜到,在另一个hermes项目(https://github.com/facebook/hermes)中找到了evaluateJavaScriptWithSourceMap函数和evaluateJavaScript函数

evaluateJavaScript函数对应so的地址0xbb867431 libhermes.so!0x11431

evaluateJavaScriptWithSourceMap函数中调用了prepareJavaScriptWithSourceMap函数, 继续调用isHermesBytecode函数

isHermesBytecode用来判断是否是Hermes的Bytecode

MAGIC和index.android.bunddle的前8个字节是一直的,至此已经知道index.android.bundle并不是被应用gl加密了,而是被Hermes编译成了bytecode

前面的分析过程,已经知道了index.android.bundle是Hermes的bytecode,没办法直接查看源码,需要借助其他工具进行反编译

Hermes官方提供了hbcdump工具,可以进行反编译,但使用起来比较麻烦,有另一个开源工具hbctool可以对hermesbytecode进行反编译与回编译

https://github.com/bongtrop/hbctool 提供了59, 62, 74, 76版本的反编译

https://github.com/niosega/hbctool/tree/draft/hbc-v84 对84版本的Hermes进行补充

安装可以反编译84版本的hbctool

反编译

回编译

bytecode反编译出来的代码如下:搜索两处能md5相关的代码

并不需要深入bytecode,指令详情,了解几个简单指令即可。

只需要写一个打印日志的函数,变成成bytecode,反编译后替换掉这两个函数就能看到这两个md5函数的输入参数

先编译Hermes源码,会得到./build/bin/hermes工具,

test.js

写了一些简单的js代码,把test.js编译成bytecode

010editor打开test.hbc可以看到MAGIC

反编译test.hbc

得到

把反编译出来的bytecode,替换到md5函数中

需要对字符串的id进行修改,字符串对应hbctool反编译出来的string.json中的字符串id

再次回编译,得到index.android.bundle.re

现在替换app目录下的index.android.bundle

结束app, 运行 adb logcat "*:S ReactNative:V ReactNativeJS:V", 再次运行app就可以到得到md5函数的输入参数

算法分析完成

https://github.com/facebook/react-native.git

https://github.com/lasting-yang/frida_hook_libart

https://github.com/facebook/hermes

https://github.com/bongtrop/hbctool

https://github.com/niosega/hbctool/tree/draft/hbc-v84

 
 
 
 
 
 
function hook_ssl() {
    Java.perform(function () {
        var ClassName = "com.android.org.conscrypt.Platform";
        var Platform = Java.use(ClassName);
        var targetMethod = "checkServerTrusted";
        var len = Platform[targetMethod].overloads.length;
        console.log(targetMethod, len);
        for (var i = 0; i < len; ++i) {
            Platform[targetMethod].overloads[i].implementation = function () {
                console.log("class:", ClassName, "target:", targetMethod, " i:", i, arguments);
            };
        }
        var ClassName = "com.android.org.conscrypt.TrustManagerImpl";
        var Platform = Java.use(ClassName);
        var targetMethod = "checkTrustedRecursive";
        var len = Platform[targetMethod].overloads.length;
        console.log(targetMethod, len);
        var ArrayList = Java.use("java.util.ArrayList")
        var X509Certificate = Java.use("java.security.cert.X509Certificate");
        for (var i = 0; i < len; ++i) {
            Platform[targetMethod].overloads[i].implementation = function () {
                console.log("class:", ClassName, "target:", targetMethod, " i:", i, arguments);
                return ArrayList.$new();
            };
        }
    });
}
function hook_ssl() {
    Java.perform(function () {
        var ClassName = "com.android.org.conscrypt.Platform";
        var Platform = Java.use(ClassName);
        var targetMethod = "checkServerTrusted";
        var len = Platform[targetMethod].overloads.length;
        console.log(targetMethod, len);
        for (var i = 0; i < len; ++i) {
            Platform[targetMethod].overloads[i].implementation = function () {
                console.log("class:", ClassName, "target:", targetMethod, " i:", i, arguments);
            };
        }
        var ClassName = "com.android.org.conscrypt.TrustManagerImpl";
        var Platform = Java.use(ClassName);
        var targetMethod = "checkTrustedRecursive";
        var len = Platform[targetMethod].overloads.length;
        console.log(targetMethod, len);
        var ArrayList = Java.use("java.util.ArrayList")
        var X509Certificate = Java.use("java.security.cert.X509Certificate");
        for (var i = 0; i < len; ++i) {
            Platform[targetMethod].overloads[i].implementation = function () {
                console.log("class:", ClassName, "target:", targetMethod, " i:", i, arguments);
                return ArrayList.$new();
            };
        }
    });
}
 
 
 
 
Binary file ./files/RN/rnbundle/index.android.bundle matches
Binary file ./files/RN/rnbundle/index.android.bundle matches
cp ./files/RN/rnbundle/index.android.bundle /data/local/tmp/index.android.bundle
chmod 777 /data/local/tmp/index.android.bundle
 
adb pull /data/local/tmp/index.android.bundle
cp ./files/RN/rnbundle/index.android.bundle /data/local/tmp/index.android.bundle
chmod 777 /data/local/tmp/index.android.bundle
 
adb pull /data/local/tmp/index.android.bundle
 
 
 
private native void jniLoadScriptFromAssets(AssetManager assetManager, String assetURL, boolean loadSynchronously);
 
private native void jniLoadScriptFromFile(String fileName, String sourceURL, boolean loadSynchronously);
private native void jniLoadScriptFromAssets(AssetManager assetManager, String assetURL, boolean loadSynchronously);
 
private native void jniLoadScriptFromFile(String fileName, String sourceURL, boolean loadSynchronously);
[RegisterNatives] java_class: com.facebook.react.bridge.CatalystInstanceImpl name: jniLoadScriptFromAssets sig: (Landroid/content/res/AssetManager;Ljava/lang/String;Z)V fnPtr: 0xb4e99a85  fnOffset: 0x80a85  callee: 0xb4d2021d libhermes-executor-release.so!_ZN8facebook3jni6JClass15registerNativesESt16initializer_listI15JNINativeMethodE+0x20
[RegisterNatives] java_class: com.facebook.react.bridge.CatalystInstanceImpl name: jniLoadScriptFromFile sig: (Ljava/lang/String;Ljava/lang/String;Z)V fnPtr: 0xb4e99aa1  fnOffset: 0x80aa1  callee: 0xb4d2021d libhermes-executor-release.so!_ZN8facebook3jni6JClass15registerNativesESt16initializer_listI15JNINativeMethodE+0x20
 
这时候会遇到一个问题,callee在libhermes-executor-release.so,使用ida打开libhermes-executor-release.so后,去fnOffset: 0x80a85和fnOffset: 0x80aa1找不到对应的函数。
 
于是使用frida的 Process.findModuleByAddress(ptr(0xb4e99a85)) 找jniLoadScriptFromAssets函数所在的模块,在libreactnativejni.so里面
 
{
    "base": "0xb4e19000",
    "name": "libreactnativejni.so",
    "path": "/data/app/~~klydM6uPsWM_heluFCfyKQ==/com.xxxxx.xxx.xxxxxxxxxx.xxxxxx-zC5SUJ_WxA0rwldHieq_fg==/lib/arm/libreactnativejni.so",
    "size": 815104
}
[RegisterNatives] java_class: com.facebook.react.bridge.CatalystInstanceImpl name: jniLoadScriptFromAssets sig: (Landroid/content/res/AssetManager;Ljava/lang/String;Z)V fnPtr: 0xb4e99a85  fnOffset: 0x80a85  callee: 0xb4d2021d libhermes-executor-release.so!_ZN8facebook3jni6JClass15registerNativesESt16initializer_listI15JNINativeMethodE+0x20
[RegisterNatives] java_class: com.facebook.react.bridge.CatalystInstanceImpl name: jniLoadScriptFromFile sig: (Ljava/lang/String;Ljava/lang/String;Z)V fnPtr: 0xb4e99aa1  fnOffset: 0x80aa1  callee: 0xb4d2021d libhermes-executor-release.so!_ZN8facebook3jni6JClass15registerNativesESt16initializer_listI15JNINativeMethodE+0x20
 
这时候会遇到一个问题,callee在libhermes-executor-release.so,使用ida打开libhermes-executor-release.so后,去fnOffset: 0x80a85和fnOffset: 0x80aa1找不到对应的函数。
 
于是使用frida的 Process.findModuleByAddress(ptr(0xb4e99a85)) 找jniLoadScriptFromAssets函数所在的模块,在libreactnativejni.so里面
 
{
    "base": "0xb4e19000",
    "name": "libreactnativejni.so",
    "path": "/data/app/~~klydM6uPsWM_heluFCfyKQ==/com.xxxxx.xxx.xxxxxxxxxx.xxxxxx-zC5SUJ_WxA0rwldHieq_fg==/lib/arm/libreactnativejni.so",
    "size": 815104
}
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;
                        console.log("android_dlopen_ext:", this.path);
                    }
                }
            },
            onLeave: function (retval) {
                if (this.canhook) {
                    fun();
                }
            }
        });
    }
}
 
function hook_libreactnativejni() {
    let base_libreactnativejni = Module.findBaseAddress("libreactnativejni.so");
    if (base_libreactnativejni == null) {
        return;
    }
    let jniLoadScriptFromAssets = base_libreactnativejni.add(0x80a85);
    let jniLoadScriptFromFile = base_libreactnativejni.add(0x80aa1);
    //private native void jniLoadScriptFromAssets(AssetManager assetManager, String assetURL, boolean loadSynchronously);
    Interceptor.attach(jniLoadScriptFromAssets, {
        onEnter(args) {
            console.log("jniLoadScriptFromAssets:", Java.vm.tryGetEnv().getStringUtfChars(args[3]).readCString())
        }
    })
    //private native void jniLoadScriptFromFile(String fileName, String sourceURL, boolean loadSynchronously);
    Interceptor.attach(jniLoadScriptFromFile, {
        onEnter(args) {
            console.log("jniLoadScriptFromFile:", Java.vm.tryGetEnv().getStringUtfChars(args[2]).readCString(), Java.vm.tryGetEnv().getStringUtfChars(args[3]).readCString())
        }
    })
}
 
setImmediate(() => {
    hook_dlopen("libreactnativejni.so", hook_libreactnativejni)
    hook_libreactnativejni();
})
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;
                        console.log("android_dlopen_ext:", this.path);
                    }
                }
            },
            onLeave: function (retval) {
                if (this.canhook) {
                    fun();
                }
            }
        });
    }
}
 
function hook_libreactnativejni() {
    let base_libreactnativejni = Module.findBaseAddress("libreactnativejni.so");
    if (base_libreactnativejni == null) {
        return;
    }
    let jniLoadScriptFromAssets = base_libreactnativejni.add(0x80a85);
    let jniLoadScriptFromFile = base_libreactnativejni.add(0x80aa1);
    //private native void jniLoadScriptFromAssets(AssetManager assetManager, String assetURL, boolean loadSynchronously);
    Interceptor.attach(jniLoadScriptFromAssets, {
        onEnter(args) {
            console.log("jniLoadScriptFromAssets:", Java.vm.tryGetEnv().getStringUtfChars(args[3]).readCString())
        }
    })
    //private native void jniLoadScriptFromFile(String fileName, String sourceURL, boolean loadSynchronously);
    Interceptor.attach(jniLoadScriptFromFile, {
        onEnter(args) {
            console.log("jniLoadScriptFromFile:", Java.vm.tryGetEnv().getStringUtfChars(args[2]).readCString(), Java.vm.tryGetEnv().getStringUtfChars(args[3]).readCString())
        }
    })
}
 
setImmediate(() => {
    hook_dlopen("libreactnativejni.so", hook_libreactnativejni)
    hook_libreactnativejni();
})
 
void CatalystInstanceImpl::jniLoadScriptFromFile(
    const std::string &fileName,
    const std::string &sourceURL,
    bool loadSynchronously) {
  auto reactInstance = instance_;
  if (!reactInstance) {
    return;
  }
 
  switch (getScriptTagFromFile(fileName.c_str())) {    //根据文件头判断脚本类型,
    case ScriptTag::MetroHBCBundle: {
      std::unique_ptr<const JSBigFileString> script;
      RecoverableError::runRethrowingAsRecoverable<std::system_error>(
          [&fileName, &script]() {
            script = JSBigFileString::fromPath(fileName);
          });
      const char *buffer = script->c_str();
      uint32_t bufferLength = (uint32_t)script->size();
      uint32_t offset = 8;
      while (offset < bufferLength) {
        uint32_t segment = offset + 4;
        uint32_t moduleLength =
            bufferLength < segment ? 0 : *(((uint32_t *)buffer) + offset / 4);
 
        reactInstance->loadScriptFromString(
            std::make_unique<const JSBigStdString>(
                std::string(buffer + segment, buffer + moduleLength + segment)),
            sourceURL,
            false);
 
        offset += ((moduleLength + 3) & ~3) + 4;
      }
      break;
    }
    case ScriptTag::RAMBundle:
      instance_->loadRAMBundleFromFile(fileName, sourceURL, loadSynchronously);
      break;
    case ScriptTag::String:
    default: {
      std::unique_ptr<const JSBigFileString> script;
      RecoverableError::runRethrowingAsRecoverable<std::system_error>(
          [&fileName, &script]() {
            script = JSBigFileString::fromPath(fileName);
          });
      instance_->loadScriptFromString(
          std::move(script), sourceURL, loadSynchronously);
    }
  }
}
void CatalystInstanceImpl::jniLoadScriptFromFile(
    const std::string &fileName,
    const std::string &sourceURL,
    bool loadSynchronously) {
  auto reactInstance = instance_;
  if (!reactInstance) {
    return;
  }
 
  switch (getScriptTagFromFile(fileName.c_str())) {    //根据文件头判断脚本类型,
    case ScriptTag::MetroHBCBundle: {
      std::unique_ptr<const JSBigFileString> script;
      RecoverableError::runRethrowingAsRecoverable<std::system_error>(
          [&fileName, &script]() {
            script = JSBigFileString::fromPath(fileName);
          });
      const char *buffer = script->c_str();
      uint32_t bufferLength = (uint32_t)script->size();
      uint32_t offset = 8;
      while (offset < bufferLength) {
        uint32_t segment = offset + 4;
        uint32_t moduleLength =
            bufferLength < segment ? 0 : *(((uint32_t *)buffer) + offset / 4);
 
        reactInstance->loadScriptFromString(
            std::make_unique<const JSBigStdString>(
                std::string(buffer + segment, buffer + moduleLength + segment)),
            sourceURL,
            false);
 
        offset += ((moduleLength + 3) & ~3) + 4;
      }
      break;
    }
    case ScriptTag::RAMBundle:
      instance_->loadRAMBundleFromFile(fileName, sourceURL, loadSynchronously);
      break;
    case ScriptTag::String:
    default: {
      std::unique_ptr<const JSBigFileString> script;
      RecoverableError::runRethrowingAsRecoverable<std::system_error>(
          [&fileName, &script]() {
            script = JSBigFileString::fromPath(fileName);
          });
      instance_->loadScriptFromString(
          std::move(script), sourceURL, loadSynchronously);
    }
  }
}
void Instance::loadScriptFromString(
    std::unique_ptr<const JSBigString> string,
    std::string sourceURL,
    bool loadSynchronously) {
  SystraceSection s("Instance::loadScriptFromString", "sourceURL", sourceURL);
  if (loadSynchronously) {
    loadBundleSync(nullptr, std::move(string), std::move(sourceURL));
  } else {
    loadBundle(nullptr, std::move(string), std::move(sourceURL));
  }
}
void Instance::loadScriptFromString(
    std::unique_ptr<const JSBigString> string,
    std::string sourceURL,
    bool loadSynchronously) {
  SystraceSection s("Instance::loadScriptFromString", "sourceURL", sourceURL);
  if (loadSynchronously) {
    loadBundleSync(nullptr, std::move(string), std::move(sourceURL));
  } else {
    loadBundle(nullptr, std::move(string), std::move(sourceURL));
  }
}
let loadScriptFromString = base_libreactnativejni.add(0xA0BF8 + 1);
    Interceptor.attach(loadScriptFromString, {
        onEnter(args) {
            console.log("loadScriptFromString:", (args[1]), ptr(args[2]).add(Process.pointerSize * 2).readPointer().readCString(), args[3])
        }
    })
let loadScriptFromString = base_libreactnativejni.add(0xA0BF8 + 1);
    Interceptor.attach(loadScriptFromString, {
        onEnter(args) {
            console.log("loadScriptFromString:", (args[1]), ptr(args[2]).add(Process.pointerSize * 2).readPointer().readCString(), args[3])
        }
    })
void Instance::loadBundle(
    std::unique_ptr<RAMBundleRegistry> bundleRegistry,
    std::unique_ptr<const JSBigString> string,
    std::string sourceURL) {
  callback_->incrementPendingJSCalls();
  SystraceSection s("Instance::loadBundle", "sourceURL", sourceURL);
  nativeToJsBridge_->loadBundle(
      std::move(bundleRegistry), std::move(string), std::move(sourceURL));
}
 
//Instance::loadBundle调用了nativeToJsBridge_->loadBundle,
void NativeToJsBridge::loadBundle(
    std::unique_ptr<RAMBundleRegistry> bundleRegistry,
    std::unique_ptr<const JSBigString> startupScript,
    std::string startupScriptSourceURL) {
  runOnExecutorQueue(
      [this,
       bundleRegistryWrap = folly::makeMoveWrapper(std::move(bundleRegistry)),
       startupScript = folly::makeMoveWrapper(std::move(startupScript)),
       startupScriptSourceURL =
           std::move(startupScriptSourceURL)](JSExecutor *executor) mutable {
        auto bundleRegistry = bundleRegistryWrap.move();
        if (bundleRegistry) {
          executor->setBundleRegistry(std::move(bundleRegistry));
        }
        try {
          executor->loadBundle(
              std::move(*startupScript), std::move(startupScriptSourceURL));
        } catch (...) {
          m_applicationScriptHasFailure = true;
          throw;
        }
      });
}
 
//NativeToJsBridge::loadBundle里面调用了NativeToJsBridge::runOnExecutorQueue
void Instance::loadBundle(
    std::unique_ptr<RAMBundleRegistry> bundleRegistry,
    std::unique_ptr<const JSBigString> string,
    std::string sourceURL) {
  callback_->incrementPendingJSCalls();
  SystraceSection s("Instance::loadBundle", "sourceURL", sourceURL);
  nativeToJsBridge_->loadBundle(
      std::move(bundleRegistry), std::move(string), std::move(sourceURL));
}
 
//Instance::loadBundle调用了nativeToJsBridge_->loadBundle,
void NativeToJsBridge::loadBundle(
    std::unique_ptr<RAMBundleRegistry> bundleRegistry,
    std::unique_ptr<const JSBigString> startupScript,
    std::string startupScriptSourceURL) {
  runOnExecutorQueue(
      [this,
       bundleRegistryWrap = folly::makeMoveWrapper(std::move(bundleRegistry)),
       startupScript = folly::makeMoveWrapper(std::move(startupScript)),
       startupScriptSourceURL =

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2022-7-4 22:16 被Imyang编辑 ,原因:
收藏
免费 12
支持
分享
打赏 + 50.00雪花
打赏次数 1 雪花 + 50.00
 
赞赏  Editor   +50.00 2022/07/25 恭喜您获得“雪花”奖励,安全圈有你而精彩!
最新回复 (19)
雪    币: 593
活跃值: (4562)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
2
连夜加班更新
2022-7-4 22:59
0
雪    币: 6003
活跃值: (3490)
能力值: ( LV6,RANK:96 )
在线值:
发帖
回帖
粉丝
3
乌云科技团队 连夜加班更新
已经更新了
2022-7-5 09:33
0
雪    币: 129
活跃值: (4505)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
4
我记得之前遇到过,还以为加密了,然后hook openAsster函数,找到了打开bundle函数,然后直接拿到了解密好的数据
2022-7-5 10:55
0
雪    币: 846
活跃值: (4010)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
5
yang神乱杀
2022-7-5 11:00
0
雪    币: 7227
活跃值: (21980)
能力值: ( LV12,RANK:550 )
在线值:
发帖
回帖
粉丝
6
牛呀
2022-7-5 11:24
0
雪    币: 576
活跃值: (2035)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
mark,感谢分享
2022-7-5 12:46
0
雪    币: 298
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
8
热更新的话, 密钥动态变化的吧
2022-7-5 13:38
0
雪    币: 4256
活跃值: (3843)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
D-t
9
Imyang 已经更新了
更新了 他的key也没变
2022-7-5 14:40
0
雪    币: 232
活跃值: (1818)
能力值: ( LV5,RANK:73 )
在线值:
发帖
回帖
粉丝
10
Imyang 已经更新了
这个更新是替换md5为log的方法失效了吗,跟着试了一下发现logcat没有输出
2022-7-6 23:17
0
雪    币: 6003
活跃值: (3490)
能力值: ( LV6,RANK:96 )
在线值:
发帖
回帖
粉丝
11
falconnnn 这个更新是替换md5为log的方法失效了吗,跟着试了一下发现logcat没有输出
在我的星球,有快速获取signcode算法的方法,联系我加入星球
2022-8-17 17:39
0
雪    币: 6003
活跃值: (3490)
能力值: ( LV6,RANK:96 )
在线值:
发帖
回帖
粉丝
12
Imyang 在我的星球,有快速获取signcode算法的方法,联系我加入星球
刚试了3.2.0 的signcode
2022-8-17 17:40
0
雪    币: 199
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
13
为啥我用frida注入以后,lg就立马退出了
2022-8-26 09:03
0
雪    币: 6003
活跃值: (3490)
能力值: ( LV6,RANK:96 )
在线值:
发帖
回帖
粉丝
14
Imyang 在我的星球,有快速获取signcode算法的方法,联系我加入星球
https://t.zsxq.com/05JiuFAu7
2022-8-26 12:03
0
雪    币: 21
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
15
新手完全看不懂 适合老手
2022-9-12 11:14
0
雪    币: 731
活跃值: (1542)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
gl是哪个app 
2022-9-18 16:51
0
雪    币: 0
活跃值: (1003)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
hasm能直接添加函数吗?metadata.json中要改的东西还挺多
2023-5-5 17:29
0
雪    币: 116
活跃值: (1012)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18
mark
2023-5-5 23:34
0
雪    币: 33
活跃值: (60)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
2023-5-6 01:11
0
雪    币: 283
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
20
Imyang https://t.zsxq.com/05JiuFAu7
yang神,打开这个知识星球的连接显示没有权限,能再发一下吗
2024-8-26 13:45
0
游客
登录 | 注册 方可回帖
返回
//