<menu id="guoca"></menu>
<nav id="guoca"></nav><xmp id="guoca">
  • <xmp id="guoca">
  • <nav id="guoca"><code id="guoca"></code></nav>
  • <nav id="guoca"><code id="guoca"></code></nav>

    React Native Hermes 逆向實踐

    VSole2022-07-23 16:25:30

    Android 應用gl,使用了加固i,老版本的應用gl是js源碼,新版本更新后,剛開始以為是加密了源碼,分析后才知道是使用了Hermes優化引擎。

    一、Hermes簡介

    Hermes是Facebook為React Native開源的一款javascript優化引擎。

    原來的index.android.bundle是javascript的,被Hermes優化后變成了Bytecode。

    Hermes優化的優化效果如下:

    優化前:

    優化后:

    二、前期準備

    2.1 繞過root檢測

    應用gl使用了加固i,在被root 的手機上運行,閃退。

    繞過方法也很簡單,在magisk的設置中,開啟遵守排除列表,然后在配置排除列表中選擇應用gl。

    應用被添加到排除列表后,將沒辦法使用lspoed,只能使用frida。

    2.2 繞過ssl pinning

    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();            };        }    });}
    

    2.3 抓包

     

    抓包可以看到登錄接口有個signcode加密參數,69e34d747c5757236142a19f4595d313 是32位字符串,猜測跟md5相關。

    三、signcode分析

    3.1 確定signcode的來源

    由于我分析過應用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。

    Binary file ./files/RN/rnbundle/index.android.bundle matches
    

    把./files/RN/rnbundle/index.android.bundle拿出來。

    cp ./files/RN/rnbundle/index.android.bundle /data/local/tmp/index.android.bundlechmod 777 /data/local/tmp/index.android.bundle
    adb pull /data/local/tmp/index.android.bundle
    

    使用010editor打開后,就看到如下圖的內容:

    剛打開index.android.bundle, 我就猜測這個文件難道被加密了?(備注:在這之前我沒有分析過被Hermes優化的應用)。

    因為應用gl有加固i,我并沒有研究加固,于是只能研究React Native的源碼,看不能找到最終加載源碼的地方。

    3.2 通過React Native源碼研究的Hermes調用流程

    下載源碼 https://github.com/facebook/react-native.git

    在源碼中搜索 LoadScript,找到2個可疑的函數。

    private native void jniLoadScriptFromAssets(AssetManager assetManager, String assetURL, boolean loadSynchronously);
    private native void jniLoadScriptFromFile(String fileName, String sourceURL, boolean loadSynchronously);
    

    這2個函數是native,使用https://github.com/lasting-yang/frida_hook_libart/blob/master/hook_RegisterNatives.js,可以找到函數對應的so。

    [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}
    

    對jniLoadScriptFromAssets和jniLoadScriptFromFile進行hook,需要配合hook_dlopen一起使用,因為frida注入的時候,libreactnativejni.so還沒有加載。

    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();})
    

    jniLoadScriptFromFile被加載,傳入參數為index.android.bundle文件路徑。

    繼續閱讀源碼,jniLoadScriptFromFile中會調用loadScriptFromString。

    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 script;      RecoverableError::runRethrowingAsRecoverable(          [&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(                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 script;      RecoverableError::runRethrowingAsRecoverable(          [&fileName, &script]() {            script = JSBigFileString::fromPath(fileName);          });      instance_->loadScriptFromString(          std::move(script), sourceURL, loadSynchronously);    }  }}
    

    loadScriptFromString

    void Instance::loadScriptFromString(    std::unique_ptr 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])        }    })
    

    hook loadScriptFromString后,可以知道loadSynchronously為0, 繼續分析loadBundle。

    void Instance::loadBundle(    std::unique_ptr bundleRegistry,    std::unique_ptr 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 bundleRegistry,    std::unique_ptr 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
    

    runOnExecutorQueue的參數是一個Lambda表達式,它的回調函數里面調用了loadBundle,在源碼中搜索loadBundle,找到了很多處實現代碼,這時候我們酒不知道loadBundle具體實現在哪里,繼續寫hook代碼hook_loadBundle。

    function hook_loadBundle() {        //根據前面分析RN的一些so,可以發現大部分函數符號都還在so里面,那么我們通過DebugSymbol的findFunctionsMatching,找到所有loadBundle函數,并進行hook    DebugSymbol.findFunctionsMatching("*loadBundle*").map(addr => {        Interceptor.attach(addr, {            onEnter(args) {                console.log("loadBundle:", DebugSymbol.fromAddress(addr));            }        })    })}hook 結果如下:
    loadBundle: 0xbb70699d libreactnativejni.so!_ZN8facebook5react8Instance10loadBundleENSt6__ndk110unique_ptrINS0_17RAMBundleRegistryENS2_14default_deleteIS4_EEEENS3_IKNS0_11JSBigStringENS5_IS9_EEEENS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEloadBundle: 0xbb70a845 libreactnativejni.so!_ZN8facebook5react16NativeToJsBridge10loadBundleENSt6__ndk110unique_ptrINS0_17RAMBundleRegistryENS2_14default_deleteIS4_EEEENS3_IKNS0_11JSBigStringENS5_IS9_EEEENS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEEloadBundle: 0xbb9a5ec5 libhermes-executor-release.so!_ZN8facebook5react11JSIExecutor10loadBundleENSt6__ndk110unique_ptrIKNS0_11JSBigStringENS2_14default_deleteIS5_EEEENS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE
    最終找到了libhermes-executor-release.so的facebook::react::JSIExecutor::loadBundle函數
    

    facebook::react::JSIExecutor::loadBundle函數中調用了evaluateJavaScript。

    void JSIExecutor::loadBundle(    std::unique_ptr script,    std::string sourceURL) {  SystraceSection s("JSIExecutor::loadBundle");
      bool hasLogger(ReactMarker::logTaggedMarker);  std::string scriptName = simpleBasename(sourceURL);  if (hasLogger) {    ReactMarker::logTaggedMarker(        ReactMarker::RUN_JS_BUNDLE_START, scriptName.c_str());  }  runtime_->evaluateJavaScript(      std::make_unique(std::move(script)), sourceURL);  flush();  if (hasLogger) {    ReactMarker::logTaggedMarker(        ReactMarker::RUN_JS_BUNDLE_STOP, scriptName.c_str());  }}
    

    hook "*evaluateJavaScript*",

    function hook_evaluateJavaScript() {    DebugSymbol.findFunctionsMatching("*evaluateJavaScript*").map(addr => {               Interceptor.attach(addr, {            onEnter(args) {                console.log("evaluateJavaScript:", DebugSymbol.fromAddress(addr), "\r", print_native_stack("evaluateJavaScript", this));            }        })    })}
    并沒有找到evaluateJavaScript函數,只找到了一個evaluateJavaScriptWithSourceMap函數
    evaluateJavaScript: 0xbb866775 libhermes.so!_ZN8facebook6hermes13HermesRuntime31evaluateJavaScriptWithSourceMapERKNSt6__ndk110shared_ptrIKNS_3jsi6BufferEEES9_RKNS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE
    [evaluateJavaScript] called from:0xbb867431 libhermes.so!0x114310xbb6605b9 libhermes-executor-common-release.so!0x1c5b90xbb727051 libhermes-executor-release.so!_ZN8facebook5react11JSIExecutor10loadBundleENSt6__ndk110unique_ptrIKNS0_11JSBigStringENS2_14default_deleteIS5_EEEENS2_12basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE+0x18c0xbb4b94e7 libreactnativejni.so!0xa54e70xbb4ba133 libreactnativejni.so!_ZNKSt6__ndk18functionIFvPN8facebook5react10JSExecutorEEEclES4_+0x160xbb4a5ae1 libreactnativejni.so!0x91ae10xbb4961d3 libreactnativejni.so!_ZN8facebook3jni6detail13MethodWrapperIMNS_5react15JNativeRunnableEFvvEXadL_ZNS4_3runEvEES4_vJEE8dispatchENS0_9alias_refIPNS1_8JTypeForINS0_11HybridClassIS4_NS3_8RunnableEE8JavaPartESB_vE11_javaobjectEEE+0xe0xbb49617f libreactnativejni.so!_ZN8facebook3jni6detail15FunctionWrapperIPFvNS0_9alias_refIPNS1_8JTypeForINS0_11HybridClassINS_5react15JNativeRunnableENS6_8RunnableEE8JavaPartES8_vE11_javaobjectEEEESD_vJEE4callEP7_JNIEnvP8_jobjectSG_+0x260xee6708df libart.so!art_quick_generic_jni_trampoline+0x2e0x71915663 boot-framework.oat!0x54e663
    

    evaluateJavaScriptWithSourceMap函數 在React Native源碼中沒有搜到,在另一個hermes項目(https://github.com/facebook/hermes)中找到了evaluateJavaScriptWithSourceMap函數和evaluateJavaScript函數。

    evaluateJavaScript函數對應so的地址0xbb867431 libhermes.so!0x11431

    jsi::Value HermesRuntimeImpl::evaluateJavaScript(    const std::shared_ptr &buffer,    const std::string &sourceURL) {  return evaluateJavaScriptWithSourceMap(buffer, nullptr, sourceURL);}
    jsi::Value HermesRuntime::evaluateJavaScriptWithSourceMap(    const std::shared_ptr &buffer,    const std::shared_ptr &sourceMapBuf,    const std::string &sourceURL) {  return impl(this)->evaluatePreparedJavaScript(      impl(this)->prepareJavaScriptWithSourceMap(          buffer, sourceMapBuf, sourceURL));}
    

    evaluateJavaScriptWithSourceMap函數中調用了prepareJavaScriptWithSourceMap函數, 繼續調用isHermesBytecode函數。

    HermesRuntimeImpl::prepareJavaScriptWithSourceMap(    const std::shared_ptr &jsiBuffer,    const std::shared_ptr &sourceMapBuf,    std::string sourceURL) {  std::pair, std::string> bcErr{};  auto buffer = std::make_unique(std::move(jsiBuffer));  vm::RuntimeModuleFlags runtimeFlags{};  runtimeFlags.persistent = true;
      bool isBytecode = isHermesBytecode(buffer->data(), buffer->size());
    

    isHermesBytecode用來判斷是否是Hermes的Bytecode。

    bool HermesRuntime::isHermesBytecode(const uint8_t *data, size_t len) {  return hbc::BCProviderFromBuffer::isBytecodeStream(      llvh::ArrayRef(data, len));}
    static bool isBytecodeStream(llvh::ArrayRef aref) {    const auto *header =        reinterpret_cast(aref.data());    return (        aref.size() >= sizeof(hbc::BytecodeFileHeader) &&        header->magic == hbc::MAGIC);}
    const static uint64_t MAGIC = 0x1F1903C103BC1FC6;
    

    MAGIC和index.android.bunddle的前8個字節是一直的,至此已經知道index.android.bundle并不是被應用gl加密了,而是被Hermes編譯成了bytecode。

      BytecodeFileHeader(      uint64_t magic,        //0x1F1903C103BC1FC6      uint32_t version,    //0x54        表示是84版本,commit 0bac657c61ac47a3a9537d982921f5f6c9630d41 (HEAD, tag: v0.8.1)      ......}
    hermes/include/hermes/BCGen/HBC/BytecodeVersion.h路徑中有定義BYTECODE_VERSION
    const static uint32_t BYTECODE_VERSION = 84;
    

    3.3 反編譯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。

    pip install https://github.com/niosega/hbctool/archive/ac6fabb69a7229ed9764997d153d4f703d1381aa.zip
    

    反編譯

    hbctool disasm index.android.bundle bundle
    

    回編譯

    hbctool asm bundle index.android.bundle.re
    

    bytecode反編譯出來的代碼如下:搜索兩處能md5相關的代碼。

    并不需要深入bytecode,指令詳情,了解幾個簡單指令即可。

    只需要寫一個打印日志的函數,變成成bytecode,反編譯后替換掉這兩個函數就能看到這兩個md5函數的輸入參數。

    3.4 js代碼編譯成Hermes bytecode

    先編譯Hermes源碼,會得到./build/bin/hermes工具,

    test.js

    function hook_log(a, b) {    window.nativeLoggingHook(a + " " + b, 1);    return " ";}
    function test() {    hook_log("333", "555");}
    

    寫了一些簡單的js代碼,把test.js編譯成bytecode

    ./build/bin/hermes  -emit-binary -out test.hbc test.js
    

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

    反編譯test.hbc

    hbctool disasm test.hbc testdir
    

    得到

    Function1(3 params, 14 registers, 0 symbols):    GetGlobalObject         Reg8:0                                ; 先獲取全局變量 Reg8:0    TryGetById              Reg8:4, Reg8:0, UInt8:1, UInt16:7    ; 通過window字符串從Reg8:0全局變量中拿到window變量,存放在Reg8:4    ; Oper[3]: String(7) 'window'
        GetByIdShort            Reg8:3, Reg8:4, UInt8:2, UInt8:5    ; 從windows變量中拿nativeLoggingHook,存放在Reg8:3    ; Oper[3]: String(5) 'nativeLoggingHook'
        LoadParam               Reg8:1, UInt8:1    LoadConstString         Reg8:0, UInt16:0    ; Oper[1]: String(0) ' '
        Add                     Reg8:2, Reg8:1, Reg8:0    LoadParam               Reg8:1, UInt8:2    Add                     Reg8:2, Reg8:2, Reg8:1    LoadConstUInt8          Reg8:1, UInt8:1    Call3                   Reg8:1, Reg8:3, Reg8:4, Reg8:2, Reg8:1    ;調用window.nativeLoggingHook函數    Ret                     Reg8:0EndFunction
    

    3.5 替換bytecode,得到signcode算法

    把反編譯出來的bytecode,替換到md5函數中。

    需要對字符串的id進行修改,字符串對應hbctool反編譯出來的string.json中的字符串id。

    {    "id": 253,    "isUTF16": false,    "value": "window"},{    "id": 33087,    "isUTF16": false,    "value": "nativeLoggingHook"},{    "id": 18880,    "isUTF16": false,    "value": " "},
    Function13508(3 params, 14 registers, 0 symbols):    GetGlobalObject         Reg8:0    TryGetById              Reg8:4, Reg8:0, UInt8:1, UInt16:253    ; 修改字符串id UInt16:7-> UInt16:253    ; Oper[3]: String(254) 'window'
        GetById                 Reg8:3, Reg8:4, UInt8:2, UInt16:33087    ;修改字符串id UInt8:5 -> UInt16:33087, 從UInt8改成UInt16, 需要把GetByIdShort修改成GetById指令    ; Oper[3]: String(4397) 'nativeLoggingHook'
        LoadParam               Reg8:1, UInt8:1    LoadConstString         Reg8:0, UInt16:18880            ; 修改字符串id UInt16:0 -> UInt16:18880    ; Oper[1]: String(674) ' '
        Add                     Reg8:2, Reg8:1, Reg8:0    LoadParam               Reg8:1, UInt8:2    Add                     Reg8:2, Reg8:2, Reg8:1    LoadConstUInt8          Reg8:1, UInt8:1    Call3                   Reg8:1, Reg8:3, Reg8:4, Reg8:2, Reg8:1    Ret                     Reg8:0EndFunction
    

    再次回編譯,得到index.android.bundle.re。

    hbctool asm bundle index.android.bundle.re
    md5sum index.android.bundle.re7eba6c20134268a82e5a0af948ca550b  index.android.bundle.re
    

    現在替換app目錄下的index.android.bundle。

    adb push index.android.bundle.re /data/local/tmp/index.android.bundle.re
    adb shellsucd /data/data/com.pcakge.name/files/RN/rnbundle/cp index.android.bundle index.android.bundle.bak    # 對原來的文件備份cp /data/local/tmp/index.android.bundle.re index.android.bundle
    

    結束app, 運行 adb logcat "*:S ReactNative:V ReactNativeJS:V", 再次運行app就可以到得到md5函數的輸入參數。

    ReactNativeJS: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXAPPKEYGL_RN_D02F48E720CACLIENTANDROIDDEVICEIDBBC6AD7E-1561-4702-8C1E-3AAC682B4D8BENCRYPT1PASSWORD6666666666TIMESTAMPUINFO666666666VERSION3.1.0XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX undefined
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX脫敏
    

    算法分析完成。

    bundlereact
    本作品采用《CC 協議》,轉載必須注明作者和本文鏈接
    Android 應用gl,使用了加固i,老版本的應用gl是js源碼,新版本更新后,剛開始以為是加密了源碼,分析后才知道是使用了Hermes優化引擎。Hermes優化的優化效果如下:優化前:優化后:二、前期準備2.1 繞過root檢測應用gl使用了加固i,在被root 的手機上運行,閃退。繞過方法也很簡單,在magisk的設置中,開啟遵守排除列表,然后在配置排除列表中選擇應用gl。
    巧解一道CTF Android題
    2022-08-10 16:15:40
    無須還原代碼,窮舉爆破。我們打開jeb工具,定位到當前activity。我們看一下saveSN方法,可以看到這是一個native方法。我們解包一下apk,獲取到so文件。下面進入ida分析。導出函數并沒有相關java的native方法,說明是動態注冊。我們看下JNI_ONLOAD函數:jint JNI_OnLoad{ if ( !
    本文會詳細敘述客戶端風控對抗的“邊界值”在哪里,如果你是在做風控對抗 ,不管你是這場游戲中在演“貓”的角色還是“老鼠”的角色 。本文將站在上帝視角去講解對應的“規則” 和“玩法”,以及如何實現角色轉換。通過之前的系列文章,配合這篇文章希望每個小白玩家都能知道大廠是怎么玩的,如何設置游戲規則,我們應該如何進行解謎。而這個協議里面具體發送的內容,就是IPC協議裝的“包裹”就是用的Parcel 。
    簡介pwcrack-framework是@L-codes師傅用Ruby寫的一個密碼自動破解框架,目前提供了22個在線破解和30個離線破解接口,支持53種算法破解。特點Ruby3.1+支持Linux/OSX/Windows平臺運行支持在線和離線的進行破解密碼明文支持自動分析密文算法調用插件破解提供簡單的DSL編寫插件配置java環境擴展,支持更多算法,可安裝gem install rjb
    先看第二個LoopCrypto老規矩,先查殼:然后就可以看看java層啦:先在xml文件中找到文件的入口點就可以分析了:然后進入到入口點:就是用這個函數Decode.m2957a()先解密兩個字符串。
    請勿利用文章內的相關技術從事非法測試,如因此產生的一切不良后果與文章作者和本公眾號無關。
    安卓工具總結
    2021-10-14 08:39:34
    JRE:Java Runtime Environment是Java運行時環境,包含了java虛擬機,java基礎類庫安裝過程:1)雙擊啟動安裝程序2)默認安裝路徑3)jre路徑選擇4)配置環境變量JAVA_HOME. 這里介紹幾款不錯的安卓模擬器。
    Windows 11已知問題匯總
    2021-10-11 16:00:36
    距10月5日Windows 11正式發布已好些天,想必感興趣的朋友都已經安裝體驗過了。
    人們普遍認為macOS比Windows更安全,于是乎很多中小企業就利用macOS來追求安全性,但對于完全依賴macOS來保證安全的中小型企業來說,這是非常危險的。比如,用戶將找不到macOS中內置的類似Defender的安全中心。
    隨后谷歌以Apache開源許可證的授權方式,發布了Android的源代碼。在Android安裝或更新App時,系統首先檢驗App簽名,如果App未簽名或簽名校驗失敗,安裝操作將被拒絕。簽名利用摘要和非對稱加密技術技術確保APK由開發者發布且未被篡改。Android系統優先選擇其所支持高版本簽名進行校驗,當不存在高版本簽名時則向下選擇。
    VSole
    網絡安全專家
      亚洲 欧美 自拍 唯美 另类