Frida 学习

Frida 学习笔记

环境开发

查看安卓手机的版本

1
adb shell getprop ro.product.cpu.abi

安装Python环境和frida-server

1
2
3
4
5
6
7
8
9
10
pip install frida==15.0.11
pip install frida-tools==10.2.1
pip install objection
wget https://github.com/frida/frida/releases?page=7#:~:text=frida%2Dserver%2D15.0.11%2Dandroid%2Darm64.xz
adb push frida-server-15.0.11 /data/local/tmp/
adb shell
su root
cd /data/local/tmp
chmod +x frida-server-15.0.11
./frida-server-15.0.11 -l 0.0.0.0:12345

frida 基础

一些函数签名

Field Descriptor Java Language Type
Z boolean
B byte
C char
S short
I int
J long
F float
D double
[ array
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
// 修改静态参数和非静态参数
// 如果类中 成员函数 和 成员变量名称相同,则成员变量前添加 _
Java.perform(function () {
console.log("start")
var FridaActivity2 = Java.use("com.example.androiddemo.Activity.FridaActivity2")
//hook静态函数直接调用
FridaActivity2.setStatic_bool_var()
//hook动态函数,找到instance实例,从实例调用函数方法
Java.choose("com.example.androiddemo.Activity.FridaActivity2", {
onMatch: function (instance) {
instance.setBool_var()
},
onComplete: function () {
console.log("end")
}
})
})

// Hook 内部类
var InnerClasses = Java.use("com.example.androiddemo.Activity.FridaActivity4$InnerClasses")

// 修改默认的Java Loader
Java.enumerateClassLoaders({
onMatch: function (loader) {
try {
// 查看当前Loader中是否含有该类
if(loader.findClass("com.example.androiddemo.Dynamic.DynamicCheck")){
console.log("Successfully found loader")
console.log(loader);
// 如果存在则设置为默认的Loader
Java.classFactory.loader = loader ;
}
}
catch(error){
console.log("find error:" + error)
}
},
onComplete: function () {
console.log("end1")
}
})
Java.use("com.example.androiddemo.Dynamic.DynamicCheck").check.implementation = function () {
return true
}

// 遍历所有静态类
Java.enumerateLoadedClasses({
onMatch: function (name, handle){
if (name.indexOf("com.example.androiddemo.Activity.Frida6") != -1) {
console.log("name:" + name + " handle:" + handle)
Java.use(name).check.implementation = function () {
return true
}
}
},
onComplete: function () {
console.log("end")
}
})

// 搜索interface的具体实现类 利用反射得到类里面实现的interface数组,并打印出来。
Java.enumerateLoadedClasses({
onMatch: function (class_name){
if (class_name.indexOf("com.example.androiddemo") < 0) {
return
}
else {
var hook_cls = Java.use(class_name)
var interfaces = hook_cls.class.getInterfaces()
if (interfaces.length > 0) {
console.log(class_name + ": ")
for (var i in interfaces) {
console.log("\t", interfaces[i].toString())
}
}
}
},
onComplete: function () {
console.log("end")
}
})

// Hook 构造函数
Java.use("com.tlamb96.kgbmessenger.b.a").$init.implementation = function (i, str1, str2, z) {
this.$init(i, str1, str2, z)
console.log(i, str1, str2, z)
printStack("com.tlamb96.kgbmessenger.b.a")
}

// 强制转换
Java.cast(Childer, Java.use("com.androidapp.Father"))

// 新建Class
var interfaceClass = Java.use("com.androidapp.InterfaceClazz");
var newClass = Java.registerClass({
name: 'com.androidapp.newClass',
implements: [interfaceClass],
methods: {
flow: function () {
return "OK";
}
}
});
console.log(newClass.$new().flow())

// 枚举类
Java.choose("com.exampleapp.Signal",{
onMatch:function(instance){
console.log("instance.name:",instance.name());
console.log("instance.getDeclaringClass:",instance.getDeclaringClass());
},onComplete:function(){
console.log("search completed!")
}
})

外部调用

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
import frida
import sys
import os


class HookManager:
def __init__(self, arg, Flag):
self.arg = arg
self.js_code = ''
self.JS_FILE = 'jscode/'
self.load_js()
if flag: self.log = open('log/' + arg + '.txt', 'w+', encoding='utf-8')

def load_js(self):
file_names = os.listdir(self.JS_FILE)
for filename in file_names:
print('载入:' + filename)
with open(self.JS_FILE + filename, 'r', encoding='utf-8') as f:
self.js_code += f.read()
print('\n')

def message(self, msg, data):
if msg["type"] == 'send':
print(u"[*] {0}".format(msg['payload']))
if not self.log: return
self.log.write(u"[*] {0}\n".format(msg['payload']))
self.log.flush()
else:
print(msg)

def hooking(self, host):
try:
process = frida.get_device_manager().add_remote_device(host).attach(self.arg)
# one devices use
# process = frida.get_remote_device(host).attach(self.arg)
script = process.create_script(self.js_code)
script.on("message", self.message)
script.load()
sys.stdin.read()
except frida.ServerNotRunningError:
print('没有开启对应app, 或没有开启映射端口')

def close(self):
self.log.close()


if __name__ == '__main__':

bak = "com.example.test"
host_list = [
"192.168.191.2:9898",
]

flag = True if len(host_list) ==1 else flag == False # 只有一台机子的时候默认是调试模式, 多台就是控制模式
hk = HookManager(bak, flag)

for host in host_list:
hk.hooking(host)

hk.close()

frida-tools 方法

1
frida-ps -U # 查看当前存在的进程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
1. 脱离PC使用Frida的几种方式
a) 在手机上使用Termux终端
b) frida-inject
c) frida-gadget.so
优点:可以免root使用frida、frida-gadget比较稳定
缺点:需要重打包app,局限性较大。但是我们可以通过魔改系统,让系统帮我们注入so,免去重打包的繁琐

