易游网-易游模拟器

 找回密码
 立即注册
查看: 4561|回复: 0

[破解逆向] frida android 常用脚本备忘

[复制链接]

3382

主题

3401

帖子

38

积分

超级版主

Rank: 8Rank: 8

积分
38

技术达人

发表于 2021-4-27 13:06:13 | 显示全部楼层 |阅读模式
1、//基础数据类型char
var char= Java.use("java.lang.Class").getPrimitiveClass("char")

2、挂钩dlopen函数
  1. //第一种方式(针对较老的系统版本)
  2. var dlopen = Module.findExportByName(null, "dlopen");
  3. console.log(dlopen);
  4. if(dlopen != null){
  5.     Interceptor.attach(dlopen,{
  6.         onEnter: function(args){
  7.             var soName = args[0].readCString();
  8.             console.log(soName);
  9.             if(soName.indexOf("libc.so") != -1){
  10.                 this.hook = true;
  11.             }
  12.         },
  13.         onLeave: function(retval){
  14.             if(this.hook) {
  15.                 dlopentodo();
  16.             };
  17.         }
  18.     });
  19. }

  20. //第二种方式(针对新系统版本)
  21. var android_dlopen_ext = Module.findExportByName(null, "android_dlopen_ext");
  22. console.log(android_dlopen_ext);
  23. if(android_dlopen_ext != null){
  24.     Interceptor.attach(android_dlopen_ext,{
  25.         onEnter: function(args){
  26.             var soName = args[0].readCString();
  27.             console.log(soName);
  28.             if(soName.indexOf("libc.so") != -1){
  29.                 this.hook = true;
  30.             }
  31.         },
  32.         onLeave: function(retval){
  33.             if(this.hook) {
  34.                 dlopentodo();
  35.             };
  36.         }
  37.     });
  38. }
  39. function dlopentodo(){
  40.     //todo ...
  41. }
复制代码


3、打印java层堆栈
  1. function show_java_trace(){
  2. Java.perform(function(){
  3.         var MessageDigest = Java.use("java.security.MessageDigest");
  4.         MessageDigest.digest.overload().implementation = function(){
  5.             //var stack = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new());
  6.             var stack = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new());
  7.             console.log(stack);
  8.             return this.digest();
  9.         }
  10.     });
  11. }
复制代码


4、打印Native堆栈

  1. function show_native_trace(){
  2.     var func = Module.findBaseAddress("libil2cpp.so").add(0x56FCA8);
  3.     Interceptor.attach(func, {
  4.         onEnter: function(args){
  5.             console.log("called from:\n"+
  6.                 Thread.backtrace(this.context,Backtracer.ACCURATE)
  7.                 .map(DebugSymbol.fromAddress).join("\n"));
  8.         },
  9.         onLeave: function(retval){
  10.             
  11.         }
  12.     });
  13. }
复制代码


5、挂钩Java中的loadLibrary并打印堆栈
  1. function hook_library(){
  2.     Java.perform(function() {
  3.         const System = Java.use('java.lang.System');
  4.         const Runtime = Java.use('java.lang.Runtime');
  5.         const VMStack = Java.use('dalvik.system.VMStack');

  6.         System.loadLibrary.implementation = function(library) {
  7.             try {
  8.                 console.log('System.loadLibrary("' + library + '")');
  9.                 console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));
  10.                 const loaded = Runtime.getRuntime().loadLibrary0(VMStack.getCallingClassLoader(), library);
  11.                 return loaded;
  12.             } catch(ex) {
  13.                 console.log(ex);
  14.             }
  15.         };

  16.         System.load.implementation = function(library) {
  17.             try {
  18.                 console.log('System.load("' + library + '")');
  19.                 console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));
  20.                 const loaded = Runtime.getRuntime().load0(VMStack.getCallingClassLoader(), library);
  21.                 return loaded;
  22.             } catch(ex) {
  23.                 console.log(ex);
  24.             }
  25.         };
  26.     });
  27. }
复制代码


