0%

2020-05-07-Frida常用Hook安卓APP方式

最近学习了下看雪的安卓培训网课,但是时间比较紧张,才抽空学了几节,课程很不错内容很干(大力推荐),例子动手做了一遍,记录下Frida常用的Hook方法,后续可能会根据内容拆成几篇总结(自己记录备忘用,主要还是靠多练习额。。光看这些没用,而且这里总结的也不够全面。详细的讲解还是推荐去听看雪的课,因版权限制附件先暂不提供下载),先备份下等有空了再把相关知识好好写写,现在根本不是能给人看的东西。。。。

L1: Frida Hook Java

hook_l1.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
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
function hook_java()
{
//hook java static函数
Java.perform(function ()
{
console.log("[*]:" + "L0\n");
var LoginActivity = Java.use("com.example.androiddemo.Activity.LoginActivity");
LoginActivity.a.overload('java.lang.String', 'java.lang.String').implementation = function (arg0){
console.log("L1:",arg0,this.a(arg0,arg0));
return "kanxue";
}
});

Java.perform(function(){
console.log("[*]:" + "L1\n");
var FridaActivity1 = Java.use("com.example.androiddemo.Activity.FridaActivity1");
FridaActivity1.a.implementation = function(arg0){
console.log("L2:",this.a(arg0));
return "R4jSLLLLLLLLLLOrLE7/5B+Z6fsl65yj6BgC6YWz66gO6g2t65Pk6a+P65NK44NNROl0wNOLLLL=";
}
});

//可以通过call_FridaActivity2方式主动调用 也可以通过下面的方式重写check函数 check函数中直接调用或choose调用其他静态或非静态函数均可

Java.perform(function(){
console.log("[*]:" + "L2\n");
var FridaActivity2 = Java.use("com.example.androiddemo.Activity.FridaActivity2");
FridaActivity2.onCheck.implementation = function(){
this.setStatic_bool_var();
Java.choose("com.example.androiddemo.Activity.FridaActivity2" , {
onMatch : function(instance){
instance.setBool_var();
},
onComplete : function(){

}
});
// 不用Java.choose直接调用this.setBool_var也可
//this.setBool_var();
return this.onCheck();
}
});
}
//注意主动调用只有在示例存在时调用才有效,在未进入该activity时调用无效
function call_FridaActivity2(){
Java.perform(function(){
var FridaActivity2 = Java.use("com.example.androiddemo.Activity.FridaActivity2");
FridaActivity2.setStatic_bool_var();
Java.choose("com.example.androiddemo.Activity.FridaActivity2" , {
onMatch : function(instance){
instance.setBool_var();
},
onComplete : function(){

}
});
});
}
//修改变量
function call_FridaActivity3(){
Java.perform(function(){
var FridaActivity3 =Java.use("com.example.androiddemo.Activity.FridaActivity3");
FridaActivity3.static_bool_var.value = true;
console.log(FridaActivity3.static_bool_var.value);
Java.choose("com.example.androiddemo.Activity.FridaActivity3" , {
onMatch : function(instance){
instance.bool_var.value = true;
instance._same_name_bool_var.value = true;
console.log(instance.bool_var.value,instance._same_name_bool_var.value)
},
onComplete : function(){

}
});
});
}
//hook innerclass
function call_FridaActivity4(){
Java.perform(function(){
var FridaActivity4InnerClass =Java.use("com.example.androiddemo.Activity.FridaActivity4$InnerClasses");
console.log(FridaActivity4InnerClass);
FridaActivity4InnerClass.check1.implementation = function(){
return true;
};
FridaActivity4InnerClass.check2.implementation = function(){
return true;
};
FridaActivity4InnerClass.check3.implementation = function(){
return true;
};
FridaActivity4InnerClass.check4.implementation = function(){
return true;
};
FridaActivity4InnerClass.check5.implementation = function(){
return true;
};
FridaActivity4InnerClass.check6.implementation = function(){
return true;
};

});
}


