└── README.md /README.md: -------------------------------------------------------------------------------- 1 | # Android 2 | Android 加固应用Hook方式-Frida 3 | ```javascript 4 | Java.perform(function () { 5 | var application = Java.use('android.app.Application'); 6 | 7 | application.attach.overload('android.content.Context').implementation = function(context){ 8 | 9 | var result = this.attach(context); 10 | var classloader = context.getClassLoader(); 11 | Java.classFactory.loader = classloader; 12 | 13 | var yeyoulogin = Java.classFactory.use('com.zcm.主窗口'); 14 | console.log("yeyoulogin:"+ yeyoulogin); 15 | 16 | 17 | yeyoulogin.按钮_用户登录$被单击.implementation = function(arg){ 18 | console.log("retval:"+ this.返回值); 19 | } 20 | 21 | } 22 | }); 23 | ``` 24 | 列出加载的类 25 | ```javascript 26 | Java.enumerateLoadedClasses( 27 | { 28 | "onMatch": function(className){ 29 | console.log(className) 30 | }, 31 | "onComplete":function(){} 32 | } 33 | ) 34 | ``` 35 | 36 | # Hook 动态加载类 37 | ## 获取构造函数的参数 38 | ```javascript 39 | Java.perform(function(){ 40 | //创建一个DexClassLoader的wapper 41 | var dexclassLoader = Java.use("dalvik.system.DexClassLoader"); 42 | //hook 它的构造函数$init,我们将它的四个参数打印出来看看。 43 | dexclassLoader.$init.implementation = function(dexPath,optimizedDirectory,librarySearchPath,parent){ 44 | console.log("dexPath:"+dexPath); 45 | console.log("optimizedDirectory:"+optimizedDirectory); 46 | console.log("librarySearchPath:"+librarySearchPath); 47 | console.log("parent:"+parent); 48 | //不破换它原本的逻辑,我们调用它原本的构造函数。 49 | this.$init(dexPath,optimizedDirectory,librarySearchPath,parent); 50 | } 51 | console.log("down!"); 52 | 53 | }); 54 | ``` 55 | ## 获取动态加载的类 56 | ```javascript 57 | Java.perform(function(){ 58 | var dexclassLoader = Java.use("dalvik.system.DexClassLoader"); 59 | var hookClass = undefined; 60 | var ClassUse = Java.use("java.lang.Class"); 61 | 62 | dexclassLoader.loadClass.overload('java.lang.String').implementation = function(name){ 63 | //定义一个String变量,指定我们需要的类 64 | var hookname = "cn.chaitin.geektan.crackme.MainActivityPatch"; 65 | //直接调用第二个重载方法,跟原本的逻辑相同。 66 | var result = this.loadClass(name,false); 67 | //如果loadClass的name参数和我们想要hook的类名相同 68 | if(name === hookname){ 69 | //则拿到它的值 70 | hookClass = result; 71 | //打印hookClass变量的值 72 | console.log(hookClass); 73 | send(hookClass); 74 | return result; 75 | } 76 | return result; 77 | } 78 | }); 79 | ``` 80 | ## 通过Java.cast处理泛型方法(JAVA中Class表示泛型),在调用动态加载方法 81 | ```javascript 82 | Java.perform(function(){ 83 | var hookClass = undefined; 84 | var ClassUse = Java.use("java.lang.Class"); 85 | var dexclassLoader = Java.use("dalvik.system.DexClassLoader"); 86 | var constructorclass = Java.use("java.lang.reflect.Constructor"); 87 | var objectclass= Java.use("java.lang.Object"); 88 | dexclassLoader.loadClass.overload('java.lang.String').implementation = function(name){ 89 | var hookname = "cn.chaitin.geektan.crackme.MainActivityPatch"; 90 | var result = this.loadClass(name,false); 91 | 92 | if(name == hookname){ 93 | var hookClass = result; 94 | console.log("------------------------------CAST--------------------------------") 95 | //类型转换 96 | var hookClassCast = Java.cast(hookClass,ClassUse); 97 | //调用getMethods()获取类下的所有方法 98 | var methods = hookClassCast.getMethods(); 99 | console.log(methods); 100 | console.log("-----------------------------NOT CAST-----------------------------") 101 | //未进行类型转换,看看能否调用getMethods()方法 102 | var methodtest = hookClass.getMethods(); 103 | console.log(methodtest); 104 | console.log("---------------------OVER------------------------") 105 | return result; 106 | 107 | } 108 | return result; 109 | } 110 | 111 | 112 | }); 113 | ``` 114 | ### 利用getDeclaredConstructor()获取具有指定参数列表构造函数的Constructor 并实例化 115 | ```javascript 116 | Java.perform(function(){ 117 | var hookClass = undefined; 118 | var ClassUse = Java.use("java.lang.Class"); 119 | var objectclass= Java.use("java.lang.Object"); 120 | var dexclassLoader = Java.use("dalvik.system.DexClassLoader"); 121 | var orininclass = Java.use("cn.chaitin.geektan.crackme.MainActivity"); 122 | var Integerclass = Java.use("java.lang.Integer"); 123 | //实例化MainActivity对象 124 | var mainAc = orininclass.$new(); 125 | 126 | 127 | dexclassLoader.loadClass.overload('java.lang.String').implementation = function(name){ 128 | var hookname = "cn.chaitin.geektan.crackme.MainActivityPatch"; 129 | var result = this.loadClass(name,false); 130 | 131 | if(name == hookname){ 132 | var hookClass = result; 133 | var hookClassCast = Java.cast(hookClass,ClassUse); 134 | console.log("-----------------------------BEGIN-------------------------------------"); 135 | //获取构造器 136 | var ConstructorParam =Java.array('Ljava.lang.Object;',[objectclass.class]); 137 | var Constructor = hookClassCast.getDeclaredConstructor(ConstructorParam); 138 | console.log("Constructor:"+Constructor); 139 | console.log("orinin:"+mainAc); 140 | //实例化,newInstance的参数也是Ljava.lang.Object; 141 | var instance = Constructor.newInstance([mainAc]); 142 | console.log("patchAc:"+instance); 143 | send(instance); 144 | console.log("--------------------------------------------------------------------"); 145 | return result; 146 | 147 | } 148 | return result; 149 | } 150 | }); 151 | ``` 152 | ### 利用getDeclaredMethods(),获取本类中的所有方法 153 | ```javascript 154 | Java.perform(function(){ 155 | var hookClass = undefined; 156 | var ClassUse = Java.use("java.lang.Class"); 157 | var objectclass= Java.use("java.lang.Object"); 158 | var dexclassLoader = Java.use("dalvik.system.DexClassLoader"); 159 | var orininclass = Java.use("cn.chaitin.geektan.crackme.MainActivity"); 160 | var Integerclass = Java.use("java.lang.Integer"); 161 | //实例化MainActivity对象 162 | var mainAc = orininclass.$new(); 163 | 164 | 165 | dexclassLoader.loadClass.overload('java.lang.String').implementation = function(name){ 166 | var hookname = "cn.chaitin.geektan.crackme.MainActivityPatch"; 167 | var result = this.loadClass(name,false); 168 | 169 | if(name == hookname){ 170 | var hookClass = result; 171 | var hookClassCast = Java.cast(hookClass,ClassUse); 172 | console.log("-----------------------------BEGIN-------------------------------------"); 173 | //获取构造器 174 | var ConstructorParam =Java.array('Ljava.lang.Object;',[objectclass.class]); 175 | var Constructor = hookClassCast.getDeclaredConstructor(ConstructorParam); 176 | console.log("Constructor:"+Constructor); 177 | console.log("orinin:"+mainAc); 178 | //实例化,newInstance的参数也是Ljava.lang.Object; 179 | var instance = Constructor.newInstance([mainAc]); 180 | console.log("MainActivityPatchInstance:"+instance); 181 | send(instance); 182 | console.log("----------------------------Methods---------------------------------"); 183 | var func = hookClassCast.getDeclaredMethods(); 184 | console.log(func); 185 | console.log("--------------------------Need Method---------------------------------"); 186 | console.log(func[0]); 187 | var f = func[0]; 188 | console.log("---------------------------- OVER---------------------------------"); 189 | return result; 190 | 191 | } 192 | return result; 193 | } 194 | }); 195 | ``` 196 | ## 调用Method.invoke()去执行方法(invoke方法的第一个参数是执行这个方法的对象实例,第二个参数是带入的实际值数组,返回值是Object,也既是该方法执行后的返回值) 197 | ``` 198 | f.invoke(instance,Array); 199 | ``` 200 | 201 | ## read-std-string 202 | ```javascript 203 | /* 204 | * Note: Only compatible with libc++, though libstdc++'s std::string is a lot simpler. 205 | */ 206 | 207 | function readStdString (str) { 208 | const isTiny = (str.readU8() & 1) === 0; 209 | if (isTiny) { 210 | return str.add(1).readUtf8String(); 211 | } 212 | 213 | return str.add(2 * Process.pointerSize).readPointer().readUtf8String(); 214 | } 215 | ``` 216 | 217 | ## whereisnative 218 | ```javascript 219 | Java.perform(function() { 220 | 221 | var SystemDef = Java.use('java.lang.System'); 222 | 223 | var RuntimeDef = Java.use('java.lang.Runtime'); 224 | 225 | var exceptionClass = Java.use('java.lang.Exception'); 226 | 227 | var SystemLoad_1 = SystemDef.load.overload('java.lang.String'); 228 | 229 | var SystemLoad_2 = SystemDef.loadLibrary.overload('java.lang.String'); 230 | 231 | var RuntimeLoad_1 = RuntimeDef.load.overload('java.lang.String'); 232 | 233 | var RuntimeLoad_2 = RuntimeDef.loadLibrary.overload('java.lang.String'); 234 | 235 | var ThreadDef = Java.use('java.lang.Thread'); 236 | 237 | var ThreadObj = ThreadDef.$new(); 238 | 239 | SystemLoad_1.implementation = function(library) { 240 | send("Loading dynamic library => " + library); 241 | stackTrace(); 242 | return SystemLoad_1.call(this, library); 243 | } 244 | 245 | SystemLoad_2.implementation = function(library) { 246 | send("Loading dynamic library => " + library); 247 | stackTrace(); 248 | SystemLoad_2.call(this, library); 249 | return; 250 | } 251 | 252 | RuntimeLoad_1.implementation = function(library) { 253 | send("Loading dynamic library => " + library); 254 | stackTrace(); 255 | RuntimeLoad_1.call(this, library); 256 | return; 257 | } 258 | 259 | RuntimeLoad_2.implementation = function(library) { 260 | send("Loading dynamic library => " + library); 261 | stackTrace(); 262 | RuntimeLoad_2.call(this, library); 263 | return; 264 | } 265 | 266 | function stackTrace() { 267 | var stack = ThreadObj.currentThread().getStackTrace(); 268 | for (var i = 0; i < stack.length; i++) { 269 | send(i + " => " + stack[i].toString()); 270 | } 271 | send("--------------------------------------------------------------------------"); 272 | } 273 | 274 | }); 275 | ``` 276 | 277 | ## Non-ASCII 278 | ```java 279 | int ֏(int x) { 280 | return x + 100; 281 | } 282 | ``` 283 | 甚至有一些不可视, 所以可以先编码打印出来, 再用编码后的字符串去 hook.<\br> 284 | ```javascript 285 | Java.perform( 286 | function x() { 287 | 288 | var targetClass = "com.example.hooktest.MainActivity"; 289 | 290 | var hookCls = Java.use(targetClass); 291 | var methods = hookCls.class.getDeclaredMethods(); 292 | 293 | for (var i in methods) { 294 | console.log(methods[i].toString()); 295 | console.log(encodeURIComponent(methods[i].toString().replace(/^.*?\.([^\s\.\(\)]+)\(.*?$/, "$1"))); 296 | } 297 | 298 | hookCls[decodeURIComponent("%D6%8F")] 299 | .implementation = function (x) { 300 | console.log("original call: fun(" + x + ")"); 301 | var result = this[decodeURIComponent("%D6%8F")](900); 302 | return result; 303 | } 304 | } 305 | ) 306 | ``` 307 | 308 | ## Hook 数据库 309 | ```javascript 310 | var SQLiteDatabase = Java.use('com.tencent.wcdb.database.SQLiteDatabase'); 311 | var Set = Java.use("java.util.Set"); 312 | var ContentValues = Java.use("android.content.ContentValues"); 313 | SQLiteDatabase.insert.implementation = function (arg1,arg2,arg3) { 314 | 315 | this.insert.call(this, arg1, arg2, arg3); 316 | console.log("[insert] -> arg1:" + arg1 + "\t arg2:" + arg2); 317 | var values = Java.cast(arg3, ContentValues); 318 | var sets = Java.cast(values.keySet(), Set); 319 | 320 | var arr = sets.toArray().toString().split(","); 321 | for (var i = 0; i < arr.length; i++){ 322 | console.log("[insert] -> key:" + arr[i] + "\t value:" + values.get(arr[i])); 323 | } 324 | }; 325 | 326 | ``` 327 | ## Hook JNI Native GetStringUTFChars 328 | ```javascript 329 | function hook_native_GetStringUTFChars() { 330 | var env = Java.vm.getEnv(); 331 | var handlePointer = Memory.readPointer(env.handle); 332 | console.log("env handle: " + handlePointer); 333 | var GetStringUTFCharsPtr = Memory.readPointer(handlePointer.add(0x2A4)); 334 | console.log("GetStringUTFCharsPtr addr: " + GetStringUTFCharsPtr); 335 | Interceptor.attach(GetStringUTFCharsPtr, { 336 | onEnter: function (args) { 337 | var str = ""; 338 | Java.perform(function () { 339 | str = Java.cast(args[1], Java.use('java.lang.String')); 340 | }); 341 | console.log("GetStringUTFChars: " + str); 342 | 343 | } 344 | }); 345 | } 346 | ``` 347 | ## 主动弹窗 348 | ```javascript 349 | Java.perform(function() { 350 | var System = Java.use('java.lang.System'); 351 | var ActivityThread = Java.use("android.app.ActivityThread"); 352 | var AlertDialogBuilder = Java.use("android.app.AlertDialog$Builder"); 353 | var DialogInterfaceOnClickListener = Java.use('android.content.DialogInterface$OnClickListener'); 354 | 355 | Java.use("android.app.Activity").onCreate.overload("android.os.Bundle").implementation = function(savedInstanceState) { 356 | var currentActivity = this; 357 | 358 | // Get Main Activity 359 | var application = ActivityThread.currentApplication(); 360 | var launcherIntent = application.getPackageManager().getLaunchIntentForPackage(application.getPackageName()); 361 | var launchActivityInfo = launcherIntent.resolveActivityInfo(application.getPackageManager(), 0); 362 | 363 | // Alert Will Only Execute On Main Package Activity Creation 364 | console.log(this.getComponentName().getClassName()) 365 | /** 366 | * non protective application 367 | * if (launchActivityInfo === this.getComponentName().getClassName()) { 368 | * ... 369 | * } 370 | */ 371 | 372 | if (this.getComponentName().getClassName() === "com.xxx") { 373 | 374 | var alert = AlertDialogBuilder.$new(this); 375 | var jString = Java.use('java.lang.String'); 376 | var CharSequence = Java.use('java.lang.CharSequence'); 377 | var charSequence = Java.cast(jString.$new("What you want to do now?"), CharSequence); 378 | var charSequence1 = Java.cast(jString.$new("Dismiss"), CharSequence); 379 | var charSequence2 = Java.cast(jString.$new("Force Close!"), CharSequence); 380 | alert.setMessage(charSequence); 381 | 382 | alert.setPositiveButton(charSequence1, Java.registerClass({ 383 | name: 'il.co.realgame.OnClickListenerPositive', 384 | implements: [DialogInterfaceOnClickListener], 385 | methods: { 386 | getName: function() { 387 | return 'OnClickListenerPositive'; 388 | }, 389 | onClick: function(dialog, which) { 390 | // Dismiss 391 | dialog.dismiss(); 392 | } 393 | } 394 | }).$new()); 395 | 396 | alert.setNegativeButton(charSequence2, Java.registerClass({ 397 | name: 'il.co.realgame.OnClickListenerNegative', 398 | implements: [DialogInterfaceOnClickListener], 399 | methods: { 400 | getName: function() { 401 | return 'OnClickListenerNegative'; 402 | }, 403 | onClick: function(dialog, which) { 404 | // Close Application 405 | //currentActivity.finish(); 406 | System.exit(0); 407 | } 408 | } 409 | }).$new()); 410 | 411 | // Create Alert 412 | alert.create().show(); 413 | } 414 | return this.onCreate.overload("android.os.Bundle").call(this, savedInstanceState); 415 | }; 416 | }); 417 | ``` 418 | # Hook prettyMethod 419 | ```javascript 420 | const STD_STRING_SIZE = 3 * Process.pointerSize; 421 | class StdString { 422 | constructor() { 423 | this.handle = Memory.alloc(STD_STRING_SIZE); 424 | } 425 | 426 | dispose() { 427 | const [data, isTiny] = this._getData(); 428 | if (!isTiny) { 429 | Java.api.$delete(data); 430 | } 431 | } 432 | 433 | disposeToString() { 434 | const result = this.toString(); 435 | this.dispose(); 436 | return result; 437 | } 438 | 439 | toString() { 440 | const [data] = this._getData(); 441 | return data.readUtf8String(); 442 | } 443 | 444 | _getData() { 445 | const str = this.handle; 446 | const isTiny = (str.readU8() & 1) === 0; 447 | const data = isTiny ? str.add(1) : str.add(2 * Process.pointerSize).readPointer(); 448 | return [data, isTiny]; 449 | } 450 | } 451 | 452 | function prettyMethod(method_id, withSignature) { 453 | const result = new StdString(); 454 | Java.api['art::ArtMethod::PrettyMethod'](result, method_id, withSignature ? 1 : 0); 455 | return result.disposeToString(); 456 | } 457 | ``` 458 | 459 | # bypass frida detection 460 | ` 461 | result = pthread_create(v102, 0LL, sub_F74, 0LL); 462 | ` 463 | ```javascript 464 | function hook_pthread_create(){ 465 | var pt_create_func = Module.findExportByName(null,'pthread_create'); 466 | var detect_frida_loop_addr = null; 467 | console.log('pt_create_func:',pt_create_func); 468 | 469 | Interceptor.attach(pt_create_func,{ 470 | onEnter:function(){ 471 | if(detect_frida_loop_addr == null) 472 | { 473 | var base_addr = Module.getBaseAddress('libnative-lib.so'); 474 | if(base_addr != null){ 475 | detect_frida_loop_addr = base_addr.add(0x0000000000000F74) 476 | console.log('this.context.x2: ', detect_frida_loop_addr , this.context.x2); 477 | if(this.context.x2.compare(detect_frida_loop_addr) == 0) { 478 | hook_anti_frida_replace(this.context.x2); 479 | } 480 | } 481 | 482 | } 483 | 484 | }, 485 | onLeave : function(retval){ 486 | // console.log('retval',retval); 487 | } 488 | }) 489 | } 490 | function hook_anti_frida_replace(addr){ 491 | console.log('replace anti_addr :',addr); 492 | Interceptor.replace(addr,new NativeCallback(function(a1){ 493 | console.log('replace success'); 494 | return; 495 | },'pointer',[])); 496 | 497 | } 498 | 499 | setImmediate(hook_pthread_create()); 500 | ``` 501 | # find svc 502 | ```javascript 503 | let target_code_hex; 504 | let call_number_openat; 505 | let call_number_faccessat; 506 | let arch = Process.arch; 507 | let call_number_sendto; 508 | let call_number_sendmsg; 509 | let call_number_kill; 510 | if ("arm" === arch){ 511 | target_code_hex = "00 00 00 EF"; 512 | call_number_openat = 322; 513 | call_number_faccessat = 334; 514 | call_number_sendto = 206; 515 | call_number_sendmsg = 221; 516 | call_number_kill = 129; 517 | }else if("arm64" === arch){ 518 | target_code_hex = "01 00 00 D4"; 519 | call_number_openat = 56; 520 | call_number_faccessat = 48; 521 | call_number_sendto = 206; 522 | call_number_sendmsg = 221; 523 | call_number_kill = 129; 524 | 525 | }else { 526 | console.log("arch not support!") 527 | } 528 | 529 | if (arch){ 530 | console.log("\nthe_arch = " + arch); 531 | // 直接Process.enumerateModules(),可能会因为某些地址不可读造成非法访问 532 | Process.enumerateRanges('r--').forEach(function (range) { 533 | if(!range.file || !range.file.path){ 534 | return; 535 | } 536 | let path = range.file.path; 537 | if ((!path.startsWith("/data/app/")) || (!path.endsWith(".so"))){ 538 | return; 539 | } 540 | let baseAddress = Module.getBaseAddress(path); 541 | console.log("\npath = " + path + " , baseAddress = " + baseAddress + " , rangeAddress = " + range.base + " , size = " + range.size); 542 | 543 | Memory.scan(range.base, range.size, target_code_hex, { 544 | onMatch: function (match){ 545 | let code_address = match; 546 | let code_address_str = code_address.toString(); 547 | if (code_address_str.endsWith("0") || code_address_str.endsWith("4") || code_address_str.endsWith("8") || code_address_str.endsWith("c")){ 548 | console.log("--------------------------"); 549 | let call_number = 0; 550 | if ("arm" === arch){ 551 | // call_number = (code_address.sub(0x4).readS16() - 28672); // 0x7000 552 | call_number = (code_address.sub(0x4).readS32()) & 0xFFF; 553 | }else if("arm64" === arch){ 554 | call_number = (code_address.sub(0x4).readS32() >> 5) & 0xFFFF; 555 | }else { 556 | console.log("the arch get call_number not support!") 557 | } 558 | console.log("find svc : address = " + code_address + " , call_number = " + call_number + " , offset = " + code_address.sub(baseAddress)); 559 | 560 | // hook svc __NR_openat 561 | if (call_number_openat === call_number){ 562 | let target_hook_addr = code_address; 563 | let target_hook_addr_offset = target_hook_addr.sub(baseAddress); 564 | console.log("find svc openat , start inlinehook by frida!") 565 | Interceptor.attach(target_hook_addr, { 566 | onEnter: function (args){ 567 | console.log("\nonEnter_" + target_hook_addr_offset + " , __NR_openat , args[1] = " + args[1].readCString()); 568 | this.new_addr = Memory.allocUtf8String("/proc/self/status11"); 569 | args[1] = this.new_addr; 570 | console.log("onEnter_" + target_hook_addr_offset + " , __NR_openat , args[1] = " + args[1].readCString()); 571 | }, onLeave: function (retval){ 572 | console.log("onLeave_" + target_hook_addr_offset + " , __NR_openat , retval = " + retval) 573 | } 574 | }); 575 | 576 | } 577 | // hook svc __NR_faccessat 578 | if (call_number_faccessat === call_number){ 579 | let target_hook_addr = code_address; 580 | let target_hook_addr_offset = target_hook_addr.sub(baseAddress); 581 | console.log("find svc faccessat , start inlinehook by frida!") 582 | Interceptor.attach(target_hook_addr, { 583 | onEnter: function (args){ 584 | console.log("\nonEnter_" + target_hook_addr_offset + " , __NR_faccessat , args[1] = " + args[1].readCString()); 585 | // this.new_addr = Memory.allocUtf8String("/proc/self/status11"); 586 | // args[1] = this.new_addr; 587 | console.log("onEnter_" + target_hook_addr_offset + " , __NR_faccessat , args[1] = " + args[1].readCString()); 588 | }, onLeave: function (retval){ 589 | console.log("onLeave_" + target_hook_addr_offset + " , __NR_faccessat , retval = " + retval) 590 | } 591 | }); 592 | 593 | } 594 | } 595 | }, onComplete: function () {} 596 | }); 597 | 598 | }); 599 | } 600 | ``` 601 | # USB Debugging Bypass 602 | ```javascript 603 | function USBDebuggingBypass() { 604 | var Secure = Java.use('android.provider.Settings$Secure'); 605 | var System = Java.use('android.provider.Settings$System'); 606 | var Global = Java.use('android.provider.Settings$Global'); 607 | 608 | Secure.getInt.overload('android.content.ContentResolver', 'java.lang.String', 'int').implementation = function(arg1, arg2, arg3) { 609 | if(arg2.indexOf('adb_enabled') !== -1) { 610 | console.warn('[!] USB Debugging Check Bypass !'); 611 | return 0; 612 | } else { 613 | return this.getInt(arg1, arg2, arg3); 614 | } 615 | } 616 | System.getInt.overload('android.content.ContentResolver', 'java.lang.String', 'int').implementation = function(arg1, arg2, arg3) { 617 | if(arg2.indexOf('adb_enabled') !== -1) { 618 | console.warn('[!] USB Debugging Check Bypass !'); 619 | return 0; 620 | } else { 621 | return this.getInt(arg1, arg2, arg3); 622 | } 623 | } 624 | Global.getInt.overload('android.content.ContentResolver', 'java.lang.String', 'int').implementation = function(arg1, arg2, arg3) { 625 | if(arg2.indexOf('adb_enabled') !== -1) { 626 | console.warn('[!] USB Debugging Check Bypass !'); 627 | return 0; 628 | } else { 629 | return this.getInt(arg1, arg2, arg3); 630 | } 631 | } 632 | 633 | var Debug = Java.use('android.os.Debug'); 634 | Debug.isDebuggerConnected.implementation = function() { 635 | console.warn('[*] Debug.isDebuggerConnected() Bypass !'); 636 | 637 | return false; 638 | } 639 | } 640 | 641 | ``` 642 | # hook read & open 643 | ```javascript 644 | var TraceSysFD = {}; 645 | function prettyLog(str) { 646 | console.log("---------------------------\n" + str); 647 | } 648 | 649 | Interceptor.attach(Module.findExportByName(null, "read"), { 650 | // fd, buff, len 651 | onEnter: function (args) { 652 | var bfr = args[1], sz = args[2].toInt32(); 653 | var path = (TraceSysFD["fd-" + args[0].toInt32()] != null) ? TraceSysFD["fd-" + args[0].toInt32()] : "[unknow path]"; 654 | prettyLog("[Libc::read] Read FD (" + path + "," + bfr + "," + sz + ")\n"); 655 | }, 656 | onLeave: function (ret) { 657 | } 658 | }); 659 | Interceptor.attach(Module.findExportByName(null, "open"), { 660 | // path, flags, mode 661 | onEnter: function (args) { 662 | this.path = args[0].readCString(); 663 | }, 664 | onLeave: function (ret) { 665 | TraceSysFD["fd-" + ret.toInt32()] = this.path; 666 | prettyLog("[Libc::open] Open file '" + this.path + "' (fd: " + ret.toInt32() + ")"); 667 | } 668 | }); 669 | 670 | ``` 671 | 672 | # hook readlink 673 | ```javascript 674 | var aaa,bbb,ccc; 675 | Interceptor.attach(Module.findExportByName(null, "readlink"),{ 676 | onEnter: function(args){ 677 | aaa = args[0]; 678 | bbb = args[1]; 679 | ccc = args[2]; 680 | }, 681 | onLeave: function(retval){ 682 | // console.log('\nreadlink(' + 's1="' + aaa.readCString() + '"' + ', s2="' + bbb.readCString() + '"' + ', s3="' + ccc + '"' + ')'); 683 | if(bbb.readCString().indexOf("frida")!==-1 || 684 | bbb.readCString().indexOf("gum-js-loop")!==-1|| 685 | bbb.readCString().indexOf("gmain")!==-1 || 686 | bbb.readCString().indexOf("tmp")!==-1 || 687 | bbb.readCString().indexOf("linjector")!==-1){ 688 | console.log('\nreadlink(' + 's1="' + aaa.readCString() + '"' + ', s2="' + bbb.readCString() + '"' + ', s3="' + ccc + '"' + ')'); 689 | bbb.writeUtf8String("/system/framework/boot.art") 690 | //console.log("replce with: "+bbb.readCString()) 691 | retval.replace(0x1A) 692 | //console.log("retval: "+retval) 693 | } 694 | } 695 | }); 696 | 697 | ``` 698 | 699 | # hook strstr 700 | ```javascript 701 | var strstr = Module.findExportByName(null, "strstr"); 702 | if (null !== strstr) { 703 | Interceptor.attach(strstr, { 704 | onEnter: function (args) { 705 | this.frida = Boolean(0); 706 | 707 | this.haystack = args[0]; 708 | this.needle = args[1]; 709 | 710 | if (this.haystack.readCString() !== null && this.needle.readCString() !== null) { 711 | if (this.haystack.readCString().indexOf("frida") !== -1 || 712 | this.needle.readCString().indexOf("frida") !== -1 || 713 | this.haystack.readCString().indexOf("gum-js-loop") !== -1 || 714 | this.needle.readCString().indexOf("gum-js-loop") !== -1 || 715 | this.haystack.readCString().indexOf("gmain") !== -1 || 716 | this.needle.readCString().indexOf("gmain") !== -1 || 717 | this.haystack.readCString().indexOf("linjector") !== -1 || 718 | this.needle.readCString().indexOf("linjector") !== -1) { 719 | this.frida = Boolean(1); 720 | } 721 | } 722 | }, 723 | onLeave: function (retval) { 724 | if (this.frida) { 725 | retval.replace(ptr("0x0")); 726 | } 727 | 728 | } 729 | }) 730 | console.log("anti anti-frida"); 731 | } 732 | 733 | ``` 734 | 735 | # hook strcmp 736 | ```javascript 737 | var strcmp = Module.findExportByName(null,"strcmp"); 738 | console.log("find strcmp:",strcmp); 739 | Interceptor.attach(strcmp, { 740 | onEnter: function (args) { 741 | if(ptr(args[1]).readCString().indexOf("frida")>=0){ 742 | // ptr(args[1]).writeUtf8String('fuck u'); 743 | console.log("[*] strcmp (" + ptr(args[0]).readCString() + "," + ptr(args[1]).readCString()+")"); 744 | 745 | this.ishack = true; 746 | } 747 | 748 | }, 749 | onLeave: function(retval){ 750 | if(this.ishack){ 751 | retval.replace(ptr("0x0")) 752 | console.log("the ishack's result :",retval); 753 | } 754 | 755 | } 756 | }); 757 | 758 | ``` 759 | --------------------------------------------------------------------------------