首页
社区
课程
招聘
[原创]CTF 丛林的秘密:算法分析
发表于: 2024-1-19 15:52 12804

[原创]CTF 丛林的秘密:算法分析

2024-1-19 15:52
12804

这一题很有迷惑性,设置了很多陷阱,看似正常的逻辑其实是假象。里面用到了Webassembly逆向,我也是第一次遇到这种,之前没有触过wasm汇编语言,看到代码也是无从下手,也是一边学习一边算法逆向。

从代码可以看出满足native int check_key(String str) 为真时候,则验证通过,同时也调用了sayHello(),调用的具体作用还看不出来。
图片描述

从导出函数列表中,找到我们的目标函数:
图片描述

这段代码的意思就是返回字符串:http://127.0.0.1:8000
图片描述

图片描述
主要步骤如下:

通过 JNI 调用 Java 中的方法(通过函数指针调用),返回结果存储在 result 变量中。
如果调用成功,进入密钥检查的逻辑。
使用 srand(0x32u) 设置随机数生成器的种子。
在循环中,生成随机数 v8,然后根据一些条件检查当前密钥字节是否符合预期。
如果所有密钥字节都通过检查,返回 0;否则,关闭套接字并返回 1。
v8是一个随机数,if ( *(_BYTE *)(v6 + v7) != (v8 - (v9 & 0xFFFFFF80) != (unsigned __int8)aD584a68d4e213d[v7]) )
结果肯定是不相等的,那么通过分析返回值永远都是0,那么不成立,这个函数岂不是无解?

既然通过代码分析,我们知道他们调用了_check_key、sayHello这个2个函数,那么我们就hook他们,验证下。

图片描述
通过结果可以看出,只调用了sayHello函数并没有调用check_key函数,结合之前的分析可以得出,此处并非是真正的位置,check_key函数又在哪调用的呢?
再来看java层代码中:
((WebView) findViewById(R.id.text1View)).loadUrl(this.u);
((WebView) findViewById(R.id.text1View)).getSettings().setJavaScriptEnabled(true);
this.u = :http://127.0.0.1:8000 setJavaScriptEnabled 启用了JavaScript。接着分析:
在so文件JNI_OnLoad中调用了inti_proc函数:
图片描述

使用一个循环,将一系列向量进行初始化,涉及到按位异或操作。
使用一系列操作配置了套接字相关的参数,包括套接字类型、协议等。
通过 getaddrinfo 获取了本地主机(IP地址为0)在端口8000上的地址信息,并将结果存储在 v19 中。
在获取的地址信息上循环,尝试创建套接字并设置一些选项。
套接字创建和配置成功,创建了多个线程。
返回值 nullsub_
图片描述
mm0 是关键 我们hook之

图片描述
得到一串代码,可以看出他是一个html页面,看来交互就是和他进行了。我们在弄出完整的html页面看看:

图片描述

WebAssembly(简称为Wasm)是一种面向Web的二进制指令格式。它是一种可移植、高性能的虚拟机,旨在在Web浏览器中执行底层代码,以提供接近本地代码执行速度的性能。以下是关于WebAssembly的基本概念:

二进制指令格式:

WebAssembly使用紧凑的二进制格式,可以更高效地传输和解码,同时减小加载时间。这使得WebAssembly成为Web平台上的一个通用执行格式。
独立于编程语言:

WebAssembly并不依赖于特定的编程语言,而是设计为与多种语言兼容。它可以被用作JavaScript之外的语言的目标,使得开发者可以使用各种语言编写Web应用的核心功能。
执行环境:

WebAssembly代码在浏览器中执行,但它不直接在JavaScript引擎上运行。相反,WebAssembly有自己的虚拟机,与浏览器的JavaScript引擎分开。这使得WebAssembly能够获得与本地代码相媲美的性能。
跨平台:

WebAssembly是一个跨平台的技术,可以在不同体系结构和操作系统上运行。这使得开发者可以编写一次代码,并在各种设备和环境中部署,而无需修改。
安全性:

WebAssembly被设计为在Web环境中运行,同时具有强大的安全性。它在一个受控的沙箱中运行,防止对计算机系统的恶意访问。此外,WebAssembly模块可以通过浏览器的同源策略限制来提高安全性。
JavaScript和WebAssembly的互操作性:

