
本文共 12981 字,大约阅读时间需要 43 分钟。
文章目录
简介
Frida是一款基于python + javascript 的hook框架,适用于android/ios/linux/win/osx等平台。Frida的动态代码执行功能,主要是在它的核心引擎Gum中用C语言来实现的。
- 注入模式:大部分情况下,我们都是附加到一个已经运行到进程,或者是在程序启动到时候进行劫持,然后再在目标进程中运行我们的代码逻辑。这种方式是Frida最常用的使用方式。注入模式的大致实现思路是这样的,带有GumJS的Frida核心引擎被打包成一个动态连接库,然后把这个动态连接库注入到目标进程中,同时提供了一个双向通信通道,这样控制端就可以和注入的模块进行通信了,在不需要的时候,还可以在目标进程中把这个注入的模块给卸载掉。
- 嵌入模式:针对没root过的设备Frida提供了一个动态连接库组件 frida-gadget, 可以把这个动态库集成到程序里面来使用Frida的动态执行功能。一旦集成了gadget,就可以和程序使用Frida进行交互。
- 预加载模式:自动加载Js文件。
环境搭建
- 下载FRIDA
pip install frida
- 下载frida-server
去github上下载frida-server,网址为 ,frida-server 是一个守护进程,通过TCP和Frida核心引擎通信,默认的监听端口是27042
adb devices
- 解压后,使用adb将frida-server放到手机目录/data/local/tmp,然后修改属性为可执行
adb push G:\buuctf\frida-server-14.2.2-android-x86\fs data/local/tmp/frida-server_test
sucd data/local/tmpchmod 777 frida-server_test
- 启动手机上的frida服务器,记得要以root权限启动,
./frida-server_test
- 在windows主机上另外开启一个cmd,输入命令
frida-ps -U
,这行命令是列出手机上所有的进程信息,如果出现进程信息则说明环境搭配成功:
frida-ps -U
疑问点
但是我这里利用脱壳脚本,去连接frida-server
,直接连接不上
求救
脱壳已解决
- 第一个问题:未进行端口转发
adb forward tcp:27042 tcp:27042adb forward tcp:27043 tcp:27043
2.第二个问题:sdk中的adb和夜神中的abd版本不合。。adb server version (31) doesn’t match this client (36)
,以至于每次一使用脚本连接,然后frida-server
就会挂掉,然后就出现了上方的报错,只需要把sdk的adb复制一份放在夜神里面就行喽
- 解码
D:\桌面\apktool.jar d D:\桌面\02.apk -o targetappFolder
- 将apk重新打包
D:\桌面\apktool.jar b -o repackaged.apk targetappFolder/
- 创建keystore(如果没有的话)
keytool -genkey -v -keystore custom.keystore -alias mykeyaliasname -keyalg RSA -keysize 2048 -validity 10000
- 签名
jarsigner -sigalg SHA256withRSA -digestalg SHA1 -keystore custom.keystore -storepass 你的密码 repackaged.apk mykeyaliasname
这个custom.keystore也就是前面所生成的keystore,注意路径问题就行
- 验证
jarsigner -verify repackaged.apk
D:\桌面>D:\桌面\apktool.jar d targetapp.apk -o targetappFolderD:\桌面>D:\桌面\apktool.jar d targetapp.apk -o targetappFolderD:\桌面>D:\桌面\apktool.jar d D:\桌面\02.apk -o targetappFolderD:\桌面>apktool b -o repackaged.apk targetappFolder/'apktool' 不是内部或外部命令,也不是可运行的程序或批处理文件。D:\桌面>apktool b -o repackaged.apk targetappFolder/'apktool' 不是内部或外部命令,也不是可运行的程序或批处理文件。D:\桌面>D:\桌面\apktool.jar apktool b -o repackaged.apk targetappFolder/D:\桌面>D:\桌面\apktool.jar b -o repackaged.apk targetappFolder/D:\桌面>keytool -genkey -v -keystore custom.keystore -alias mykeyaliasname -keyalg RSA -keysize 2048 -validity 10000输入密钥库口令:再次输入新口令:您的名字与姓氏是什么? [Unknown]: 张瑞彪您的组织单位名称是什么? [Unknown]: 江科大您的组织名称是什么? [Unknown]: 江科大您所在的城市或区域名称是什么? [Unknown]: 江科大您所在的省/市/自治区名称是什么? [Unknown]: 江科大该单位的双字母国家/地区代码是什么? [Unknown]: 江科大CN=张瑞彪, OU=江科大, O=江科大, L=江科大, ST=江科大, C=江科大是否正确? [否]: 是正在为以下对象生成 2,048 位RSA密钥对和自签名证书 (SHA256withRSA) (有效期为 10,000 天): CN=张瑞彪, OU=江科大, O=江科大, L=江科大, ST=江科大, C=江科大[正在存储custom.keystore]D:\桌面>jarsigner -sigalg SHA256withRSA -digestalg SHA1 -keystore custom.keystore -storepass 你的密码 repackaged.apk mykeyaliasnamejarsigner 错误: java.lang.RuntimeException: 密钥库加载: keystore password was incorrectD:\桌面>jarsigner -sigalg SHA256withRSA -digestalg SHA1 -keystore custom.keystore -storepass 123456 repackaged.apk mykeyaliasnamejarsigner 错误: java.lang.RuntimeException: 密钥库加载: D:\桌面\custom.keystore (系统找不到指定的文件。)D:\桌面>jarsigner -sigalg SHA256withRSA -digestalg SHA1 -keystore D:\桌面\custom.keystore -storepass 123456 repackaged.apk mykeyaliasnamejar 已签名。警告:签名者证书为自签名证书。为 -digestalg 选项指定的 SHA1 算法被视为存在安全风险。此算法将在未来的更新中被禁用。D:\桌面>zipalign 4 repackaged.apk final.apk'zipalign' 不是内部或外部命令,也不是可运行的程序或批处理文件。D:\桌面>jarsigner -verify repackaged.apkjar 已验证。警告:此 jar 包含其证书链无效的条目。原因: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target此 jar 包含其签名者证书为自签名证书的条目。SHA1 摘要算法被视为存在安全风险。此算法将在未来的更新中被禁用。此 jar 包含的签名没有时间戳。如果没有时间戳, 则在其中任一签名者证书到期 (最早为 2048-08-30) 之后, 用户可能无法验证此 jar。有关详细信息, 请使用 -verbose 和 -certs 选项重新运行。
工具
frida-ps
--version show program's version number and exit -h, --help show this help message and exit -D ID, --device=ID connect to device with the given ID -U, --usb connect to USB device -R, --remote connect to remote frida-server -H HOST, --host=HOST connect to remote frida-server on HOST -a, --applications list only applications -i, --installed include all installed applications
2. frida-trace
动态跟踪
--version show program's version number and exit -h, --help show this help message and exit -D ID, --device=ID connect to device with the given ID -U, --usb connect to USB device -R, --remote connect to remote frida-server -H HOST, --host=HOST connect to remote frida-server on HOST -f FILE, --file=FILE spawn FILE -n NAME, --attach-name=NAME attach to NAME -p PID, --attach-pid=PID attach to PID --debug enable the Node.js compatible script debugger --disable-jit disable JIT -I MODULE, --include-module=MODULE include MODULE -X MODULE, --exclude-module=MODULE exclude MODULE -i FUNCTION, --include=FUNCTION include FUNCTION -x FUNCTION, --exclude=FUNCTION exclude FUNCTION -a MODULE!OFFSET, --add=MODULE!OFFSET add MODULE!OFFSET -T, --include-imports include program's imports -t MODULE, --include-module-imports=MODULE include MODULE imports -m OBJC_METHOD, --include-objc-method=OBJC_METHOD include OBJC_METHOD
示例:
注意:使用frida-trace
时,Android端一定要打开frida-server
,否则就会出现这样
启动手机中的Chrome浏览器
frida-trace -i "open" -U com.android.chrome
可以看到终端中出现:open:Loaded handler at :”/用户名/__handlers__/libc.so/open.js”
frida-trace会生成一个javascript文件,然后Frida会将其注入到进程中,并跟踪特定的调用。生成的open.js脚本将钩住libc.so中的open函数并输出参数.
默认的open.js:
/* * Auto-generated by Frida. Please modify to match the signature of open. * This stub is currently auto-generated from manpages when available. * * For full API reference, see: https://frida.re/docs/javascript-api/ */{ /** * Called synchronously when about to call open. * * @this {object} - Object allowing you to store state for use in onLeave. * @param {function} log - Call this function with a string to be presented to the user. * @param {array} args - Function arguments represented as an array of NativePointer objects. * For example use args[0].readUtf8String() if the first argument is a pointer to a C string encoded as UTF-8. * It is also possible to modify arguments by assigning a NativePointer object to an element of this array. * @param {object} state - Object allowing you to keep state across function calls. * Only one JavaScript function will execute at a time, so do not worry about race-conditions. * However, do not use this to store function arguments across onEnter/onLeave, but instead * use "this" which is an object for keeping state local to an invocation. */ onEnter(log, args, state) { log('open()'); }, /** * Called synchronously when about to return from open. * * See onEnter for details. * * @this {object} - Object allowing you to access state stored in onEnter. * @param {function} log - Call this function with a string to be presented to the user. * @param {NativePointer} retval - Return value represented as a NativePointer object. * @param {object} state - Object allowing you to keep state across function calls. */ onLeave(log, retval, state) { }}
可以修改open.js
进行操作,然后进行终端输出:
/* * Auto-generated by Frida. Please modify to match the signature of open. * This stub is currently auto-generated from manpages when available. * * For full API reference, see: http://www.frida.re/docs/javascript-api/ */ { /** * Called synchronously when about to call open. * * @this {object} - Object allowing you to store state for use in onLeave. * @param {function} log - Call this function with a string to be presented to the user. * @param {array} args - Function arguments represented as an array of NativePointer objects. * For example use Memory.readUtf8String(args[0]) if the first argument is a pointer to a C string encoded as UTF-8. * It is also possible to modify arguments by assigning a NativePointer object to an element of this array. * @param {object} state - Object allowing you to keep state across function calls. * Only one JavaScript function will execute at a time, so do not worry about race-conditions. * However, do not use this to store function arguments across onEnter/ onLeave, but instead * use "this" which is an object for keeping state local to an invocation. */ onEnter: function (log, args, state) { log("open(" + "path=\"" + Memory.readUtf8String(args[0]) + "\"" + ", oflag=" + args[1] + ")"); }, /** * Called synchronously when about to return from open. * * See onEnter for details. * * @this {object} - Object allowing you to access state stored in onEnter. * @param {function} log - Call this function with a string to be presented to the user. * @param {NativePointer} retval - Return value represented as a NativePointer object. * @param {object} state - Object allowing you to keep state across function calls. */ onLeave: function (log, retval, state) { } }
Python绑定
示例:
从Python
注入chrome.js
脚本
注意:从命令行加载脚本然后生成一个命令的进程时,Frida容易崩溃。所以先生成进程,再让Frida注入脚本
#!/usr/bin/python import frida # js jscode= """ console.log("[*] Starting script"); Java.perform(function() { var Activity = Java.use("android.app.Activity"); Activity.onResume.implementation = function () { console.log("[*] onResume() got called!"); this.onResume(); }; }); """ # startup frida and attach to com.android.chrome process on a usb device process = frida.get_remote_device().attach("com.android.chrome") # create a script for frida of jsccode script = process.create_script(jscode) # and load the script script.load()
注意点:
- 记得端口转发
adb forward tcp:27042 tcp:27042adb forward tcp:27043 tcp:27043
否则如下报错
- 别用
frida.get_usb_device().attach()
,改用frida.get_remote_device().attach()
,否则如下报错:
使用
学习Frida的magic,并通过Frida覆盖一个函数。此外,我们还将介绍如何从外部脚本加载代码,而不是将代码键入cli,因为这种方式更方便。首先,将下面的代码保存到一个脚本文件中,例如chrome.js:
1.
Java.perform(function () { var Activity = Java.use("android.app.Activity"); Activity.onResume.implementation = function () { console.log("[*] onResume() got called!"); this.onResume(); };});
上面的代码将会覆盖android.app.Activity类的onResume函数。它会调用Java.use来接收这个类的包装对象,并访问其onResume函数的implementation属性,以提供一个新的实现。在新的函数体中,它将通过this.onResume()调用原始的onResume实现,所以应用程序依然可以继续正常运行。
通过命令行注入:
frida -U -l chrome.js com.android.chrome
一旦触发了onResume——例如切换到另一个应用程序并返回到模拟器中的Chrome——您将收到下列输出:[*] onResume() got called!
如上图所示。
个人误区
但是我使用python绑定进行注入,直接没用。。。搞不懂为什么
#!/usr/bin/pythonimport frida# put your javascript-code herejscode= """console.log("[*] Starting script");Java.perform(function() { var Activity = Java.use("android.app.Activity"); Activity.onResume.implementation = function () { console.log("[*] onResume() got called!"); this.onResume(); };});"""# startup frida and attach to com.android.chrome process on a usb deviceprocess = frida.get_usb_device().attach("com.android.chrome")# create a script for frida of jsccodescript = process.create_script(jscode)# and load the scriptscript.load()
这里呢,是我误会了这行命令行的作用:
frida -U -f com.android.xxxxx —no-pause
它的作用也就是:—no-pause不会中断应用程序,并将生成的进程的任务留给FRIDA,这会打开一个shell,在里边使用Javascript API向Frida写命令,至于用
frida -U -l chrome.js com.android.chrome
它仅仅只是注入js脚本,然后进行阻塞,回传log
python绑定和它并没有任何关系。python绑定的log回传是在Python脚本里面的。
使用命令的时候,建议使用如下这个:
frida -U -f com.android.chrome --no-pause
如果不加--no-pause
的话,那么需要手动启动主线程函数
输入%resume
来进行线程的启动
python绑定解决
这里的话请教了夜影学长,然后他说Python脚本注入的话,显示log是在python里面显示的
显示的东西是由frida里执行的js
发给py的,所以的话,py
要自己负责阻塞,需要input阻塞,在最后加上sys.stdin.read()
,最后也就变成这样:
#!/usr/bin/pythonimport fridaimport sys# put your javascript-code herejscode= """console.log("[*] Starting script");Java.perform(function() { var Activity = Java.use("android.app.Activity"); Activity.onResume.implementation = function () { console.log("[*] onResume() got called!"); this.onResume(); };});"""# startup frida and attach to com.android.chrome process on a usb deviceprocess = frida.get_usb_device().attach("com.android.chrome")# create a script for frida of jsccodescript = process.create_script(jscode)# and load the scriptscript.load()sys.stdin.read()
发表评论
最新留言
关于作者