6、String转Byte
  1. function stringToBytes(str) {  
  2.     var ch, st, re = [];
  3.     for (var i = 0; i < str.length; i++ ) {
  4.         ch = str.charCodeAt(i);  
  5.         st = [];                 
  6.         do {  
  7.             st.push( ch & 0xFF );  
  8.             ch = ch >> 8;         
  9.         }   
  10.         while ( ch );  
  11.         re = re.concat( st.reverse() );
  12.     }  
  13.     return re;  
  14. }
复制代码


7、hexToBytes
  1. function hexToBytes(str) {
  2.     var pos = 0;
  3.     var len = str.length;
  4.     if (len % 2 != 0) {
  5.         return null;
  6.     }
  7.     len /= 2;
  8.     var hexA = new Array();
  9.     for (var i = 0; i < len; i++) {
  10.         var s = str.substr(pos, 2);
  11.         var v = parseInt(s, 16);
  12.         hexA.push(v);
  13.         pos += 2;
  14.     }
  15.     return hexA;
  16. }
复制代码


8、bytes2Hex
  1. function bytes2Hex(arr) {
  2.     var str = "[";
  3.     for (var i = 0; i < arr.length; i++) {
  4.         var z = parseInt(arr[i]);
  5.         if (z < 0) z = 255 + z;
  6.         var tmp = z.toString(16);
  7.         if (tmp.length == 1) {
  8.             tmp = "0" + tmp;
  9.         }
  10.         str = str + " " + tmp;
  11.     }
  12.     return (str + " ]").toUpperCase();
  13. }
复制代码


9、ArrayBuffer 转换
  1. function ab2Hex(buffer) {
  2.     var arr = Array.prototype.map.call(new Uint8Array(buffer), function (x) {return ('00' + x.toString(16)).slice(-2)}).join(" ").toUpperCase();
  3.     return "[" + arr + "]";
  4. }

  5. function ab2Str(buffer) {
  6.     return String.fromCharCode.apply(null, new Uint8Array(buffer));
  7. }
复制代码


10、jstring, jbytearray显示

  1. function jstring2Str(jstring) {
  2.    var ret;
  3.    Java.perform(function() {
  4.        var String = Java.use("java.lang.String");
  5.        ret = Java.cast(jstring, String);
  6.    });
  7.    return ret;
  8. }

  9. function jbyteArray2Array(jbyteArray) {
  10.    var ret;
  11.    Java.perform(function() {
  12.        var b = Java.use('[B');
  13.        var buffer = Java.cast(jbyteArray, b);
  14.        ret = Java.array('byte', buffer);
  15.    });
  16.    return ret;
  17. }
复制代码


11、主线程调用
  1. function RunOnMain(){
  2.     Java.perform(function(){
  3.         var cls_main = null
  4.         //获取Context
  5.         Java.choose("com.lzy.ndk.MainActivity",{
  6.             onMatch:function(clazz){
  7.                 cls_main = clazz
  8.             },
  9.             onComplete:function(){}
  10.         })
  11.         //动态注册一个类实现Runnable方法
  12.         var cls_run = Java.registerClass({
  13.             name:"com.lzy.frida.runnable",
  14.             implements:[Java.use("java.lang.Runnable")],
  15.             //创建类成员变量
  16.             fields:{
  17.                 description: 'java.lang.String',
  18.                 limit: 'int'
  19.             },
  20.             //创建方法以及重载方法的用法
  21.             methods:{
  22.                 run:function(){
  23.                     Java.use("android.widget.Toast").makeText(cls_main,Java.use("java.lang.String").$new("this is a test Toast"),1).show()
  24.                
  25.                 },
  26.                 add:[{
  27.                     returnType:'java.lang.String',
  28.                     argumentTypes:['java.lang.String','java.lang.String'],
  29.                     implementation:function(str1,str2){
  30.                         return str1+"+++"+str2
  31.                     }
  32.                 },
  33.                 {
  34.                     returnType:'java.lang.String',
  35.                     argumentTypes:['java.lang.String'],
  36.                     implementation:function(str1){
  37.                         return str1+"==="
  38.                     }
  39.                 }
  40.                 ]
  41.             }
  42.         })
  43.         //这里的实现主线程调用方法很多,这里举例一种
  44.         //1.随便在MainActivity找一个View,View.post(Runnable)
  45.         cls_main.bt1.value.post(cls_run.$new())
  46.         //2.Activity的方法runOnUiThread()
  47.         cls_main.runOnUiThread(cls_run.$new())
  48.         //3.new Handler(getMainLooper()).post()
  49.         Java.use("android.os.Handler").$new(cls_main.getMainLooper()).post(cls_run.$new())
  50.         //4.Java.scheduleOnMainThread(function(){}) 不推荐,不好用总是出问题
  51.         Java.scheduleOnMainThread(function(){
  52.             console.log(Java.isMainThread())
  53.         })
  54.     })
  55. }
