0x00 前言

Native层逆向,主动调一下就可以了

0x01 解

先进jadax看看

MainActivity的判断逻辑如下:

其中legal函数如下:

1
2
3
private boolean legal(String paramString) {
return paramString.length() == 38 && paramString.startsWith("flag{") && paramString.charAt(paramString.length() - 1) == '}' && !inspect.inspect(paramString.substring(5, paramString.length() - 1));
}

可以知道flag总长为38bytes,会对flag{}做判断,中间部分看inspect类的inspect函数

跟进去看

用到了java里面的crypto库,使用DES加密,模式是CBC,padding用的是PKCS5,最后还有base64

密文是JqslHrdvtgJrRs2QAp+FEVdwRPNLswrnykD/sZMivmjGRKUMVIC/rw==

因此需要获取keyiv

这两个的来源一个是str2,一个是ivBytes,都是jni这个类里面的

去so库里面找找,直接看apk里面的lib-arm64-v8a-libSecret_entrance.so,导出表里面就可以看到这两个函数

都是静态的

直接上frida在java层hook看看

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 先hook getiv试试
function hook(){
let jni = Java.use("com.example.re11113.jni");
jni["getiv"].implementation = function () {
console.log(`jni.getiv is called`);
let result = this["getiv"]();
console.log(`jni.getiv result=${result}`);
return result;
};
}

function main(){
Java.perform(function(){
hook();
});
}
setImmediate(main);

iv能成功获取,为Wf3DLups

之后再试试getkey

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function hook(){
let jni = Java.use("com.example.re11113.jni");
jni["getkey"].implementation = function () {
console.log(`jni.getkey is called`);
let result = this["getkey"]();
console.log(`jni.getkey result=${result}`);
return result;
};
}

function main(){
Java.perform(function(){
hook();
});
}
setImmediate(main);

一运行就炸

试试在native层hook

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function hook() {
var getKeyBase = Module.findExportByName("libSecret_entrance.so", "Java_com_example_re11113_jni_getkey");
Interceptor.attach(getKeyBase, {
onEnter: function(args) {
},
onLeave: function(retval) {
console.log(Java.vm.getEnv().getStringUtfChars(retval, null).readCString())
}
});
}

function main(){
Java.perform(function(){
hook();
});
}
setImmediate(main);

可以正常输出,key是A8UdWaeq

但尝试直接主动调用这个函数就会直接报错

1
2
3
4
5
6
7
8
9
function hook() {

Java.perform(function () {
var getKeyBase = Module.findExportByName("libSecret_entrance.so", "Java_com_example_re11113_jni_getkey");
let key_func = new NativeFunction(getKeyBase, 'pointer', ['pointer']);
let result = key_func(Java.vm.getEnv());
})
}
hook();
1
Error: abort was called

看雪上有个[CISCN2024]androidso_re题解以及崩溃原因分析

大致意思是直接主动调用这个getkey会导致传给NewStringUTF的值出错,只有在先hook的情况下才能主动调用,如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// native层主动调用
function hook() {
var getKeyBase = Module.findExportByName("libSecret_entrance.so", "Java_com_example_re11113_jni_getkey");
Interceptor.attach(getKeyBase, {
onEnter: function(args) {
},
onLeave: function(retval) {
}
});
var key_func = new NativeFunction(getKeyBase , 'pointer', ['pointer']);
var res = key_func(Java.vm.getEnv());
console.log("Key: " + Java.vm.getEnv().getStringUtfChars(res, null).readCString())
}
function main(){
Java.perform(function(){
hook();
});
}
setImmediate(main);

或者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// java层主动调用
function hook() {
var getKeyBase = Module.findExportByName("libSecret_entrance.so", "Java_com_example_re11113_jni_getkey");
Interceptor.attach(getKeyBase, {
onEnter: function(args) {
},
onLeave: function(retval) {
}
});
var key = jni.getkey();
console.log("Key: " + key);
}
function main(){
Java.perform(function(){
hook();
});
}
setImmediate(main);

才能正常输出

就,挺弱智的

最后没什么别的操作,直接base64+des解就行

flag{188cba3a5c0fbb2250b5a2e590c391ce}