WebAssembly与JavaScript有良好的互操作性。JavaScript可以调用WebAssembly的函数,而WebAssembly也可以调用JavaScript的函数,使得两者可以共同工作。
使用场景:

WebAssembly广泛应用于需要高性能的Web应用程序,例如图形、游戏、模拟器、数据处理等。它允许开发者在Web上执行密集型计算任务,而不会损失性能。
工具链支持:

WebAssembly有完整的工具链,包括编译器和调试器,使得开发者能够方便地将其集成到现有的开发工作流程中。

从github下载工具,对文件进行反编译 https://github.com/WebAssembly/wabt

此时代码看上去是又多又长,分析起来比较吃力。gcc编译web.c获得中间文件web.o

将web.o拖到IDA中分析。
w2c_check_key()就是核心代码了
图片描述
w2c_o内部逻辑都是一样的。
图片描述
函数签名:
函数名为 w2c_o。
返回一个64位整数 __int64。
使用 __fastcall 调用约定,表明一些参数可能会通过寄存器传递。
接受四个无符号整数参数 a1、a2、a3、a4。
局部变量和参数:
使用了一系列整数变量,如 v4、v5、v6、...、v28。
v26、v17、v16、v15、v23、v21 等变量在后续的运算中被使用。
内存操作:
使用 i32_load8_u 和 i32_load8_s 从内存中加载8位整数。
使用 i32_store8 将8位整数写入内存。
逻辑运算和条件判断:
对变量进行递增、逻辑与、逻辑或等操作,生成一系列的逻辑条件。
根据条件判断执行不同的逻辑分支。
循环:
使用 do-while 循环,在循环体内执行一系列的操作。
返回值:
最终返回一个64位整数 v18。
调用 wasm_rt_trap 函数:
在代码开头,使用 wasm_rt_call_stack_depth 变量判断调用深度,如果超过一定深度,就会调用 wasm_rt_trap 函数,并传递参数7。
数据处理和异或运算:
对参数进行一系列复杂的逻辑运算,包括位异或运算,与运算,或运算等。
条件判断:
根据条件的不同执行不同的逻辑分支。
最后的返回:
根据条件计算得到的最终结果 v18 作为函数的返回值。
w2c_xxx() 是一个32元方程组
图片描述

图片描述
对相应位进行异或

function hook_jiami() {
    Java.perform(function () {
        var gogogoJNI = Java.use("com.example.assemgogogo.gogogoJNI");
        gogogoJNI["sayHello"].implementation = function () {
            console.log("gogogoJNI.sayHello is called");
            var result = this["sayHello"]();
            console.log("gogogoJNI.sayHello result=${result}", result);
            return result;
        };
        gogogoJNI["check_key"].implementation = function (str) {
            console.log("gogogoJNI.check_key is called: str=${str}", str);
            var result = this["check_key"](str);
            console.log("gogogoJNI.check_key result=${result}", result);
            return result;
        };
    });
}
function hook_jiami() {
    Java.perform(function () {
        var gogogoJNI = Java.use("com.example.assemgogogo.gogogoJNI");
        gogogoJNI["sayHello"].implementation = function () {
            console.log("gogogoJNI.sayHello is called");
            var result = this["sayHello"]();
            console.log("gogogoJNI.sayHello result=${result}", result);
            return result;
        };
        gogogoJNI["check_key"].implementation = function (str) {
            console.log("gogogoJNI.check_key is called: str=${str}", str);
            var result = this["check_key"](str);
            console.log("gogogoJNI.check_key result=${result}", result);
            return result;
        };
    });
}
function hook_jiami() {
    Java.perform(function () {
        var module_addr = Module.findBaseAddress("libgogogo.so");
        var mm0__addr = Module.findExportByName("libgogogo.so","mm0");
 
        console.log("module_addr = ", module_addr);
  
        var get_html = mm0__addr.readByteArray(35000);
 
        console.log("mm0__addr_addr 3333 ",get_html)
    });
}
function hook_jiami() {
    Java.perform(function () {
        var module_addr = Module.findBaseAddress("libgogogo.so");
        var mm0__addr = Module.findExportByName("libgogogo.so","mm0");
 
        console.log("module_addr = ", module_addr);
  
        var get_html = mm0__addr.readByteArray(35000);
 
        console.log("mm0__addr_addr 3333 ",get_html)
    });
}
function bytesToString(arr) {
    if (typeof arr === 'string') {
        return arr;
    }
    var str = "";
    arr = new Uint8Array(arr);
    for (var i in arr) {
        str += String.fromCharCode(arr[i]);
    }
    return str
}
 