复制代码


12、批量断点定位调用
  1. function add_native_break_points(){
  2.    
  3. // 结合Il2CppDumper使用,用于批量快速下断点,跟踪native函数调用
  4. // frida -U -f <PackageName> -l C:\Users\lzy\utils\bpoints.js --no-pause

  5. const soName = "libil2cpp.so"

  6. const arrayAddr =
  7.     ['0x71541c', '0x715b38', '0x715be4', '0x715c61']

  8. const arrayName =
  9.     ['GameManager$Awake', 'GameManager$GetParam', 'GameManager$SaveParam', 'GameManager$ActivatePrivacyButton']

  10. function breakPoints(){

  11.     const soAddr = Module.findBaseAddress(soName);
  12.     console.error('\nsoAddr:' + soAddr + "\n");

  13.     Java.perform(function(){
  14.         arrayAddr
  15.             .map(function(temp){return soAddr.add(temp)})
  16.             .forEach(function(value,index,array){
  17.                 console.log("-------------------------");
  18.                 console.log('currentAddr:' + value);
  19.                 try{
  20.                     funcTmp(value,index,arrayName);
  21.                 }catch(e){
  22.                     //Thumb指令集地址要加一
  23.                     funcTmp(value.add(1),soAddr,index,arrayName);
  24.                 }
  25.             console.log("\t\t---->"+index,value+" is prepared ");
  26.         })
  27.         console.log("\n")
  28.     })

  29.     function funcTmp(currentAddr,index,arrayName){
  30.         Interceptor.attach(currentAddr, {
  31.             onEnter: function(args){
  32.                 console.log("called : "+arrayName[index]+"  ----- addr : " + currentAddr.sub(soAddr) +"\n");
  33.                 this.temp = currentAddr.sub(soAddr);
  34.                 if(this.temp === 0xef3080) {
  35.                     console.log('CCCryptorCreate called from:\n' +
  36.                         Thread.backtrace(this.context, Backtracer.ACCURATE)
  37.                             .map(DebugSymbol.fromAddress).join('\n') + '\n');
  38.                 }
  39.             },
  40.             onLeave: function(retval){

  41.             }
  42.         });
  43.     }
  44. }

  45. function hook_dlopen() {
  46.     // const dlopen = Module.findExportByName(null, "dlopen");
  47.     const dlopen = Module.findExportByName(null, "android_dlopen_ext");

  48.     if (dlopen != null) {
  49.         Interceptor.attach(dlopen, {
  50.             onEnter: function (args) {
  51.                 var l_soName = args[0].readCString()
  52.                 console.log(l_soName)
  53.                 if (l_soName.indexOf(soName) != -1) {
  54.                     this.hook = true
  55.                 }
  56.             },
  57.             onLeave: function (retval) {
  58.                 if (this.hook) {
  59.                     console.warn("\nLoaded "+soName + " add break points")
  60.                     breakPoints()
  61.                 }
  62.             }
  63.         })
  64.     }
  65. }

  66. setImmediate(hook_dlopen())
  67. }
复制代码