2. frida-inject的配置、选项和使用
-f、-p、-n、-s、-e

3. 脱离pc后,如何判断hook是否生效
a) 写文件,然后查看文件内容
b) 主动调用Log的方法输出信息,然后使用logcat查看
c) 修改某些方法逻辑

objection

1
2
3
4
5
6
7
8
9
10
11
12
# 启动并注入内存
objection -g xxx.xxx.xxx explore -P /Users/username/.objection/plugins

启动前就hook
objection -N -h <ip> -p <port> -g <进程名> explore --startup-command "android hooking watch class <路径.类名>"

启动前就hook打印参数、返回值、函数调用栈
objection -N -h <ip> -p <port> -g <进程名> explore -s "android hooking watch class_method <路径.类名.方法名> --dump-args --dump-return --dump-backtrace"

如果启动前需要运行多条命令,可以写到一个文件中,使用-c选项
objection -g <进程名> explore -c "路径"

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
# 查看当前加载的module
memory list modules

# 查看库的导出函数
memory list exports libssl.so

# 内存搜索
memory search

# 列出内存中所有的类
android hooking list classes

# 在内存中所有已加载的类的方法中搜索包含特定关键词的方法
android hooking search methods display

# 内存中搜索指定类的所有方法
android hooking list class_methods 类名

# 在内存中所有已加载的类中搜索包含特定关键词的类。
android hooking search classes display

# 搜索堆中的实例
android heap search instances <类名>

# Hook该类的全部方法 打印入参 调用栈 返回
android hooking watch class 类名 --dump-args --dump-backtrace --dump-return
# Hook具体的方法的所有重载方法
android hooking watch class_method 方法名

# 调用实例的方法
android heap execute 实例ID 实例方法

# 直接启动activity或者服务
android intent launch_activity/launch_service activity/服务

# 查看当前可用的activity或者service
android hooking list activities/services

# 内存堆搜索实例
android heap search instances 类名

# 通过实例调用静态和实例方法
android heap execute <handle> <方法名>

# 打印所有 activities (页面)
android hooking list activities

查看与取消hook
jobs list
jobs kill <jobId>

# 关闭ssl校验
android sslpinning disable

# 关闭root检测
android root disable


