编程开源技术交流,分享技术与知识

网站首页 > 开源技术 正文

安卓逆向jni的base笔记

wxchong 2024-06-22 21:07:51 开源技术 12 ℃ 0 评论

免责声明

本文章中所有内容仅供学习交流使用,严禁用于商业用途和非法用途。若有侵权,请联系我,立即删除!

获取当前程序的包名

adb shell dumpsys window | grep mCurrentFocus

frida 手动jnienv

frida -U -f com.james.easymd5 -l frida_hook_libart/hook_art.js --no-pause

frida 自动追踪 jnitracer

pip install jnitrace


利用objection找so名====>libeasymd5.so
    objection -g com.james.easymd5 explore
    memory list modules


      ps: libeasymd5.so    0x7386f08000  221184 (216.0 KiB)    /data/app/com.james.easymd5-3XeGcE9nwvgObFyalCNGsA==/lib/arm64/libeasymd5.s...


    emory list exports libeasymd5.so                                                                                                                     
      Save the output by adding `--json exports.json` to this command
      Type      Name                                          Address
      --------  --------------------------------------------  ----------
      function  Java_com_james_easymd5_MainActivity_mdFile    0xd2b96e39
      function  _Z7MD5InitP7MD5_CTX                           0xd2b96b63
      function  Java_com_james_easymd5_MainActivity_mdString  0xd2b96a59
      function  _Z9MD5UpdateP7MD5_CTXPhj                      0xd2b96ba5
      function  _ZN7_JNIEnv12NewStringUTFEPKc                 0xd2b96e19
      function  _Z8MD5FinalP7MD5_CTX                          0xd2b96c85
      function  _ZN7_JNIEnv17GetStringUTFCharsEP8_jstringPh   0xd2b96b3d


c++filt _Z9MD5UpdateP7MD5_CTXPhj
    MD5Update(MD5_CTX*, unsigned char*, unsigned int)


    命令:jnitrace -l libeasymd5.so com.james.easymd5   


    Tracing. Press any key to quit...
    Traced library "libeasymd5.so" loaded from path "/data/app/com.james.easymd5-3XeGcE9nwvgObFyalCNGsA==/lib/arm64".


             /* TID 7350 */
      370 ms [+] JNIEnv->NewStringUTF
      370 ms |- JNIEnv*          : 0x73a98cc1c0
      370 ms |- char*            : 0x7fd63a6cc1
      370 ms |:     Hello from C++
      370 ms |= jstring          : 0x75    { Hello from C++ }


      370 ms ----------------------------------------Backtrace----------------------------------------
      370 ms |->       0x7392b97098: _ZN7_JNIEnv12NewStringUTFEPKc+0x2c (libeasymd5.so:0x7392b88000)
      370 ms |->       0x7392b97098: _ZN7_JNIEnv12NewStringUTFEPKc+0x2c (libeasymd5.so:0x7392b88000)      

frida Hook so位置

frida -U -f com.james.easymd5 -l dump_dex.js --no-pause
    [Google Pixel XL::com.james.easymd5]-> android_dlopen_ext: /data/app/com.james.easymd5-7ZxsaFkVCnATrcrvoqQcSA==/oat/arm/base.odex
    android_dlopen_ext: /data/app/com.james.easymd5-7ZxsaFkVCnATrcrvoqQcSA==/lib/arm/libeasymd5.so
    android_dlopen_ext: /vendor/lib/hw/gralloc.msm8996.so
    dlopen: libadreno_utils.so
    dlopen: /vendor/lib/egl/libEGL_adreno.so
    android_dlopen_ext: /vendor/lib/hw/android.hardware.graphics.mapper@2.0-impl.so
    android_dlopen_ext: /vendor/lib/hw/gralloc.msm8996.so

read elf查看导出表