13、TracerPid fgets 反调试
  1. var anti_fgets = function () {
  2.         show_log("anti_fgets");
  3.         var fgetsPtr = Module.findExportByName("libc.so", "fgets");
  4.         var fgets = new NativeFunction(fgetsPtr, 'pointer', ['pointer', 'int', 'pointer']);
  5.         Interceptor.replace(fgetsPtr, new NativeCallback(function (buffer, size, fp) {
  6.             var retval = fgets(buffer, size, fp);
  7.             var bufstr = Memory.readUtf8String(buffer);
  8.             if (bufstr.indexOf("TracerPid:") > -1) {
  9.                 Memory.writeUtf8String(buffer, "TracerPid:\t0");
  10.                 // dmLogout("tracerpid replaced: " + Memory.readUtf8String(buffer));
  11.             }
  12.             return retval;
  13.         }, 'pointer', ['pointer', 'int', 'pointer']));
  14.     };
复制代码


14、日志打印
  1. function log(str){
  2.     var threadid = Process.getCurrentThreadId()
  3.     var date = new Date()
  4.     var month = date.getMonth() + 1
  5.     var strDate = date.getDate()
  6.     var hour = date.getHours()
  7.     var Minutes = date.getMinutes()
  8.     var Seconds = date.getSeconds()
  9.     if (month >= 1 && month <= 9) {
  10.         month = "0" + month
  11.     }
  12.     if (strDate >= 0 && strDate <= 9) {
  13.         strDate = "0" + strDate
  14.     }
  15.     if (hour >= 0 && hour <= 9) {
  16.         hour = "0" + hour
  17.     }
  18.     if (Minutes >= 0 && Minutes <= 9) {
  19.         Minutes = "0" + Minutes
  20.     }
  21.     if (Seconds >= 0 && Seconds <= 9) {
  22.         Second = "0" + Seconds
  23.     }
  24.     var currentDate = date.getFullYear() + "-" + month + "-" + strDate
  25.             + " " + hour + ":" + Minutes + ":" + Seconds
  26.     var log = "["+threadid+"][" + currentDate + "] --- " + str
  27.     console.log('\x1b[3' + '6;01' + 'm', log, '\x1b[39;49;00m')
  28. }
复制代码


15、内存dump so(脱壳upx壳)

  1. function dump_so(so_name) {
  2.     Java.perform(function () {
  3.         var currentApplication = Java.use("android.app.ActivityThread").currentApplication();
  4.         var dir = currentApplication.getApplicationContext().getFilesDir().getPath();
  5.         var libso = Process.getModuleByName(so_name);
  6.         console.error("------------------------------");
  7.         console.warn("[name]:", libso.name);
  8.         console.warn("[base]:", libso.base);
  9.         console.warn("[size]:", libso.size);
  10.         console.warn("[path]:", libso.path);
  11.         console.error("------------------------------");
  12.         var file_path = dir + "/" + libso.name + "_" + libso.base + "_" + ptr(libso.size) + ".so";
  13.         var file_handle = new File(file_path, "wb");
  14.         if (file_handle && file_handle != null) {
  15.             Memory.protect(ptr(libso.base), libso.size, 'rwx');
  16.             var libso_buffer = ptr(libso.base).readByteArray(libso.size);
  17.             file_handle.write(libso_buffer);
  18.             file_handle.flush();
  19.             file_handle.close();
  20.             console.log("[dump]:", file_path);
  21.         }
  22.     });
  23. }
复制代码


16、动态加载dex
  1. function loadDex(){
  2.     //这里只是提一下可以使用Frida提供的Api加载dex,你也可以解包再打包,但是显然这个方便得多
  3.     //手动去加载一些工具类(Gson,AndroidUtilCode,自己写的工具类等等)
  4.     Java.openClassFile("/data/local/tmp/helper.dex").load()
  5.     var gson = Java.use("com.google.gson.Gson").$new()
  6.     ...
  7. }
复制代码