# 直接生成该类的Hook方法
android hooking generate simple com.android.settings.DisplaySettings
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
!             # 执行操作系统的命令(注意:不是在所连接device上执行命令)
android # 执行指定的 Android 命令
clipboard
monitor
deoptimize # Force the VM to execute everything in the interpreter
heap
evaluate # 在 Java 类中执行 JavaScript 脚本。
execute # 在 Java 类中执行 方法。android heap execute 实例ID 实例方法
print
search
instances # 在当前Android heap上搜索类的实例。android heap search instances 类名
hooking
generate
class # A generic hook manager for Classes
simple # Simple hooks for each Class method
get
current_activity # 获取当前 前景(foregrounded) activity
list
activities # 列出已经登记的 Activities
class_loaders # 列出已经登记的 class loaders
class_methods # 列出一个类上的可用的方法
classes # 列出当前载入的所有类
receivers # 列出已经登记的 BroadcastReceivers
services # 列出已经登记的 Services
search
classes 关键字 # 搜索与名称匹配的Java类
methods 关键字 # 搜索与名称匹配的Java方法
set
return_value # 设置一个方法的返回值。只支持布尔返回
watch
class # Watches for invocations of all methods in a class
class_method # Watches for invocations of a specific class method
intent
launch_activity # 使用Intent启动Activity类
launch_service # Launch a Service class using an Intent
keystore
clear # 清除 Android KeyStore
list # 列出 Android KeyStore 中的条目
watch # 监视 Android KeyStore 的使用
proxy
set # 为应用程序设置代理
root
disable # 试图禁用 root 检测
simulate # 试图模拟已经 root 的环境
shell_exec # 执行shell命令
sslpinning
disable # 尝试禁用 SSL pinning 在各种 Java libraries/classes
ui
FLAG_SECURE # Control FLAG_SECURE of the current Activity
screenshot # 在当前 Activity 进行截图
cd # 改变当前工作目录
commands
clear # 清除当前会话命令的历史记录
history # 列出当前会话命令历史记录
save # 将在此会话中运行的所有惟一命令保存到一个文件中
env # 打印环境信息
evaluate # 执行 JavaScript。( Evaluate JavaScript within the agent )
exit # 退出
file
cat # 打印文件内容
download # 下载一个文件
http
start # Start's an HTTP server in the current working directory
status # Get the status of the HTTP server
stop # Stop's a running HTTP server
upload # 上传一个文件
frida # 获取关于 frida 环境的信息
import # 从完整路径导入 frida 脚本并运行
ios 执行指定的 ios 命令
bundles
cookies
heap
hooking
info
jailbreak
keychain
monitor
nsurlcredentialstorage
nsuserdefaults
pasteboard
plist
sslpinning
ui
jobs
kill # 结束一个任务。这个操作不会写在卸载或者退出当前脚本
list # 列出当前所有的任务
ls # 列出当前工作目录下的文件
memory
dump
all 文件名 # Dump 当前进程的整个内存
from_base 起始地址 字节数 文件 # 将(x)个字节的内存从基址转储到文件
list
exports # List the exports of a module. (列出模块的导出)
modules # List loaded modules in the current process. (列出当前进程中已加载的模块)
search # 搜索模块。用法:memory search "<pattern eg: 41 41 41 ?? 41>" (--string) (--offsets-only)
write # 将原始字节写入内存地址。小心使用!
ping # ping agent
plugin
load # 载入插接
pwd # 打印当前工作目录
reconnect # 重新连接 device
rm # 从 device 上删除文件
sqlite # sqlite 数据库命令
connect # 连接到SQLite数据库文件
ui
alert # 显示警报消息,可选地指定要显示的消息。(目前iOS崩溃)

wallbreaker

1
2
cd ~/.objection/plugins
git clone https://github.com/hluwa/Wallbreaker.git
1
2
3
4
5
6
7
8
9
# 搜索类
plugin wallbreaker classsearch <pattern>

# 搜索对象
plugin wallbreaker objectsearch <classname>

# 根据类名搜索内存中已经被创建的实例,列出 handle 和 toString() 的结果。
plugin wallbreaker classdump <classname> [--fullname]
plugin wallbreaker objectdump <handle> [--fullname]

frida-dexdump

1
pip3 install frida-dexdump
1
2
3
4
5
6
frida-dexdump -FU
frida-dexdump -U -f com.app.pkgname

-o OUTPUT, --output OUTPUT Output folder path, default is './<appname>/'.
-d, --deep-search Enable deep search mode.
--sleep SLEEP Waiting times for start, spawn mode default is 5s.

工具方法

打印调用栈

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

function printStack1(name) {
Java.perform(function () {
var Exception = Java.use("java.lang.Exception");
var ins = Exception.$new("Exception");
var straces = ins.getStackTrace();
if (straces != undefined && straces != null) {
var strace = straces.toString();
var replaceStr = strace.replace(/,/g, "\\n");
console.log("=============================" + name + " Stack strat=======================");
console.log(replaceStr);
console.log("=============================" + name + " Stack end=======================\r\n");
Exception.$dispose();
}
});
}

function printStack2(str_tag) {
var Exception= Java.use("java.lang.Exception");
var ins = Exception.$new("Exception");
var straces = ins.getStackTrace();

if (undefined == straces || null == straces)
{
return;
}

console.log("=============================" + str_tag + " Stack strat=======================");
console.log("");


for (var i = 0; i < straces.length; i++)
{
var str = " " + straces[i].toString();
console.log(str);
}

console.log("");
console.log("=============================" + str_tag + " Stack end=======================\r\n");
Exception.$dispose();
}

