当前位置:   article > 正文

frida框架

frida

简介

Frida是一款基于python + javascript 的hook框架,适用于android/ios/linux/win/osx等平台。Frida的动态代码执行功能,主要是在它的核心引擎Gum中用C语言来实现的。

  1. 注入模式:大部分情况下,我们都是附加到一个已经运行到进程,或者是在程序启动到时候进行劫持,然后再在目标进程中运行我们的代码逻辑。这种方式是Frida最常用的使用方式。注入模式的大致实现思路是这样的,带有GumJS的Frida核心引擎被打包成一个动态连接库,然后把这个动态连接库注入到目标进程中,同时提供了一个双向通信通道,这样控制端就可以和注入的模块进行通信了,在不需要的时候,还可以在目标进程中把这个注入的模块给卸载掉。
  2. 嵌入模式:针对没root过的设备Frida提供了一个动态连接库组件 frida-gadget, 可以把这个动态库集成到程序里面来使用Frida的动态执行功能。一旦集成了gadget,就可以和程序使用Frida进行交互。
  3. 预加载模式:自动加载Js文件。
    在这里插入图片描述

环境搭建

  1. 下载FRIDA
    直接安装frida和frida-tools的最新版本
pip install frida
pip install frida-tools


紧接着查看自己frida版本:
frida --version


然后查看自己的目标机架构版本,但有些可能不能显示出目标机架构版本,所以我直接到客户端:
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

在这里插入图片描述
模拟器版本: 7.0.1.0005-7.1.2700210226
系统版本: Windows10-64bit-8cpu
电脑型号: ASUSTeK COMPUTER INC.-TUF Gaming FX505DT_FX95DT
CPU: AMD Ryzen 7 3750H with Radeon Vega Mobile Gfx
总内存: 15809MB
可用内存: 8615MB
是否开启VT: 开启
渲染模式: OpenGL+
OpenGL版本: 4.6.0 NVIDIA 431.87
OpenGL渲染: GeForce GTX 1650/PCIe/SSE2
是否独显: 开启
显卡1: NVIDIA GeForce GTX 1650
显卡2: AMD Radeon™ RX Vega 10 Graphics
防火墙: 开启(推荐关闭)
安装路径: D:\夜神模拟器\Nox\bin
日志文件路径: C:\Users\ASUS\AppData\Local\Nox
模拟器磁盘大小: 总共 64G, 剩余 61G

在这里插入图片描述
64位程序执行不起来,所以的话frida-server下载32位

  1. 下载frida-server
    去github上下载frida-server,网址为 https://github.com/frida/frida/releasesfrida-server 是一个守护进程,通过TCP和Frida核心引擎通信,默认的监听端口是27042
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

adb devices
  • 1

在这里插入图片描述

  1. 解压后,使用adb将frida-server放到手机目录/data/local/tmp,然后修改属性为可执行
adb push G:\buuctf\frida-server-14.2.2-android-x86\fs  data/local/tmp/frida-server_test						
  • 1

在这里插入图片描述

注意点1:

使用push指令,这里注意点,如果是新安装的夜神模拟器,那么会遇到这个报错:

adb: error: failed to copy 'G:\buuctf\frida-server-14.2.14-android-x86_64\fs_Rui' to 
'data\local\tmp\fs_Rui': couldn't create file: Read-only file system
  • 1
  • 2

在这里插入图片描述
文件系统仅仅可读。

  1. 在夜神模拟器中查看/proc/mounts文件里面的目录的权限,确定是否缺少w权限,如果是的话,那么在proc目录下执行以下代码:
mount -o remount,rw /
  • 1

(一般到这里就可以试试push指令能不能用了,因为报错是文件系统的原因)

  1. 执行以下命令
adb remount
adb root
  • 1
  • 2

注意点2:

linux下的目录(后者是linux目录)都是反斜杠,写正的没用。

错误写法:
adb push  G:\buuctf\frida-server-14.2.14-android-x86_64\fs_Rui data\local\tmp\fs_Rui
  • 1
正确写法:
adb push G:\buuctf\frida-server-14.2.2-android-x86\fs  data/local/tmp/frida-server_test
  • 1
adb shell //进入模拟器
exit//退出模拟器

//以下均为linux命令行 
su
cd data/local/tmp
chmod 777 frida-server_test
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

在这里插入图片描述

  1. 启动手机上的frida服务器,记得要以root权限启动,
./frida-server_test
  • 1

在这里插入图片描述

  1. 在windows主机上另外开启一个cmd,输入命令 frida-ps -U ,这行命令是列出手机上所有的进程信息,如果出现进程信息则说明环境搭配成功:
frida-ps -U
  • 1

在这里插入图片描述

疑问点

但是我这里利用脱壳脚本,去连接frida-server,直接连接不上
在这里插入图片描述
求救

脱壳已解决

  1. 第一个问题:未进行端口转发
adb forward tcp:27042 tcp:27042
adb forward tcp:27043 tcp:27043
  • 1
  • 2
  1. 第二个问题:sdk中的adb和夜神中的abd版本不合。。adb server version (31) doesn’t match this client (36),以至于每次一使用脚本连接,然后frida-server就会挂掉,然后就出现了上方的报错,只需要把sdk的adb复制一份放在夜神里面就行喽

在这里插入图片描述

没有SDK环境的报错

