首页
社区
课程
招聘
[原创]webassembly-1.使用ollvm和wasi-sdk混淆
发表于: 2024-2-25 07:07 3926

[原创]webassembly-1.使用ollvm和wasi-sdk混淆

2024-2-25 07:07
3926

标签: webassembly混淆


webassmebly作为新型平台越来越受到重视,其中WASM的混淆也尤为重要。本文介绍一种简单的混淆方法在ubuntu22.04下使用,并且使用wasi-sdk的类C库,混淆的WASM程序可以使用C库函数实现类似功能。

1. 下载ollvm并编译安装

原始的ollvm版本已经年久失修,跟不上新版本的开发,如果使用会遇到很多bug,这里我采用一个修改版的ollvm,
github地址:[Pluto-Obfuscator][1]

下载:
git clone https://github.com/xubenji/Pluto-Obfuscator
下载好以后需要编译安装,
进入项目目录,直接执行
bash build.sh
就可以编译安装ollvm了(确保机器中有编译工具,cmake,ninja-build,g++等),这里build.sh我已经修改好了,编译安装以后的ollvm支持编译C代码到WASM。

在/Pluto-Obfuscator/build/bin文件夹下就是编译好的工具。
进入此目录,使用编译好的clang将C文件编译为wasm,以下是编译命令:

1
2
3
/root/Pluto-Obfuscator/build/bin/clang \
             --target=wasm32 -nostdlib   -Wl,--no-entry\
        -Wl,--export-all        -g -O0 loop.c -o  loop.wasm

这个时候会出现以下错误:

1
2
clang-12: error: unable to execute command: Executable "wasm-ld" doesn't exist!
clang-12: error: linker command failed with exit code 1 (use -v to see invocation)

2. 拆解编译流程,使用wasi-sdk中的链接器

我们使用wasi-sdk中的clang编译此文件并且看看链接部分的命令是什么。
下载wasi-sdk:

1
2
wget https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-21/wasi-sdk-21.0-linux.tar.gz
tar -xzvf wasi-sdk-21.0-linux.tar.gz

loop.c内容如下:

1
2
3
4
5
6
7
8
9
10
int main(){
    int n1 = 10;
    int n2 = 20;
    if (n1 > 0){
        for(int i = 0; i < n2; i++){
            n1 += n2;
        }
    }
    return n1;
}

(其实函数名是不是main没有关系)
使用wasi-sdk中的clang和相同的命令编译loop.c,但是加上-v选项。

1
2
3
/root/wasi-sdk-21.0/bin/clang -v \
      --target=wasm32 -nostdlib   -Wl,--no-entry\
 -Wl,--export-all        -g -O0 loop.c -o  loop.wasm

运行后得到如下输出:

1
2
3
4
5
6
7
8
9
10
11
12
13
root@localhost:~# /root/wasi-sdk-21.0/bin/clang -v              --target=wasm32 -nostdlib   -Wl,--no-entry      -Wl,--export-all        -g -O0 loop.c -o  loop.wasm
clang version 17.0.6
Target: wasm32
Thread model: posix
InstalledDir: /root/wasi-sdk-21.0/bin
 "/root/wasi-sdk-21.0/bin/clang-17" -cc1 -triple wasm32 -emit-obj -mrelax-all -dumpdir loop.wasm- -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name loop.c -mrelocation-model static -mframe-pointer=none -ffp-contract=on -fno-rounding-math -mconstructor-aliases -target-cpu generic -fvisibility=hidden -debug-info-kind=constructor -dwarf-version=4 -debugger-tuning=gdb -v -fcoverage-compilation-dir=/root -resource-dir /root/wasi-sdk-21.0/lib/clang/17 -isysroot /root/wasi-sdk-21.0/bin/../share/wasi-sysroot -internal-isystem /root/wasi-sdk-21.0/lib/clang/17/include -internal-isystem /root/wasi-sdk-21.0/bin/../share/wasi-sysroot/include -O0 -fdebug-compilation-dir=/root -ferror-limit 19 -fgnuc-version=4.2.1 -fcolor-diagnostics -o /tmp/loop-34b990.o -x c loop.c
clang -cc1 version 17.0.6 based upon LLVM 17.0.6 default target wasm32-wasi
#include "..." search starts here:
#include <...> search starts here:
 /root/wasi-sdk-21.0/lib/clang/17/include
 /root/wasi-sdk-21.0/bin/../share/wasi-sysroot/include
End of search list.
 "/root/wasi-sdk-21.0/bin/wasm-ld" -m wasm32 -L/root/wasi-sdk-21.0/bin/../share/wasi-sysroot/lib --no-entry --export-all /tmp/loop-34b990.o -o loop.wasm

注意到这条命令就是链接命令:

1
"/root/wasi-sdk-21.0/bin/wasm-ld" -m wasm32 -L/root/wasi-sdk-21.0/bin/../share/wasi-sysroot/lib --no-entry --export-all /tmp/loop-34b990.o -o loop.wasm

因为编译安装的clang中没有设置wasm-ld的地址,所以clang找不到链接器,一种办法是设置环境变量,一种办法是直接使用wasi-sdk中的链接器,有一些版本的clang可能会提示找不到wasm-ld-14,wasm-ld-13等等,考虑到这种情况设置环境变量可能不太好,直接独立使用sdk中的wasm-ld会更好。
所以我们修改一下链接命令得到如下:

1
"/root/wasi-sdk-21.0/bin/wasm-ld" -m wasm32 -L/root/wasi-sdk-21.0/bin/../share/wasi-sysroot/lib --no-entry --export-all /root/loop.o -o /root/loop.wasm

编译命令也要先编译为.o文件才行:
这是修改后的编译命令:

