2019-09-11 | UNLOCK

2019-9-11-hook技术的实际使用(面对经过混淆的APK)

hook技术的实际使用(面对经过混淆的APK)

hook获取函数及返回值

以hook工具frida举例,hook的难点主要在于逆向代码,需要知道APK包名以及所要hook的类,之后就能使用Javause()来调用这个类。

frida主要能获取java类中的函数的参数值以及返回值,还有在类中定义的变量

举一个函数作为例子

1
2
3
4
5
class d{
public static int dA(int a,int b){
return a+b;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Java.perform(function () {
try{
console.log("star hook!");
var classf = Java.use("com.a.b.c.d");//d是一个class
classf.dA.implementation = function(p1,p2) {
//dA为d这个class中的函数,p1、p2可以随意命名,只要参数的数量与实际函数符合就行
console.log("--------------------------------");
console.log("function a hook");
console.log(JSON.stringify(p1));
console.log(JSON.stringify(p2));
var result=classf.dA(p1,p2);
console.log("--------------------------------");
return result;//return是为了让手机中的程序正常运行,如果没有return,程序会报错
};
}catch(e){//js是弱类型的语言,所以报错信息不需要说明类型,可以直接打印e,打印错误信息是为了方便调试
console.log("ERROR!");
console.log(e);
}
});

像上面这个js程序,就能够打印出dA这个函数的参数以及返回值了。像这里的com.a.b.c.d就是经过混淆后的包名和类名,在实际hook中,以apk中的包名和类名为准,而不是以源码为准。

当然还需要一个python程序来调用这个js脚本。

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

reload(sys)

sys.setdefaultencoding('utf-8')
os.system("adb forward tcp:27042 tcp:27042")
os.system("adb forward tcp:27043 tcp:27043")

output = os.popen('adb shell ps |grep testapk')#taskapk为要hook的apk名字
info = output.read()
output.close()
print(info)
pid=0
for line in info.splitlines():
if line.__contains__("system"):
item = line.split(" ")
for i in item[1:]:
if(len(i)>1):
print(i)
pid=int(i)
break

rdev = frida.get_remote_device()
session = rdev.attach(pid)
with open("test.js") as f://test.js是实际hook手机程序的js脚本文件名
src = f.read()
script = session.create_script(src.decode("utf-8"))

def on_message(message, data):
print(message)

script.on("message",on_message)
script.load()

hook的函数没有运行

在实际hook中,可能hook的是通信过程中的加密或解密函数,像我们这么写的python脚本运行几秒就会结束,在这点时间内如果加密或解密函数没有运行,那就白跑了,什么数据都抓不到。

第一种方法:

在python脚本底部增加

1
raw_input()

这样在python脚本等待输入的时候,只要hook的函数有运行到,那就会打印出参数和返回值

第二种方法:

用RPC远程调用函数,RPC可以不管目标函数是否有调用,从而强行去调用它

在js脚本中可以这么写

1
2
3
4
5
6
rpc.exports = {

myfunc: function(a,b){
Java.perform(function () {
//与上文一样
});

在python中可以在 script.load() 之后添加 script.exports.myfunc(a,b)从而调用这个函数

其它

frida编写js脚本的时候还有一些需要注意的点,比如java中私有函数和开放函数的时候返回值就不一样,前者是 return this.dA(p1,p2); 后者是return classf.dA(p1,p2);

在类中的变量可以直接用class.value来调用,就跟调用函数一样。

遗留问题:目前还是不知道怎么打印出函数内的局部变量

参考

https://www.freebuf.com/articles/system/190565.html 一篇文章带你领悟Frida的精髓(基于安卓8.1)

https://mabin004.github.io/2018/02/08/frida%E5%AF%BC%E5%87%BA%E5%87%BD%E6%95%B0%E4%BB%BB%E6%84%8F%E8%B0%83%E7%94%A8/ frida导出函数任意调用

https://blog.csdn.net/jiangwei0910410003/article/details/80372118 Android逆向之旅—Hook神器家族的Frida工具使用详解

评论加载中