当前位置:   article > 正文

【Android安全】Frida安装| Frida Java hook| Frida命令参数_frida android

frida android

Frida安装

objection与Frida版本对应

注意,只有安装frida-tools之后,才能使用frida --version命令

可行的版本组合1(到20220804为止的最新版):

pip install frida==15.2.2
发布时间:2022 07 21

pip install frida-tools==11.0.0

Objection安装的前置条件:
python版本 > 3.4
pip版本 > 9.0

pip install objection==1.11.0


可行的版本组合2:
pip install frida==12.5.9
发布时间:28 May 2019

pip install frida-tools==2.1.1
发布时间:15 Aug 2019


pip install frida==14.2.2
发布时间:20 Dec 2020

pip install frida-tools==9.2.0
发布时间:11 Feb 2021

参考:
https://blog.csdn.net/qq_39799322/article/details/124017424


Frida 代码自动补全

需要安装Frida-gum

先将vscode安装好,
然后将nodejs安装好,
接着就是使用命令,如果不想安装全局那就使用

npm  i  @types/frida-gum
  • 1

如果想随便那个文件夹都有这个提示,那就

npm  i -g @types/frida-gum
  • 1

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


打印backtrace时删除末尾的换行

var bt = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new());
bt = bt.substr(0, bt.length - 1);
send("Backtrace:" + bt);
  • 1
  • 2
  • 3

例如:

var hook_class = Java.use('java.io.FileInputStream');

hook_class.$init.overload('java.io.File').implementation = function (arg1) {
    var bt = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new());
    bt = bt.substr(0, bt.length - 1);

    console.log(" ");
    send('1');
    send("Backtrace:" + bt);
    send('arg1 : ' + arg1);
    send("return");

    return this.$init(arg1);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

byte[]打印为16进制数形式

function byteArrayToHex(byteArray) {
    var ByteString = Java.use("com.android.okhttp.okio.ByteString");
	return ByteString.of(byteArray).hex();
}

  • 1
  • 2
  • 3
  • 4
  • 5

示例代码:

Java.perform(function () {
	var class_name = 'java.io.DataOutputStream';
	var hook_class = Java.use(class_name);
	hook_class.write.overload('[B', 'int', 'int').implementation = function (arg1, arg2, arg3) {
        var bt = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new());
        
        if(bt.indexOf("csns.aH") != -1)
        // if(bt.indexOf("bdpg") != -1) 
        // if (1) 
        {
            send(class_name + ' hooked');
            send("Backtrace:" + bt);
            send('arg1 : ' + arg1);
            send('arg1 : ' + byteArrayToHex(arg1));
            send('arg2 : ' + arg2);
            send('arg3 : ' + arg3);
            send("return");
            return this.write(arg1, arg2, arg3);
        }
        else
        {
            return this.write(arg1, arg2, arg3);
        }
	}
});

function byteArrayToHex(byteArray) {
    var ByteString = Java.use("com.android.okhttp.okio.ByteString");
	return ByteString.of(byteArray).hex();
}
  • 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
[*] arg1 : 10,-103,1,10,32,-2,-11,85
[*] arg1 : 0a99010a20fef555
[*] arg2 : 0
[*] arg3 : 4096
[*] return
  • 1
  • 2
  • 3
  • 4
  • 5

byte[]打印为String形式

 function byteToString(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);
			}
			str += String.fromCharCode(parseInt(store, 2));
			i += bytesLength - 1;
		} else {
			str += String.fromCharCode(_arr[i]);
		}
	}
	return str;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

Frida打印类的成员变量

打印类的a成员变量:

send('this.a : ' + this.a.value);
  • 1

有相同方法名的成员变量

如果有方法和变量重名,则在访问变量时加上_
例如:

var class_name = 'csns';
var hook_class = Java.use(class_name);