function call_FridaActivity4_hookmulclass(){
Java.perform(function(){
var classname = "com.example.androiddemo.Activity.FridaActivity4$InnerClasses";
var FridaActivity4InnerClass =Java.use(classname);
//console.log(FridaActivity4InnerClass.class.getDeclaredMethods());
var allMethods = FridaActivity4InnerClass.class.getDeclaredMethods();
for(var i = 0; i< allMethods.length ;i++)
{
console.log(allMethods[i]);
var method = allMethods[i];
var methodStr = method.toString();
//字符串处理
var substring = methodStr.substr(methodStr.indexOf(classname) + classname.length + 1);
var methodname = substring.substr(0,substring.indexOf("("));
console.log(methodname);
FridaActivity4InnerClass[methodname].implementation = function (){
console.log("hook mul function\n",this);
return true;
}
}
});
}
//hook动态加载的类
function call_FridaActivity5_hookdyndex()
{
Java.perform(function(){
var FridaActivity5 = Java.use("com.example.androiddemo.Activity.FridaActivity5");
Java.choose("com.example.androiddemo.Activity.FridaActivity5",{
onMatch : function (instance){
console.log(instance.getDynamicDexCheck().$className);
},onComplete: function(){

}
});

Java.enumerateClassLoaders({
onMatch : function(loader){
try {
if(loader.findClass("com.example.androiddemo.Dynamic.DynamicCheck"))
{
console.log(loader);
Java.classFactory.loader = loader;
}
} catch (error) {

}
},
onComplete : function(){

}
});
var DynamicCheck = Java.use("com.example.androiddemo.Dynamic.DynamicCheck");
console.log(DynamicCheck);
DynamicCheck.check.implementation = function (){
console.log("DynamicCheck.check");
return true;
}

});
}


function call_FridaActivity6()
{
Java.perform(function(){
console.log(com.example.androiddemo.Activity.Frida6);
var Frida6Class0 = Java.use("com.example.androiddemo.Activity.Frida6.Frida6Class0");
Frida6Class0.check.implementation = function (){
return true;
};
var Frida6Class1 = Java.use("com.example.androiddemo.Activity.Frida6.Frida6Class1");
Frida6Class1.check.implementation = function (){
return true;
};
var Frida6Class2 = Java.use("com.example.androiddemo.Activity.Frida6.Frida6Class2");
Frida6Class2.check.implementation = function (){
return true;
};
});
}

function call_FridaActivity6_mulclass()
{
Java.perform(function(){
Java.enumerateLoadedClasses({
onMatch: function(name ,handle){
if(name.indexOf("com.example.androiddemo.Activity.Frida6") >= 0){
console.log(name);
var tmp = Java.use(name);
tmp.check.implementation = function(){
console.log("Frida6 Check");
return true;
}
}
},
onComplete : function()
{

}
});
});
}
function main()
{
hook_java();
}

setImmediate(main);

L2: Frida 动态加载DEX

自己编译的Decode.java:

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
package com.example.mytest;

public class Decode {
public static String decode_p(){
String str1 = "";
String p = "V@]EAASB\u0012WZF\u0012e,a$7(&am2(3.\u0003";
str1 = a(p);
return str1;
};
public static String a(String str) {
char[] charArray = str.toCharArray();
for (int i = 0; i < charArray.length / 2; i++) {
char c = charArray[i];
charArray[i] = (char) (charArray[(charArray.length - i) - 1] ^ 'A');
charArray[(charArray.length - i) - 1] = (char) (c ^ '2');
}
return new String(charArray);
}

public static String s2hex(){
String r = "\u0000dslp}oQ\u0000 dks$|M\u0000h +AYQg\u0000P*!M$gQ\u0000";
byte r_bytearray[] = r.getBytes();
String result = "";
for (int i = 0;i < r_bytearray.length ;i++){
result = result + String.format("%02x",r_bytearray[i]);
}
return result;
};
}

