【愚公系列】2023年08月 攻防世界-MOBILE(丛林的秘密)
前言
下面介绍三个反编译工具
- jadx是一个用于反编译Android APK文件的开源工具,静态反编译,查找索引功能强大
- jeb和IDA很像,属于动态调试,可以看java汇编也可以生成伪代码,还可以动态attach到目标调试
- Dex2jar:Dex2jar是一种工具,可以将Android的.dex文件转换为Java的.class文件,以便更方便地进行反编译和分析。
对于so文件的逆向工具选择
- IDA逆向工具是一款反汇编器,被广泛应用于软件逆向工程领域,能够反汇编各种不同平台的二进制程序代码,并还原成可读的汇编代码。
Objection是一款移动设备运行时漏洞利用工具,该工具由Frida驱动,可以帮助研究人员访问移动端应用程序,并在无需越狱或root操作的情况下对移动端应用程序的安全进行评估检查。
安装命令
pip3 install objection
frida是一款便携的、自由的、支持全平台的hook框架,可以通过编写JavaScript、Python代码来和frida_server端进行交互
frida的安装可以参考:https://www.jianshu.com/p/60cfd3f6afde
一、丛林的秘密
1.题目
2.答题
1、jadx查看代码
package com.example.assemgogogo;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.webkit.WebView;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
/* loaded from: classes.dex */
public class MainActivity extends AppCompatActivity {
private Button button1;
private EditText eText1;
private TextView txView1;
public String u = gogogoJNI.sayHello();
static {
System.loadLibrary("gogogo");
}
/* JADX INFO: Access modifiers changed from: protected */
@Override // android.support.v7.app.AppCompatActivity, android.support.v4.app.FragmentActivity, android.support.v4.app.SupportActivity, android.app.Activity
public void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.activity_main);
this.eText1 = (EditText) findViewById(R.id.editText);
this.txView1 = (TextView) findViewById(R.id.textView);
((WebView) findViewById(R.id.text1View)).loadUrl(this.u);
((WebView) findViewById(R.id.text1View)).getSettings().setJavaScriptEnabled(true);
this.button1 = (Button) findViewById(R.id.button);
this.button1.setOnClickListener(new View.OnClickListener() { // from class: com.example.assemgogogo.MainActivity.1
@Override // android.view.View.OnClickListener
public void onClick(View view) {
if (gogogoJNI.check_key(MainActivity.this.eText1.getText().toString()) == 1) {
MainActivity.this.txView1.setText("Congratulations!");
} else {
MainActivity.this.txView1.setText("Not Correct!");
}
}
});
}
}
先从so库中获取了一个字符串,而后还使用了WebView组件,最后注册按钮事件,调用native中的check函数对输入进行check。
查看native层,sayHello函数如下,返回了本机地址的8000端口字符串。sayHello函数返回字串’http://127.0.0.1:8000’ ,而check_key似乎不像校验函数:
int __fastcall Java_com_example_assemgogogo_gogogoJNI_check_key(JNIEnv *a1, int a2, jstring a3)
{
int v5; // r8
const char *v6; // r0
const char *v7; // r4
unsigned int v8; // r5
int v9; // r0
int v10; // r1
int v11; // r0
v5 = 0;
v6 = (*a1)->GetStringUTFChars(a1, a3, 0);
if ( v6 )
{
v7 = v6;
(*a1)->ReleaseStringUTFChars(a1, a3, v6);
srand(0x32u);
v8 = 0;
while ( v8 <= 0x1F )
{
v9 = rand();
v10 = (unsigned __int8)v7[v8];
v11 = v9 % 128 - (unsigned __int8)aD584a68d4e213d[v8++];
if ( v10 != (v11 != 0) )
return 0;
}
close(sock_fd_g);
return 1;
}
return v5;
}
在JNI_OnLoad函数中调用了地址为B30的函数,解码了大量数据,并建立了socket,监听8000端口,模拟web服务,有客户端连接后将解码的数据发送到客户端。
直接用frida来hook解密的数据。数据解码后为html内容,内嵌WebAssembly,html部分内容为(去除了WebAssembly部分):
function hookNative() {
const libName = 'libgogogo.so'
const baseAddr = Module.findBaseAddress(libName)
console.log("base",baseAddr)
console.log(baseAddr.add(0x12008).readCString())
}
setTimeout(hookNative,50)
可发现是一个html页面源码,主要内容如下。
<html><head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta charset="utf-8">
<style>
body {
background-color: rgb(255, 255, 255);
}
</style>
</head>
<script>
var instance;
WebAssembly.compile(new Uint8Array(`
bin data ......
`.trim().split(/[\s\r\n]+/g).map(str => parseInt(str, 16))
)).then(module => {
new WebAssembly.instantiate(module).then(results => {
instance = results;
}).catch(console.error);})
function check_flag(){
var value = document.getElementById("key_value").value;
if(value.length != 32)
{
document.getElementById("tips").innerHTML = "Not Correct!";
return;
}
instance.exports.set_input_flag_len(value.length);
for(var ii=0;ii<value.length;ii++){
instance.exports.set_input_flag(value[ii].charCodeAt(),ii);
}
var ret = instance.exports.check_key();
if (ret == 1){
document.getElementById("tips").innerHTML = "Congratulations!"
}
else{
document.getElementById("tips").innerHTML = "Not Correct!"
}
}
</script>
<body>
<div>Key: <input id="key_value" type="text" name="key" style="width:60%" ;="" value=""> <input type="submit" value="check" onclick="check_flag()"></div>
<div> <label id="tips"></label></div>
</body></html>
其中限定输入长度为32,调用WebAssembly.compile()方法编译WebAssembly二进制代码,真正的check_key函数在wasm中实现。
将其中数据保存,反汇编为c文件后,再进行编译,用ida进行分析。
check_key函数如下。
__int64 check_key()
{
unsigned int v0; // ST00_4
if ( ++wasm_rt_call_stack_depth > 0x1F4u )
wasm_rt_trap(7LL);
o(1024u, 1025u, 1026u, 1027u);
oo(1028u, 1029u, 1030u, 1031u);
ooo(1032u, 1033u, 1034u, 1035u);
oooo(1036u, 1037u, 1038u, 1039u);
ooooo(0x410u, 0x411u, 0x412u, 0x413u);
oooooo(0x414u, 0x415u, 0x416u, 0x417u);
ooooooo(0x418u, 0x419u, 0x41Au, 0x41Bu);
oooooooo(0x41Cu, 0x41Du, 0x41Eu, 0x41Fu);
v0 = xxx();
--wasm_rt_call_stack_depth;
return v0;
}
先调用了8个函数对输入的32字节进行异或处理,然后调用xxx函数进行最终校验,xxx函数中通过32个32元一次代数方程进行校验,直接解方程得到
y = [83,48,109,51,116,105,109,101,
95,108,49,116,116,49,101,95,
99,48,100,101,95,49,115,95,
117,115,51,102,117,108,51,51]
即:S0m3time_l1tt1e_c0de_1s_us3ful33
32字节异或的常量值为:
x = [0x18, 0x09, 0x03, 0x6b, 0x01, 0x5a, 0x32, 0x57,
0x30, 0x5d, 0x40, 0x46, 0x2b, 0x46, 0x56, 0x3d,
0x02, 0x43, 0x17, 0x00, 0x32, 0x53, 0x1f, 0x26,
0x2a, 0x01, 0x00, 0x10, 0x10, 0x1e, 0x40, 0x00]
直接异或得到原始输入:
>>> for i in range(32):
... l.append(x[i]^y[i])
...
>>> print ''.join(map(chr,l))
K9nXu3_2o1q2_w3bassembly_r3vers3
得到flag:flag{K9nXu3_2o1q2_w3bassembly_r3vers3}
- 点赞
- 收藏
- 关注作者
评论(0)