function hook_jiami() {
    Java.perform(function () {
        var module_addr = Module.findBaseAddress("libgogogo.so");
        var mm0__addr = Module.findExportByName("libgogogo.so","mm0");
        console.log("module_addr = ", module_addr);
        var get_html = mm0__addr.readByteArray(35000);
        var get_html1 = bytesToString(get_html);
        console.log("nmm0__addr_addr 4444 ",bytesToString(get_html))
    
    });
}
function bytesToString(arr) {
    if (typeof arr === 'string') {
        return arr;
    }
    var str = "";
    arr = new Uint8Array(arr);
    for (var i in arr) {
        str += String.fromCharCode(arr[i]);
    }
    return str
}
 
function hook_jiami() {
    Java.perform(function () {
        var module_addr = Module.findBaseAddress("libgogogo.so");
        var mm0__addr = Module.findExportByName("libgogogo.so","mm0");
        console.log("module_addr = ", module_addr);
        var get_html = mm0__addr.readByteArray(35000);
        var get_html1 = bytesToString(get_html);
        console.log("nmm0__addr_addr 4444 ",bytesToString(get_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(`
 00 61 73 6D 01 00 00 00 01 1B 05 60 00 00 60 04
7F 7F 7F 7F 01 7F 60 02 7F 7F 01 7F 60 01 7F 01
7F 60 00 01 7F 03 0E 0D 00 01 01 01 01 01 01 01
01 02 03 04 04 04 05 01 70 01 01 01 05 03 01 00
02 06 15 03 7F 01 41 D0 89 04 0B 7F 00 41 D0 89
 
...
 
00 00 00 83 01 04 6E 61 6D 65 01 7C 0D 00 11 5F
5F 77 61 73 6D 5F 63 61 6C 6C 5F 63 74 6F 72 73
01 01 6F 02 02 6F 6F 03 03 6F 6F 6F 04 04 6F 6F
6F 6F 05 05 6F 6F 6F 6F 6F 06 06 6F 6F 6F 6F 6F
6F 07 07 6F 6F 6F 6F 6F 6F 6F 08 08 6F 6F 6F 6F
6F 6F 6F 6F 09 0E 73 65 74 5F 69 6E 70 75 74 5F
66 6C 61 67 0A 12 73 65 74 5F 69 6E 70 75 74 5F
66 6C 61 67 5F 6C 65 6E 0B 09 63 68 65 63 6B 5F
6B 65 79 0C 03 78 78 78
`.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>
<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(`
 00 61 73 6D 01 00 00 00 01 1B 05 60 00 00 60 04
7F 7F 7F 7F 01 7F 60 02 7F 7F 01 7F 60 01 7F 01
7F 60 00 01 7F 03 0E 0D 00 01 01 01 01 01 01 01
01 02 03 04 04 04 05 01 70 01 01 01 05 03 01 00
02 06 15 03 7F 01 41 D0 89 04 0B 7F 00 41 D0 89
 
...
 
00 00 00 83 01 04 6E 61 6D 65 01 7C 0D 00 11 5F
5F 77 61 73 6D 5F 63 61 6C 6C 5F 63 74 6F 72 73
01 01 6F 02 02 6F 6F 03 03 6F 6F 6F 04 04 6F 6F
6F 6F 05 05 6F 6F 6F 6F 6F 06 06 6F 6F 6F 6F 6F
6F 07 07 6F 6F 6F 6F 6F 6F 6F 08 08 6F 6F 6F 6F
6F 6F 6F 6F 09 0E 73 65 74 5F 69 6E 70 75 74 5F
66 6C 61 67 0A 12 73 65 74 5F 69 6E 70 75 74 5F
66 6C 61 67 5F 6C 65 6E 0B 09 63 68 65 63 6B 5F
6B 65 79 0C 03 78 78 78
`.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;

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

上传的附件:
收藏
免费 4
支持
分享
最新回复 (2)
雪    币: 11
活跃值: (1846)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
Amazing , Thanks
2024-1-20 01:14
0
雪    币: 3004
活跃值: (30866)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
感谢分享
2024-1-20 21:43
1
游客
登录 | 注册 方可回帖
返回
//