byte2String

1
2
3
4
function byteToString(bytes){
const JString = Java.use('java.lang.String');
return JString.$new(bytes);
}

Hook Md5 aes base64 等

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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
//frida hook aes
function hook_cipher(){
var cipher = Java.use("javax.crypto.Cipher");
cipher.doFinal.implementation = function(data, offset, length){
var ret = this.doFinal(data, offset, length);
console.log("doFinal: " + ret);
return ret;
}
}
function hook_aes(){
var aes = Java.use("javax.crypto.spec.SecretKeySpec");
aes.getEncoded.implementation = function(){
var ret = this.getEncoded();
console.log("getEncoded: " + ret);
return ret;
}
}
function hook_base64(){
var base64 = Java.use("android.util.Base64");
base64.encodeToString.implementation = function(data, flags){
var ret = this.encodeToString(data, flags);
console.log("encodeToString: " + ret);
return ret;
}
}
function hook_md5(){
var md5 = Java.use("java.security.MessageDigest");
md5.digest.implementation = function(data){
var ret = this.digest(data);
console.log("digest: " + ret);
return ret;
}
}
function hook_sha1(){
var sha1 = Java.use("java.security.MessageDigest");
sha1.digest.implementation = function(data){
var ret = this.digest(data);
console.log("digest: " + ret);
return ret;
}
}
function hook_sha256(){
var sha256 = Java.use("java.security.MessageDigest");
sha256.digest.implementation = function(data){
var ret = this.digest(data);
console.log("digest: " + ret);
return ret;
}
}
function hook_sha512(){
var sha512 = Java.use("java.security.MessageDigest");
sha512.digest.implementation = function(data){
var ret = this.digest(data);
console.log("digest: " + ret);
return ret;
}
}
function hook_hmac(){
var hmac = Java.use("javax.crypto.Mac");
hmac.doFinal.implementation = function(data){
var ret = this.doFinal(data);
console.log("doFinal: " + ret);
return ret;
}
}
function hook_rsa(){
var rsa = Java.use("java.security.interfaces.RSAPublicKey");
rsa.getEncoded.implementation = function(){
var ret = this.getEncoded();
console.log("getEncoded: " + ret);
return ret;
}
}
function hook_map(){
var map = Java.use("java.util.HashMap");
map.put.implementation = function(key, value){
var ret = this.put(key, value);
console.log("put: " + ret);
return ret;
}

}
function hook_list(){
var list = Java.use("java.util.ArrayList");
list.add.implementation = function(value){
var ret = this.add(value);
console.log("add: " + ret);
return ret;
}
}
function hook_perform_click(){
var click = Java.use("android.view.View");
click.performClick.implementation = function(){
var ret = this.performClick();
console.log("performClick: " + ret);
return ret;
}
}
function hook_set_text(){
var text = Java.use("android.widget.TextView");
text.setText.implementation = function(text){
var ret = this.setText(text);
console.log("setText: " + ret);
return ret;
}
}
function hook_get_text(){
var text = Java.use("android.widget.TextView");
text.getText.implementation = function(){
var ret = this.getText();
console.log("getText: " + ret);
return ret;
}
}
function hook_get_package_name(){
var package_name = Java.use("android.content.Context");
package_name.getPackageName.implementation = function(){
var ret = this.getPackageName();
console.log("getPackageName: " + ret);
return ret;
}
}
//frida byte to string
function hook_byte_to_string(){
var byte = Java.use("[B");
byte.toString.implementation = function(){
var ret = this.toString();
console.log("toString: " + ret);
return ret;
}
}
//frida string to byte
function hook_string_to_byte(){
var string = Java.use("java.lang.String");
string.getBytes.implementation = function(){
var ret = this.getBytes();
console.log("getBytes: " + ret);
return ret;
}
}
function hook_response(){
var response = Java.use("okhttp3.Response");
response.body.implementation = function(){
var ret = this.body();
console.log("body: " + ret);
return ret;
}
}
function hook_request_url(){
var request = Java.use("okhttp3.Request");
request.url.implementation = function(){
var ret = this.url();
console.log("url: " + ret);
return ret;
}
}
function hook_url(){
var url = Java.use("java.net.URL");
url.toString.implementation = function(){
var ret = this.toString();
console.log("toString: " + ret);
return ret;
}
}
function hook_url_connection(){
var url_connection = Java.use("java.net.URLConnection");
url_connection.getInputStream.implementation = function(){
var ret = this.getInputStream();
console.log("getInputStream: " + ret);
return ret;
}
}
function hook_output_stream(){
var output_stream = Java.use("java.io.OutputStream");
output_stream.write.implementation = function(data){
var ret = this.write(data);
console.log("write: " + ret);
return ret;
}
};
function hook_loadLibrary(){
var lib = Java.use("java.lang.System");
lib.loadLibrary.implementation = function(name){
var ret = this.loadLibrary(name);
console.log("loadLibrary: " + ret);
return ret;
}
var linker = Java.use("dalvik.system.DexClassLoader");
linker.loadClass.implementation = function(name){
var ret = this.loadClass(name);
console.log("loadClass: " + ret);
return ret;
}

}
function libart_hook(){
var libart = Java.use("libart.DexFile");
libart.openDexFile.implementation = function(path,name,flags){
var ret = this.openDexFile(path,name,flags);
console.log("openDexFile: " + ret);
return ret;
}
var libart_native = Java.use("libart.DexFile.Native");
libart_native.dexFileOpen.implementation = function(path,name,flags){
var ret = this.dexFileOpen(path,name,flags);
console.log("dexFileOpen: " + ret);
return ret;
}

}

