frida native端使用笔记

frida native端使用笔记:

注意:frida hook native端的一个宗旨就是拿到内存地址 有了地址就可以操作
hexdump(ptr(this.arg2).add(Process.pointerSize).readPointer())
ptr(retval).readCString() 
hexdump(args[1], { length: parseInt(args[2]) })
hexdump(ptr(this.arg8).add(Process.pointerSize * 2).readPointer())
ptr(Java.vm.tryGetEnv().getByteArrayElements(args[i])).readCString(parseInt(args[i + 1]))


特别重点:
	1.获取上下文context
		var context = Java.use("android.app.ActivityThread").currentApplication().getApplicationContext();
	2.获取JNIEnv函数
		Java.vm.tryGetEnv().getStringUtfChars() 可以代替hook JNIEnv的函数

打印调用栈:
	//打印调用栈
	console.log('addr_GetStringUTFChars onEnter called from:\n' +
	Thread.backtrace(this.context, Backtracer.FUZZY)
	.map(DebugSymbol.fromAddress).join('\n') + '\n');

重点一:frida hook JNIEnv的函数
	因为JNIEnv的函数都在libart.so文件中 所以枚举libart.so文件 
	var module_libart = Process.findModuleByName("libart.so");
	var symbols = module_libart.enumerateSymbols();     // enumerateSymbols函数的作用就是枚举模块的所有符号
	var addr_GetStringUTFChars = null;
	for (var i = 0; i < symbols.length; i++) {
		var name = symbols[i].name;  // name获取符号的名字
		if (name.indexOf("art") >= 0) {
			if ((name.indexOf("CheckJNI") == -1) && (name.indexOf("JNI") >= 0)) {
				if (name.indexOf("GetStringUTFChars") >= 0) {
					console.log(name);
					addr_GetStringUTFChars = symbols[i].address;  // address获取符号的地址
				} 
			}
		}
	}
	
	// 拿到地址后就可以进行hook
	if (addr_GetStringUTFChars) {
		Interceptor.attach(addr_GetStringUTFChars, {
			onEnter: function (args) {
				
			}, onLeave: function (retval) {
				// retval const char*
				console.log("addr_GetStringUTFChars onLeave:", ptr(retval).readCString(), "\r\n");
			}
		});
	}
	
重点二:frida hook libc.so文件的函数
	function hook_libc() {
		//hook libc的函数
		var strcmp = Module.findExportByName("libc.so", "strcmp");  // 获取libc.so文件中的strcmp函数
		console.log("strcmp:", strcmp);
		Interceptor.attach(strcmp, {
			onEnter: function (args) {
				var str_2 = ptr(args[1]).readCString();
				if (str_2 == "EoPAoY62@ElRD") {
					console.log("strcmp:", ptr(args[0]).readCString(),
						ptr(args[1]).readCString());
				}
			}, onLeave: function (retval) {
			}
		});

	}
	
重点三:frida native 主动写文件的两种方式
	通过frida file api来写文件
		function write_reg_dat() {
			//frida 的api来写文件
			var file = new File("/sdcard/reg.dat", "w");
			file.write("EoPAoY62@ElRD");
			file.flush();
			file.close();
		}
		
	通过把C函数定义为NativeFunction来写文件
	function write_reg_dat2() {
		//把C函数定义为NativeFunction来写文件
		var addr_fopen = Module.findExportByName("libc.so", "fopen");
		var addr_fputs = Module.findExportByName("libc.so", "fputs");
		var addr_fclose = Module.findExportByName("libc.so", "fclose");

		var fopen = new NativeFunction(addr_fopen, "pointer", ["pointer", "pointer"]);
		var fputs = new NativeFunction(addr_fputs, "int", ["pointer", "pointer"]);
		var fclose = new NativeFunction(addr_fclose, "int", ["pointer"]);

		var filename = Memory.allocUtf8String("/sdcard/reg.dat");  // 这里是需要注意的点 需要使用Memory api 来将字符串转为native可用格式
		var open_mode = Memory.allocUtf8String("w+");
		var file = fopen(filename, open_mode);  // 打开文件 返回一个文件指针
		
		var buffer = Memory.allocUtf8String("EoPAoY62@ElRD");
		fputs(buffer, file);  // 写入文件 fputs函数有两个参数 参数1:buffer 为需要写入的值 参数2:file 为需要写入的文件指针
		
		fclose(file);  // 关闭文件
	}
	
	