7z x app-debug.apk
  cd lib/armeabi-v7a
  readelf -s libeasymd5.so


    Symbol table '.dynsym' contains 30 entries:
       Num:    Value  Size Type    Bind   Vis      Ndx Name
         0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND 
         1: 00000000     0 FUNC    GLOBAL DEFAULT  UND __cxa_atexit@LIBC (2)
         2: 00000000     0 FUNC    GLOBAL DEFAULT  UND __cxa_f[...]@LIBC (2)
         3: 00000000     0 OBJECT  GLOBAL DEFAULT  UND __sF@LIBC (2)
         4: 00000000     0 FUNC    GLOBAL DEFAULT  UND __stack[...]@LIBC (2)
         5: 00000000     0 OBJECT  GLOBAL DEFAULT  UND __stack[...]@LIBC (2)
         6: 00000000     0 FUNC    GLOBAL DEFAULT  UND __strlen_chk@LIBC (2)
         7: 00000000     0 FUNC    GLOBAL DEFAULT  UND __vspri[...]@LIBC (2)
         8: 00000000     0 FUNC    GLOBAL DEFAULT  UND fclose@LIBC (2)
         9: 00000000     0 FUNC    GLOBAL DEFAULT  UND fopen@LIBC (2)
        10: 00000000     0 FUNC    GLOBAL DEFAULT  UND fprintf@LIBC (2)
        11: 00000000     0 FUNC    GLOBAL DEFAULT  UND fread@LIBC (2)
        12: 00000000     0 FUNC    GLOBAL DEFAULT  UND strlen@LIBC (2)
        13: 00000000     0 FUNC    GLOBAL DEFAULT  UND abort@LIBC (2)
        14: 00000000     0 FUNC    GLOBAL DEFAULT  UND fflush@LIBC (2)
        15: 00000000     0 FUNC    GLOBAL DEFAULT  UND __aeabi_memclr
        16: 00000000     0 FUNC    GLOBAL DEFAULT  UND __aeabi_memcpy
        17: 00000000     0 FUNC    GLOBAL DEFAULT  UND __gnu_Unwind_Fin[...]
        18: 00000000     0 FUNC    GLOBAL DEFAULT  UND dladdr@LIBC (3)
        19: 00000000     0 FUNC    GLOBAL DEFAULT  UND snprintf@LIBC (2)
        20: 00000e39   324 FUNC    GLOBAL DEFAULT   13 Java_com_james_e[...]
        21: 00000b63    66 FUNC    GLOBAL DEFAULT   13 _Z7MD5InitP7MD5_CTX
        22: 00005044     0 NOTYPE  GLOBAL DEFAULT  ABS _edata
        23: 00005045     0 NOTYPE  GLOBAL DEFAULT  ABS _end
        24: 00000a59   228 FUNC    GLOBAL DEFAULT   13 Java_com_james_e[...]
        25: 00000ba5   224 FUNC    GLOBAL DEFAULT   13 _Z9MD5UpdateP7MD[...]
        26: 00000e19    32 FUNC    WEAK   DEFAULT   13 _ZN7_JNIEnv12New[...]
        27: 00005044     0 NOTYPE  GLOBAL DEFAULT  ABS __bss_start
        28: 00000c85   284 FUNC    GLOBAL DEFAULT   13 _Z8MD5FinalP7MD5_CTX
        29: 00000b3d    38 FUNC    WEAK   DEFAULT   13 _ZN7_JNIEnv17Get[...]


  objdump -T libeasymd5.so


    libeasymd5.so:     file format elf32-little


    DYNAMIC SYMBOL TABLE:
    00000000      DF *UND*  00000000 (LIBC)       __cxa_atexit
    00000000      DF *UND*  00000000 (LIBC)       __cxa_finalize
    00000000      DO *UND*  00000000 (LIBC)       __sF
    00000000      DF *UND*  00000000 (LIBC)       __stack_chk_fail
    00000000      DO *UND*  00000000 (LIBC)       __stack_chk_guard
    00000000      DF *UND*  00000000 (LIBC)       __strlen_chk
    00000000      DF *UND*  00000000 (LIBC)       __vsprintf_chk
    00000000      DF *UND*  00000000 (LIBC)       fclose
    00000000      DF *UND*  00000000 (LIBC)       fopen
    00000000      DF *UND*  00000000 (LIBC)       fprintf
    00000000      DF *UND*  00000000 (LIBC)       fread
    00000000      DF *UND*  00000000 (LIBC)       strlen
    00000000      DF *UND*  00000000 (LIBC)       abort
    00000000      DF *UND*  00000000 (LIBC)       fflush
    00000000      DF *UND*  00000000              __aeabi_memclr
    00000000      DF *UND*  00000000              __aeabi_memcpy
    00000000      DF *UND*  00000000              __gnu_Unwind_Find_exidx
    00000000      DF *UND*  00000000 (LIBC)       dladdr
    00000000      DF *UND*  00000000 (LIBC)       snprintf
    00000e39 g    DF .text  00000144  Base        Java_com_james_easymd5_MainActivity_mdFile
    00000b63 g    DF .text  00000042  Base        _Z7MD5InitP7MD5_CTX
    00005044 g    D  *ABS*  00000000  Base        _edata
    00005045 g    D  *ABS*  00000000  Base        _end
    00000a59 g    DF .text  000000e4  Base        Java_com_james_easymd5_MainActivity_mdString
    00000ba5 g    DF .text  000000e0  Base        _Z9MD5UpdateP7MD5_CTXPhj
    00000e19  w   DF .text  00000020  Base        _ZN7_JNIEnv12NewStringUTFEPKc
    00005044 g    D  *ABS*  00000000  Base        __bss_start
    00000c85 g    DF .text  0000011c  Base        _Z8MD5FinalP7MD5_CTX
    00000b3d  w   DF .text  00000026  Base        _ZN7_JNIEnv17GetStringUTFCharsEP8_jstringPh