17、计划任务
  1. function ScheduledTask(){
  2.     //用在Spawn启动的时候
  3.     setImmediate(function(){
  4.         console.log("立即执行,只执行一次")
  5.     })
  6.     setTimeout(function(){
  7.         console.log("一秒后执行,只执行一次")
  8.     },1000)
  9.     //Frida Api
  10.     setInterval(function(){
  11.         console.log("每隔一秒执行一次")
  12.     },1000)
  13.     // Java Api
  14.     Java.perform(function(){
  15.         Java.registerClass({
  16.             name:"com.lzy.frida.tsk",
  17.             superClass:Java.use("java.util.TimerTask"),
  18.             methods:{
  19.                 run:function(){
  20.                     console.log("等待两秒后每隔一秒调用一次")
  21.                 }
  22.             }
  23.         })
  24.         Java.use("java.util.Timer").$new().schedule(Java.use("com.lzy.frida.tsk").$new(),2000,1000)
  25.     })
  26. }
复制代码


18、JNI函数Trace Demo
  1. function TraceJni(){
  2.     Java.perform(function(){

  3.         var pSize = Process.pointerSize
  4.         var env = Java.vm.getEnv()

  5.         //JNI函数相对env偏移位置参考:
  6.         //https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/functions.html#NewStringUTF
  7.         var GetStaticMethodID = 113,findclass = 6,RegisterNatives = 215;
  8.    
  9.         function getNativeAddress(idx) {
  10.             return env.handle.readPointer().add(idx * pSize).readPointer()
  11.         }

  12.         Interceptor.attach(getNativeAddress(findclass),{
  13.             onEnter:function(args){
  14.                 console.error("-------------findClass-------------")
  15.                 console.warn("env\t--->\t"+args[0])
  16.                 console.warn("class\t--->\t"+args[1].readCString())
  17.             },
  18.             onLeave:function(retval){}
  19.         })

  20.         Interceptor.attach(getNativeAddress(GetStaticMethodID),{
  21.             onEnter:function(args){
  22.                 console.error("\n-------------GetStaticMethodID-------------")
  23.                 console.warn(args[0])
  24.                 console.warn(args[1])
  25.                 console.warn(args[2].readCString())
  26.             },
  27.             onLeave:function(retval){}
  28.         })

  29.         //RegisterNative结构体参照:
  30.         //https://android.googlesource.com/platform/libnativehelper/+/master/include_jni/jni.h#129
  31.         Interceptor.attach(getNativeAddress(RegisterNatives), {
  32.             onEnter: function(args) {
  33.                 console.log(parseInt(args[3]))
  34.                 for (var i = 0,nMethods = parseInt(args[3]); i < nMethods; i++) {
  35.                     var structSize = pSize * 3; // = sizeof(JNINativeMethod)
  36.                     var methodsPtr = ptr(args[2]);
  37.                     var signature = methodsPtr.add(i * structSize + pSize).readPointer();
  38.                     var fnPtr = methodsPtr.add(i * structSize + (pSize * 2)).readPointer(); // void* fnPtr
  39.                     var jClass = jclassAddress2NameMap[args[0]].split('/');
  40.                     var methodName = methodsPtr.add(i * structSize).readPointer().readCString();
  41.                     console.log('\x1b[3' + '6;01' + 'm', JSON.stringify({
  42.                         module: DebugSymbol.fromAddress(fnPtr)['moduleName'],
  43.                         // https://www.frida.re/docs/javascript-api/#debugsymbol
  44.                         package: jClass.slice(0, -1).join('.'),
  45.                         class: jClass[jClass.length - 1],
  46.                         method: methodName,
  47.                         // methodsPtr.readPointer().readCString(), // char* name
  48.                         signature: signature.readCString(),
  49.                         // char* signature TODO Java bytecode signature parser { Z: 'boolean', B: 'byte', C: 'char', S: 'short', I: 'int', J: 'long', F: 'float', D: 'double', L: 'fully-qualified-class;', '[': 'array' } https://github.com/skylot/jadx/blob/master/jadx-core/src/main/java/jadx/core/dex/nodes/parser/SignatureParser.java
  50.                         address: fnPtr
  51.                     }), '\x1b[39;49;00m');
  52.                 }
  53.             }
  54.         });
  55.     })
  56. }
复制代码


