TSCTF-J 2024 部分题目复现(未完结)
iPlayBingo:
F12拿到answerCheck.wasm文件,同时观察js代码找到关键函数Check()
利用Wabt将answerCheck.wasm文件转为answerCheck.c和answerCheck.h文件,但此时可读性依然较差。用gcc链接成answerCheck.o文件,此时可以使用IDA反汇编。
关键的函数w2c_answerChecker_check_0()
__int64 __fastcall w2c_answerChecker_check_0(
unsigned int *a1,
int a2,
unsigned __int64 a3,
unsigned __int64 a4,
unsigned __int64 a5,
__int64 a6,
__int64 a7,
__int64 a8,
__int64 a9,
__int64 a10)
{
_DWORD *address; // rax
int v11; // eax
int v12; // eax
_DWORD *v13; // rax
unsigned int v15; // [rsp+4Ch] [rbp-34h]
unsigned int v16; // [rsp+4Ch] [rbp-34h]
int v17; // [rsp+58h] [rbp-28h]
int v18; // [rsp+58h] [rbp-28h]
unsigned int v19; // [rsp+5Ch] [rbp-24h]
unsigned int v20; // [rsp+60h] [rbp-20h]
unsigned int v21; // [rsp+64h] [rbp-1Ch]
bool v22; // [rsp+64h] [rbp-1Ch]
bool v23; // [rsp+64h] [rbp-1Ch]
bool v24; // [rsp+64h] [rbp-1Ch]
bool v25; // [rsp+64h] [rbp-1Ch]
bool v26; // [rsp+64h] [rbp-1Ch]
bool v27; // [rsp+64h] [rbp-1Ch]
unsigned __int8 v28; // [rsp+64h] [rbp-1Ch]
int v29; // [rsp+68h] [rbp-18h]
int v30; // [rsp+6Ch] [rbp-14h]
int v31; // [rsp+70h] [rbp-10h]
unsigned int v32; // [rsp+70h] [rbp-10h]
unsigned int v33; // [rsp+74h] [rbp-Ch]
int v34; // [rsp+74h] [rbp-Ch]
int v35; // [rsp+74h] [rbp-Ch]
int v36; // [rsp+74h] [rbp-Ch]
int v37; // [rsp+78h] [rbp-8h]
unsigned int v38; // [rsp+78h] [rbp-8h]
unsigned int v39; // [rsp+78h] [rbp-8h]
int i; // [rsp+78h] [rbp-8h]
unsigned int v41; // [rsp+7Ch] [rbp-4h]
unsigned int v42; // [rsp+7Ch] [rbp-4h]
unsigned int v43; // [rsp+7Ch] [rbp-4h]
unsigned int v46; // [rsp+98h] [rbp+18h]
unsigned int v47; // [rsp+98h] [rbp+18h]
int v48; // [rsp+98h] [rbp+18h]
v29 = 0;
address = (_DWORD *)_emutls_get_address(refptr___emutls_v_wasm_rt_call_stack_depth);
if ( ++*address > 0x1F4u )
wasm_rt_trap(9i64);
v20 = *a1 - 112;
*a1 = v20;
i32_store8(a1 + 2, v20 + 96i64, 0i64);
i64_store(a1 + 2, v20 + 88i64, a10);
i64_store(a1 + 2, v20 + 80i64, a9);
i64_store(a1 + 2, v20 + 72i64, a8);
i64_store(a1 + 2, v20 + 64i64, a7);
i64_store(a1 + 2, v20 + 48i64, a5);
i64_store(a1 + 2, v20 + 40i64, a4);
i64_store(a1 + 2, v20 + 32i64, a3);
i64_store(a1 + 2, v20 + 56i64, a6);
v41 = 1;
switch ( a2 )
{
case 7:
goto LABEL_27;
case 12:
v41 = 0;
v46 = v20 + 32;
if ( ((v20 + 32) & 3) == 0 )
goto LABEL_9;
v21 = 0;
if ( (unsigned int)i32_load8_u(a1 + 2, v46) )
{
while ( (++v46 & 3) != 0 )
{
if ( !(unsigned int)i32_load8_u(a1 + 2, v46) )
goto LABEL_11;
}
do
{
LABEL_9:
v33 = v46;
v46 += 4;
v37 = i32_load(a1 + 2, v33);
}
while ( ((v37 | (16843008 - v37)) & 0x80808080) == -2139062144 );
do
v46 = v33++;
while ( (unsigned int)i32_load8_u(a1 + 2, v46) );
LABEL_11:
v21 = v46 - (v20 + 32);
}
if ( v21 == 32 )
{
v17 = i32_load8_s(a1 + 2, v20 + 63i64);
v15 = (unsigned int)i32_load8_s(a1 + 2, v20 + 61i64) << 16;
v16 = ((unsigned int)i32_load8_u(a1 + 2, v20 + 60i64) << 24) | v15;
v11 = i32_load8_s(a1 + 2, v20 + 62i64);
i32_store(a1 + 2, v20 + 28i64, (v11 << 8) | v16 | v17);
i32_store(
a1 + 2,
v20 + 16i64,
((int)a5 >> 24) | (__int16)((int)a5 >> 8) & 0xFFFFFF00 | ((_DWORD)a5 << 24) | ((__int16)a5 << 8) & 0xFFFF0000);
i32_store(
a1 + 2,
v20 + 8i64,
((int)a4 >> 24) | (__int16)((int)a4 >> 8) & 0xFFFFFF00 | ((_DWORD)a4 << 24) | ((__int16)a4 << 8) & 0xFFFF0000);
i32_store(
a1 + 2,
v20,
((int)a3 >> 24) | (__int16)((int)a3 >> 8) & 0xFFFFFF00 | ((_DWORD)a3 << 24) | ((__int16)a3 << 8) & 0xFFFF0000);
v18 = i32_load8_s(a1 + 2, v20 + 59i64);
v12 = i32_load8_s(a1 + 2, v20 + 58i64);
i32_store(a1 + 2, v20 + 24i64, (v12 << 8) | ((_DWORD)a6 << 24) | ((__int16)a6 << 8) & 0xFFFF0000 | v18);
i32_store(
a1 + 2,
v20 + 20i64,
(SHIDWORD(a5) >> 24) | (a5 >> 8) & 0xFF000000 | ((int)(a5 >> 16) >> 8) & 0xFFFF0000 | ((int)(a5 >> 24) >> 16) & 0xFFFFFF00);
i32_store(
a1 + 2,
v20 + 12i64,
(SHIDWORD(a4) >> 24) | (a4 >> 8) & 0xFF000000 | ((int)(a4 >> 16) >> 8) & 0xFFFF0000 | ((int)(a4 >> 24) >> 16) & 0xFFFFFF00);
i32_store(
a1 + 2,
v20 + 4i64,
(SHIDWORD(a3) >> 24) | (a3 >> 8) & 0xFF000000 | ((int)(a3 >> 16) >> 8) & 0xFFFF0000 | ((int)(a3 >> 24) >> 16) & 0xFFFFFF00);
do //XXTEA_encode
{
v19 = 8 * v29 + v20;
v47 = i32_load(a1 + 2, v19);
v42 = i32_load(a1 + 2, v19 + 4i64);
v34 = 31;
v38 = 0;
do
{
v38 -= 1640531527;
v47 += (((v42 >> 3) ^ (32 * v42)) + ((v42 >> 4) ^ (4 * v42))) ^ ((v38 ^ v42)
+ (v42 ^ i32_load(
a1 + 2,
4 * ((v38 >> 2) & 3) + 1424)));
v42 += ((v38 ^ v47) + (i32_load(a1 + 2, 4 * ((v38 >> 2) & 3 ^ 1) + 1424) ^ v47)) ^ (((v47 >> 3) ^ (32 * v47))
+ ((v47 >> 4) ^ (4 * v47)));
v31 = v34--;
v30 = 0;
}
while ( v31 );
v35 = 0;
v39 = 0;
do //XTEA_encode
{
v47 += (v42 + ((v42 >> 5) ^ (16 * v42))) ^ (v39 + i32_load(a1 + 2, 4 * (v39 & 3) + 1424));
v39 -= 1640531527;
v42 += (v39 + i32_load(a1 + 2, ((v39 >> 9) & 0xC) + 1424)) ^ (v47 + ((v47 >> 5) ^ (16 * v47)));
++v35;
}
while ( v35 != 33 );
for ( i = 0; i != 32; ++i ) //TEA_Encode
{
v30 -= 1183238242;
v47 += (16 * v42 + 19088743) ^ ((v42 >> 5) - 1985229329) ^ (v42 + v30);//密钥
v42 += ((v47 >> 5) - 1161903906) ^ (v30 + v47) ^ (16 * v47 - 559038737);
}
i32_store(a1 + 2, v19 + 4i64, v42);
i32_store(a1 + 2, v19, v47);
++v29;
}
while ( v29 != 4 );//密文
v22 = (unsigned int)i32_load(a1 + 2, v20) == 1569711840;
v23 = (unsigned int)i32_load(a1 + 2, v20 + 4i64) == -1153260111 && v22;
v24 = (unsigned int)i32_load(a1 + 2, v20 + 8i64) == -92922495 && v23;
v25 = (unsigned int)i32_load(a1 + 2, v20 + 12i64) == 852271051 && v24;
v26 = (unsigned int)i32_load(a1 + 2, v20 + 16i64) == -40115131 && v25;
v27 = (unsigned int)i32_load(a1 + 2, v20 + 20i64) == 37303748 && v26;
v28 = (unsigned int)i32_load(a1 + 2, v20 + 24i64) == -352841794 && v27;
v41 = ((unsigned int)i32_load(a1 + 2, v20 + 28i64) == -449956141) & v28;
}
LABEL_27:
*a1 = v20 + 112;
v13 = (_DWORD *)_emutls_get_address(refptr___emutls_v_wasm_rt_call_stack_depth);
--*v13;
return v41;
default:
v32 = i32_load(a1 + 2, (unsigned int)(4 * a2 + 1312));
v48 = i32_load8_u(a1 + 2, v32);
v43 = v20 + 32;
v36 = i32_load8_u(a1 + 2, v20 + 32);
if ( v36 && v48 == v36 )
{
do
{
v48 = i32_load8_u(a1 + 2, v32 + 1i64);
v36 = i32_load8_u(a1 + 2, v43 + 1i64);
if ( !v36 )
break;
++v32;
++v43;
}
while ( v48 == v36 );
}
v41 = v48 == v36;
goto LABEL_27;
}
}
阅读完这个函数,很清晰的看出来依次使用了XXTEA,XTEA,TEA加密,同时看到一个while循环的检查函数,知道这就是密文。从hint中也可以得知,三个算法共享密钥,而最后的TEA加密清晰的给出了密钥。整理得到:
int enc[] = [ 1569711840, -1153260111, -92922495, 852271051, -40115131,
37303748, -352841794, -449956141]
int k[] ={ 19088743, -1985229329, -559038737, -1161903906 }
另外,观察三个加密算法,可以看出部分轮函数、Delta、轮数都被魔改了,所以用网上的解题脚本得稍微修改一下。
解题脚本详见Official_wp
iPlayCal
使用DIE查看
DIE告诉我们这是一个魔改UPX壳,所以upx -d不奏效。
打开x32dbg开始调试
F9运行到pushad部分,单步步过,找到右上角的ESP寄存器,下硬件访问断点
找到OEP,插件dump出来脱壳完毕
IDA点开,易见如下字符串:
Shellcode的本质就是16进制机器码
我们把他全部提取出来,用Base64解码,再把解码出来的16进制转成2进制文件(这样才可以使用IDA分析)
关于怎么转存为二进制文件:Ubuntu指令: echo <十六进制数据> | xxd -r -ps <二进制文件>
注意,使用IDA分析时,选择Binary File 以及metapc模式
看到这里得恶补一下密码学。从flag密文的形式来猜应该是用了某种变换将字符映射过去了。
Official_WP说这叫仿射密码,但没有细讲。所以我详细写一写
仿射密码是一种单表代换的对称密码。明文中所有字母对应成数值,经过加密函数加密成新的数值,再对应到相应的字母,组成密文, 密文和明文一样经过解密函数恢复成明文。
其中乘法逆元比较简单的是用扩展欧几里得算法求解。当然现在网上已经可以找到成熟的在线解密工具
输入密文以及key(a,b)就可以得到flag
(这里建议还是自己逆向算法写脚本,因为涉及大小写的问题)
标签:a1,v20,int,unsigned,rbp,2024,WP,TSCTF,rsp From: https://www.cnblogs.com/railgun666----/p/18437239