Frida hook jni

Interceptor.attach(Module.findExportByName(null, "android_dlopen_ext"), {
        onEnter: function(args) {
            var pathptr = args[0];
            this.target = false
            if (pathptr !== undefined && pathptr != null) {
                var path = ptr(pathptr).readCString();
                console.log("android_dlopen_ext:", path);
                if (path.indexOf("libeasymd5.so") >= 0) {
                    this.target = true;
                    console.log("[android_dlopen_ext:]", path);
                }
            }
        },
        onLeave: function(retval) {
            if (this.target) {
                var mdString_addr = Module.findExportByName("libeasymd5.so","Java_com_james_easymd5_MainActivity_mdString");
                console.log("mdString address is => ",mdString_addr)
                Interceptor.attach(mdString_addr, {
                    onEnter: function (args) {
                        console.log("arg2 jstring => ", args[2]);//mdString的方法第三个参数是我们要的值
                        console.log("arg2 jstring => ", Java.vm.tryGetEnv().getStringUtfChars(args[2], null).readCString());
                        console.log('CCCryptorCreate called from:\n' +
                            Thread.backtrace(this.context, Backtracer.ACCURATE)
                                .map(DebugSymbol.fromAddress).join('\n') + '\n');


                    }, onLeave: function (retval) {


                        console.log("retval is => ", retval);
                        console.log("retval is => ", Java.vm.tryGetEnv().getStringUtfChars(retval, null).readCString());
                    }
                })
            }
            // if (this.can_hook_libart && !is_hook_libart) {
            //     dump_dex();
            //     is_hook_libart = true;
            // }
        }
    });


  ps: Invoke JNI===>Java.vm.tryGetEnv()


  结果:
    [Google Pixel XL::com.james.easymd5]-> android_dlopen_ext: /data/app/com.james.easymd5-7ZxsaFkVCnATrcrvoqQcSA==/oat/arm/base.odex
  android_dlopen_ext: /data/app/com.james.easymd5-7ZxsaFkVCnATrcrvoqQcSA==/lib/arm/libeasymd5.so
  [android_dlopen_ext:] /data/app/com.james.easymd5-7ZxsaFkVCnATrcrvoqQcSA==/lib/arm/libeasymd5.so
  mdString address is =>  0xd1873a59
  arg2 jstring =>  0xffc6e2f0
  arg2 jstring =>  1234567890
  CCCryptorCreate called from:
  0xd1a6a143 base.odex!oatexec+0x143                                                                                                                                                                                                                                                                                                                                                                                                                 


  retval is =>  0x79
  retval is =>  e807f1fcf82d132f9bb018ca6738a19f
  android_dlopen_ext: /vendor/lib/hw/gralloc.msm8996.so
  dlopen: libadreno_utils.so
  dlopen: /vendor/lib/egl/libEGL_adreno.so
  android_dlopen_ext: /vendor/lib/hw/android.hardware.graphics.mapper@2.0-impl.so
  android_dlopen_ext: /vendor/lib/hw/gralloc.msm8996.so






Interceptor.attach(Module.findExportByName(null, "android_dlopen_ext"), {
        onEnter: function(args) {
            var pathptr = args[0];
            this.target = false
            if (pathptr !== undefined && pathptr != null) {
                var path = ptr(pathptr).readCString();
                console.log("android_dlopen_ext:", path);
                if (path.indexOf("libeasymd5.so") >= 0) {
                    this.target = true;
                    console.log("[android_dlopen_ext:]", path);
                }
            }
        },
        onLeave: function(retval) {
            if (this.target) {
                var mdString_addr = Module.findExportByName("libeasymd5.so","Java_com_james_easymd5_MainActivity_mdString");
                console.log("mdString address is => ",mdString_addr)




                var md5string = new NativeFunction(mdString_addr,"pointer",["pointer","pointer","pointer"]);
            
                Interceptor.replace(mdString_addr,new NativeCallback(function(env, jclass,jstring){
                    
                    console.log(Java.vm.tryGetEnv().getStringUtfChars(jstring, null).readCString())
                    var newJSTRING = Java.vm.tryGetEnv().newStringUtf('james123456');
                    var retval = md5string(env, jclass,newJSTRING);
                    console.log("retval is => ", Java.vm.tryGetEnv().getStringUtfChars(retval, null).readCString());                                   
                
                    return newJSTRING;
                },"pointer",["pointer","pointer","pointer"]))


            }
            // if (this.can_hook_libart && !is_hook_libart) {
            //     dump_dex();
            //     is_hook_libart = true;
            // }
        }
    });


 结果:
   [Google Pixel XL::com.james.easymd5]-> android_dlopen_ext: /data/app/com.james.easymd5-qBJw9ZijDSWX-eOLgtln-A==/oat/arm/base.odex
  android_dlopen_ext: /data/app/com.james.easymd5-qBJw9ZijDSWX-eOLgtln-A==/lib/arm/libeasymd5.so
  [android_dlopen_ext:] /data/app/com.james.easymd5-qBJw9ZijDSWX-eOLgtln-A==/lib/arm/libeasymd5.so
  mdString address is =>  0xd17d2a59
  1234567890
  retval is =>  cc6e7cb7cb71073647e833e2fb89482b

