这个就是个frida脚本,可以从中学习到一些hook思路
1. javahook(white, black, target = null)
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
| function javahook(white, black, target = null) { console.Red("start") if (!(target === null)) { console.LightGreen("Begin enumerateClassLoaders ...") Java.enumerateClassLoaders({ onMatch: function (loader) { try { if (loader.findClass(target)) { console.Red("Successfully found loader") console.Blue(loader); Java.classFactory.loader = loader; console.Red("Switch Classloader Successfully ! ") } } catch (error) { console.Red(" continuing :" + error) } }, onComplete: function () { console.Red("EnumerateClassloader END") } }) }
console.Red("Begin Search Class...") var targetClasses = new Array(); Java.enumerateLoadedClasses({ onMatch: function (className) { if (className.toString().toLowerCase().indexOf(white.toLowerCase()) >= 0 && (black == null || black == '' || className.toString().toLowerCase().indexOf(black.toLowerCase()) < 0)) { console.Black("Found Class => " + className) targetClasses.push(className); traceClass(className); } }, onComplete: function () { console.Black("Search Class Completed!") } })
var output = "On Total Tracing :" + String(targetClasses.length) + " classes :\r\n"; targetClasses.forEach(function (target) { output = output.concat(target); output = output.concat("\r\n") }) console.Green(output + "Start Tracing ...") }
|
进行最初始的追踪类:
先从JVM中开始寻找目标类
然后再扫描全部已经加载的类(这样会节约不少时间,但是坏处是有的时候会hook不上某些方法),通过处理获得类名然后释放(节约内存空间),再将类名加入一个Array中
每加入一个类每个类进行进一步的操作:traceClass(className);
2. traceClass(targetClass)
1 2 3 4 5 6 7 8 9 10 11
| function traceClass(targetClass) { if (Java.available) { Java.perform(function () { JavaTraceClass(targetClass) }) } else if (ObjC.available) { IosTraceClass(targetClass) } else { console.log("please connect to either iOS or Android device ...") } }
|
3. JavaTraceClass(targetClass)
我超这作者居然写注释,爱了
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
| function JavaTraceClass(targetClass) { var hook = Java.use(targetClass); var methods = hook.class.getDeclaredMethods(); hook.$dispose; var parsedMethods = []; var output = ""; output = output.concat("\tSpec: => \r\n") methods.forEach(function (method) { output = output.concat(method.toString()) output = output.concat("\r\n") parsedMethods.push(method.toString().replace(targetClass + ".", "TOKEN").match(/\sTOKEN(.*)\(/)[1]); }); var Targets = uniqBy(parsedMethods, JSON.stringify); var constructors = hook.class.getDeclaredConstructors(); if (constructors.length > 0) { constructors.forEach(function (constructor) { output = output.concat("Tracing ", constructor.toString()) output = output.concat("\r\n") }) Targets = Targets.concat("$init") } Targets.forEach(function (targetMethod) { traceMethod(targetClass + "." + targetMethod); }); for (var p = 0; p < 100; p++) { output = output.concat("+"); } console.Green(output); }
|
这个函数依次对目标类进行所有方法名字(包括构造方法)记录,然后去重,再依次hook(traceMethod
)
4. traceMethod(targetClassMethod)
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
| function traceMethod(targetClassMethod) { var delim = targetClassMethod.lastIndexOf("."); if (delim === -1) return; var targetClass = targetClassMethod.slice(0, delim) var targetMethod = targetClassMethod.slice(delim + 1, targetClassMethod.length) var hook = Java.use(targetClass); if (!hook[targetMethod]) { return; } var overloadCount = hook[targetMethod].overloads.length; console.Red("Tracing Method : " + targetClassMethod + " [" + overloadCount + " overload(s)]"); for (var i = 0; i < overloadCount; i++) { hook[targetMethod].overloads[i].implementation = function () { var output = ""; for (var p = 0; p < 100; p++) { output = output.concat("=="); } if (!isLite) { output = inspectObject(this, output); } output = output.concat("\n*** entered " + targetClassMethod); output = output.concat("\r\n") var retval = this[targetMethod].apply(this, arguments); if (!isLite) { for (var j = 0; j < arguments.length; j++) { output = output.concat("arg[" + j + "]: " + arguments[j] + " => " + JSON.stringify(arguments[j])); output = output.concat("\r\n") } output = output.concat(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new())); output = output.concat("\nretval: " + retval + " => " + JSON.stringify(retval)); } output = output.concat("\n*** exiting " + targetClassMethod); var r = parseInt((Math.random() * 7).toFixed(0)); var i = r; var printOutput = null; switch (i) { case 1: printOutput = console.Red; break; case 2: printOutput = console.Yellow; break; case 3: printOutput = console.Green; break; case 4: printOutput = console.Cyan; break; case 5: printOutput = console.Blue; break; case 6: printOutput = console.Gray; break; default: printOutput = console.Purple; } printOutput(output); return retval; } } }
|
就是hook java层的方法,可惜也只是在java层了。
有意思的是获得调用栈的方式:
通过hook安卓自带的Log来获取堆栈信息
创建的一个新的Throwable对象。Throwable是Java中用于表示异常的基类,包含相关异常信息,包括堆栈跟踪。