├── README.md └── lingzhiyi-hook-tools-v1.js /README.md: -------------------------------------------------------------------------------- 1 | # lingzhiyi-hook-tools 2 | 3 | ## traceOneMethod函数 4 | 要求传入的方法名为完整的方法名 5 | ```js 6 | traceOneMethod("javax.crypto.Cipher.doFinal") // 对javax.crypto.Cipher.doFinal进行hook,包括重载方法的hook; 7 | traceOneMethod("javax.crypto.Cipher.doFinal","[B") // 传入方法签名的时候,仅对参数为[B的方法进行hook; 8 | ``` 9 | ---- 10 | 11 | ## traceAllMethod函数 12 | ```js 13 | traceAllMethod(".*http.*") //对类名中包含了http的类进行hook,批量hook成千上万个函数; 14 | ``` 15 | ---- 16 | 17 | ## hook_RegisterNatives_new函数 18 | 19 | 对动态注册的函数进行hook,获取其注册到的类名,签名以及so的文件名和偏移。 20 | 21 | ---- 22 | 23 | ## future等待实现 24 | 25 | frida提供了很多可能,现在只是列出一些想到的,可以做成工具避免重复劳动 26 | 将在之后慢慢实现的功能。 27 | 28 | ### findInterfaceImpl函数(待实现) 29 | 30 | ### print_value(部分实现) 31 | 在case里面增加想要打印的参数格式,针对常见不同的参数类型进行不同的打印方式,完成适配 32 | 33 | ### HttpURLConnection/ok3/retrofit2的hook(待实现) 34 | 35 | ### c层非标准算法的主动调用(待实现) 36 | 基于frida的new CModule相关api可以进行非标准算法的快速调用与实现 37 | 38 | ### stalker对natvie层的追踪(待实现) 39 | 40 | ### Instruction.parse反汇编api的使用(待实现) 41 | 42 | ### socket的使用(待实现) 43 | -------------------------------------------------------------------------------- /lingzhiyi-hook-tools-v1.js: -------------------------------------------------------------------------------- 1 | /* 2 | v1版本 3 | 20210514更新 4 | 5 | 参考了objection,frida_fart,wallbreaker等源码 6 | 7 | 代码还是有好多问题~忧桑 8 | */ 9 | var is_print_java_stackTrace = 1 10 | var is_print_args = 1; // print args 11 | var is_print_retval = 1; // print retval 12 | var is_spawn = 0 13 | var is_hooked = false 14 | var is_dumpClass_declared = 1; 15 | var context = null; 16 | var currentApplication = null; 17 | var matched_methods_list = [] 18 | var matched_classes = [] 19 | var ins_all = [] 20 | var last_ins = null 21 | var StringClass = null 22 | 23 | function prepare_env() { 24 | Java.performNow(function() { 25 | StringClass = Java.use("java.lang.String") 26 | }) 27 | } 28 | 29 | function print_stackTrace() { 30 | Java.perform(function() { 31 | console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new())); 32 | }); 33 | } 34 | 35 | function get_now() { 36 | var date = new Date() 37 | var year = date.getFullYear() 38 | var month = date.getMonth() 39 | var day = date.getDate() 40 | var hour = date.getHours() 41 | var min = date.getMinutes() 42 | var seconds = date.getSeconds() 43 | var millsec = date.getMilliseconds() 44 | var result1 = [year, month, day] 45 | var result2 = [hour, min, seconds, millsec] 46 | return "[CurrentTime]" + result1.join("-") + " " + result2.join(":") 47 | } 48 | 49 | function print_log(user_log_list, tag) { 50 | if (tag == undefined) { 51 | tag = "" 52 | } 53 | var num = 20 54 | var start_symbol = "=" 55 | var end_symbol = "-" 56 | var now = get_now() 57 | user_log_list.unshift(now) 58 | var log_start = new Array(num).join(start_symbol) + "[ThreadId:" + Process.getCurrentThreadId() + "]" + tag + " start!!!" + new Array(num).join(start_symbol) 59 | user_log_list.unshift(log_start) 60 | if (is_print_java_stackTrace) { 61 | user_log_list.push(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new())) 62 | } 63 | var log_end = new Array(num).join(end_symbol) + "[ThreadId:" + Process.getCurrentThreadId() + "]" + tag + " end!!!" + new Array(num).join(end_symbol) 64 | user_log_list.push(log_end) 65 | console.log(user_log_list.join("\n")); 66 | } 67 | 68 | function checkByteArrayFromString(bytearray) { 69 | var bytearray0 = Java.array("byte", bytearray); 70 | for (var i = 0; i < bytearray0.length; i++) { 71 | if (isVisible(bytearray[i]) == false) { 72 | return false; 73 | } 74 | } 75 | return true; 76 | } 77 | 78 | function isVisible(value) { 79 | if (value >= 32 && value <= 126) { 80 | return true; 81 | } 82 | return false; 83 | } 84 | 85 | function bytesToHex(arr) { 86 | var str = ""; 87 | var k, j; 88 | for (var i = 0; i < arr.length; i++) { 89 | k = arr[i]; 90 | j = k; 91 | if (k < 0) { 92 | j = k + 256; 93 | } 94 | if (j < 16) { 95 | str += "0"; 96 | } 97 | str += j.toString(16); 98 | } 99 | return str; 100 | } 101 | 102 | function print_value(param, paramType, i) { 103 | var result = "" 104 | var name = null; 105 | if (i == undefined) { 106 | name = "(" + paramType + ")retval"; 107 | } else { 108 | name = "(" + paramType + ")arg[" + i + "]"; 109 | } 110 | switch (paramType) { 111 | case "[B": 112 | var canToString = checkByteArrayFromString(param); 113 | if (canToString) { 114 | result = name + " _bytearray= " + StringClass.$new(param) 115 | } else { 116 | var param_hex = bytesToHex(param); 117 | result = name + "_hex = " + param_hex 118 | } 119 | break; 120 | case "java.security.Key": 121 | var param_bytearray = param.getEncoded(); 122 | var canToString = checkByteArrayFromString(param_bytearray); 123 | if (canToString) { 124 | result = name + "_key_str= " + StringClass.$new(param_bytearray) 125 | } else { 126 | var param_hex = bytesToHex(param_bytearray); 127 | result = name + "_key_hex = " + param_hex 128 | } 129 | break; 130 | case "java.security.spec.AlgorithmParameterSpec": 131 | var IVClass = Java.use("javax.crypto.spec.IvParameterSpec"); 132 | var ivObject = Java.cast(param, IVClass); 133 | var ivByte = ivObject.getIV(); 134 | var canToString = checkByteArrayFromString(ivByte); 135 | if (canToString) { 136 | result = name + "_iv_str= " + StringClass.$new(ivByte) 137 | } else { 138 | var param_hex = bytesToHex(ivByte); 139 | result = name + "_iv_hex = " + param_hex 140 | } 141 | break; 142 | default: 143 | result = name + "=" + param 144 | break; 145 | } 146 | return result 147 | } 148 | 149 | function findActivities() { 150 | Java.performNow(function() { 151 | const packageManager = Java.use("android.content.pm.PackageManager"); 152 | const GET_ACTIVITIES = packageManager.GET_ACTIVITIES.value; 153 | Array.prototype.concat(context.getPackageManager().getPackageInfo(context.getPackageName(), GET_ACTIVITIES).activities.value.map((activityInfo) => { 154 | console.log("find activity = " + activityInfo.name.value); 155 | })); 156 | }) 157 | } 158 | 159 | function findCurrentActivity() { 160 | Java.performNow(function() { 161 | const activityThread = Java.use("android.app.ActivityThread"); 162 | const activity = Java.use("android.app.Activity"); 163 | const activityClientRecord = Java.use("android.app.ActivityThread$ActivityClientRecord"); 164 | const currentActivityThread = activityThread.currentActivityThread(); 165 | const activityRecords = currentActivityThread.mActivities.value.values().toArray(); 166 | let currentActivity; 167 | for (const i of activityRecords) { 168 | const activityRecord = Java.cast(i, activityClientRecord); 169 | if (!activityRecord.paused.value) { 170 | currentActivity = Java.cast(Java.cast(activityRecord, activityClientRecord).activity.value, activity); 171 | break; 172 | } 173 | } 174 | if (currentActivity) { 175 | // Discover an active fragment 176 | const fm = currentActivity.getFragmentManager(); 177 | const _id = context.getResources().getIdentifier("content_frame", "id", context.getPackageName()); 178 | const fragment = fm.findFragmentById(_id); 179 | console.log("currentActivity = " + currentActivity.$className); 180 | console.log("fragment = " + fragment.$className); 181 | } else { 182 | console.log("findCurrentActivity error"); 183 | } 184 | }) 185 | } 186 | /* 187 | from imyang 188 | https://github.com/lasting-yang 189 | */ 190 | function hook_RegisterNatives_new() { 191 | var addrRegisterNatives = ptr(DebugSymbol.fromName("_ZN3art3JNI15RegisterNativesEP7_JNIEnvP7_jclassPK15JNINativeMethodi").address); 192 | if (addrRegisterNatives) { 193 | Interceptor.attach(addrRegisterNatives, { 194 | onEnter: function(args) { 195 | print_equals(100, "="); 196 | console.log("[RegisterNatives] method_count:", args[3]); 197 | var env = args[0]; 198 | var java_class = args[1]; 199 | // var class_name = env.getClassName(java_class) 200 | var class_name = Java.vm.getEnv().getClassName(java_class); 201 | var methods_ptr = ptr(args[2]); 202 | var method_count = parseInt(args[3]); 203 | for (var i = 0; i < method_count; i++) { 204 | var name_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3)); 205 | var sig_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize)); 206 | var fnPtr_ptr = Memory.readPointer(methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize * 2)); 207 | var name = Memory.readCString(name_ptr); 208 | var sig = Memory.readCString(sig_ptr); 209 | var find_module = Process.findModuleByAddress(fnPtr_ptr); 210 | console.log("[RegisterNatives] java_class:", class_name, "name:", name, "sig:", sig, "fnPtr:", fnPtr_ptr, "module_name:", find_module.name, "module_base:", find_module.base, "offset:", ptr(fnPtr_ptr).sub(find_module.base)); 211 | } 212 | }, 213 | onLeave: function(retval) {}, 214 | }); 215 | } 216 | } 217 | 218 | function demangle(name) { 219 | // demangle("_ZN3art3JNI15RegisterNativesEP7_JNIEnvP7_jclassPK15JNINativeMethodi") 220 | // extern "C" char* __cxa_demangle(const char*, char*, size_t*, int*); 221 | var __cxa_demangle = DebugSymbol.fromName("__cxa_demangle").address; 222 | var func_demangle = new NativeFunction(__cxa_demangle, "pointer", ["pointer", "pointer", "pointer", "pointer"]) 223 | // var str = Memory.allocUtf8String("_ZN3art3JNI15RegisterNativesEP7_JNIEnvP7_jclassPK15JNINativeMethodi"); 224 | var str = Memory.allocUtf8String(name); 225 | // var output = Memory.alloc(name.length*2) 226 | // var output_len = Memory.alloc(4) 227 | // var status = Memory.alloc(2) 228 | var result = func_demangle(new NativePointer(ptr(str)), ptr(0), ptr(0), ptr(0)); 229 | console.log((result).readCString()) 230 | // console.log(JSON.stringify(Module.enumerateSymbols("libart.so"))) 231 | } 232 | 233 | function getClassNameListFromClassloader(classloader) { 234 | var tmpClassNameList = [] 235 | Java.performNow(function() { 236 | var DexFileClass = Java.use("dalvik.system.DexFile"); 237 | var BaseDexClassLoaderClass = Java.use("dalvik.system.BaseDexClassLoader"); 238 | var DexPathListClass = Java.use("dalvik.system.DexPathList"); 239 | var ElementClass = Java.use("dalvik.system.DexPathList$Element"); 240 | var mBaseDexClassLoader = Java.cast(classloader, BaseDexClassLoaderClass); 241 | var mPathList = mBaseDexClassLoader.pathList.value; 242 | var pathListObj = Java.cast(mPathList, DexPathListClass); 243 | var dexElements = pathListObj.dexElements.value; 244 | if (dexElements != null) { 245 | for (var i = 0; i < dexElements.length; i++) { 246 | var tmpObj = dexElements[i] 247 | var elementObj = Java.cast(tmpObj, ElementClass) 248 | var dexFileObj = elementObj.dexFile.value; 249 | if (dexFileObj != null) { 250 | var mCookie = dexFileObj.mCookie.value; 251 | var tmpClassNameList = dexFileObj.getClassNameList(mCookie) 252 | tmpClassNameList = tmpClassNameList.concat(tmpClassNameList) 253 | } 254 | } 255 | } 256 | }) 257 | return tmpClassNameList 258 | } 259 | //比起纯粹的枚举加载类,这个方法多了未加载的类 260 | //但是仍有不完善的地方,有些系统类有时候并没有获取到 261 | function getAllClassNameList() { 262 | var allClassNameList = [] 263 | Java.performNow(function() { 264 | if (is_spawn) { 265 | console.log("is_spawning!!!!!") 266 | Java.use("android.app.Application").attachBaseContext.overload('android.content.Context').implementation = function(context) { 267 | var result = this.attachBaseContext(context) 268 | currentApplication = this.currentApplication(); 269 | context = currentApplication.getApplicationContext(); 270 | return result 271 | } 272 | currentApplication = Java.use("android.app.ActivityThread").currentApplication(); 273 | context = currentApplication.getApplicationContext(); 274 | var mPathClassLoader = context.getClassLoader() 275 | var tmpClassNameList = getClassNameListFromClassloader(mPathClassLoader) 276 | allClassNameList = allClassNameList.concat(tmpClassNameList) 277 | } else { 278 | console.log("is_attaching!!!!!") 279 | var enumerateClassLoaders = Java.enumerateClassLoadersSync() 280 | for (var i = 0; i < enumerateClassLoaders.length; i++) { 281 | var loader = enumerateClassLoaders[i] 282 | if (loader.toString().indexOf("BootClassLoader") != -1) { 283 | continue 284 | } 285 | var tmpClassNameList = getClassNameListFromClassloader(enumerateClassLoaders[i]) 286 | allClassNameList = allClassNameList.concat(tmpClassNameList) 287 | } 288 | } 289 | var loadedClasses = Java.enumerateLoadedClassesSync() //这里主要是为了加载系统基础类 290 | allClassNameList = allClassNameList.concat(loadedClasses) 291 | // allClassNameList = loadedClasses 292 | allClassNameList = Array.from(new Set(allClassNameList)) 293 | }) 294 | return allClassNameList 295 | } 296 | 297 | function traceAllMethod(classnameFilter, methodFilter, overloadFilter) { 298 | /* 299 | traceALlMethod("*.Base64") // trace all class match Base64 300 | traceAllMethod("","encode","[B,int") // trace all class and method equals encode and overload equals [B,int 301 | traceAllMethod("*Base64*","*encode","[B,int") // trace class match Base64 and method match encode and overload equals [B,int 302 | */ 303 | Java.performNow(function() { 304 | findMethods(classnameFilter, methodFilter); 305 | var toBeHookingMethods = [] 306 | // console.log("[traceAllMethod]matched_methods_list.length=", matched_methods_list.length) 307 | for (var i = 0; i < matched_methods_list.length; i++) { 308 | var tmpClassName = matched_methods_list[i].getDeclaringClass().getName() 309 | var tmpMethodName = matched_methods_list[i].getName() 310 | if (tmpMethodName == tmpClassName) { 311 | tmpMethodName = "$init" 312 | } 313 | var tmpMethodFullName = tmpClassName + "." + tmpMethodName 314 | toBeHookingMethods.push(tmpMethodFullName) 315 | } 316 | toBeHookingMethods = Array.from(new Set(toBeHookingMethods)) 317 | // console.log("[traceAllMethod]toBeHookingMethods.length=", toBeHookingMethods.length) 318 | for (var i = 0; i < toBeHookingMethods.length; i++) { 319 | var method = toBeHookingMethods[i] 320 | traceOneMethod(method, overloadFilter) 321 | } 322 | }) 323 | } 324 | 325 | function traceOneMethod(fullMethodName, overloadFilter) { 326 | /* 327 | traceOneMethod("java.net.URL.$init") // trace all method of $init 328 | traceOneMethod("java.net.URL.$init","java.lang.String") 329 | traceOneMethod("java.net.URL.$init","java.net.URL,java.lang.String") 330 | */ 331 | var split_length = fullMethodName.split(".").length; 332 | var method = fullMethodName.split(".")[split_length - 1]; 333 | var classname = fullMethodName.slice(0, fullMethodName.length - method.length - 1); // -1是为了去掉那个点 334 | Java.performNow(function() { 335 | var tmpClass = Java.use(classname); 336 | tmpClass[method].overloads.forEach(function(m) { 337 | var argumentTypes = m.argumentTypes; 338 | var returnType = m.returnType.name; 339 | var parameterStrArray = []; 340 | for (var tmpArg of argumentTypes) { 341 | parameterStrArray.push(tmpArg["className"]); 342 | } 343 | if (overloadFilter != undefined && overloadFilter != parameterStrArray.join(",")) { 344 | return true 345 | } else { 346 | console.log("hooking " + classname + "." + method + "(" + parameterStrArray.join(",") + ")"); 347 | m.implementation = function() { 348 | var user_log_list = [] 349 | var retval = m.apply(this, arguments); 350 | var user_log_list = ["called " + classname + "." + method + "(" + parameterStrArray.join(",") + ")"] 351 | for (var i = 0; i < arguments.length; i++) { 352 | if (is_print_args) { 353 | var tmp_print_value = print_value(arguments[i], parameterStrArray[i], i); 354 | user_log_list.push(tmp_print_value) 355 | } 356 | } 357 | if (is_print_retval) { 358 | var tmp_print_value = print_value(retval, returnType); 359 | user_log_list.push(tmp_print_value) 360 | } 361 | print_log(user_log_list, classname+"."+method) 362 | return retval; 363 | }; 364 | } 365 | }); 366 | }); 367 | } 368 | 369 | function findClasses(classnameFilter) { 370 | matched_classes = [] 371 | var classReg = new RegExp("^" + classnameFilter + "$") 372 | var classNameList = getAllClassNameList() 373 | for (var i = 0; i < classNameList.length; i++) { 374 | var tmpClassName = classNameList[i] 375 | if (classReg.exec(tmpClassName) != null) { 376 | console.log("[findClasses] matched classes => " + tmpClassName) 377 | matched_classes.push(tmpClassName) 378 | } 379 | } 380 | // return matched_classes 381 | } 382 | 383 | function findMethods(classnameFilter, methodFilter) { 384 | matched_methods_list = []; 385 | Java.performNow(function() { 386 | var classNameList = getAllClassNameList() 387 | for (var i = 0; i < classNameList.length; i++) { 388 | var classReg = new RegExp("^" + classnameFilter + "$") 389 | if (classReg.exec(classNameList[i]) != null) { 390 | // matchedClasses.push(classNameList[i]) 391 | var tmp_methods_list = get_methods_by_className(classNameList[i], methodFilter) 392 | matched_methods_list = matched_methods_list.concat(tmp_methods_list) 393 | } 394 | } 395 | if (matched_methods_list.length == 0) { 396 | console.log("[findMethods]no matched method,please check your input!!!") 397 | } else { 398 | for (var i = 0; i < matched_methods_list.length; i++) { 399 | console.log("[findMethods]matched method=", matched_methods_list[i]) 400 | } 401 | console.log("[findMethods]matched methods_list count=", matched_methods_list.length) 402 | } 403 | }) 404 | // return matched_methods_list 405 | } 406 | 407 | function get_methods_by_className(classname, methodFilter) { 408 | var methods_list = [] 409 | if (methodFilter != undefined) { 410 | var methodFilterReg = new RegExp("^" + methodFilter + "$") 411 | } 412 | Java.performNow(function() { 413 | var tmpClass = Java.use(classname) 414 | var method_init_all = tmpClass.class.getConstructors(); 415 | for (var i = 0; i < method_init_all.length; i++) { 416 | var method_init = method_init_all[i] 417 | if (methodFilterReg == undefined) { 418 | methods_list.push(method_init) 419 | } else if (methodFilterReg && methodFilterReg.exec(method_init.getName()) != null) { 420 | methods_list.push(method_init) 421 | } 422 | } 423 | var method_all = tmpClass.class.getDeclaredMethods(); 424 | for (var i = 0; i < method_all.length; i++) { 425 | var method = method_all[i] 426 | if (methodFilterReg == undefined) { 427 | methods_list.push(method) 428 | } else if (methodFilterReg && methodFilterReg.exec(method.getName()) != null) { 429 | methods_list.push(method) 430 | } 431 | } 432 | }) 433 | return methods_list 434 | } 435 | /* 436 | from hanbing 437 | https://github.com/hanbinglengyue 438 | */ 439 | function hookThread() { 440 | Java.perform(function() { 441 | var ThreadClass = Java.use("java.lang.Thread"); 442 | ThreadClass.init2.implementation = function(arg0) { 443 | var target = this.target.value; 444 | if (target != null) { 445 | //通过直接实现Runnagle接口run来创建新线程 446 | var user_log_list = ["go into new Thread.init2->Runnable class:" + target.$className] 447 | print_log(user_log_list, "java.lang.Thread") 448 | } else { 449 | //通过继承Thread类并覆写run函数来创建新线程 450 | var user_log_list = ["go into extends Thread.init2->Runnable class:" + this.$className] 451 | print_log(user_log_list, "java.lang.Thread") 452 | var threadClassname = this.$className; 453 | var ChindThreadClass = Java.use(threadClassname); 454 | ChindThreadClass.run.implementation = function() { 455 | var user_log_list = ["go into " + threadClassname + ".run"] 456 | print_log(user_log_list, "java.lang.Thread") 457 | var result = this.run(); 458 | return result; 459 | }; 460 | } 461 | var result = this.init2(arg0); 462 | return result; 463 | }; 464 | ThreadClass.run.implementation = function() { 465 | var target = this.target.value; 466 | if (target != null) { 467 | var user_log_list = ["go into new Thread.run->Runnable class:" + target.$className] 468 | print_log(user_log_list, "java.lang.Thread") 469 | } 470 | var reuslt = this.run(); 471 | return reuslt; 472 | }; 473 | }); 474 | } 475 | 476 | function searchAllInstance(classFullName) { 477 | ins_all = [] 478 | console.log("start searchOneInstance:" + classFullName); 479 | Java.performNow(function() { 480 | Java.choose(classFullName, { 481 | onMatch: function(inst) { 482 | console.log(new Array(100).join("=")) 483 | console.log("[searchAllInstance]ins=", inst) 484 | ins_all.push(inst); 485 | }, 486 | onComplete: function() {}, 487 | }); 488 | }); 489 | console.log("[searchAllInstance] search finished") 490 | if (ins_all.length == 0) { 491 | console.log("[searchAllInstance]not found instance of " + classFullName) 492 | } else { 493 | console.log("[searchAllInstance]found " + ins_all.length + " instance of " + classFullName) 494 | for (var i = 0; i < ins_all.length; i++) { 495 | if (i == ins_all.length - 1) { 496 | last_ins = ins_all[i] 497 | } 498 | } 499 | } 500 | } 501 | 502 | function getParameterTypesToString(parameterTypes) { 503 | var result = [] 504 | for (var i = 0; i < parameterTypes.length; i++) { 505 | var tmpType = parameterTypes[i] 506 | var typeName = tmpType.getName() 507 | result.push(typeName) 508 | } 509 | return result.join(", ") 510 | } 511 | 512 | function dumpClass(classFullName) { 513 | Java.performNow(function() { 514 | var tmpClass = Java.use(classFullName) 515 | var packageName = tmpClass.class.getPackage().getName() 516 | if (is_dumpClass_declared) { 517 | var field_all = tmpClass.class.getDeclaredFields(); 518 | } else { 519 | var field_all = tmpClass.class.getFields(); 520 | } 521 | var Modifier = Java.use("java.lang.reflect.Modifier"); 522 | var user_log_list = [] 523 | var classObj = { 524 | "static_fileds": [], 525 | "ins_fields": [], 526 | "contructor_methods": [], 527 | "static_methods": [], 528 | "methods": [] 529 | } 530 | for (var i = 0; i < field_all.length; i++) { 531 | var field = field_all[i] 532 | var fieldType = field.getType().getName(); 533 | var fieldName = field.getName(); 534 | var isStatic = Modifier.isStatic(field.getModifiers()) 535 | if (isStatic) { 536 | var fieldValue = tmpClass[fieldName].value; 537 | classObj["static_fileds"].push({ 538 | "key": fieldType + " " + fieldName, 539 | "value": fieldValue 540 | }) 541 | } else { 542 | classObj["ins_fields"].push({ 543 | "key": fieldType + " " + fieldName, 544 | "value": null 545 | }) 546 | } 547 | } 548 | var method_init_all = tmpClass.class.getConstructors(); 549 | for (var i = 0; i < method_init_all.length; i++) { 550 | var method_init = method_init_all[i] 551 | var method_init_str = method_init.toString().split("throws")[0].trim() 552 | var method_init_ParameterTypes = method_init.getParameterTypes() 553 | var method_init_ParameterTypesStr = getParameterTypesToString(method_init_ParameterTypes) 554 | var method_init_str = "$init(" + method_init_ParameterTypesStr + ")" 555 | classObj["contructor_methods"].push(method_init_str) 556 | } 557 | if (is_dumpClass_declared) { 558 | var method_all = tmpClass.class.getDeclaredMethods(); 559 | } else { 560 | var method_all = tmpClass.class.getMethods(); 561 | } 562 | for (var i = 0; i < method_all.length; i++) { 563 | var method = method_all[i] 564 | var methodStr = method.toString().split("throws")[0].trim() 565 | var methodReturnType = method.getReturnType().getName() 566 | var methodName = method.getName() 567 | var methodParameterTypes = method.getParameterTypes() 568 | var method_ParameterTypesStr = getParameterTypesToString(methodParameterTypes) 569 | var method_str = methodReturnType + " " + methodName + " (" + method_ParameterTypesStr + ")" 570 | var isStatic = Modifier.isStatic(method.getModifiers()) 571 | if (isStatic) { 572 | classObj["static_methods"].push(method_str) 573 | } else { 574 | classObj["methods"].push(method_str) 575 | } 576 | } 577 | //开始打印classObj 578 | var user_log_list = [] 579 | var tab = new Array(8).join(" ") 580 | user_log_list.push("package " + packageName + ";") 581 | console.log(classFullName.slice(classFullName.indexOf(packageName))) 582 | user_log_list.push("class " + classFullName.slice(packageName.length + 1) + " {") 583 | user_log_list.push("") 584 | user_log_list.push(tab + "/* static fields */") 585 | var static_fileds = classObj["static_fileds"] 586 | for (var i = 0; i < static_fileds.length; i++) { 587 | var tmpField = static_fileds[i] 588 | var tmpFieldName = tmpField["key"] 589 | var tmpFieldValue = tmpField["value"] 590 | user_log_list.push(tab + tmpFieldName + " => " + tmpFieldValue) 591 | } 592 | user_log_list.push("") 593 | user_log_list.push(tab + "/* instance fields */") 594 | var ins_fields = classObj["ins_fields"] 595 | for (var i = 0; i < ins_fields.length; i++) { 596 | var tmpField = ins_fields[i] 597 | var tmpFieldName = tmpField["key"] 598 | var tmpFieldValue = tmpField["value"] 599 | user_log_list.push(tab + tmpFieldName + " => " + tmpFieldValue) 600 | } 601 | user_log_list.push("") 602 | user_log_list.push(tab + "/* constructor methods */") 603 | var contructor_methods = classObj["contructor_methods"] 604 | for (var i = 0; i < contructor_methods.length; i++) { 605 | var contructor_method = contructor_methods[i] 606 | user_log_list.push(tab + contructor_method) 607 | } 608 | user_log_list.push("") 609 | user_log_list.push(tab + "/* static methods */") 610 | var static_methods = classObj["static_methods"] 611 | for (var i = 0; i < static_methods.length; i++) { 612 | var static_method = static_methods[i] 613 | user_log_list.push(tab + static_method) 614 | } 615 | user_log_list.push("") 616 | user_log_list.push(tab + "/* methods */") 617 | var methods = classObj["methods"] 618 | for (var i = 0; i < methods.length; i++) { 619 | var method = methods[i] 620 | user_log_list.push(tab + method) 621 | } 622 | user_log_list.push("}") 623 | print_log(user_log_list, classFullName) 624 | return 0 625 | }) 626 | } 627 | 628 | function hook_java() { 629 | //根据需求手动设置变量is_spawn的值,然后再下方的TODO处写用户代码 630 | if (is_spawn) { 631 | Java.use("android.app.Application").onCreate.implementation = function() { 632 | var result = this.onCreate() 633 | console.log("enter android.app.Application.onCreate!!!") 634 | if (!is_hooked) { 635 | // TODO 在此处添加用户代码 636 | // traceOneMethod("android.util.Base64.encodeToString") 637 | is_hooked = true 638 | } 639 | return result 640 | } 641 | } else { 642 | // TODO 在此处添加用户代码 643 | // traceOneMethod("android.util.Base64.encodeToString") 644 | is_hooked = true 645 | } 646 | } 647 | 648 | function main() { 649 | prepare_env() 650 | hook_java() 651 | // test() 652 | } 653 | setImmediate(main) --------------------------------------------------------------------------------