'); }

2021蓝帽杯_calc


0x1

第一次接触到wasm,又是被装环境ex到的一天,跟着官方README.md安装都给我报错了,做实离谱,自己添加了一些参数才下载完;之后就开始去学习wasm逆向知识。学到了一些有关Chrome调试的操作。

正好极客大挑战出了一个xorwasm,真的舒坦,直接平稳过渡。

0x2

打开zip,得到三个文件,一个html,一个js,一个wasm,标准的wasm三件套。

个人处理方式

  1. 先获得能被ida反编译且可读性较高的文件,通过ida分析大致操作,
  2. 如果简单就直接推出flag,反之通过Chrome调试去分析,通过设置断点,多次调试确定判断位置,动调分析。

wasm2c下载后,通过wasm2c将wasm转换成.c文件和.h文件(进入到calc目录

[wasm2c目录] [文件名.wasm] -o [转换后的文件名.c]

image-20211105234430714

虽然获得的.c文件已经可以分析了,但是分析起来还是比较难受,可以进一步优化一下,将转换出来的两个文件和wasm-rt.h,wasm-rt-impl.c,wasm-rt-impl.h放在一起

后面三个文件在下载的工具wabt/wasm2c文件夹中

image-20211106001815486

进入到文件夹,通过gcc编译将.c文件进一步转换为.o文件,提高反汇编后的可读性。

gcc -c wasm.c -o calc.o

image-20211106002352011

这样就会获得一个.o文件,这时候拖入ida进行反编译。

在init_memory发现这一串数据,肯定是有用的,先留着

image-20211106201412298

找主函数ing…

__int64 (__fastcall *init_exports())()
{
  __int64 (__fastcall *result)(); // rax

  Z_e = (__int64)&w2c_e;
  Z_fZ_vv = (__int64)w2c_f;
  Z_gZ_iii = (__int64)w2c_g;
  Z_hZ_ii = (__int64)w2c_h;
  Z_i = (__int64)&w2c_i;
  Z_jZ_iv = (__int64)w2c_j;
  Z_kZ_vi = (__int64)w2c_k;
  result = w2c_l;
  Z_lZ_ii = (__int64)w2c_l;
  return result;
}

在这里面函数挨个看了一下,最可疑的就是为w2c_h函数

_BOOL8 __fastcall w2c_h(unsigned int a1)
{
  unsigned int v1; // eax
  int v3; // [rsp+Ch] [rbp-14h]
  unsigned int v4; // [rsp+10h] [rbp-10h]

  if ( ++wasm_rt_call_stack_depth > 0x1F4u )
    wasm_rt_trap(7LL);
  w2c_g0 -= 128;
  v4 = w2c_g0;
  w2c_f81(a1, (unsigned int)w2c_g0);
  v3 = w2c_f45(v4);
  if ( v3 )
    v1 = 0x43D;
  else
    v1 = 0x435;
  w2c_f29(v1);
  w2c_g0 = v4 + 128;
  --wasm_rt_call_stack_depth;
  return v3 == 0;
}

0x400多的数一般是字符串的偏移量(忘记在哪里看到的知识点了,可能有错

image-20211106161109667

0x31EE0-0x400+0x43D=0x31F1D

正好对应字符串”Oops….something wrong”

并且在w2c_f81函数中找到了0x421,按照上面的计算方法对应着”length is not valid”,基本确定上面就是主函数

image-20211106201637526

主函数内的大致:输值,判断长度,加密,比较,打印正确或者错误。

之后进行动调

动调需要使用浏览器调试,先在本地起一个简易的服务器

先进入需要调试文件的文件夹

python -m http.server -b localhost

image-20211106163324069

然后在浏览器输入网址:

http://localhost:8000/calc.html

F12,选择Sources,在calc.html判断位置下断

image-20211106164157265

递步后会跑到calc.wasm中,在calc.wasm设置断点多次调试确定使用位置

image-20211106164621792

当运行过func29后,屏幕会显示字符串,再根据之前ida查看的内容,基本可以推测出,func81为加密函数,func45为比较函数,func29则为输出函数。其中参数var0用于判断,var1为我们输入的数据。

可以在调试器右上角的watch中设置这两个参数,用于查看内容

image-20211106165018113

不知道为什么

为了更好的理解中间加密过程,从大师傅写的wp那里获得了一个js脚本,用于分析输入值的变化。

第一次只输入一个值A

image-20211106170453109

第二次输入两个值AA

image-20211106170724319

这里值需要颠倒一下顺序,我卡在这里了好久….

以此类推,可以得到规律

flag[0] | flag[1]<<7 | flag[2]<<14 ....

根据上面ida获取的数据写脚本

cmp_data = [0xF3, 0x39, 0x4C, 0x3A, 0xFE, 0xE6, 0x63, 0xE2, 0xF6, 0x6C, 0x3E, 0x0F, 0x8B, 0x67, 0x77][::-1]
s = ''.join(bin(a)[2:].zfill(8) for a in cmp_data)[1:]
for i in range(0, len(s), 7):
    print(chr(int(s[i:i+7], 2)), end='')

直接引用的大佬的wp脚本,关于python写脚本的知识点++

得到flag:

flag{w3bass3mb1y_cR0ss}

  目录