Frida 环境部署及使用

Frida 环境部署

Frida 是一款基于 Python + JavaScriptHook 与调试框架

Frida大致原理是手机端安装一个server程序,然后把手机端的端口转到PC端,PC端写python脚本进行通信,而python脚本中需要hook的代码采用javascript语言。

官方文档:https://frida.re/docs/javascript-api/#java-cast

安装:

pip install frida
pip install frida-tools

服务端配置

https://github.com/frida/frida/releases下载对应平台的服务端

frida-server-12.11.12-android-arm64.xz

然后解压,移动到Android设备

adb

下载地址

https://developer.android.google.cn/studio/releases/platform-tools

然后配置环境变量

adb push frida-server-12.5.7-android-x86 /data/local/tmp/

adb shell
cd  /data/local/tmp/
chmod 777 frida-server-12.11.12-android-arm64

然后启动运行,转发端口

./frida-server-12.11.12-android-arm64

adb forward tcp:27042 tcp:27042

基本运行

查看连接到的设备

frida-ls-devices

Id                Type    Name
----------------  ------  ------------
local             local   Local System
ENU7N15A30003435  usb     Nexus 6P
socket            remote  Local Socket

查看设备上的进程信息

frida-ps -U

关闭防火墙

adb shell
su
setenforce 0

使用

import frida
import sys

def on_message(message , data):
    if message["type"] == "send":
        print("[*] {0}".format(message['payload']))
    else:
        print(message)



jscode_signature = """
Java.perform(function(){
    var TestSig = Java.use('com.yaotong.crackme.MainActivity');
    
    TestSig.securityCheck.implementation = function(str){
    send('I am here');
    return true;
    };
});
"""

# 查找USB设备并附加到目标进程
process = frida.get_remote_device().attach('com.yaotong.crackme')
# 在目标进程里创建脚本
script = process.create_script(jscode_signature)
# 注册消息回调
script.on("message", on_message)
print('[*] Runing CTF')
# 加载创建好的javascript脚本
script.load()
# 读取系统输入
sys.stdin.read()

载入类

Java.use方法用于声明一个Java类,在用一个Java类之前首先得声明。比如声明一个String类,要指定完整的类名:

var StringClass=Java.use("java.lang.String");

修改函数的实现

修改一个函数的实现是逆向调试中相当有用的。修改一个函数的实现后,如果这个函数被调用,我们的Javascript代码里的函数实现也会被调用

函数参数类型表示

不同的参数类型都有自己的表示方法

  1. 对于基本类型,直接用它在Java中的表示方法就可以了,不用改变,例如:
  • int
  • short
  • char
  • byte
  • boolean
  • float
  • double
  • long
  1. 基本类型数组,用左中括号接上基本类型的缩写

基本类型缩写表示表:

基本类型 缩写
boolean Z
byte B
char C
double D
float F
int I
long J
short S

例如:int[]类型,在重载时要写成[I

  1. 任意类,直接写完整类名即可

例如:java.lang.String

  1. 对象数组,用左中括号接上完整类名再接上分号

例如:[java.lang.String;

带参数的构造函数

修改参数为byte[]类型的构造函数的实现

ClassName.$init.overload('[B').implementation=function(param){
    //do something
}

注:ClassName是使用Java.use定义的类;param是可以在函数体中访问的参数

修改多参数的构造函数的实现

ClassName.$init.overload('[B','int','int').implementation=function(param1,param2,param3){
    //do something
}

无参数构造函数

ClassName.$init.overload().implementation=function(){
    //do something
}

调用原构造函数

ClassName.$init.overload().implementation=function(){
    //do something
    this.$init();
    //do something
}

注意:当构造函数(函数)有多种重载形式,比如一个类中有两个形式的func:void func()void func(int),要加上overload来对函数进行重载,否则可以省略overload

一般函数

修改函数名为func,参数为byte[]类型的函数的实现

ClassName.func.overload('[B').implementation=function(param){
    //do something
    //return ...
}

无参数的函数

ClassName.func.overload().implementation=function(){
    //do something
}

注: 在修改函数实现时,如果原函数有返回值,那么我们在实现时也要返回合适的值

ClassName.func.overload().implementation=function(){
    //do something
    return this.func();
}

调用函数

和Java一样,创建类实例就是调用构造函数,而在这里用$new表示一个构造函数。

var ClassName=Java.use("com.luoye.test.ClassName");
var instance = ClassName.$new();

实例化以后调用其他函数

var ClassName=Java.use("com.luoye.test.ClassName");
var instance = ClassName.$new();
instance.func();

类型转换

Java.cast方法来对一个对象进行类型转换,如将variable转换成java.lang.String

var StringClass=Java.use("java.lang.String");
var NewTypeClass=Java.cast(variable,StringClass);

Java.available字段

这个字段标记Java虚拟机(例如: Dalvik 或者 ART)是否已加载, 操作Java任何东西的之前,要确认这个值是否为true

Java.perform方法

Java.perform(fn)在Javascript代码成功被附加到目标进程时调用,我们核心的代码要在里面写。格式:

Java.perform(function(){
//do something...
});
原文地址:https://www.cnblogs.com/kai-/p/13622623.html