重点四:frida hook dlopen 一开始就获取加载的so文件
	function hook_dlopen() {
		// 低版本Android系统使用diopen
		var dlopen = Module.findExportByName(null, "dlopen");
		Interceptor.attach(dlopen, {
			onEnter: function (args) {
				this.call_hook = false;
				var so_name = ptr(args[0]).readCString();  // 获取加载的so文件
				if (so_name.indexOf("libhello-jni.so") >= 0) {
					console.log("dlopen:", ptr(args[0]).readCString());
					this.call_hook = true;
				}

			}, onLeave: function (retval) {
				if (this.call_hook) {
					inline_hook();
				}
			}
		});
		// 高版本Android系统使用android_dlopen_ext
		var android_dlopen_ext = Module.findExportByName(null, "android_dlopen_ext");
		Interceptor.attach(android_dlopen_ext, {
			onEnter: function (args) {
				this.call_hook = false;
				var so_name = ptr(args[0]).readCString();  // 获取加载的so文件
				if (so_name.indexOf("libhello-jni.so") >= 0) {
					console.log("android_dlopen_ext:", ptr(args[0]).readCString());
					this.call_hook = true;
				}

			}, onLeave: function (retval) {
				if (this.call_hook) {
					inline_hook();
				}
			}
		});
	}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你好!Frida是一个强大的动态代码注入和调试工具,可以用于hook和修改应用程序的行为。如果你想要hook Native代码,可以使用Frida的JavaScript API来实现。 首先,你需要在设备上安装Frida,并确保设备已经越狱(iOS)或者已经root(Android)。 接下来,你需要编写一个JavaScript脚本来进行hook。在脚本中,你可以使用Frida提供的一些函数来定位和修改Native函数。 例如,下面的代码可以用来hook一个Native函数并修改它的行为: ```javascript // 导入Frida模块 const frida = require('frida'); // 目标进程的名称 const targetProcessName = 'your_target_process_name'; // 要hook的函数名称 const targetFunctionName = 'your_target_function_name'; // Frida attach到目标进程 frida.attach(targetProcessName) .then(session => { // 创建一个脚本对象 const script = session.createScript(` // 找到目标函数 const targetFunction = Module.findExportByName(null, "${targetFunctionName}"); // 替换目标函数的实现 Interceptor.replace(targetFunction, new NativeCallback(() => { // 修改函数的行为,这里可以写你想要的逻辑 console.log("Function ${targetFunctionName} hooked!"); // 调用原始函数 const originalFunction = new NativeFunction(targetFunction, 'void', []); originalFunction.call(); // 可以在这里添加你的自定义代码 }, 'void', [])); }); // 加载并运行脚本 script.load() .then(() => { console.log("Script loaded successfully!"); }) .catch(error => { console.log(`Script error: ${error}`); }); }) .catch(error => { console.log(`Attach error: ${error}`); }); ``` 在上面的代码中,我们首先导入了Frida模块,然后指定了目标进程的名称和要hook的函数名称。然后我们使用`frida.attach()`函数来连接到目标进程,并创建一个脚本对象。在脚本中,我们使用`Module.findExportByName()`函数来找到目标函数,然后使用`Interceptor.replace()`函数替换目标函数的实现。在替换的实现中,我们可以添加一些自定义的逻辑以修改函数的行为。 最后,我们使用`script.load()`函数加载并运行脚本。如果一切顺利,你应该能看到"Script loaded successfully!"的输出。 这只是一个简单的例子,你可以根据你的需求进行更复杂的hook和修改。希望对你有所帮助!如果有任何问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值