hook_l2.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
36
37
38
39
40
41
42
43
// bullhead:/ # input text "codenameduchess"                                      
// bullhead:/ # input text guest
// bullhead:/ # input text "Boris, give me the password"
// bullhead:/ # input text " ay I *P EASE* h ve the assword "
function hook_java()
{
var ddex = Java.openClassFile("/data/local/tmp/ddex.dex");
Java.perform(function(){
ddex.load();
var system_class = Java.use("java.lang.System");
system_class.getProperty.overload('java.lang.String').implementation = function (arg1){
if (arg1 == "user.home") {
console.log("userhome:" + this.getProperty("user.home"));
return "Russia";
}
return this.getProperty("user.home");
}

system_class.getenv.overload('java.lang.String').implementation = function(arg1){
console.log("user:" + this.getenv("USER"));


return "RkxBR3s1N0VSTDFOR180UkNIM1J9Cg==";
};
//hook 构造函数
var a_init = Java.use("com.tlamb96.kgbmessenger.b.a");
a_init.$init.implementation = function(i, str, str2, z){
this.$init(i, str, str2, z);
console.log("a_init_arg:",i, str, str2, z);
};

var decode_class = Java.use("com.example.mytest.Decode");
console.log("decode:"+decode_class.decode_p());
console.log("r2hex:"+decode_class.s2hex());
});
}

function main()
{
hook_java();
}

setImmediate(main)

z3求解,hook_l2.py:

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
from z3 import *
from binascii import *

s = Solver()

r = "0064736c707d6f510020646b73247c4d0068202b4159516700502a214d24675100"
charArray = bytearray(a2b_hex(r))
print charArray

for i2 in range(len(charArray)/2):
c = charArray[i2]
charArray[i2] = charArray[len(charArray) - i2 - 1]
charArray[(len(charArray) - i2) - 1] = c

print b2a_hex(charArray)

x = [BitVec("a%s" % i,32) for i in range(len(charArray))]
for i in range(len(charArray)):
print x[i]
c = charArray[i]
print(i,hex(c))
s.add(((x[i] >> (i % 8)) ^ x[i]) == c)

if s.check() == sat:
m = s.model()
print m
flag = ""
for i in range(len(charArray)):
if m[x[i]] != None:
flag += chr(m[x[i]].as_long().real)
else:
flag += " "
print "|"+flag+"|"

L3: Frida Hook Native

hook_l3.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
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
function hook_java()
{
Java.perform(function(){
var MyApp = Java.use("com.gdufs.xman.MyApp");
MyApp.saveSN.implementation = function(str){
console.log("savesn:",str);
this.saveSN(str);
}

var proc = Java.use("android.os.Process");
proc.killProcess.implementation = function(pid){
console.log("kill pid:",pid);
}
});
}

function hook_native()
{
var base_jni = Module.findBaseAddress("libmyjni.so");
var n2 = Module.findExportByName("libmyjni.so","n2");
console.log("base:",base_jni," n2:",n2);
if (base_jni!=null) {
Interceptor.attach(n2,{
onEnter : function(args){
console.log("n2 onEnter:",args[0],args[1],args[2]);
},
onLeave : function(retval){

}
})
}
}

function hook_libart()
{
//symbol (no checkjni)
var module_libart = Process.findModuleByName("libart.so");
//or?const hooks = Module.load('libc.so'); var Symbol = hooks.enumerateSymbols();
var symbols = module_libart.enumerateSymbols();

var addr_GetStringUTFChars = null;
var addr_FindClass = null;
var addr_GetStaticFieldID = null;
var addr_SetStaticIntField = null;

for(var i = 0; i < symbols.length;i++)
{
if (symbols[i].name.indexOf("art") != -1) {
if (symbols[i].name.indexOf("CheckJNI") == -1) {
if (symbols[i].name.indexOf("GetStringUTFChars") != -1) {
addr_GetStringUTFChars = symbols[i].address;
console.log(symbols[i].name,addr_GetStringUTFChars);
}
if (symbols[i].name.indexOf("art3JNI9FindClass") != -1) {
addr_FindClass = symbols[i].address;
console.log(symbols[i].name,addr_FindClass);
}
if (symbols[i].name.indexOf("GetStaticFieldID") != -1) {
addr_GetStaticFieldID = symbols[i].address;
console.log(symbols[i].name,addr_GetStaticFieldID);
}
if (symbols[i].name.indexOf("SetStaticIntField") != -1) {
addr_SetStaticIntField = symbols[i].address;
console.log(symbols[i].name,addr_SetStaticIntField);
}

}
}
}
//print str

//print so stack : FUZZY and ACCURATE两种方式
if (addr_GetStringUTFChars) {
Interceptor.attach(addr_GetStringUTFChars,{
onEnter : function(args){
// console.log('addr_GetStringUTFChars onEnter called from:\n' +
// Thread.backtrace(this.context, Backtracer.FUZZY)
// .map(DebugSymbol.fromAddress).join('\n') + '\n');
},
onLeave : function(retval){
console.log("GetStringUTFChars:",ptr(retval).readCString())
}
});
}

if (addr_FindClass) {
Interceptor.attach(addr_FindClass,{
onEnter : function(args){
console.log("FindClass Arg:", ptr(args[1]).readCString());
},
onLeave : function(retval){
}
});
}

if (addr_GetStaticFieldID) {
Interceptor.attach(addr_GetStaticFieldID,{
onEnter : function(args){
console.log("GetStaticFieldID Arg3:", ptr(args[2]).readCString(),"Arg4:",ptr(args[3]).readCString());
},
onLeave : function(retval){
}
});
}

if (addr_SetStaticIntField) {
Interceptor.attach(addr_SetStaticIntField,{
onEnter : function(args){
console.log("SetStaticIntField Arg4:",args[3]);
},
onLeave : function(retval){
}
});
}
//hook findclass getstaticfiledid


}