19、Native Log日志Hook
  1. #int __android_log_print(int prio, const char* tag, const char* fmt, ...)
  2. function hookLog() {
  3.     Interceptor.attach(Module.findExportByName("liblog.so","__android_log_print"), {
  4.         onEnter: function (args) {
  5.             // var level = ""
  6.             // var level_i = parseInt(args[0])
  7.             // if(level_i == 0){
  8.             //     level = "ANDROID_LOG_UNKNOWN"
  9.             // }else if(level_i == 1){
  10.             //     level = "ANDROID_LOG_DEFAULT"
  11.             // }else if(level_i == 2){
  12.             //     level = "ANDROID_LOG_VERBOSE"
  13.             // }else if(level_i == 3){
  14.             //     level = "ANDROID_LOG_DEBUG"
  15.             // }else if(level_i == 4){
  16.             //     level = "ANDROID_LOG_INFO"
  17.             // }else if(level_i == 5){
  18.             //     level = "ANDROID_LOG_WARN"
  19.             // }else if(level_i == 6){
  20.             //     level = "ANDROID_LOG_ERROR"
  21.             // }else if(level_i == 7){
  22.             //     level = "ANDROID_LOG_FATAL"
  23.             // }else if(level_i == 8){
  24.             //     level = "ANDROID_LOG_SILENT"
  25.             // }
  26.             // if(level_i==5){
  27.             //     console.warn(level+"\t"+args[1].readCString()+"\t"+args[2].readCString())
  28.             // }else if(level_i > 5){
  29.             //     console.error(level+"\t"+args[1].readCString()+"\t"+args[2].readCString())
  30.             // }else{
  31.             //     console.log(level+"\t"+args[1].readCString()+"\t"+args[2].readCString())
  32.             // }
  33.             console.log(args[1].readCString()+"\t"+args[2].readCString())
  34.         }
  35.     });
  36. }
复制代码


20、Native函数断点/调用/替换
  1. //主动调用native函数
  2.     var soAddr = Module.findBaseAddress("libil2cpp.so");
  3.     new NativeFunction(soAddr.add(0x4c33b0),"void",['pointer'])(Java.vm.tryGetEnv())

  4. //替换native函数
  5. //支持的类型:void,pointer,int,uint,long,ulong,char,uchar,float,double,int8,uint8,int16,uint16,int32,uint32,int64,uint64,bool
  6.     Interceptor.replace(new NativeFunction(soAddr.add(0x58F0F4),'void', ['pointer']), new NativeCallback(function (arg) {
  7.         console.log("called from:\n"+
  8.                 Thread.backtrace(this.context,Backtracer.FUZZY)
  9.                 .map(DebugSymbol.fromAddress).join("\n"));
  10.     }, 'void', ['pointer']));

  11. //拦截native函数
  12.     Interceptor.attach(soAddr.add(0xb7a93c),{
  13.         onEnter:function(arg){
  14.             console.log("called 0xb7a93c")
  15.         },
  16.         onLeave:function(retval){
  17.             console.warn(retval)
  18.         }
  19.     })
复制代码


21、获取参数类型
  1. function getParamType(obj) {
  2.     return obj == null ? String(obj) : Object.prototype.toString.call(obj).replace(/\[object\s+(\w+)\]/i, "$1") || "object";
  3. }
复制代码


22、hook 所有重载函数
  1. function hookAllOverloads(targetClass, targetMethod) {
  2.     Java.perform(function () {
  3.          var targetClassMethod = targetClass + '.' + targetMethod;
  4.          var hook = Java.use(targetClass);
  5.          var overloadCount = hook[targetMethod].overloads.length;
  6.          for (var i = 0; i < overloadCount; i++) {
  7.                 hook[targetMethod].overloads[i].implementation = function() {
  8.                      var retval = this[targetMethod].apply(this, arguments);
  9.                      //这里可以打印结果和参数
  10.                      return retval;
  11.                  }
  12.               }
  13.    });
  14. }
复制代码


您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|易游网-易游模拟器 Copyright @2015-2021 ( 浙ICP备15028007号-1 )

GMT+8, 2024-11-27 09:38 , Processed in 0.031002 second(s), 10 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表