1
2
3
/root/Pluto-Obfuscator/build/bin/clang \
             --target=wasm32 -nostdlib   -Wl,--no-entry\
        -Wl,--export-all        -g -O0 loop.c -c -o  loop.o

整合到一起就能编译loop.c到loop.wasm了。
使用runtime运行loop.wasm, 得不到任何结果,因为我们没有一些输出信息, 但是加入标准库以后clang会提示找不到c库。

1
2
root@localhost:~/wasmtime-v17.0.1-x86_64-linux# ./wasmtime /root/loop.wasm
root@localhost:~/wasmtime-v17.0.1-x86_64-linux#

3. 使用wasi-sdk中模拟的标准C库输出信息,并开启混淆

在loop.c中加入打印代码:

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
int main(){
    printf("hello world\n");
    int n1 = 10;
    int n2 = 20;
    if (n1 > 0){
        for(int i = 0; i < n2; i++){
            n1 += n2;
        }
    }
    return 0;
}

编译这个C文件需要指定C库的地址,使用wasi-sdk中的clang编译文件命令如下:

1
root@localhost:~/wasi-sdk-21.0/bin# ./clang -O0  --target=wasm32-wasi --sysroot=/root/wasi-sdk-21.0/share/wasi-sysroot/ /root/loop.c  -o /root/loop.wasm

同上我们使用-v选项查看整个链接过程,得到如下信息:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
root@localhost:~/wasi-sdk-21.0/bin#  ./clang -v -O0 --target=wasm32-wasi --sysroot=/root/wasi-sdk-21.0/share/wasi-sysroot/ /root/loop.c  -o /root/loop.wasm
clang version 17.0.6
Target: wasm32-unknown-wasi
Thread model: posix
InstalledDir: /root/wasi-sdk-21.0/bin/.
 "/root/wasi-sdk-21.0/bin/clang-17" -cc1 -triple wasm32-unknown-wasi -emit-obj -mrelax-all -dumpdir /root/loop.wasm- -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name loop.c -mrelocation-model static -mframe-pointer=none -ffp-contract=on -fno-rounding-math -mconstructor-aliases -target-cpu generic -fvisibility=hidden -debugger-tuning=gdb -v -fcoverage-compilation-dir=/root/wasi-sdk-21.0/bin -resource-dir /root/wasi-sdk-21.0/lib/clang/17 -isysroot /root/wasi-sdk-21.0/share/wasi-sysroot/ -internal-isystem /root/wasi-sdk-21.0/lib/clang/17/include -internal-isystem /root/wasi-sdk-21.0/share/wasi-sysroot//include/wasm32-wasi -internal-isystem /root/wasi-sdk-21.0/share/wasi-sysroot//include -fdebug-compilation-dir=/root/wasi-sdk-21.0/bin -ferror-limit 19 -fgnuc-version=4.2.1 -fcolor-diagnostics -o /tmp/loop-c1b686.o -x c /root/loop.c
clang -cc1 version 17.0.6 based upon LLVM 17.0.6 default target wasm32-wasi
ignoring nonexistent directory "/root/wasi-sdk-21.0/share/wasi-sysroot//include/wasm32-wasi"
#include "..." search starts here:
#include <...> search starts here:
 /root/wasi-sdk-21.0/lib/clang/17/include
 /root/wasi-sdk-21.0/share/wasi-sysroot//include
End of search list.
 "/root/wasi-sdk-21.0/bin/./wasm-ld" -m wasm32 -L/root/wasi-sdk-21.0/share/wasi-sysroot//lib/wasm32-wasi /root/wasi-sdk-21.0/share/wasi-sysroot//lib/wasm32-wasi/crt1-command.o /tmp/loop-c1b686.o -lc /root/wasi-sdk-21.0/lib/clang/17/lib/wasi/libclang_rt.builtins-wasm32.a -o /root/loop.wasm

使用ollvm中的clang先将文件编译为。o文件,然后链接为wasm文件。

1
2
3
/root/Pluto-Obfuscator/build/bin/clang -O0 --target=wasm32-wasi --sysroot=/root/wasi-sdk-21.0/share/wasi-sysroot/ loop.c -c -o loop.o
 
"/root/wasi-sdk-21.0/bin/./wasm-ld" -m wasm32 -L/root/wasi-sdk-21.0/share/wasi-sysroot//lib/wasm32-wasi /root/wasi-sdk-21.0/share/wasi-sysroot//lib/wasm32-wasi/crt1-command.o /root/loop.o -lc /root/wasi-sdk-21.0/lib/clang/17/lib/wasi/libclang_rt.builtins-wasm32.a -o /root/loop.wasm

使用wasmtime运行如下:

1
2
root@localhost:~/wasmtime-v17.0.1-x86_64-linux# ./wasmtime /root/loop.wasm
hello world

这样我们就可以开启ollvm flattning混淆了,命令如下:

1
/root/Pluto-Obfuscator/build/bin/clang -mllvm -fla -O0 --target=wasm32-wasi --sysroot=/root/wasi-sdk-21.0/share/wasi-sysroot/ loop.c -c -o loop.o

混淆前的loop.wasm和混淆后的loop_fla.wasm在ghidra中对比效果:
loop.wasm(未混淆):

loop_fla.wasm(已混淆):

ollvm中有许多其他混淆选项也可以试试~
[1]: https://github.com/xubenji/Pluto-Obfuscator


[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

最后于 2024-2-25 07:23 被北美老徐编辑 ,原因: 更改小标题
收藏
免费 1
支持
分享
最新回复 (1)
雪    币: 3070
活跃值: (30876)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
感谢分享
2024-2-26 10:02
1
游客
登录 | 注册 方可回帖
返回
//