jni的动态注册(jni_onload)

1、// Dynamic register


  #define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))




  jstring zlj666(
          JNIEnv *env, jclass obj, jstring str) {
      MD5_CTX mdContext;
      int m = 0;
      char *inString = const_cast<char *>(env->GetStringUTFChars(str, NULL));


      unsigned int len = strlen(inString);


      MD5Init(&mdContext);
      MD5Update(&mdContext, reinterpret_cast<unsigned char *>(inString), len);
      MD5Final(&mdContext);


      int i;
      char dest[32] = { 0 };
      for (i = 0; i < 16; i++) {
          sprintf(dest + i * 2, "%02x", mdContext.digest[i]);
      }


      return env->NewStringUTF(dest);
  }


  // name (java function name) signature【签名】 jadx打开看mdString的smali的后缀
  static JNINativeMethod method_table[] = {
          {"mdString", "(Ljava/lang/String;)Ljava/lang/String;", (void *) zlj666},
  };


  static int registerMethods(JNIEnv *env, const char *className,
                             JNINativeMethod *gMethods, int numMethods) {
      jclass clazz = env->FindClass(className);
      if (clazz == nullptr) {
          return JNI_FALSE;
      }
      if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {
          return JNI_FALSE;
      }
      return JNI_TRUE;
  }


  JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *reserved) {
      JNIEnv *env = nullptr;
      if (vm->GetEnv((void **) &env, JNI_VERSION_1_6) != JNI_OK) {
          return JNI_ERR;
      }


      // 注册native方法
      if (!registerMethods(env,"com/james/easymd5/MainActivity" , method_table, NELEM(method_table))) {
          return JNI_ERR;
      }


      return JNI_VERSION_1_6;
  }




  2、frida hook jni动态注册
    2.1java层调用:
      setTimeout(() => {
          Java.perform(() => {
              var result = Java.use("com.james.easymd5.MainActivity").mdString("1234567890");
              console.log("result is => ",result)


          })
      }, 0);
      frida -UF -l invoke.js --runtime=V8   【程序要在运行中】
      结果:
        result is =>  e807f1fcf82d132f9bb018ca6738a19f
    2.2nativ层调用
    
     Java.perform(() => {


          var zlj666_address = Module.findExportByName('libeasymd5.so',"_Z6zlj666P7_JNIEnvP7_jclassP8_jstring")
          console.log("found address =>", zlj666_address)
          var zlj666 = new NativeFunction(zlj666_address, "pointer", ["pointer", "pointer", "pointer"]);
          var newJSTRING = Java.vm.tryGetEnv().newStringUtf("12345james")
          var result = zlj666(Java.vm.tryGetEnv(), Java.vm.tryGetEnv(), newJSTRING);
          console.log("result is => ", Java.vm.tryGetEnv().getStringUtfChars(result, null).readCString());


      })
      结果:
        found address => 0xd6b9cba5
      result is =>  048943059b19127c86e2069c6e804f3f
      [Google Pixel XL::easymd5]->  


    2.3脱离app环境运行so环境
      adb push libeasymd5.so /data/local/tmp
      cp -rf libeasymd5.so  /data/app
      chmod 777 libeasymd5.so


          Java.perform(() => {
              var module = Module.load("/data/app/libeasymd5.so")
              var zlj666_address = module.findExportByName("_Z6zlj666P7_JNIEnvP7_jclassP8_jstring")
              console.log("found address =>", zlj666_address)
              var zlj666 = new NativeFunction(zlj666_address, "pointer", ["pointer", "pointer", "pointer"]);
              var newJSTRING = Java.vm.tryGetEnv().newStringUtf("12345james")
              var result = zlj666(Java.vm.tryGetEnv(), Java.vm.tryGetEnv(), newJSTRING);
              console.log("result is => ", Java.vm.tryGetEnv().getStringUtfChars(result, null).readCString());


          })




      结果:
        found address => 0xd6b9cba5
        result is =>  048943059b19127c86e2069c6e804f3f
        [Google Pixel XL::easymd5]->


      判断32/64位进程:660就是32位
      marlin:/data/app # ps -ef | grep -i zyg
      root           659     1 1 16:25:38 ?     00:33:28 zygote64
      root           660     1 0 16:25:38 ?     00:00:02 zygote


      marlin:/data/app # ps -ef | grep -i 660                                                                                                                                                           
      root           660     1 0 16:25:38 ?     00:00:02 zygote
      u0_a134       5071   660 0 15:17:58 ?     00:00:06 com.james.easymd5


    2.4 调用非静态函数(java调用对象或者实例一个对象)
        Java.scheduleOnMainThread(() =>{
            var result = Java.use("com.roysue.easymd5.MainActivity").$new().mdString("12345james");
            console.log("result is => ",result)
        })
      结果:
        found address => 0xd6b9cba5
        result is =>  048943059b19127c86e2069c6e804f3f
        [Google Pixel XL::easymd5]->