自吐算法

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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
# -*- coding: UTF-8 -*-
import frida, sys

jsCode = """
function showStacks() {
Java.perform(function () {
send(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new()));
});
}
(function () {
var base64EncodeChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',
base64DecodeChars = new Array((-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), (-1), 62, (-1), (-1), (-1), 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, (-1), (-1), (-1), (-1), (-1), (-1), (-1), 0, 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, (-1), (-1), (-1), (-1), (-1), (-1), 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, (-1), (-1), (-1), (-1), (-1));
this.stringToBase64 = function (e) {
var r,a,c,h,o,t;
for (c = e.length, a = 0, r = ''; a < c; ) {
if (h = 255 & e.charCodeAt(a++), a == c) {
r += base64EncodeChars.charAt(h >> 2),
r += base64EncodeChars.charAt((3 & h) << 4),
r += '==';
break
}
if (o = e.charCodeAt(a++), a == c) {
r += base64EncodeChars.charAt(h >> 2),
r += base64EncodeChars.charAt((3 & h) << 4 | (240 & o) >> 4),
r += base64EncodeChars.charAt((15 & o) << 2),
r += '=';
break
}
t = e.charCodeAt(a++),
r += base64EncodeChars.charAt(h >> 2),
r += base64EncodeChars.charAt((3 & h) << 4 | (240 & o) >> 4),
r += base64EncodeChars.charAt((15 & o) << 2 | (192 & t) >> 6),
r += base64EncodeChars.charAt(63 & t)
}
return r
}
this.base64ToString = function (e) {
var r,a,c,h,o,t,d;
for (t = e.length, o = 0, d = ''; o < t; ) {
do
r = base64DecodeChars[255 & e.charCodeAt(o++)];
while (o < t && r == -1);
if (r == -1)
break;
do
a = base64DecodeChars[255 & e.charCodeAt(o++)];
while (o < t && a == -1);
if (a == -1)
break;
d += String.fromCharCode(r << 2 | (48 & a) >> 4);
do {
if (c = 255 & e.charCodeAt(o++), 61 == c)
return d;
c = base64DecodeChars[c]
} while (o < t && c == -1);
if (c == -1)
break;
d += String.fromCharCode((15 & a) << 4 | (60 & c) >> 2);
do {
if (h = 255 & e.charCodeAt(o++), 61 == h)
return d;
h = base64DecodeChars[h]
} while (o < t && h == -1);
if (h == -1)
break;
d += String.fromCharCode((3 & c) << 6 | h)
}
return d
}
this.hexToBase64 = function (str) {
return base64Encode(String.fromCharCode.apply(null, str.replace(/\r|\n/g, "").replace(/([\da-fA-F]{2}) ?/g, "0x$1 ").replace(/ +$/, "").split(" ")));
}
this.base64ToHex = function (str) {
for (var i = 0, bin = base64Decode(str.replace(/[ \r\n]+$/, "")), hex = []; i < bin.length; ++i) {
var tmp = bin.charCodeAt(i).toString(16);
if (tmp.length === 1)
tmp = "0" + tmp;
hex[hex.length] = tmp;
}
return hex.join("");
}
this.hexToBytes = function (str) {
var pos = 0;
var len = str.length;
if (len % 2 != 0) {
return null;
}
len /= 2;
var hexA = new Array();
for (var i = 0; i < len; i++) {
var s = str.substr(pos, 2);
var v = parseInt(s, 16);
hexA.push(v);
pos += 2;
}
return hexA;
}
this.bytesToHex = function (arr) {
var str = '';
var k,j;
for(var i = 0; i<arr.length; i++) {
k = arr[i];
j = k;
if (k < 0) {
j = k + 256;
}
if (j < 16) {
str += "0";
}
str += j.toString(16);
}
return str;
}
this.stringToHex = function (str) {
var val = "";
for (var i = 0; i < str.length; i++) {
if (val == "")
val = str.charCodeAt(i).toString(16);
else
val += str.charCodeAt(i).toString(16);
}
return val
}
this.stringToBytes = function (str) {
var ch, st, re = [];
for (var i = 0; i < str.length; i++ ) {
ch = str.charCodeAt(i);
st = [];
do {
st.push( ch & 0xFF );
ch = ch >> 8;
}
while ( ch );
re = re.concat( st.reverse() );
}
return re;
}
//将byte[]转成String的方法
this.bytesToString = function (arr) {
var str = '';
arr = new Uint8Array(arr);
for(i in arr){
str += String.fromCharCode(arr[i]);
}
return str;
}
this.bytesToBase64=function(e){
var r,a,c,h,o,t;
for (c = e.length, a = 0, r = ''; a < c; ) {
if (h = 255 & e[a++], a == c) {
r += base64EncodeChars.charAt(h >> 2),
r += base64EncodeChars.charAt((3 & h) << 4),
r += '==';
break
}
if (o = e[a++], a == c) {
r += base64EncodeChars.charAt(h >> 2),
r += base64EncodeChars.charAt((3 & h) << 4 | (240 & o) >> 4),
r += base64EncodeChars.charAt((15 & o) << 2),
r += '=';
break
}
t = e[a++],
r += base64EncodeChars.charAt(h >> 2),
r += base64EncodeChars.charAt((3 & h) << 4 | (240 & o) >> 4),
r += base64EncodeChars.charAt((15 & o) << 2 | (192 & t) >> 6),
r += base64EncodeChars.charAt(63 & t)
}
return r
}
this.base64ToBytes=function(e){
var r,a,c,h,o,t,d;
for (t = e.length, o = 0, d = []; o < t; ) {
do
r = base64DecodeChars[255 & e.charCodeAt(o++)];
while (o < t && r == -1);
if (r == -1)
break;
do
a = base64DecodeChars[255 & e.charCodeAt(o++)];
while (o < t && a == -1);
if (a == -1)
break;
d.push(r << 2 | (48 & a) >> 4);
do {
if (c = 255 & e.charCodeAt(o++), 61 == c)
return d;
c = base64DecodeChars[c]
} while (o < t && c == -1);
if (c == -1)
break;
d.push((15 & a) << 4 | (60 & c) >> 2);
do {
if (h = 255 & e.charCodeAt(o++), 61 == h)
return d;
h = base64DecodeChars[h]
} while (o < t && h == -1);
if (h == -1)
break;
d.push((3 & c) << 6 | h)
}
return d
}
})();
//stringToBase64 stringToHex stringToBytes
//base64ToString base64ToHex base64ToBytes
// hexToBase64 hexToBytes
// bytesToBase64 bytesToHex bytesToString
Java.perform(function () {
var secretKeySpec = Java.use('javax.crypto.spec.SecretKeySpec');
secretKeySpec.$init.overload('[B','java.lang.String').implementation = function (a,b) {
showStacks();
var result = this.$init(a, b);
send("======================================");
send("算法名:" + b + "|Dec密钥:" + bytesToString(a));
send("算法名:" + b + "|Hex密钥:" + bytesToHex(a));
return result;
}
var mac = Java.use('javax.crypto.Mac');
mac.getInstance.overload('java.lang.String').implementation = function (a) {
showStacks();
var result = this.getInstance(a);
send("======================================");
send("算法名:" + a);
return result;
}
mac.update.overload('[B').implementation = function (a) {
showStacks();
this.update(a);
send("======================================");
send("update:" + bytesToString(a))
}
mac.update.overload('[B','int','int').implementation = function (a,b,c) {
showStacks();
this.update(a,b,c)
send("======================================");
send("update:" + bytesToString(a) + "|" + b + "|" + c);
}
mac.doFinal.overload().implementation = function () {
showStacks();
var result = this.doFinal();
send("======================================");
send("doFinal结果:" + bytesToHex(result));
send("doFinal结果:" + bytesToBase64(result));
return result;
}
mac.doFinal.overload('[B').implementation = function (a) {
showStacks();
var result = this.doFinal(a);
send("======================================");
send("doFinal参数:" + bytesToString(a));
send("doFinal结果:" + bytesToHex(result));
send("doFinal结果:" + bytesToBase64(result));
return result;
}
var md = Java.use('java.security.MessageDigest');
md.getInstance.overload('java.lang.String','java.lang.String').implementation = function (a,b) {
showStacks();
send("======================================");
send("算法名:" + a);
return this.getInstance(a, b);
}
md.getInstance.overload('java.lang.String').implementation = function (a) {
showStacks();
send("======================================");
send("算法名:" + a);
return this.getInstance(a);
}
md.update.overload('[B').implementation = function (a) {
showStacks();
send("======================================");
send("update:" + bytesToString(a))
return this.update(a);
}
md.update.overload('[B','int','int').implementation = function (a,b,c) {
showStacks();
send("======================================");
send("update:" + bytesToString(a) + "|" + b + "|" + c);
return this.update(a,b,c);
}
md.digest.overload().implementation = function () {
showStacks();
send("======================================");
var result = this.digest();
send("digest结果:" + bytesToHex(result));
send("digest结果:" + bytesToBase64(result));
return result;
}
md.digest.overload('[B').implementation = function (a) {
showStacks();
send("======================================");
send("digest参数:" + bytesToString(a));
var result = this.digest(a);
send("digest结果:" + bytesToHex(result));
send("digest结果:" + bytesToBase64(result));
return result;
}
var ivParameterSpec = Java.use('javax.crypto.spec.IvParameterSpec');
ivParameterSpec.$init.overload('[B').implementation = function (a) {
showStacks();
var result = this.$init(a);
send("======================================");
send("iv向量:" + bytesToString(a));
send("iv向量:" + bytesToHex(a));
return result;
}
var cipher = Java.use('javax.crypto.Cipher');
cipher.getInstance.overload('java.lang.String').implementation = function (a) {
showStacks();
var result = this.getInstance(a);
send("======================================");
send("模式填充:" + a);
return result;
}
cipher.update.overload('[B').implementation = function (a) {
showStacks();
var result = this.update(a);
send("======================================");
send("update:" + bytesToString(a));
return result;
}
cipher.update.overload('[B','int','int').implementation = function (a,b,c) {
showStacks();
var result = this.update(a,b,c);
send("======================================");
send("update:" + bytesToString(a) + "|" + b + "|" + c);
return result;
}
cipher.doFinal.overload().implementation = function () {
showStacks();
var result = this.doFinal();
send("======================================");
send("doFinal结果:" + bytesToHex(result));
send("doFinal结果:" + bytesToBase64(result));
return result;
}
cipher.doFinal.overload('[B').implementation = function (a) {
showStacks();
var result = this.doFinal(a);
send("======================================");
send("doFinal参数:" + bytesToString(a));
send("doFinal结果:" + bytesToHex(result));
send("doFinal结果:" + bytesToBase64(result));
return result;
}
var x509EncodedKeySpec = Java.use('java.security.spec.X509EncodedKeySpec');
x509EncodedKeySpec.$init.overload('[B').implementation = function (a) {
showStacks();
var result = this.$init(a);
send("======================================");
send("RSA密钥:" + bytesToBase64(a));
return result;
}
var rSAPublicKeySpec = Java.use('java.security.spec.RSAPublicKeySpec');
rSAPublicKeySpec.$init.overload('java.math.BigInteger','java.math.BigInteger').implementation = function (a,b) {
showStacks();
var result = this.$init(a,b);
send("======================================");
//send("RSA密钥:" + bytesToBase64(a));
send("RSA密钥N:" + a.toString(16));
send("RSA密钥E:" + b.toString(16));
return result;
}
});
""";

