这一题很有迷惑性,设置了很多陷阱,看似正常的逻辑其实是假象。里面用到了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;
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!