function hook_libc()
{
//strcmp(or hook lib import)
var addr_strcmp = Module.findExportByName("libc.so","strcmp");
Interceptor.attach(addr_strcmp,{
onEnter: function(args){
var str_dst = ptr(args[1]).readCString();
if (str_dst == "EoPAoY62@ElRD") {
console.log("strcmp:", ptr(args[0]).readCString(),
ptr(args[1]).readCString());
}
}
});
}

function writefile()
{
//frida api write file
//frida 的api来写文件
var file = new File("/sdcard/reg.dat", "w");
file.write("EoPAoY62@ElRD");
file.flush();
file.close();
}
function writefile2()
{
//frida native function write file
var addr_fopen = Module.findExportByName("libc.so","fopen");
var addr_fputs = Module.findExportByName("libc.so","fputs");
var addr_fclose = Module.findExportByName("libc.so","fclose");

console.log("addr file api:",addr_fopen,addr_fputs,addr_fclose);

var fopen = new NativeFunction(addr_fopen,"pointer",["pointer","pointer"]);
var fputs = new NativeFunction(addr_fputs,"int",["pointer","pointer"]);
var fclose = new NativeFunction(addr_fclose,"int",["pointer"]);

var filename = Memory.allocUtf8String("/sdcard/reg.dat");
var open_type = Memory.allocUtf8String("w+");
var handle = fopen(filename,open_type);

var buffer = Memory.allocUtf8String("EoPAoY62@ElRD");
var ret = fputs(buffer,handle);
fclose(handle);
}

function main()
{
hook_java();
hook_native();
hook_libart();
hook_libc();
}

setImmediate(main);

z3 求解hook_l3.py:

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
from z3 import *

s = Solver()

r = "EoPAoY62@ElRD"
v13 = "W3_arE_whO_we_ARE"
x = [BitVec("a%s" % i,8) for i in range(len(r))]
v9 = 2016
v11 = 0
for i in range(len(r)):
if i %3 == 1:
v9 = (v9 + 5) % 16
v11 = v13[v9 + 1]
elif i %3 == 2:
v9 = (v9 + 7) % 15
v11 = v13[v9 + 2]
else :
v9 = (v9 + 3) % 13
v11 = v13[v9 + 3]
print r[i],v11
s.add((x[i] ^ ord(v11)) == ord(r[i]))

if s.check() == sat:
m = s.model()
print m
flag = ""
for i in range(len(r)):
if m[x[i]] != None:
flag += chr(m[x[i]].as_long().real)
else:
flag += " "
print "|"+flag+"|"

小结

  1. 打印SO调用栈时选FUZZY(模糊方式)与ACCURATE(准确方式)的区别。
  2. 重写函数中调用非静态函数达到与主动调用choose方式同样的目的。
  3. Frida调用自定义的dex(jar转dex)。
    附件下载:链接