fw = open(sys.argv[1],'w+',encoding='utf-8')

def message(message, data):
if message["type"] == 'send':
print(u"[*] {0}".format(message['payload']))
fw.write(u"[*] {0}\n".format(message['payload']))
fw.flush()
else:
print(message)

process = frida.get_remote_device().attach(sys.argv[1])
script= process.create_script(jsCode)
script.on("message", message)
script.load()
sys.stdin.read()

常见算法hook

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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
Java.perform(function () {
var secretKeySpec = Java.use('javax.crypto.spec.SecretKeySpec');
secretKeySpec.$init.overload('[B', 'java.lang.String').implementation = function (a, b) {
showStacks();
var result = this.$init(a, b);
send("======================================");
send("算法名:" + b + "|Dec密钥:" + bytesToString(a));
send("算法名:" + b + "|Hex密钥:" + bytesToHex(a));
return result;
}
var mac = Java.use('javax.crypto.Mac');
mac.getInstance.overload('java.lang.String').implementation = function (a) {
showStacks();
var result = this.getInstance(a);
send("======================================");
send("算法名:" + a);
return result;
}
mac.update.overload('[B').implementation = function (a) {
showStacks();
this.update(a);
send("======================================");
send("update:" + bytesToString(a))
}
mac.update.overload('[B', 'int', 'int').implementation = function (a, b, c) {
showStacks();
this.update(a, b, c)
send("======================================");
send("update:" + bytesToString(a) + "|" + b + "|" + c);
}
mac.doFinal.overload().implementation = function () {
showStacks();
var result = this.doFinal();
send("======================================");
send("doFinal结果:" + bytesToHex(result));
send("doFinal结果:" + bytesToBase64(result));
return result;
}
mac.doFinal.overload('[B').implementation = function (a) {
showStacks();
var result = this.doFinal(a);
send("======================================");
send("doFinal参数:" + bytesToString(a));
send("doFinal结果:" + bytesToHex(result));
send("doFinal结果:" + bytesToBase64(result));
return result;
}
var md = Java.use('java.security.MessageDigest');
md.getInstance.overload('java.lang.String', 'java.lang.String').implementation = function (a, b) {
showStacks();
send("======================================");
send("算法名:" + a);
return this.getInstance(a, b);
}
md.getInstance.overload('java.lang.String').implementation = function (a) {
showStacks();
send("======================================");
send("算法名:" + a);
return this.getInstance(a);
}
md.update.overload('[B').implementation = function (a) {
showStacks();
send("======================================");
send("update:" + bytesToString(a))
return this.update(a);
}
md.update.overload('[B', 'int', 'int').implementation = function (a, b, c) {
showStacks();
send("======================================");
send("update:" + bytesToString(a) + "|" + b + "|" + c);
return this.update(a, b, c);
}
md.digest.overload().implementation = function () {
showStacks();
send("======================================");
var result = this.digest();
send("digest结果:" + bytesToHex(result));
send("digest结果:" + bytesToBase64(result));
return result;
}
md.digest.overload('[B').implementation = function (a) {
showStacks();
send("======================================");
send("digest参数:" + bytesToString(a));
var result = this.digest(a);
send("digest结果:" + bytesToHex(result));
send("digest结果:" + bytesToBase64(result));
return result;
}
var ivParameterSpec = Java.use('javax.crypto.spec.IvParameterSpec');
ivParameterSpec.$init.overload('[B').implementation = function (a) {
showStacks();
var result = this.$init(a);
send("======================================");
send("iv向量:" + bytesToString(a));
send("iv向量:" + bytesToHex(a));
return result;
}
var cipher = Java.use('javax.crypto.Cipher');
cipher.getInstance.overload('java.lang.String').implementation = function (a) {
showStacks();
var result = this.getInstance(a);
send("======================================");
send("模式填充:" + a);
return result;
}
cipher.update.overload('[B').implementation = function (a) {
showStacks();
var result = this.update(a);
send("======================================");
send("update:" + bytesToString(a));
return result;
}
cipher.update.overload('[B', 'int', 'int').implementation = function (a, b, c) {
showStacks();
var result = this.update(a, b, c);
send("======================================");
send("update:" + bytesToString(a) + "|" + b + "|" + c);
return result;
}
cipher.doFinal.overload().implementation = function () {
showStacks();
var result = this.doFinal();
send("======================================");
send("doFinal结果:" + bytesToHex(result));
send("doFinal结果:" + bytesToBase64(result));
return result;
}
cipher.doFinal.overload('[B').implementation = function (a) {
showStacks();
var result = this.doFinal(a);
send("======================================");
send("doFinal参数:" + bytesToString(a));
send("doFinal结果:" + bytesToHex(result));
send("doFinal结果:" + bytesToBase64(result));
return result;
}
var x509EncodedKeySpec = Java.use('java.security.spec.X509EncodedKeySpec');
x509EncodedKeySpec.$init.overload('[B').implementation = function (a) {
showStacks();
var result = this.$init(a);
send("======================================");
send("RSA密钥:" + bytesToBase64(a));
return result;
}
var rSAPublicKeySpec = Java.use('java.security.spec.RSAPublicKeySpec');
rSAPublicKeySpec.$init.overload('java.math.BigInteger', 'java.math.BigInteger').implementation = function (a, b) {
showStacks();
var result = this.$init(a, b);
send("======================================");
//send("RSA密钥:" + bytesToBase64(a));
send("RSA密钥N:" + a.toString(16));
send("RSA密钥E:" + b.toString(16));
return result;
}
});