hook_class.k.overload('[B', 'int', 'int').implementation = function (arg1,arg2,arg3)
{
    send('this.a : ' + this._a.value);
	return this.k(arg1,arg2,arg3);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

参考:
https://github.com/liyansong2018/FridaHookAndroid

设置成员变量的值

//主动调用静态方法
var clazz = Java.use("类名");
 //设置静态成员变量
clazz.static_var.value = something;
  • 1
  • 2
  • 3
  • 4

包名填写无误,但找不到进程

process = frida.get_usb_device().attach('com.demo.sysintegrity')
script = process.create_script(jscode)
  • 1
  • 2

报错 unable to find process with name ‘xxx’:

frida.ProcessNotFoundError: unable to find process with name 'com.demo.sysintegrity'
  • 1

原因:某些版本的Frida,需要写App名称(或者进程PID),而不能写包名

解决:查看APP名称:frida-ps -Uai
在这里插入图片描述

process = frida.get_usb_device().attach('HMSSafetyDetectSample')
script = process.create_script(jscode)
  • 1
  • 2

frida常用参数

  • -U, connect to USB device

  • -f FILE, --file=FILE spawn FILE

  • -j JAVA_METHOD, --include-java-method=JAVA_METHOD
    include JAVA_METHOD 插桩某个java方法

  • -J JAVA_METHOD, --exclude-java-method=JAVA_METHOD
    exclude JAVA_METHOD 排除某个java方法

  • -F, attach to frontmost application
    例如在iOS设备上打开淘宝app,然后执行frida -UF -l frida-script.js
    frida-script.js中无需指定hook的app
    frida也能自动找到最前台的app进程,并将js代码注入
    在这里插入图片描述

spawn hook

#coding=utf-8

import frida,importlib, sys
importlib.reload(sys)

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

jscode = """
Java.perform(function () {
	
    var class_name ='com.baidu.protect.StubApplication';
	var hook_class = Java.use(class_name);
	hook_class.attachBaseContext.overload('android.content.Context').implementation = function (arg1) {
	var bt = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new());
	send('');
	send(class_name + " hooked");
	console.log("Backtrace:" + bt);

	// send('arg1 : ' + byteToString(arg1));
	// send('arg2 : ' + arg2);
	// send('arg3 : ' + arg3);

	send("return");

	return this.write(arg1);
	}

});

 function byteToString(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);
			}
			str += String.fromCharCode(parseInt(store, 2));
			i += bytesLength - 1;
		} else {
			str += String.fromCharCode(_arr[i]);
		}
	}
	return str;
}

function utf8ByteToUnicodeStr(utf8Bytes){
    var unicodeStr ="";
    for (var pos = 0; pos < utf8Bytes.length;){
        var flag= utf8Bytes[pos];
        var unicode = 0 ;
        if ((flag >>>7) === 0 ) {
            unicodeStr+= String.fromCharCode(utf8Bytes[pos]);
            pos += 1;

        } else if ((flag &0xFC) === 0xFC ){
            unicode = (utf8Bytes[pos] & 0x3) << 30;
            unicode |= (utf8Bytes[pos+1] & 0x3F) << 24;
            unicode |= (utf8Bytes[pos+2] & 0x3F) << 18;
            unicode |= (utf8Bytes[pos+3] & 0x3F) << 12;
            unicode |= (utf8Bytes[pos+4] & 0x3F) << 6;
            unicode |= (utf8Bytes[pos+5] & 0x3F);
            unicodeStr+= String.fromCharCode(unicode) ;
            pos += 6;

        }else if ((flag &0xF8) === 0xF8 ){
            unicode = (utf8Bytes[pos] & 0x7) << 24;
            unicode |= (utf8Bytes[pos+1] & 0x3F) << 18;
            unicode |= (utf8Bytes[pos+2] & 0x3F) << 12;
            unicode |= (utf8Bytes[pos+3] & 0x3F) << 6;
            unicode |= (utf8Bytes[pos+4] & 0x3F);
            unicodeStr+= String.fromCharCode(unicode) ;
            pos += 5;

        } else if ((flag &0xF0) === 0xF0 ){
            unicode = (utf8Bytes[pos] & 0xF) << 18;
            unicode |= (utf8Bytes[pos+1] & 0x3F) << 12;
            unicode |= (utf8Bytes[pos+2] & 0x3F) << 6;
            unicode |= (utf8Bytes[pos+3] & 0x3F);
            unicodeStr+= String.fromCharCode(unicode) ;
            pos += 4;

        } else if ((flag &0xE0) === 0xE0 ){
            unicode = (utf8Bytes[pos] & 0x1F) << 12;;
            unicode |= (utf8Bytes[pos+1] & 0x3F) << 6;
            unicode |= (utf8Bytes[pos+2] & 0x3F);
            unicodeStr+= String.fromCharCode(unicode) ;
            pos += 3;

        } else if ((flag &0xC0) === 0xC0 ){ //110
            unicode = (utf8Bytes[pos] & 0x3F) << 6;
            unicode |= (utf8Bytes[pos+1] & 0x3F);
            unicodeStr+= String.fromCharCode(unicode) ;
            pos += 2;

        } else{
            unicodeStr+= String.fromCharCode(utf8Bytes[pos]);
            pos += 1;
        }
    }
    return unicodeStr;
}

"""

device = frida.get_usb_device()
pid = device.spawn("com.example.test")
device.resume(pid)
# time.sleep(1)
process = device.attach(pid)


script = process.create_script(jscode)
script.on('message', on_message)
print('[*] Running hooking')
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
  • 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
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128

Frida打印Map内容

方法:p0.s.a(java.util.Map) : void
想打印其参数内容

// p0.s.a(java.util.Map) : void
var class_name5 = 'p0.s';
var hook_class5 = Java.use(class_name5);
hook_class5.a.overload('java.util.Map').implementation = function (arg1) {
    var bt = Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new());
    
    // if(bt.indexOf("csns.aH") != -1)
    // if(bt.indexOf("bdpg") != -1) 
    if (1) 
    {
        send('---------------------------------------------------');
        send(class_name5 + ' hooked');
        console.log(class_name5 + " Backtrace:" + bt);
        // send(class_name5 + ' arg1 : ' + arg1);

        var keys = arg1.keySet();
        var iterator = keys.iterator();
        while (iterator.hasNext()) {
          var k = iterator.next();
          console.log(k + " : " + arg1.get(k));
        }
        
        send(class_name5 + " return");
        return this.a(arg1);
    }
    else
    {
        return this.a(arg1);
    }
} 
  • 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

frida-trace

启动com.example.test,hook 所有方法签名带有 “attachBase” 的java方法:

frida-trace -U -f com.example.test --runtime=v8 -j '*!*attachBase*/isu'
  • 1

注意'*!*attachBase*/isu'
s:in their signature
i:ignoring case
u:only searching in user-defined classes
!用来分隔MODULE和OFFSET,例如"gdi32full.dll!ExtTextOutW"
*代表匹配任意内容

Native Hook

参见:https://editor.csdn.net/md/?articleId=129849293


关于so分析中的Memory.readByteArray

不要这么写:

console.log("\\n"+Memory.readByteArray(ptr(0x7751a537ec),128));
  • 1

就是不要在Memory.readByteArray前加"\n",会报错
可以用send
也可以单独将"\n"输出

关于frida中的数据类型

https://bbs.pediy.com/thread-261052-1.htm

一些参考资料

https://zyzling.gitee.io/2020/05/12/Frida%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/

https://onejane.github.io/2021/05/06/frida%E6%B2%99%E7%AE%B1%E8%87%AA%E5%90%90%E5%AE%9E%E7%8E%B0/

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Gausst松鼠会/article/detail/569655
推荐阅读
相关标签
  

闽ICP备14008679号