unidbg调用jni

public class MainActivity {


      public static void main(String[] args) {
          long start = System.currentTimeMillis();
          com.james.easymd5.MainActivity mainActivity = new com.james.easymd5.MainActivity();
          System.out.println("load offset=" + (System.currentTimeMillis() - start) + "ms");
          mainActivity.crack();
      }


      private final AndroidEmulator emulator;
      private final VM vm;
      private final DvmClass dvmClass;


      private MainActivity() {
          emulator = AndroidEmulatorBuilder
                  .for32Bit()
                  .addBackendFactory(new DynarmicFactory(true))
                  .build();
          Memory memory = emulator.getMemory();
          LibraryResolver resolver = new AndroidResolver(23);
          memory.setLibraryResolver(resolver);


          vm = emulator.createDalvikVM();
          vm.setVerbose(true); // 日志开关
          DalvikModule dm = vm.loadLibrary(new File("unidbg-android/src/test/resources/example_binaries/armeabi-v7a/libeasymd5.so"), false);
          dm.callJNI_OnLoad(emulator);
          dvmClass = vm.resolveClass("com/james/easymd5/MainActivity");
      }


      private void crack() {




      //静态函数
          DvmObject result =  dvmClass.callStaticJniMethodObject(emulator,"mdString(Ljava/lang/String;)Ljava/lang/String;","12345james");
          System.out.println("result is => " + result.getValue());
      //非静态函数
          DvmObject<?> obj = ProxyDvmObject.createObject(vm, this);
          DvmObject result2  = obj.callJniMethodObject(emulator,"mdString(Ljava/lang/String;)Ljava/lang/String;","12345james");
          System.out.println("result2 is => " + result2.getValue());




      }
  }
  结果:
    JNIEnv->FindClass(com/james/easymd5/MainActivity) was called from RX@0x40001ed1[libeasymd5.so]0x1ed1
    JNIEnv->RegisterNatives(com/james/easymd5/MainActivity, RW@0x40005000[libeasymd5.so]0x5000, 1) was called from RX@0x40001f01[libeasymd5.so]0x1f01
    RegisterNative(com/james/easymd5/MainActivity, mdString(Ljava/lang/String;)Ljava/lang/String;, RX@0x40000ba5[libeasymd5.so]0xba5)
    load offset=734ms
    Find native function Java_com_james_easymd5_MainActivity_mdString => RX@0x40000ba5[libeasymd5.so]0xba5
    JNIEnv->GetStringUtfChars("12345james") was called from RX@0x40000cb7[libeasymd5.so]0xcb7
    JNIEnv->NewStringUTF("048943059b19127c86e2069c6e804f3f") was called from RX@0x40000f8d[libeasymd5.so]0xf8d
    result is => 048943059b19127c86e2069c6e804f3f
    Find native function Java_com_james_easymd5_MainActivity_mdString => RX@0x40000ba5[libeasymd5.so]0xba5
    JNIEnv->GetStringUtfChars("12345james") was called from RX@0x40000cb7[libeasymd5.so]0xcb7
    JNIEnv->NewStringUTF("048943059b19127c86e2069c6e804f3f") was called from RX@0x40000f8d[libeasymd5.so]0xf8d
    result2 is => 048943059b19127c86e2069c6e804f3f
    

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表