白乐天

道阻且长,行则将至。

hook脚本大全

Java层

框架

1
2
3
4
5
function hook(){
Java.perform(function(){

})
}

PrintMap

1
2
3
4
5
6
7
8
9
function printMap(map){
let key = map.keySet();
let it = key.iterator();
while(it.hasNext()){
let keystr = it.next();
let valuestr = map.get(keystr);
console.log("key:",keystr,"| value:",valuestr);
}
}

PrintTreeMap

1
2
3
4
5
function printMap(map){
var TreeMap = Java.use("java.util.TreeMap");
var cast_map = Java.cast(map,TreeMap);
console.log("map:",cast_map.toString());
}

PrintHashMap

1
2
3
4
5
function printHashMap(map){
let hashMap = Java.use("java.util.HashMap");
let cast_map = Java.cast(map,hashMap);
console.log(cast_map.toString());
}

PrintSet

1
2
3
4
5
6
function printSet(set){
console.log(set.size())
while(set.hasNext){
console.log("set:",set.next())
}
}

打印调用栈

Java

1
2
3
4
5
6
7
8
function showStacks() {
console.log(
Java.use("android.util.Log")
.getStackTraceString(
Java.use("java.lang.Throwable").$new()
)
);
}
1
console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function printStack(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();
}
});
}

native

