Frida Hook
Frida API介绍 : https://frida.re/docs/javascript-api/
Python + Javascript
Python代码作用是控制,写法固定,负责跟frida-server通信,把JS代码传递给fridaserver
Javascript代码作用:Hook操作
Frida 常用模块API:
Java 模块:Hook Java 层的类 方法 相关
Process 模块:处理当前线程相关
Interceptor 模块:操作指针相关,多用来Hook Native 相关
Memory 模块:内存操作相关
Module 模块:处理so相关
改变程序执行流程的一种技术 在函数被调用前,通过HOOK技术,先得到该函数的控制权,实现该函数的逻辑改写
Hook 加密函数
案例1
import frida
import sys
def on_message(message , data):
if message["type"] == "send":
print("[*] {0}".format(message['payload']))
else:
print(message)
jscode = """
function printstack(){
send(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Exception").$new()));
}
// array 转 string
function array2string(array){
var buffer = Java.array('byte', array);
var result = "";
for(var i=0; i<buffer.length; ++i){
result += (String.fromCharCode(buffer[i]));
}
return result;
}
Java.perform(
function(){
var MessageDigest = Java.use('java.security.MessageDigest');
MessageDigest.update.overload('[B').implementation = function(bytesarray){
send('I am here 0:');
send("ori:"+array2string(bytesarray));
printstack();
this.update(bytesarray);
},
MessageDigest.update.overload('byte').implementation = function(bytesarray){
send('I am here 0:');
send("ori:"+array2string(bytesarray));
printstack();
this.update(bytesarray);
},
MessageDigest.update.overload('[B', 'int', 'int').implementation = function(bytesarray){
send('I am here 0:');
send("ori:"+array2string(bytesarray));
printstack();
this.update(bytesarray);
},
MessageDigest.getInstance.overloads[0].implementation = function(algorithm){
send("call -> getInstance for" + algorithm);
printstack();
return this.getInstance.overloads[0].apply(this, arguments);
}
}
);
"""
device = frida.get_remote_device()
# 先通过frida.add_remote_device来找到device,然后spawn方式启动settings,然后attach到上面,并执行frida脚本
pid = device.spawn('com.iCitySuzhou.suzhou001')
process = device.attach(pid)
script = process.create_script(jscode)
script.on('message', on_message)
print('[*] Runing CTF')
script.load()
device.resume(pid)
sys.stdin.read()
然后有几率会打印出加密字符串,可以看到是怎么加密的
下面还可以看到调用的栈
然后用 ApkTool 逆向,找到加密代码
案例2
import frida, sys
def on_message(message, data):
if message['type'] == 'send':
print("[*] {0}".format(message['payload']))
else:
print(message)
test='''
Java.perform(
function(){
console.log('i am coming')
var MainActivity = Java.use('com.example.seccon2015.rock_paper_scissors.MainActivity') // 类名
MainActivity.onClick.implementation = function(v){ // 类名.函数.implementation v 参数
this.onClick(v) // hook 之后要继续执行被 hook 的函数,以免影响正常执行流程
console.log('mmm:'+this.m.value)
console.log('nnn:'+this.n.value)
}
var TT = Java.use('com.example.seccon2015.rock_paper_scissors.MainActivity$1')
TT.run.implementation = function(){
this.this$0.value.m.value = 1 // 匿名类的成员变量名
this.this$0.value.n.value = 2
this.run()
}
}
)
'''
#两种启动方式
#启动方式1
process = frida.get_usb_device(-1).attach('com.example.seccon2015.rock_paper_scissors') # 进程
script = process.create_script(test) # 载入 hook 代码
script.on('message', on_message)
script.load() # 执行
sys.stdin.read() # 让程序不要断掉
#启动方式2 spawn 重启APP 可以hook APP启动阶段
# device = frida.get_usb_device(-1)
# pid = device.spawn(['com.example.seccon2015.rock_paper_scissors'])
# process = device.attach(pid)
# script = process.create_script(test)
# script.on('message', on_message)
# print('[*] Running')
# script.load()
# device.resume(pid)
# sys.stdin.read()
-
attach 进程名 :APP启动后再hook,不能hook app启动阶段
-
spawn :重启APP,适合hook app 启动阶段
淘宝 Hook
import frida, sys
hook_code = """
Java.perform(
function(){
var SwitchConfig = Java.use('mtopsdk.mtop.global.SwitchConfig')
SwitchConfig.isGlobalSpdySwitchOpen.implementation = function(){
// send('SwitchConfig')
return false
}
}
)
"""
def on_message(message, data):
if message['type'] == 'send':
print(f"[*] {message['payload']}")
else:
print(message)
process = frida.get_remote_device().attach('com.taobao.taobao')
script = process.create_script(hook_code)
script.on('message', on_message)
script.load()
sys.stdin.read()