【愚公系列】2023年05月 攻防世界-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}

猜你喜欢

转载自blog.csdn.net/aa2528877987/article/details/130445103