frida hook使用手册 平时整理

if(Java.available){
	
	//java打印堆栈调用方法
	function printStack(str_tag) {
		var Exception=  Java.use("java.lang.Exception");
		var ins = Exception.$new("Exception");
		var straces = ins.getStackTrace();

		if (undefined == straces || null  == straces) 
		{
			return;
		}

		//console.log("=============================" + str_tag + " Stack strat=======================");
		//console.log("");

		for (var i = 0; i < straces.length; i++)
		{
			var str = "   " + straces[i].toString();
			console.log(str);
		}

		//console.log("");
		//console.log("=============================" + str_tag + " Stack end=======================\r\n");
		Exception.$dispose();
	}
	
	// jstring, jbytearray 输出
	function jstring2Str(jstring) {
       var ret;
	   Java.perform(function() {
		   var String = Java.use("java.lang.String");
		   ret = Java.cast(jstring, String);
	   });
	   return ret;
	}
	 
	function jbyteArray2Array(jbyteArray) {
	   var ret;
	   Java.perform(function() {
		   var b = Java.use('[B');
		   var buffer = Java.cast(jbyteArray, b);
		   ret = Java.array('byte', buffer);
	   });
	   return ret;
	}
	//bytes2Hex 
	function bytes2Hex(arr) {
		var str = "[";
		for (var i = 0; i < arr.length; i++) {
			var z = parseInt(arr[i]);
			if (z < 0) z = 255 + z;
			var tmp = z.toString(16);
			if (tmp.length == 1) {
				tmp = "0" + tmp;
			}
			str = str + " " + tmp;
		}
		return (str + " ]").toUpperCase();
	}
	
	//bytes2String
	function bytes2String(arr) {
		if(typeof arr === 'string') {
			return arr;
		}
		var str = '',
			_arr = arr;
		for(var i = 0; i < _arr.length; i++) {
			var one = _arr[i].toString(2),
				v = one.match(/^1+?(?=0)/);
			if(v && one.length == 8) {
				var bytesLength = v[0].length;
				var store = _arr[i].toString(2).slice(7 - bytesLength);
				for(var st = 1; st < bytesLength; st++) {
					store += _arr[st + i].toString(2).slice(2);
				}
				try {
					str += String.fromCharCode(parseInt(store, 2));
				} catch (error) {
					str += parseInt(store, 2).toString(); 
					console.log(error);
				}
				
				i += bytesLength - 1;
			} else {
				try {
					str += String.fromCharCode(_arr[i]);
				} catch (error) {
					str += parseInt(store, 2).toString(); 
					console.log(error);
				}
				
			}
		}
		return str;
	}

	//输出类所有方法名
	function enumMethods(targetClass) {
		var ret;
		Java.perform(function() {
				var hook = Java.use(targetClass);
				var ret = hook.class.getDeclaredMethods();
				ret.forEach(function(s) {
					console.log(s);
				})
		})
		return ret;
	}
	
	//hook 所有重载函数
	function hookAllOverloads(targetClass, targetMethod) {
		Java.perform(function () {
			 var targetClassMethod = targetClass + '.' + targetMethod;
			 var hook = Java.use(targetClass);
			 var overloadCount = hook[targetMethod].overloads.length;
			 for (var i = 0; i < overloadCount; i++) {
					hook[targetMethod].overloads[i].implementation = function() {
						 var retval = this[targetMethod].apply(this, arguments);
						 //这里可以打印结果和参数
						 return retval;
					 }
				  }
	   });
	 }
	 
	 //输出 byte[] 等 java 对象
	 function jobj2Str(jobject) {
		var ret = JSON.stringify(jobject);
		return ret;
	}
	
	//dump 地址
	function dumpAddr(address, length) {
		length = length || 1024;
		console.log(hexdump(address, {
			offset: 0,
			length: length,
			header: true,
			ansi: false
		}));
	}
	
	//ArrayBuffer 转换 
	function ab2Hex(buffer) {
		var arr = Array.prototype.map.call(new Uint8Array(buffer), function (x) {return ('00' + x.toString(16)).slice(-2)}).join(" ").toUpperCase();
		return "[" + arr + "]";
	}
	 
	function ab2Str(buffer) {
		return String.fromCharCode.apply(null, new Uint8Array(buffer));
	}
	
	//获取类型
	function getParamType(obj) {
		return obj == null ? String(obj) : Object.prototype.toString.call(obj).replace(/\[object\s+(\w+)\]/i, "$1") || "object";
	}
	
	//Hook 函数的参数为 map 等特殊类型
	//方法1
	var HashMap = Java.use('java.util.HashMap');
    var ShufferMap = Java.use('com.xx.app.ShufferMap');
    ShufferMap.show.implementation = function (map) {
        var hm = HashMap.$new();
        hm.put("user","dajianbang");
        hm.put("pass","87654321");
        hm.put("code","123456");
        return this.show(hm);
    }
	
	//方法2  打印 map
	var ShufferMap = Java.use("com.xx.app.ShufferMap");
    console.log(ShufferMap);
    ShufferMap.show.implementation = function(map){
        console.log(JSON.stringify(map));
        //Java map的遍历
        // var key = map.keySet();
        // var it = key.iterator();
        // var result = "";
        // while(it.hasNext()){
        //     var keystr = it.next();
        //     var valuestr = map.get(keystr);
        //     result += valuestr;
        // }
        // console.log(result);
        // return result;

        map.put("pass", "wawa");
        map.put("guanwang", "666");

        var retval = this.show(map);
        console.log(retval);
        return retval;

    }

	//打印[Ljava.lang.String; 数组 [Ljava.lang.String;
	var ArrayClz = Java.use("java.lang.reflect.Array");
	var len = ArrayClz.getLength(arg4);
	for(let i=0;i!=len;i++){
		console.log("arg4 -> "+ArrayClz.get(arg4,i).toString());
	}


		//遍历list
		function printList(mapClz) {
			//var key = mapClz.keySet();
			var it = mapClz.iterator();
			while(it.hasNext()){
					var keystr = it.next();
					//var valuestr = mapClz.get(keystr);
					//result += valuestr;
					console.log("list:"+keystr);
			}
		}
	
	
	
	//主动调用函数
	 Java.choose("com.xx.xx.xx.xx",{
        onMatch: function(instance){
            instance.function();
        },
        onComplete: function(){

        }
    });

	//遍历成员及函数
	var members = CronetHttpURLConnection.class.getDeclaredFields();
	console.log("CronetHttpURLConnection output "+this.getOutputStream())
	members.forEach(function(member) {
				 	// 
		console.log("member: ", member);
	 }); 
	
	//修改静态变量
	var LoginActivity3 = Java.use("com.xx.xx.xx.xx");

	// 设置变量值后面必须加 `.value` 才能设置
	LoginActivity3.static_bool_var.value = true;
	
	//修改 动态变量
	// 动态变量必须 choose 找到示例才能操作
	Java.choose("com.xx.xx.xx.xx",{
		onMatch: function(instance){
			// 设置变量值后面必须加 `.value` 才能设置
			instance.bool_var.value = true;
			
			// 注意! 如果动态变量名与函数名重名了,就需要在前面加 _ 下划线,如下:
			instance._same_name_bool_var.value = true;
		},
		onComplete: function(){
		}
	});
	//https://www.zhangkunzhi.com/index.php/archives/3/ 具体参考
		

    Java.perform(function()
    {

		//枚举所有的加载模块
		var process_Obj_Module_Arr = Process.enumerateModules();
		for(var i = 0; i < process_Obj_Module_Arr.length; i++) {
            console.log("",process_Obj_Module_Arr[i].name);
        }
		
		console.log("hook c start");

		var str_name_so = "libc.so";
		var str_name_func = "fgets";
		
		//hook 构造函数
		var javaUri = Java.use("java.net.URL");
        javaUri.$init.overload("java.lang.String").implementation=function(Stringclass1){
			printStack("douyin");
            console.log("hook java String -> "+Stringclass1);
			
        }
		
		//打印[Ljava.lang.String; 数组
		var ArrayClz = Java.use("java.lang.reflect.Array");
		var len = ArrayClz.getLength(arg4);
		for(let i=0;i!=len;i++){
						console.log("arg4 -> "+ArrayClz.get(arg4,i).toString());
		}

		//类转换
		var retrofit2 = Java.use("com.bytedance.retrofit2.CallServerInterceptor");
		var retrofitcb = Java.use("com.bytedance.retrofit2.c.b"); //om.bytedance.retrofit2.c.a$a 为基类
		retrofit2.intercept.overload('com.bytedance.retrofit2.c.a$a').implementation = function(arg)
		{
			retrofitcb = arg;
			console.log("retrofit2 intercept.url -> ",retrofitcb.a().getUrl());
			
			return this.intercept(arg)
		}

		//********************************hook native*********************************//
		//hook export function //hook 导出函数
		var func_ptr = Module.findExportByName(str_name_so , str_name_func);
		if (null == func_ptr)
		{
			console.log(str_name_func + " point is null");
			return;
		}

		Interceptor.attach(func_ptr, 
		{
			onEnter: function(args) 
			{
				print_c_stack(this.context, str_name_func);
			},
			onLeave:function(retval)
			{
					  
			}
		}); 

		//hook 地址 打印内存
		var offset = 0x000428BC;
		var nativelibModule = Process.findModuleByName("libnative-lib.so");
	
		var func_addr = nativelibModule.base.add(offset).add(1);
		Interceptor.attach(func_addr,{
			onEnter(args){
				this.arg1 = args[1];
				this.arg0 = args[0];
				console.log("hookMD5 onEnter arg0===> ",ptr(args[0]).readUtf8String());
				// console.log("onEnter arg1===> ",hexdump(ptr(args[1])));
			},
			onLeave(retval){
				//  console.log("onLeave arg0===> ",hexdump(ptr(this.arg0)));
				// ArrayBuffer
				var arrayBuffer = ptr(this.arg1).readByteArray(16);
	
				console.log("hookMD5 result->", arrayBuffer);
				// var buffer = Java.array('byte', bytes);
				// var ByteString = Java.use("com.android.okhttp.okio.ByteString");
				// console.log("result->", bytes);
				//console.log("onLeave arg1===> ",);
			}
		})




		//将函数地址定义成一个函数能在js中进行调用#
		let so_addr = Module.findBaseAddress('libxiaowei.so');
		let encrypt_addr = so_addr.add(0x42B0);
		//returnType是函数的返回类型(const char*)
		//它这么定义的:new NativeFunction(address, returnType, argTypes[, abi])
		//参数 address,表示需要构造的函数在内存中的地址,returnType是函数的返回类型(const char*),不过frida中不用这个,需要使用 pointer argTypes 参数
		let encrypt_fun = new NativeFunction(encrypt_addr, 'pointer', ['pointer']);
		let cstring = Memory.allocUtf8String(str);
		let result = encrypt_fun(cstring);

		// function main()
		// {    
		// 	Java.perform(function () 
		// 	{      
			 var aes_addr = Module.findExportByName("libJNIEncrypt.so","AES_128_ECB_PKCS5Padding_Decrypt");      
			 var aes_128 = new NativeFunction(aes_addr , 'pointer', ['pointer', 'pointer']);          
			 var encry_text = Memory.allocUtf8String("9YuQ2dk8CSaCe7DTAmaqAA==");          
			 var key = Memory.allocUtf8String('thisisatestkey==');       
			 console.log("The result is: ",Memory.readCString(aes_128(encry_text ,key )));    
		// 	});
		// }
		//setImmediate(main)
		//将函数地址定义成一个函数能在js中进行调用  end 

		//打印c堆栈 print_c_stack(this.context,"logToSttring");
		//context 这里传入this.context
		//str_arg 这里传入堆栈显示时展示的标签
		function print_c_stack(context, str_tag)
		{
			console.log('');
			console.log("=============================" + str_tag + " Stack strat=======================");       
			console.log(Thread.backtrace(context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n'));
			console.log("=============================" + str_tag + " Stack end  =======================");
		}

		//打印地址的内容
		//而读取const char* 类型的数据需要使用:readCString
		function print_str(addr){
			var base_hello_jni = Module.findBaseAddress("libhello-jni.so");
			if(base_hello_jni){
				// base_hello_jni是一个指针, 指针需要使用.add方法, 直接用运算符是会出错的
				var addr_str = base_hello_jni.add(addr);
				console.log("addr ",addr_str,"  add_str",ptr(addr_str).readCString());
			}
		}

	//打印c++成员
	function hunkc()
	{
		var moduleso = Module.findBaseAddress("libavmdl.so");
			if(moduleso == null  || moduleso < 0)
			{
				setTimeout(hunkc,500);
				return;
			}
			 //logToSttring 日志
			 Interceptor.attach(Module.findExportByName("libavmdl.so" , "_ZN3com2ss3ttm11medialoader17AVMDLReplyTaskLog12logToSttringEv"),{
				onEnter: function(args) {
					//对象打印c++ 成员
					var obj_ptr = ptr(args[0]);
					//Process.pointerSize = 4
					var i=9
					console.log("task_type:", Memory.readInt(  obj_ptr.add(2 * Process.pointerSize)  ))
					console.log("raw_key:", Memory.readCString( Memory.readPointer( obj_ptr.add(9 * Process.pointerSize) ) ))
					
				},
				onLeave:function(retval){
	
					console.log("hook logToSttring ret "+Memory.readCString(retval));
				}
		});
	}
	setTimeout(hunkc,0);

	//frida调用so算法
	//参数 address,表示需要构造的函数在内存中的地址,returnType是函数的返回类型(const char*),不过frida中不用这个,需要使用 pointer,所以构造出来是这样的:
	//var aes_128 = new NativeFunction(aes_addr , 'pointer', ['pointer', 'pointer']);
	//现在基本思路都差不多了,写成的代码是这样的:
	function main(){    
		Java.perform(function () 
		{      
			var aes_addr = Module.findExportByName("libJNIEncrypt.so","AES_128_ECB_PKCS5Padding_Decrypt");      
			var aes_128 = new NativeFunction(aes_addr , 'pointer', ['pointer', 'pointer']);          
			var encry_text = Memory.allocUtf8String("9YuQ2dk8CSaCe7DTAmaqAA==");          
			var key = Memory.allocUtf8String('thisisatestkey==');       
			console.log("The result is: ",Memory.readCString(aes_128(encry_text ,key )));    
		});
		
	}
	setImmediate(main)
	

	//打印hook地址的寄存器
	function inline_hook(){
			var base_hello_jni = Module.findBaseAddress("libhello-jni.so");
			console.log(base_hello_jni);
			if(base_hello_jni){
				console.log("base_hello_jni",base_hello_jni);
				var addr_07320 = base_hello_jni.add(0x07320);
				// inline hook 和 hook函数是一样的
				Interceptor.attach(addr_07320,{
					onEnter:function(args){
						// 
						// 64位: X0-X30, XZR(零寄存器)   要学汇编! 不然没法玩inline hook
						console.log("addr_07320 x13",this.context.x13);
					},
					onLeave:function(retval){}
				})
		
		
			
			}
	}
			
		//********************************hook native end*********************************//

		
         
    });
}


版权声明:本文为pengzhenghui123原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。