在这里插入图片描述

  1. 解码
D:\桌面\apktool.jar d D:\桌面\02.apk -o targetappFolder
  • 1
  1. 将apk重新打包
D:\桌面\apktool.jar  b -o repackaged.apk targetappFolder/
  • 1
  1. 创建keystore(如果没有的话)
keytool -genkey -v -keystore custom.keystore -alias mykeyaliasname -keyalg RSA -keysize 2048 -validity 10000
  • 1
  1. 签名
jarsigner -sigalg SHA256withRSA -digestalg SHA1 -keystore custom.keystore -storepass 你的密码 repackaged.apk mykeyaliasname
  • 1

这个custom.keystore也就是前面所生成的keystore,注意路径问题就行

  1. 验证
jarsigner -verify repackaged.apk	
  • 1

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

D:\桌面>D:\桌面\apktool.jar d targetapp.apk -o targetappFolder

D:\桌面>D:\桌面\apktool.jar d targetapp.apk -o targetappFolder

D:\桌面>D:\桌面\apktool.jar d D:\桌面\02.apk -o targetappFolder

D:\桌面>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 mykeyaliasname
jarsigner 错误: java.lang.RuntimeException: 密钥库加载: keystore password was incorrect

D:\桌面>jarsigner -sigalg SHA256withRSA -digestalg SHA1 -keystore custom.keystore -storepass 123456 repackaged.apk mykeyaliasname
jarsigner 错误: java.lang.RuntimeException: 密钥库加载: D:\桌面\custom.keystore (系统找不到指定的文件。)

D:\桌面>jarsigner -sigalg SHA256withRSA -digestalg SHA1 -keystore D:\桌面\custom.keystore  -storepass 123456 repackaged.apk mykeyaliasname
jar 已签名。

警告:
签名者证书为自签名证书。
为 -digestalg 选项指定的 SHA1 算法被视为存在安全风险。此算法将在未来的更新中被禁用。

D:\桌面>zipalign 4 repackaged.apk final.apk
'zipalign' 不是内部或外部命令,也不是可运行的程序
或批处理文件。

D:\桌面>jarsigner -verify repackaged.apk

jar 已验证。

警告:
此 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 选项重新运行。

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69

工具

  1. 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						

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

在这里插入图片描述
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												

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

示例:
注意:使用frida-trace时,Android端一定要打开frida-server,否则就会出现这样
启动手机中的Chrome浏览器
在这里插入图片描述
在这里插入图片描述

	frida-trace -i "open" -U com.android.chrome	
  • 1

在这里插入图片描述
在这里插入图片描述

可以看到终端中出现: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) {
  }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39

在这里插入图片描述
在这里插入图片描述
可以修改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) {								
  }														
}													

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42

在这里插入图片描述

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()												

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

注意点:

  1. 记得端口转发
adb forward tcp:27042 tcp:27042
adb forward tcp:27043 tcp:27043
  • 1
  • 2

否则如下报错
在这里插入图片描述

  1. 别用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();
    };
});
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

上面的代码将会覆盖android.app.Activity类的onResume函数。它会调用Java.use来接收这个类的包装对象,并访问其onResume函数的implementation属性,以提供一个新的实现。在新的函数体中,它将通过this.onResume()调用原始的onResume实现,所以应用程序依然可以继续正常运行。

通过命令行注入:

frida -U -l chrome.js com.android.chrome
  • 1

一旦触发了onResume——例如切换到另一个应用程序并返回到模拟器中的Chrome——您将收到下列输出:[*] onResume() got called!
在这里插入图片描述

在这里插入图片描述
如上图所示。

个人误区

但是我使用python绑定进行注入,直接没用。。。搞不懂为什么

#!/usr/bin/python
import frida
# put your javascript-code here
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_usb_device().attach("com.android.chrome")
# create a script for frida of jsccode
script = process.create_script(jscode)
# and load the script
script.load()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

在这里插入图片描述
在这里插入图片描述
这里呢,是我误会了这行命令行的作用:

frida -U -f com.android.xxxxx —no-pause	

  • 1
  • 2

它的作用也就是:—no-pause不会中断应用程序,并将生成的进程的任务留给FRIDA,这会打开一个shell,在里边使用Javascript API向Frida写命令,至于用

frida -U -l chrome.js com.android.chrome
  • 1

它仅仅只是注入js脚本,然后进行阻塞,回传log

python绑定和它并没有任何关系。python绑定的log回传是在Python脚本里面的。

使用命令的时候,建议使用如下这个:

frida -U -f com.android.chrome --no-pause
  • 1

如果不加--no-pause的话,那么需要手动启动主线程函数
在这里插入图片描述
输入%resume来进行线程的启动

python绑定解决

这里的话请教了夜影学长,然后他说Python脚本注入的话,显示log是在python里面显示的
在这里插入图片描述
显示的东西是由frida里执行的js发给py的,所以的话,py要自己负责阻塞,需要input阻塞,在最后加上sys.stdin.read(),最后也就变成这样:

#!/usr/bin/python
import frida
import sys
# put your javascript-code here
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_usb_device().attach("com.android.chrome")
# create a script for frida of jsccode
script = process.create_script(jscode)
# and load the script
script.load()
sys.stdin.read()

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

在这里插入图片描述

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
  

闽ICP备14008679号