1
2
console.log(`native stack:`);
console.log(Thread.backtrace(this.context, Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n') + "\n");

消息摘要算法通杀

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
Java.perform(function () {

function showStacks() {
console.log(
Java.use("android.util.Log")
.getStackTraceString(
Java.use("java.lang.Throwable").$new()
)
);
}

var ByteString = Java.use("com.android.okhttp.okio.ByteString");
function toBase64(tag, data) {
console.log(tag + " Base64: " + ByteString.of(data).base64());
}
function toHex(tag, data) {
console.log(tag + " Hex: " + ByteString.of(data).hex());
}
function toUtf8(tag, data) {
console.log(tag + " Utf8: " + ByteString.of(data).utf8());
}


var messageDigest = Java.use("java.security.MessageDigest");
messageDigest.update.overload('byte').implementation = function (data) {
console.log("MessageDigest.update('byte') is called!");
showStacks();
return this.update(data);
}
messageDigest.update.overload('java.nio.ByteBuffer').implementation = function (data) {
console.log("MessageDigest.update('java.nio.ByteBuffer') is called!");
showStacks();
return this.update(data);
}
messageDigest.update.overload('[B').implementation = function (data) {
console.log("MessageDigest.update('[B') is called!");
showStacks();
var algorithm = this.getAlgorithm();
var tag = algorithm + " update data";
toUtf8(tag, data);
toHex(tag, data);
toBase64(tag, data);
console.log("=======================================================");
return this.update(data);
}
messageDigest.update.overload('[B', 'int', 'int').implementation = function (data, start, length) {
console.log("MessageDigest.update('[B', 'int', 'int') is called!");
showStacks();
var algorithm = this.getAlgorithm();
var tag = algorithm + " update data";
toUtf8(tag, data);
toHex(tag, data);
toBase64(tag, data);
console.log("=======================================================", start, length);
return this.update(data, start, length);
}

messageDigest.digest.overload().implementation = function () {
console.log("MessageDigest.digest() is called!");
showStacks();
var result = this.digest();
var algorithm = this.getAlgorithm();
var tag = algorithm + " digest result";
toUtf8(tag, result);
toHex(tag, result);
toBase64(tag, result);
console.log("=======================================================");
return result;
}
messageDigest.digest.overload('[B').implementation = function (data) {
console.log("MessageDigest.digest('[B') is called!");
showStacks();
var algorithm = this.getAlgorithm();
var tag = algorithm + " digest data";
toUtf8(tag, data);
toHex(tag, data);
toBase64(tag, data);
var result = this.digest(data);
var tags = algorithm + " digest result";
toUtf8(tag, result);
toHex(tags, result);
toBase64(tags, result);
console.log("=======================================================");
return result;
}
messageDigest.digest.overload('[B', 'int', 'int').implementation = function (data, start, length) {
console.log("MessageDigest.digest('[B', 'int', 'int') is called!");
showStacks();
var algorithm = this.getAlgorithm();
var tag = algorithm + " digest data";
toUtf8(tag, data);
toHex(tag, data);
toBase64(tag, data);
var result = this.digest(data, start, length);
var tags = algorithm + " digest result";
toHex(tags, result);
toBase64(tags, result);
console.log("=======================================================", start, length);
return result;
}

var mac = Java.use("javax.crypto.Mac");
mac.init.overload('java.security.Key', 'java.security.spec.AlgorithmParameterSpec').implementation = function (key, AlgorithmParameterSpec) {
console.log("Mac.init('java.security.Key', 'java.security.spec.AlgorithmParameterSpec') is called!");
return this.init(key, AlgorithmParameterSpec);
}
mac.init.overload('java.security.Key').implementation = function (key) {
console.log("Mac.init('java.security.Key') is called!");
var algorithm = this.getAlgorithm();
var tag = algorithm + " init Key";
var keyBytes = key.getEncoded();
toUtf8(tag, keyBytes);
toHex(tag, keyBytes);
toBase64(tag, keyBytes);
console.log("=======================================================");
return this.init(key);
}
mac.update.overload('byte').implementation = function (data) {
console.log("Mac.update('byte') is called!");
return this.update(data);
}
mac.update.overload('java.nio.ByteBuffer').implementation = function (data) {
console.log("Mac.update('java.nio.ByteBuffer') is called!");
return this.update(data);
}
mac.update.overload('[B').implementation = function (data) {
console.log("Mac.update('[B') is called!");
var algorithm = this.getAlgorithm();
var tag = algorithm + " update data";
toUtf8(tag, data);
toHex(tag, data);
toBase64(tag, data);
console.log("=======================================================");
return this.update(data);
}
mac.update.overload('[B', 'int', 'int').implementation = function (data, start, length) {
console.log("Mac.update('[B', 'int', 'int') is called!");
var algorithm = this.getAlgorithm();
var tag = algorithm + " update data";
toUtf8(tag, data);
toHex(tag, data);
toBase64(tag, data);
console.log("=======================================================", start, length);
return this.update(data, start, length);
}
mac.doFinal.overload().implementation = function () {
console.log("Mac.doFinal() is called!");
var result = this.doFinal();
var algorithm = this.getAlgorithm();
var tag = algorithm + " doFinal result";
toUtf8(tag, result);
toHex(tag, result);
toBase64(tag, result);
console.log("=======================================================");
return result;
}
mac.doFinal.overload('[B').implementation = function (data) {
console.log("Mac.doFinal.overload('[B') is called!");
return this.doFinal(data);
}
mac.doFinal.overload('[B', 'int').implementation = function (output, outOffset) {
console.log("Mac.doFinal.overload('[B', 'int') is called!");
return this.doFinal(output, outOffset);
}
});

获取context

1
2
3
4
5
function get_context(){
let current_application = Java.use('android.app.ActivityThread').currentApplication();
let context = current_application.getApplicationContext();
return context;
}

hook StringBuilder_toString()

1
2
3
4
5
6
7
8
9
10
function hook_StringBuilder_toString(){
Java.perform(function(){
let StringBuilder = Java.use("java.lang.StringBuilder");
StringBuilder.toString.implementation = function(){
let result = this.toString();
console.log("result:",result)
}
})
}
hook_StringBuilder_toString()

jbyteArray类型打印

1
2
3
4
5
6
7
8
9
function jbyteArray2Array(jbyteArray) {
var ret;
Java.perform(function() {
var b = Java.use('[B');
var buffer = Java.cast(jbyteArray, b);
ret = Java.array('byte', buffer);
});
return ret;
}

字节数组转字符串

1
2
3
function bArrToString(bArr) {
return Java.use("java.lang.String").$new(bArr);
}

字符串转字节数组

1
2
3
function StringToByteArray(str) {
return Java.use("java.lang.String").$new(str).getBytes();
}

hook动态加载的dex

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
// 基础监控脚本
function monitorDexLoading() {
Java.perform(() => {
// 枚举所有已加载的类
Java.enumerateLoadedClasses({
onMatch: function(className) {
// 处理每个加载的类
processClass(className);
},
onComplete: function() {
console.log('Class enumeration completed');
}
});

// 监控新类加载
Java.use("java.lang.ClassLoader").loadClass.overload('java.lang.String').implementation = function(name) {
let result = this.loadClass(name);
processClass(name);
return result;
};
});
}

function processClass(className) {
// 根据类名过滤目标类
if (className.startsWith('com.example.target')) {
console.log('Found target class:', className);
hookTargetClass(className);
}
}

so层hook

hook_dlopen

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
function hook_dlopen(){
// 在Android8.0之前加载so通过dlopen函数
var dlopen = Module.findExportByName(null,"dlopen");
console.log("addr_dlopen",dlopen);
Interceptor.attach(dlopen,{
onEnter:function(args){
var pathptr = args[0];
if(pathptr){
var path = ptr(pathptr).readCString();
console.log("dlopen:",path);
}
},
onLeave:function(retvel){
console.log("leave!");
}
})

//Android8.0之后加载so通过android_dlopen_ext函数
var android_dlopen_ext = Module.findExportByName(null,"android_dlopen_ext");
console.log("addr_android_dlopen_ext",android_dlopen_ext);
Interceptor.attach(android_dlopen_ext,{
onEnter:function(args){
var pathptr = args[0];
if(pathptr!=null && pathptr != undefined){
var path = ptr(pathptr).readCString();
console.log("android_dlopen_ext:",path);
}
},
onLeave:function(retvel){
console.log("leave!");
}
})
}
hook_dlopen()

指定so的dlopen

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function hook_dlopen(){
var android_dlopen_ext = Module.findExportByName(null,"android_dlopen_ext");
console.log("addr_android_dlopen_ext",android_dlopen_ext);
Interceptor.attach(android_dlopen_ext,{
onEnter:function(args){
var pathptr = args[0];
if(pathptr!=null && pathptr != undefined){
var path = ptr(pathptr).readCString();
if(path.indexOf("SoName")!=-1){
console.log("android_dlopen_ext:",path);
}
}
},
onLeave:function(retvel){

}
})
}
hook_dlopen()

替换参数,不加载so

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
function hook_dlopen(so_name){
var android_dlopen_ext = Module.findExportByName(null,"android_dlopen_ext");
console.log("addr_android_dlopen_ext",android_dlopen_ext);
Interceptor.attach(android_dlopen_ext,{
onEnter:function(args){
var pathptr = args[0];
if(pathptr!=null && pathptr != undefined){
var path = ptr(pathptr).readCString();
console.log(path);
if(path.indexOf(so_name)!=-1){
args[0] = Memory.allocUtf8String("libc.so");
console.log("replaced!");
this.match = true;
}

}
},
onLeave:function(retvel){
if (this.match){
console.log(so_name,"加载成功");
let module = Process.findModuleByName(so_name);
console.log(module);
}
}
})
}
hook_dlopen(so_name)

hook_pthread

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function hook_pthread() {
var pth_create = Module.findExportByName("libc.so", "pthread_create");
console.log("[pth_create]", pth_create);
Interceptor.attach(pth_create, {
onEnter: function (args) {
var module = Process.findModuleByAddress(args[2]);
if (module != null) {
console.log("address", module.name, args[2].sub(module.base));
}
},
onLeave: function (retval) {}
});
}
hook_pthread()

hook_dlopen配合pthread

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
function hook_dlopen(){
var android_dlopen_ext = Module.findExportByName(null,"android_dlopen_ext");
console.log("addr_android_dlopen_ext",android_dlopen_ext);
Interceptor.attach(android_dlopen_ext,{
onEnter:function(args){
var pathptr = args[0];
if(pathptr!=null && pathptr != undefined){
var path = ptr(pathptr).readCString();
if(path.indexOf("libmsaoaidsec.so")!=-1){
console.log("android_dlopen_ext:",path);
hook_pthread()
}
}
},
onLeave:function(retvel){

}
})
}

function hook_pthread() {
var pth_create = Module.findExportByName("libc.so", "pthread_create");
console.log("[pth_create]", pth_create);
Interceptor.attach(pth_create, {
onEnter: function (args) {
var module = Process.findModuleByAddress(args[2]);
if (module != null) {
console.log("address", module.name, args[2].sub(module.base));
}
},
onLeave: function (retval) {}
});
}

function main(){
hook_dlopen()
}

main()

替换pthread_create函数打印参数信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function func_new_pthread_create(pthread_create_addr){
const pthread_create = new NativeFunction(pthread_create_addr, "int", ["pointer", "pointer", "pointer", "pointer"]);
return new NativeCallback(function(parg0, parg1, parg2, parg3){
const module = Process.findModuleByAddress(parg2);
const so_name = module.name;
const baseAddr = module.base
console.log("pthread_create", so_name, "0x" + parg2.sub(baseAddr).toString(16), "0x" + parg3.toString(16));
return pthread_create(parg0, parg1, parg2, parg3);
},"int",["pointer", "pointer", "pointer", "pointer"])

}

function replace_pthread_create(){
var pthread_create_addr = Module.findExportByName("libart.so", "pthread_create");
var new_pthread_create = func_new_pthread_create(pthread_create_addr);
// 函数替换
Interceptor.replace(pthread_create_addr,new_pthread_create);

}

replace_pthread_create();

替换pthread_create函数并指定so

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
function func_new_pthread_create(pthread_create_addr){
const pthread_create = new NativeFunction(pthread_create_addr, "int", ["pointer", "pointer", "pointer", "pointer"]);
return new NativeCallback(function(parg0, parg1, parg2, parg3){
const module = Process.findModuleByAddress(parg2);
const so_name = module.name;
const baseAddr = module.base;
if (so_name === "libmsaoaidsec.so") {
console.log("pthread_create", so_name, "0x" + parg2.sub(baseAddr).toString(16), "0x" + parg3.toString(16))
return 0;
}
// 成功的返回值是0
return pthread_create(parg0, parg1, parg2, parg3);
},"int",["pointer", "pointer", "pointer", "pointer"])

}

function replace_pthread_create(){
var pthread_create_addr = Module.findExportByName("libart.so", "pthread_create");
var new_pthread_create = func_new_pthread_create(pthread_create_addr);
// 函数替换
Interceptor.replace(pthread_create_addr,new_pthread_create);

}

replace_pthread_create();

替换pthread_create函数并指定函数

hook_RegisterNatives

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
function hook_RegisterNatives() {
var RegisterNatives_addr = null;
var symbols = Process.findModuleByName("libart.so").enumerateSymbols();
for (var i = 0; i < symbols.length; i++) {
var symbol = symbols[i].name;
if ((symbol.indexOf("CheckJNI") == -1) && (symbol.indexOf("JNI") >= 0)) {
if (symbol.indexOf("RegisterNatives") >= 0) {
RegisterNatives_addr = symbols[i].address;
console.log("RegisterNatives_addr: ", RegisterNatives_addr);
}
}
}
Interceptor.attach(RegisterNatives_addr, {
onEnter: function (args) {
var env = args[0];
var jclass = args[1];
var class_name = Java.vm.tryGetEnv().getClassName(jclass);
var methods_ptr = ptr(args[2]);
var method_count = args[3].toInt32();
console.log("RegisterNatives method counts: ", method_count);
for (var i = 0; i < method_count; i++) {
var name = methods_ptr.add(i * Process.pointerSize * 3).readPointer().readCString();
var sig = methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize).readPointer().readCString();
var fnPtr_ptr = methods_ptr.add(i * Process.pointerSize * 3 + Process.pointerSize * 2).readPointer();
var find_module = Process.findModuleByAddress(fnPtr_ptr);
console.log("ClasssName: ", class_name, "MethodName: ", name, "Sig: ", sig, "Function_addr: ", fnPtr_ptr, "ModuleName: ", find_module.name, "Fun_Offset: ", ptr(fnPtr_ptr).sub(find_module.base));
}
},
onLeave: function (retval) {}
});
}
hook_RegisterNatives()

hook_RegisterNative2

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
const STD_STRING_SIZE = 3 * Process.pointerSize;
class StdString {
constructor() {
this.handle = Memory.alloc(STD_STRING_SIZE);
}

dispose() {
const [data, isTiny] = this._getData();
if (!isTiny) {
Java.api.$delete(data);
}
}

disposeToString() {
const result = this.toString();
this.dispose();
return result;
}

toString() {
const [data] = this._getData();
return data.readUtf8String();
}

_getData() {
const str = this.handle;
const isTiny = (str.readU8() & 1) === 0;
const data = isTiny ? str.add(1) : str.add(2 * Process.pointerSize).readPointer();
return [data, isTiny];
}
}

function prettyMethod(method_id, withSignature) {
const result = new StdString();
Java.api['art::ArtMethod::PrettyMethod'](result, method_id, withSignature ? 1 : 0);
return result.disposeToString();
}
function attach(addr) {
Interceptor.attach(addr, {
onEnter: function (args) {
this.arg0 = args[0]
},
onLeave: function (retval) {
var modulemap = new ModuleMap()
modulemap.update()
var module = modulemap.find(retval)
var string = Memory.alloc(0x100)
if (module != null) {
console.log('<' + module.name + '> method_name =>',prettyMethod(this.arg0,1), ',offset=>', ptr(retval).sub(module.base), ',module_name=>', module.name)
}else{
console.log('<anonymous> method_name =>', readStdString(string), ', addr =>', ptr(retval))
}
}
});
}

function hook_RegisterNative() {
var libart = Process.findModuleByName('libart.so')
var symbols = libart.enumerateSymbols()
for (var i = 0; i < symbols.length; i++) {
if (symbols[i].name.indexOf('RegisterNative') > -1 && symbols[i].name.indexOf('ArtMethod') > -1 && symbols[i].name.indexOf('RuntimeCallbacks') < 0) {
attach(symbols[i].address)
}

}

}
function main() {
hook_RegisterNative()
}
setImmediate(main)

hook_dlsym

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function hook_dlsym(){
// 获取dlsym函数的地址
let dlsymAddr = Module.findExportByName("libdl.so","dlsym");
console.log(dlsymAddr);
// hook dlsym
Interceptor.attach(dlsymAddr,{
onEnter:function(args){
this.args1 = args[1];
},
onLeave:function(retval){
let md= Process.findModuleByAddress(retval);
if(md==null)return;
console.log("function:"+this.args1.readCString(),"module:"+md.name,"address:"+retval,"offset:"+retval.sub(md.base));
}
})
}

hook_dlsym()

hook_call_constructors()

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
function hook_call_constructors(){
let linker = null;
if (Process.pointerSize === 4) {
linker = Process.findModuleByName("linker");
} else {
linker = Process.findModuleByName("linker64");
}
let call_constructors_addr, get_soname
let symbols = linker.enumerateSymbols();
for (let index = 0; index < symbols.length; index++) {
let symbol = symbols[index];
if (symbol.name === "__dl__ZN6soinfo17call_constructorsEv") {
call_constructors_addr = symbol.address;
} else if (symbol.name === "__dl__ZNK6soinfo10get_sonameEv") {
get_soname = new NativeFunction(symbol.address, "pointer", ["pointer"]);
}
}
Interceptor.attach(call_constructors_addr,{
onEnter:function(args){
console.log("hooked call_constructors!")
},
onLeave:function(ret){

}
})
}
hook_call_constructors()
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
function hook_init_array() {
let linker = null;
if (Process.pointerSize === 4) {
linker = Process.findModuleByName("linker");
} else {
linker = Process.findModuleByName("linker64");
}
let call_constructors_addr, get_soname
let symbols = linker.enumerateSymbols();
for (let index = 0; index < symbols.length; index++) {
let symbol = symbols[index];
if (symbol.name === "__dl__ZN6soinfo17call_constructorsEv") {
call_constructors_addr = symbol.address;
} else if (symbol.name === "__dl__ZNK6soinfo10get_sonameEv") {
get_soname = new NativeFunction(symbol.address, "pointer", ["pointer"]);
}
}
console.log(call_constructors_addr)
Interceptor.attach(call_constructors_addr, {
onEnter: function (args) {
let soinfo = args[0];
let soname = get_soname(soinfo).readCString();
// 此时还没有执行完成初始化函数
// 这个时候就可以加载so了,可以在这个位置nop掉其他的东西
},
onLeave: function (retval) {
if (this.match) {
console.log("libDexHelper.so", "加载成功")
const module = Process.findModuleByName("libDexHelper.so");
// 执行结束初始化函数了,接下来会跑dlopen结束位置,执行JNI_OnLoad
}
}
});
}

配合dlopen使用hook_call_constructors()

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
function hook_dlopen(){
var android_dlopen_ext = Module.findExportByName(null,"android_dlopen_ext");
console.log("addr_android_dlopen_ext",android_dlopen_ext);
Interceptor.attach(android_dlopen_ext,{
onEnter:function(args){
var pathptr = args[0];
if(pathptr!=null && pathptr != undefined){
var path = ptr(pathptr).readCString();
if(path.indexOf("xxx.so")!=-1){
console.log("android_dlopen_ext:",path);
hook_call_constructors()
}
}
},
onLeave:function(retvel){

}
})
}

function hook_call_constructors(){
var linker = Process.findModuleByName("linker64");
var symbols = linker.enumerateSymbols();
var addr_call_constructors = null;
var symbol = null;
for(var index =0;index<symbols.length;index++){
symbol = symbols[index];
if(symbol.name==="__dl__ZN6soinfo17call_constructorsEv"){
addr_call_constructors = symbol.address;
break;
}
}
var listener = Interceptor.attach(addr_call_constructors,{
onEnter:function(args){
console.log("hooked call_constructors")
var module = Process.findModuleByName("xxx.so")
if (module != null) {
Interceptor.replace(module.base.add(0x175f8), new NativeCallback(function () {
console.log("0x175f8:替换成功")
}, "void", []))
Interceptor.replace(module.base.add(0x16d30), new NativeCallback(function () {
console.log("0x16d30:替换成功")
}, "void", []))
listener.detach()
}
},
onLeave:function(ret){

}
})
}
function main(){
hook_dlopen()
}
main()

nop_addr

1
2
3
4
5
6
7
function nop_addr(addr) {
Memory.protect(addr, 4 , 'rwx');
var w = new Arm64Writer(addr);
w.putRet();
w.flush();
w.dispose();
}

配合hook_call_constructors()使用

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
function hook_dlopen(){
//Android8.0之后加载so通过android_dlopen_ext函数
var android_dlopen_ext = Module.findExportByName(null,"android_dlopen_ext");
console.log("addr_android_dlopen_ext",android_dlopen_ext);
Interceptor.attach(android_dlopen_ext,{
onEnter:function(args){
var pathptr = args[0];
if(pathptr!=null && pathptr != undefined){
var path = ptr(pathptr).readCString();
if(path.indexOf("libmsaoaidsec.so")!=-1){
console.log("android_dlopen_ext:",path);
hook_call_constructors()
}
}
},
onLeave:function(retvel){
//console.log("leave!");
}
})
}

function hook_call_constructors() {
var linker64_base_addr = Module.getBaseAddress("linker64")
var call_constructors_func_off = 0x2C274 //这个地址是从手机上把linker64 pull出来,然后到IDA中找到的,不同的机型,地址可能不一样
var call_constructors_func_addr = linker64_base_addr.add(call_constructors_func_off)
var listener = Interceptor.attach(call_constructors_func_addr, {
onEnter: function (args) {
console.log("hooked call_constructors")
var module = Process.findModuleByName("libmsaoaidsec.so")
if (module != null) {
nop_addr(module.base.add(0x1c544))
console.log("0x1c544:替换成功")
nop_addr(module.base.add(0x1b924))
console.log("0x1B924:替换成功")
nop_addr(module.base.add(0x26e5c))
console.log("0x26e5c:替换成功")
listener.detach()
}
},
})
}

function nop_addr(addr) {
Memory.protect(addr, 4 , 'rwx');
var w = new Arm64Writer(addr);
w.putRet();
w.flush();
w.dispose();
}


function main(){
hook_dlopen()
}

main()

hook_JNI_OnLoad()

hook JNI_OnLoad需要一个时机,就是在指定的so刚加载完成的时候进行hook

1
2
3
4
5
6
7
8
9
10
11
function hook_JNI_OnLoad(){
var Addr_JNI_OnLoad = Module.findExportByName("xxx.so","JNI_OnLoad");
Interceptor.attach(Addr_JNI_OnLoad,{
onEnter:function(args){
console.log("hooked JNI_OnLoad!");
},
onLeave:function(retval){
console.log("JNI_OnLoad over!");
}
})
}

以下是一个示例

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
function hook_dlopen(){
var android_dlopen_ext = Module.findExportByName(null,"android_dlopen_ext");
console.log("addr_android_dlopen_ext",android_dlopen_ext);
var ismsaoaidsec = false;
Interceptor.attach(android_dlopen_ext,{
onEnter:function(args){
var pathptr = args[0];
if(pathptr!=null && pathptr != undefined){
var path = ptr(pathptr).readCString();
if(path.indexOf("xxx.so")!=-1){
ismsaoaidsec = true;
console.log("android_dlopen_ext:",path);
}
}
},
onLeave:function(retvel){
if(ismsaoaidsec){
hook_JNI_OnLoad();
ismsaoaidsec = false;
}
}
})
}

function hook_JNI_OnLoad(){
var Addr_JNI_OnLoad = Module.findExportByName("xxx.so","JNI_OnLoad");
Interceptor.attach(Addr_JNI_OnLoad,{
onEnter:function(args){
console.log("hooked JNI_OnLoad!");
},
onLeave:function(retval){
console.log("JNI_OnLoad over!");
}
})
}

function main(){
hook_dlopen()
}
main()

hook_NewStringUTF()

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
// 定义 Hook NewStringUTF 函数的逻辑
function hook_NewStringUTF() {

// 同步枚举 libart.so 模块中的所有符号(Android Runtime 库)
let symbols = Module.enumerateSymbolsSync("libart.so");

// 用于存储找到的 NewStringUTF 函数地址
let addrNewStringUTF = null;

// 遍历所有符号,查找目标函数
for (let i = 0; i < symbols.length; i++) {
let symbol = symbols[i];

// 筛选条件:名称包含 NewStringUTF 且不包含 CheckJNI(避免 hook 到 JNI 检查函数)
if (symbol.name.indexOf("NewStringUTF") != -1 && symbol.name.indexOf("CheckJNI") == -1) {

// 找到符合条件的符号地址
addrNewStringUTF = symbol.address;
console.log("NewStringUTF's addr:", symbol.address, " name:", symbol.name);
break; // 找到后立即退出循环
}
}

// 确认找到目标函数地址后进行 Hook
if (addrNewStringUTF != null) {
// 使用 Frida 的 Interceptor 附加到目标地址
Interceptor.attach(addrNewStringUTF, {
// 进入函数时的回调(参数在 args 数组中)
onEnter: function (args) {
// args[1] 对应 NewStringUTF 的第二个参数:const char* bytes
var c_string = args[1];

// 从内存中读取 C 字符串(UTF-8 编码)
var dataString = c_string.readCString();

if (dataString) {
// 判断字符串长度是否为 32(例如可能用于捕获 MD5、UUID 等)
if (dataString.length === 32) {
// 打印字符串内容
console.log("捕获到 32 位字符串:", dataString);

// 打印 Native 层堆栈跟踪(使用精确回溯模式)
console.log("Native 堆栈跟踪:");
console.log(Thread.backtrace(this.context, Backtracer.ACCURATE)
.map(DebugSymbol.fromAddress).join('\n') + "\n");

// 打印 Java 层堆栈跟踪(需要 Android 环境支持)
console.log("Java 堆栈跟踪:");
console.log(Java.use("android.util.Log").getStackTraceString(
Java.use("java.lang.Throwable").$new()));
}
}
},
// 函数离开时的回调(本示例未使用)
onLeave: function () {
}
})
} else {
console.log("未找到 NewStringUTF 函数地址!");
}
}

/* 主要功能说明:
此脚本用于 Hook Android JNI 的 NewStringUTF 函数,
当检测到创建长度为 32 的字符串时,会同时打印:
- 字符串内容
- Native 层调用堆栈
- 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
30
31
32
33
34
35
36
37
function hook_NewStringUTF(){

let symbols = Module.enumerateSymbolsSync("libart.so");

let addrNewStringUTF = null;

for(let i=0;i<symbols.length;i++){
let symbol = symbols[i];

if(symbol.name.indexOf("NewStringUTF")!=-1 && symbol.name.indexOf("CheckJNI")==-1){

addrNewStringUTF = symbol.address;
console.log("NewStringUTF's addr:",symbol.address," name:",symbol.name);
break
}
}

if(addrNewStringUTF != null){
Interceptor.attach(addrNewStringUTF,{
onEnter:function(args){
var c_string = args[1];
var dataString = c_string.readCString();
if(dataString){
// console.log(dataString)
if(dataString.length===32){
console.log("dataString:",dataString);

console.log(Thread.backtrace(this.context,Backtracer.ACCURATE).map(DebugSymbol.fromAddress).join('\n')+"\n");
console.log(Java.use("android.util.Log").getStackTraceString(Java.use("java.lang.Throwable").$new()));
}
}
},
onLeave:function(){
}
})
}
}

stalker测试

1
2
3
4
5
6
7
8
9
10
11
12
let threadId = Process.getCurrentThreadId();
Stalker.follow(tid, {
transform: function(iterator) {
while (true){
const instruction = iterator.next()
if (iterator === null){
break;
}
iterator.keep();
}
}
});