本期及往期题目附件均已上传至 github,欢迎大家下载学习
https://github.com/Lucien-404/CTF-AWDP-Attachments
看到 vm 心里就有种不详的预感,感觉这种题目只有 ai 能做出来
附件概览
解压一下看到两个文件

估计 vm-encryptor.exe 会加载 code.bin,用自定义的指令集去解释执行里面的二进制字节码
用 010 editor 看一下 code.bin,在末尾(可能类似于 data 段)发现了一些可读的字符串

有明显的成功或失败的提示,还有 base64 的字符表,可以猜测用到了 base64 编码
逆向分析
vm-encryptor.exe
用 ida 打开 vm-encryptor.exe,通过字符串搜索定位到关键函数 sub_140001000()
// positive sp value has been detected, the output may be wrong!
__int64 __fastcall sub_140001000(int a1, __int64 a2)
{
FILE *v4; // rax
constchar *v5; // rcx
size_t v6; // rdx
__int64 v7; // rsi
FILE *v8; // rax
size_t v9; // rax
__int64 v10; // r8
bool v11; // zf
__int64 result; // rax
FILE *v13; // rax
FILE *v14; // rax
_BYTE v15[4108]; // [rsp+2Ch] [rbp-54h] BYREF
_OWORD v16[4864]; // [rsp+1038h] [rbp+FB8h] BYREF
int v17; // [rsp+1403Ch] [rbp+13FBCh]
char Buffer[136]; // [rsp+14040h] [rbp+13FC0h] BYREF
_QWORD v19[3]; // [rsp+140C8h] [rbp+14048h] BYREF
sub_140002420();
v19[0] = 0;
if ( a1 <= 1 )
{
v4 = __acrt_iob_func(2u);
v5 = "usage: vm-encryptor.exe <program.bin>\n";
v6 = 38;
LABEL_3:
fwrite(v5, v6, 1u, v4);
return1;
}
v7 = *(_QWORD *)(a2 + 8);
((void (__fastcall *)(_BYTE *))sub_140001190)(v15);
if ( !(unsignedint)((__int64 (__fastcall *)(_BYTE *, __int64, _QWORD *))sub_1400011B0)(v15, v7, v19) )
{
v14 = __acrt_iob_func(2u);
sub_140002C70(v14, "failed to load %s\n");
return1;
}
sub_140002CC0("Input Flag: ");
v8 = __acrt_iob_func(0);
if ( !fgets(Buffer, 128, v8) )
{
v17 = 6;
v4 = __acrt_iob_func(2u);
v5 = "failed to read input\n";
v6 = 21;
goto LABEL_3;
}
v9 = strcspn(Buffer, "\r\n");
v10 = 42;
if ( v9 < 0x2A )
v10 = v9;
memset(v16, 0, 43);
((void (__fastcall *)(_OWORD *, char *, __int64))sub_1400215B0)(v16, Buffer, v10);
v11 = (unsignedint)((__int64 (__fastcall *)(_BYTE *))sub_140001270)(v15) == 0;
result = 0;
if ( v11 )
{
v13 = __acrt_iob_func(2u);
sub_140002C70(v13, "vm error: %d\n");
return1;
}
return result;
}
首先看到了这个程序的用法是 vm-encryptor.exe <program.bin>,来尝试一下

看来之前的猜测是对的,vm-encryptor.exe 就是一个解释器,真正的校验逻辑还是在 code.bin 中
不过要读懂 code.bin,前提是要明确解释器的机制,所以我们继续来看伪代码
一个虚拟机程序运行一般需要三个步骤
sub_140001190() | ||
sub_1400011B0() | ||
switch-case 分发器实现 | sub_140001270() |
我们需要重点关注的是 vm_execute,也就是 sub_140001270() 函数
__int64 __fastcall sub_140001270(int *a1)
{
int v2; // r14d
__int64 v3; // rax
unsignedint v4; // ecx
__int64 v5; // rax
unsignedint v6; // edx
__int64 v7; // rcx
BOOL v8; // r8d
unsignedint v9; // eax
__int64 v10; // rcx
unsignedint v11; // edx
__int64 v12; // r8
unsignedint v13; // r9d
unsignedint v14; // ecx
unsignedint v15; // edx
unsignedint v16; // eax
__int64 v17; // rcx
unsignedint v18; // edx
__int64 v19; // rax
int v20; // edx
unsignedint v21; // ecx
unsignedint v22; // edx
unsignedint v23; // edx
__int64 v24; // rax
unsignedint v25; // ecx
__int64 v26; // rdx
unsignedint v27; // r8d
unsigned __int64 v28; // rax
__int64 v29; // rcx
int v30; // ecx
unsignedint v31; // eax
__int64 v32; // rcx
__int64 v33; // rcx
unsignedint v34; // eax
unsignedint v35; // ecx
unsignedint v36; // edx
unsignedint v37; // eax
__int64 v38; // rcx
unsignedint v39; // edx
unsignedint v40; // eax
unsignedint v41; // r8d
unsignedint v42; // ecx
__int64 v43; // r8
unsignedint v44; // r9d
__int64 v45; // rcx
int v46; // eax
unsignedint v47; // eax
__int64 v48; // rcx
unsigned __int64 v49; // rdx
int v50; // edx
unsigned __int64 v51; // rcx
unsignedint v52; // edx
unsignedint v53; // eax
__int64 v54; // rax
int v55; // ecx
unsignedint v56; // eax
__int64 v57; // rcx
__int64 v58; // rcx
unsignedint v59; // eax
unsigned __int64 v60; // rdx
unsignedint v61; // eax
unsignedint v62; // edx
unsignedint v63; // eax
unsignedint v64; // eax
unsignedint v65; // edx
unsignedint v66; // edx
unsignedint v67; // ecx
unsignedint v68; // eax
unsignedint v69; // edx
unsignedint v70; // ecx
__int64 v71; // r8
unsignedint v72; // r9d
unsignedint v73; // ecx
unsignedint v74; // edx
unsignedint v75; // eax
unsignedint v76; // edx
int v77; // ecx
unsignedint v78; // ecx
unsignedint v79; // edx
unsignedint v80; // eax
__int64 v81; // rax
unsigned __int64 v82; // r15
int v83; // ecx
unsignedint v84; // eax
__int64 v85; // rax
unsignedint v86; // eax
__int64 v87; // rax
unsigned __int64 v88; // rdx
a1[20483] = 1;
while ( 2 )
{
v2 = 1;
v3 = (unsignedint)*a1;
switch ( *((_BYTE *)a1 + v3 + 12) )
{
case0:
if ( (unsignedint)(v3 + 1) < 0xFFFD )
{
*a1 = *((unsigned __int8 *)a1 + (unsignedint)(v3 + 1) + 12)
| (*((unsigned __int8 *)a1 + (unsignedint)(v3 + 2) + 12) << 8)
| (*((unsigned __int8 *)a1 + (unsignedint)(v3 + 3) + 12) << 16)
| (*((unsigned __int8 *)a1 + (unsignedint)(v3 + 4) + 12) << 24);
}
else
{
*(_QWORD *)(a1 + 20483) = 0x400000000LL;
*a1 = 0;
}
goto LABEL_145;
case1:
if ( (unsignedint)(v3 + 1) < 0xFFFD )
{
v55 = *((unsigned __int8 *)a1 + (unsignedint)(v3 + 1) + 12)
| (*((unsigned __int8 *)a1 + (unsignedint)(v3 + 2) + 12) << 8)
| (*((unsigned __int8 *)a1 + (unsignedint)(v3 + 3) + 12) << 16)
| (*((unsigned __int8 *)a1 + (unsignedint)(v3 + 4) + 12) << 24);
}
else
{
*(_QWORD *)(a1 + 20483) = 0x400000000LL;
v55 = 0;
}
*a1 = v3 + 5;
v86 = a1[1];
if ( !v86 )
goto LABEL_149;
v87 = v86 - 1;
a1[1] = v87;
if ( !a1[v87 + 16387] )
goto LABEL_128;
goto LABEL_145;
case2:
if ( (unsignedint)(v3 + 1) < 0xFFFD )
{
v55 = *((unsigned __int8 *)a1 + (unsignedint)(v3 + 1) + 12)
| (*((unsigned __int8 *)a1 + (unsignedint)(v3 + 2) + 12) << 8)
| (*((unsigned __int8 *)a1 + (unsignedint)(v3 + 3) + 12) << 16)
| (*((unsigned __int8 *)a1 + (unsignedint)(v3 + 4) + 12) << 24);
}
else
{
*(_QWORD *)(a1 + 20483) = 0x400000000LL;
v55 = 0;
}
*a1 = v3 + 5;
v84 = a1[1];
if ( !v84 )
goto LABEL_149;
v85 = v84 - 1;
a1[1] = v85;
if ( !a1[v85 + 16387] )
goto LABEL_145;
LABEL_128:
*a1 = v55;
goto LABEL_145;
case3:
v51 = (unsignedint)a1[1];
if ( v51 > 0xFFF )
goto LABEL_148;
v52 = *((unsigned __int8 *)a1 + (unsignedint)(v3 + 1) + 12);
a1[1] = v51 + 1;
a1[v51 + 16387] = v52;
*a1 = v3 + 2;
goto LABEL_145;
case4:
if ( (unsignedint)(v3 + 1) < 0xFFFD )
{
v30 = *((unsigned __int8 *)a1 + (unsignedint)(v3 + 1) + 12)
| (*((unsigned __int8 *)a1 + (unsignedint)(v3 + 2) + 12) << 8)
| (*((unsigned __int8 *)a1 + (unsignedint)(v3 + 3) + 12) << 16)
| (*((unsigned __int8 *)a1 + (unsignedint)(v3 + 4) + 12) << 24);
}
else
{
*(_QWORD *)(a1 + 20483) = 0x400000000LL;
v30 = 0;
}
*a1 = v3 + 5;
v28 = (unsignedint)a1[1];
if ( v28 <= 0xFFF )
goto LABEL_132;
goto LABEL_148;
case5:
*a1 = v3 + 1;
v47 = a1[1];
if ( !v47 )
goto LABEL_149;
v48 = v47 - 1;
a1[1] = v48;
v60 = (unsignedint)a1[v48 + 16387];
if ( v60 > 0xFFFF )
goto LABEL_150;
if ( (unsignedint)v48 > 0xFFF )
goto LABEL_148;
v50 = *((unsigned __int8 *)a1 + v60 + 12);
goto LABEL_138;
case6:
*a1 = v3 + 1;
v47 = a1[1];
if ( !v47 )
goto LABEL_149;
v48 = v47 - 1;
a1[1] = v48;
v49 = (unsignedint)a1[v48 + 16387];
if ( v49 < 0xFFFD )
{
v50 = *(unsigned __int16 *)((char *)a1 + v49 + 12)
| (*((unsigned __int8 *)a1 + v49 + 14) << 16)
| (*((unsigned __int8 *)a1 + v49 + 15) << 24);
}
else
{
*(_QWORD *)(a1 + 20483) = 0x400000000LL;
v50 = 0;
}
if ( (unsignedint)v48 <= 0xFFF )
goto LABEL_138;
goto LABEL_148;
case7:
*a1 = v3 + 1;
v63 = a1[1];
if ( !v63 )
goto LABEL_149;
a1[1] = v63 - 1;
goto LABEL_145;
case8:
*a1 = v3 + 1;
v31 = a1[1];
v2 = 3;
if ( !v31 )
goto LABEL_151;
v32 = v31 - 1;
a1[1] = v32;
if ( v31 == 1 )
goto LABEL_151;
v33 = (unsignedint)a1[v32 + 16387];
v34 = v31 - 2;
a1[1] = v34;
if ( (unsignedint)v33 > 0xFFFF )
goto LABEL_150;
*((_BYTE *)a1 + v33 + 12) = a1[v34 + 16387];
goto LABEL_145;
case9:
*a1 = v3 + 1;
v56 = a1[1];
v2 = 3;
if ( !v56 )
goto LABEL_151;
v57 = v56 - 1;
a1[1] = v57;
if ( v56 == 1 )
goto LABEL_151;
v58 = (unsignedint)a1[v57 + 16387];
v59 = v56 - 2;
a1[1] = v59;
if ( (unsignedint)v58 <= 0xFFFC )
{
*(int *)((char *)a1 + v58 + 12) = a1[v59 + 16387];
LABEL_145:
if ( a1[20484] )
return0;
if ( !a1[20483] )
return1;
continue;
}
LABEL_150:
v2 = 4;
LABEL_151:
a1[20484] = v2;
a1[20483] = 0;
return0;
case0xA:
*a1 = v3 + 1;
v68 = a1[1];
v2 = 3;
if ( !v68 )
goto LABEL_151;
v17 = v68 - 1;
a1[1] = v17;
if ( v68 == 1 )
goto LABEL_151;
v69 = a1[v17 + 16387];
LODWORD(v19) = v68 - 2;
a1[1] = v19;
if ( (unsignedint)v19 > 0xFFF )
goto LABEL_148;
v19 = (unsignedint)v19;
v20 = a1[(unsignedint)v19 + 16387] + v69;
goto LABEL_107;
case0xB:
*a1 = v3 + 1;
v37 = a1[1];
v2 = 3;
if ( !v37 )
goto LABEL_151;
v38 = v37 - 1;
a1[1] = v38;
if ( v37 == 1 )
goto LABEL_151;
v39 = a1[v38 + 16387];
v40 = v37 - 2;
a1[1] = v40;
if ( v40 > 0xFFF )
goto LABEL_148;
v41 = a1[v40 + 16387] - v39;
a1[1] = v38;
a1[v40 + 16387] = v41;
goto LABEL_145;
case0xC:
*a1 = v3 + 1;
v61 = a1[1];
v2 = 3;
if ( !v61 )
goto LABEL_151;
v17 = v61 - 1;
a1[1] = v17;
if ( v61 == 1 )
goto LABEL_151;
v62 = a1[v17 + 16387];
LODWORD(v19) = v61 - 2;
a1[1] = v19;
if ( (unsignedint)v19 > 0xFFF )
goto LABEL_148;
v19 = (unsignedint)v19;
v20 = a1[(unsignedint)v19 + 16387] * v62;
goto LABEL_107;
case0xD:
*a1 = v3 + 1;
v42 = a1[1];
v2 = 3;
if ( !v42 )
goto LABEL_151;
v43 = v42 - 1;
a1[1] = v43;
if ( v42 == 1 )
goto LABEL_151;
v44 = a1[v43 + 16387];
v45 = v42 - 2;
a1[1] = v45;
if ( v44 )
{
v46 = a1[v45 + 16387] / v44;
if ( (unsignedint)v45 > 0xFFF )
goto LABEL_148;
}
else
{
*(_QWORD *)(a1 + 20483) = 0x500000000LL;
v46 = 0;
if ( (unsignedint)v45 > 0xFFF )
goto LABEL_148;
}
a1[1] = v43;
a1[v45 + 16387] = v46;
goto LABEL_145;
case0xE:
*a1 = v3 + 1;
v70 = a1[1];
v2 = 3;
if ( !v70 )
goto LABEL_151;
v71 = v70 - 1;
a1[1] = v71;
if ( v70 == 1 )
goto LABEL_151;
v72 = a1[v71 + 16387];
v48 = v70 - 2;
a1[1] = v48;
if ( v72 )
{
v50 = a1[v48 + 16387] % v72;
if ( (unsignedint)v48 > 0xFFF )
goto LABEL_148;
}
else
{
*(_QWORD *)(a1 + 20483) = 0x500000000LL;
v50 = 0;
if ( (unsignedint)v48 > 0xFFF )
{
LABEL_148:
v2 = 2;
goto LABEL_151;
}
}
a1[1] = v71;
LABEL_144:
a1[v48 + 16387] = v50;
goto LABEL_145;
case0xF:
*a1 = v3 + 1;
v64 = a1[1];
v2 = 3;
if ( !v64 )
goto LABEL_151;
v17 = v64 - 1;
a1[1] = v17;
if ( v64 == 1 )
goto LABEL_151;
v65 = a1[v17 + 16387];
LODWORD(v19) = v64 - 2;
a1[1] = v19;
if ( (unsignedint)v19 > 0xFFF )
goto LABEL_148;
v19 = (unsignedint)v19;
v20 = a1[(unsignedint)v19 + 16387] & v65;
goto LABEL_107;
case0x10:
*a1 = v3 + 1;
v75 = a1[1];
v2 = 3;
if ( !v75 )
goto LABEL_151;
v17 = v75 - 1;
a1[1] = v17;
if ( v75 == 1 )
goto LABEL_151;
v76 = a1[v17 + 16387];
LODWORD(v19) = v75 - 2;
a1[1] = v19;
if ( (unsignedint)v19 > 0xFFF )
goto LABEL_148;
v19 = (unsignedint)v19;
v20 = a1[(unsignedint)v19 + 16387] | v76;
goto LABEL_107;
case0x11:
*a1 = v3 + 1;
v47 = a1[1];
if ( !v47 )
goto LABEL_149;
LODWORD(v48) = v47 - 1;
a1[1] = v47 - 1;
if ( v47 - 1 > 0xFFF )
goto LABEL_148;
v48 = (unsignedint)v48;
v50 = ~a1[(unsignedint)v48 + 16387];
LABEL_138:
a1[1] = v47;
goto LABEL_144;
case0x12:
*a1 = v3 + 1;
v16 = a1[1];
v2 = 3;
if ( !v16 )
goto LABEL_151;
v17 = v16 - 1;
a1[1] = v17;
if ( v16 == 1 )
goto LABEL_151;
v18 = a1[v17 + 16387];
LODWORD(v19) = v16 - 2;
a1[1] = v19;
if ( (unsignedint)v19 > 0xFFF )
goto LABEL_148;
v19 = (unsignedint)v19;
v20 = a1[(unsignedint)v19 + 16387] ^ v18;
LABEL_107:
a1[1] = v17;
a1[v19 + 16387] = v20;
goto LABEL_145;
case0x13:
*a1 = v3 + 1;
v66 = a1[1];
v2 = 3;
if ( !v66 )
goto LABEL_151;
v24 = v66 - 1;
a1[1] = v24;
if ( v66 == 1 )
goto LABEL_151;
v67 = a1[v24 + 16387];
LODWORD(v26) = v66 - 2;
a1[1] = v26;
if ( (unsignedint)v26 > 0xFFF )
goto LABEL_148;
v26 = (unsignedint)v26;
v27 = a1[(unsignedint)v26 + 16387] << v67;
goto LABEL_83;
case0x14:
*a1 = v3 + 1;
v23 = a1[1];
v2 = 3;
if ( !v23 )
goto LABEL_151;
v24 = v23 - 1;
a1[1] = v24;
if ( v23 == 1 )
goto LABEL_151;
v25 = a1[v24 + 16387];
LODWORD(v26) = v23 - 2;
a1[1] = v26;
if ( (unsignedint)v26 > 0xFFF )
goto LABEL_148;
v26 = (unsignedint)v26;
v27 = (unsignedint)a1[(unsignedint)v26 + 16387] >> v25;
LABEL_83:
a1[1] = v24;
a1[v26 + 16387] = v27;
goto LABEL_145;
case0x15:
case0x16:
*a1 = v3 + 1;
v4 = a1[1];
v2 = 3;
if ( !v4 )
goto LABEL_151;
v5 = v4 - 1;
a1[1] = v5;
if ( v4 == 1 )
goto LABEL_151;
v6 = a1[v5 + 16387];
LODWORD(v7) = v4 - 2;
a1[1] = v7;
if ( (unsignedint)v7 > 0xFFF )
goto LABEL_148;
v7 = (unsignedint)v7;
v8 = a1[(unsignedint)v7 + 16387] == v6;
goto LABEL_114;
case0x17:
*a1 = v3 + 1;
v73 = a1[1];
v2 = 3;
if ( !v73 )
goto LABEL_151;
v5 = v73 - 1;
a1[1] = v5;
if ( v73 == 1 )
goto LABEL_151;
v74 = a1[v5 + 16387];
LODWORD(v7) = v73 - 2;
a1[1] = v7;
if ( (unsignedint)v7 > 0xFFF )
goto LABEL_148;
v7 = (unsignedint)v7;
v8 = a1[(unsignedint)v7 + 16387] != v74;
goto LABEL_114;
case0x18:
*a1 = v3 + 1;
v14 = a1[1];
v2 = 3;
if ( !v14 )
goto LABEL_151;
v5 = v14 - 1;
a1[1] = v5;
if ( v14 == 1 )
goto LABEL_151;
v15 = a1[v5 + 16387];
LODWORD(v7) = v14 - 2;
a1[1] = v7;
if ( (unsignedint)v7 > 0xFFF )
goto LABEL_148;
v7 = (unsignedint)v7;
v8 = a1[(unsignedint)v7 + 16387] < v15;
goto LABEL_114;
case0x19:
*a1 = v3 + 1;
v21 = a1[1];
v2 = 3;
if ( !v21 )
goto LABEL_151;
v5 = v21 - 1;
a1[1] = v5;
if ( v21 == 1 )
goto LABEL_151;
v22 = a1[v5 + 16387];
LODWORD(v7) = v21 - 2;
a1[1] = v7;
if ( (unsignedint)v7 > 0xFFF )
goto LABEL_148;
v7 = (unsignedint)v7;
v8 = a1[(unsignedint)v7 + 16387] > v22;
goto LABEL_114;
case0x1A:
*a1 = v3 + 1;
v35 = a1[1];
v2 = 3;
if ( !v35 )
goto LABEL_151;
v5 = v35 - 1;
a1[1] = v5;
if ( v35 == 1 )
goto LABEL_151;
v36 = a1[v5 + 16387];
LODWORD(v7) = v35 - 2;
a1[1] = v7;
if ( (unsignedint)v7 > 0xFFF )
goto LABEL_148;
v7 = (unsignedint)v7;
v8 = a1[(unsignedint)v7 + 16387] <= v36;
goto LABEL_114;
case0x1B:
*a1 = v3 + 1;
v78 = a1[1];
v2 = 3;
if ( !v78 )
goto LABEL_151;
v5 = v78 - 1;
a1[1] = v5;
if ( v78 == 1 )
goto LABEL_151;
v79 = a1[v5 + 16387];
LODWORD(v7) = v78 - 2;
a1[1] = v7;
if ( (unsignedint)v7 > 0xFFF )
goto LABEL_148;
v7 = (unsignedint)v7;
v8 = a1[(unsignedint)v7 + 16387] >= v79;
LABEL_114:
a1[1] = v5;
a1[v7 + 16387] = v8;
goto LABEL_145;
case0x1C:
*a1 = v3 + 1;
v28 = (unsignedint)a1[1];
if ( !a1[1] )
goto LABEL_149;
v29 = (unsignedint)(v28 - 1);
a1[1] = v29;
v2 = 2;
if ( (unsignedint)v29 > 0xFFF )
goto LABEL_151;
v30 = a1[v29 + 16387];
a1[1] = v28;
if ( (unsignedint)v28 > 0xFFF )
goto LABEL_151;
LABEL_132:
a1[1] = v28 + 1;
a1[v28 + 16387] = v30;
goto LABEL_145;
case0x1D:
*a1 = v3 + 1;
v9 = a1[1];
v2 = 3;
if ( !v9 )
goto LABEL_151;
v10 = v9 - 1;
a1[1] = v10;
if ( v9 == 1 )
goto LABEL_151;
v11 = a1[v10 + 16387];
v12 = v9 - 2;
a1[1] = v12;
v2 = 2;
if ( (unsignedint)v12 > 0xFFF )
goto LABEL_151;
v13 = a1[v12 + 16387];
a1[1] = v10;
a1[v12 + 16387] = v11;
if ( (unsignedint)v10 > 0xFFF )
goto LABEL_151;
a1[1] = v9;
a1[v10 + 16387] = v13;
goto LABEL_145;
case0x1E:
if ( (unsignedint)(v3 + 1) < 0xFFFD )
{
v77 = *((unsigned __int8 *)a1 + (unsignedint)(v3 + 1) + 12)
| (*((unsigned __int8 *)a1 + (unsignedint)(v3 + 2) + 12) << 8)
| (*((unsigned __int8 *)a1 + (unsignedint)(v3 + 3) + 12) << 16)
| (*((unsigned __int8 *)a1 + (unsignedint)(v3 + 4) + 12) << 24);
}
else
{
*(_QWORD *)(a1 + 20483) = 0x400000000LL;
v77 = 0;
}
v88 = (unsignedint)a1[1];
if ( v88 > 0xFFF )
goto LABEL_148;
a1[1] = v88 + 1;
a1[v88 + 16387] = v3 + 5;
*a1 = v77;
goto LABEL_145;
case0x1F:
v53 = a1[1];
if ( !v53 )
goto LABEL_149;
v54 = v53 - 1;
a1[1] = v54;
*a1 = a1[v54 + 16387];
goto LABEL_145;
case0x20:
*a1 = v3 + 1;
v80 = a1[1];
if ( !v80 )
{
LABEL_149:
v2 = 3;
goto LABEL_151;
}
v81 = v80 - 1;
a1[1] = v81;
v82 = (unsignedint)a1[v81 + 16387];
v2 = 4;
if ( v82 > 0xFFFF )
goto LABEL_151;
while ( 1 )
{
v83 = *((char *)a1 + v82 + 12);
if ( !*((_BYTE *)a1 + v82 + 12) )
break;
++v82;
putchar(v83);
if ( (_DWORD)v82 == 0x10000 )
goto LABEL_151;
}
putchar(10);
goto LABEL_145;
case0x21:
case0x22:
case0x23:
case0x24:
case0x25:
case0x26:
case0x27:
case0x28:
case0x29:
case0x2A:
case0x2B:
case0x2C:
case0x2D:
case0x2E:
case0x2F:
case0x30:
case0x31:
case0x32:
case0x33:
case0x34:
case0x35:
case0x36:
case0x37:
case0x38:
case0x39:
case0x3A:
case0x3B:
case0x3C:
case0x3D:
case0x3E:
case0x3F:
case0x40:
case0x41:
case0x42:
case0x43:
case0x44:
case0x45:
case0x46:
case0x47:
case0x48:
case0x49:
case0x4A:
case0x4B:
case0x4C:
case0x4D:
case0x4E:
case0x4F:
case0x50:
case0x51:
case0x52:
case0x53:
case0x54:
case0x55:
case0x56:
case0x57:
case0x58:
case0x59:
case0x5A:
case0x5B:
case0x5C:
case0x5D:
case0x5E:
case0x5F:
case0x60:
case0x61:
case0x62:
case0x63:
case0x64:
case0x65:
case0x66:
case0x67:
case0x68:
case0x69:
case0x6A:
case0x6B:
case0x6C:
case0x6D:
case0x6E:
case0x6F:
case0x70:
case0x71:
case0x72:
case0x73:
case0x74:
case0x75:
case0x76:
case0x77:
case0x78:
case0x79:
case0x7A:
case0x7B:
case0x7C:
case0x7D:
case0x7E:
case0x7F:
case0x80:
case0x81:
case0x82:
case0x83:
case0x84:
case0x85:
case0x86:
case0x87:
case0x88:
case0x89:
case0x8A:
case0x8B:
case0x8C:
case0x8D:
case0x8E:
case0x8F:
case0x90:
case0x91:
case0x92:
case0x93:
case0x94:
case0x95:
case0x96:
case0x97:
case0x98:
case0x99:
case0x9A:
case0x9B:
case0x9C:
case0x9D:
case0x9E:
case0x9F:
case0xA0:
case0xA1:
case0xA2:
case0xA3:
case0xA4:
case0xA5:
case0xA6:
case0xA7:
case0xA8:
case0xA9:
case0xAA:
case0xAB:
case0xAC:
case0xAD:
case0xAE:
case0xAF:
case0xB0:
case0xB1:
case0xB2:
case0xB3:
case0xB4:
case0xB5:
case0xB6:
case0xB7:
case0xB8:
case0xB9:
case0xBA:
case0xBB:
case0xBC:
case0xBD:
case0xBE:
case0xBF:
case0xC0:
case0xC1:
case0xC2:
case0xC3:
case0xC4:
case0xC5:
case0xC6:
case0xC7:
case0xC8:
case0xC9:
case0xCA:
case0xCB:
case0xCC:
case0xCD:
case0xCE:
case0xCF:
case0xD0:
case0xD1:
case0xD2:
case0xD3:
case0xD4:
case0xD5:
case0xD6:
case0xD7:
case0xD8:
case0xD9:
case0xDA:
case0xDB:
case0xDC:
case0xDD:
case0xDE:
case0xDF:
case0xE0:
case0xE1:
case0xE2:
case0xE3:
case0xE4:
case0xE5:
case0xE6:
case0xE7:
case0xE8:
case0xE9:
case0xEA:
case0xEB:
case0xEC:
case0xED:
case0xEE:
case0xEF:
case0xF0:
case0xF1:
case0xF2:
case0xF3:
case0xF4:
case0xF5:
case0xF6:
case0xF7:
case0xF8:
case0xF9:
case0xFA:
case0xFB:
case0xFC:
case0xFD:
case0xFE:
goto LABEL_151;
case0xFF:
*a1 = v3 + 1;
a1[20483] = 0;
goto LABEL_145;
}
}
}

这个程序定义了 33 条指令,总结如下
00 <target:u32> | |||
01 <target:u32> | |||
02 <target:u32> | |||
03 <imm:u8> | |||
04 <imm:u32> | |||
05 | |||
06 | |||
07 | |||
08 | |||
09 | |||
0A | |||
0B | |||
0C | |||
0D | |||
0E | |||
0F | |||
10 | |||
11 | |||
12 | |||
13 | |||
14 | |||
1516 | |||
17 | |||
18 | |||
19 | |||
1A | |||
1B | |||
1C | |||
1D | |||
1E <target:u32> | |||
1F | |||
20 | |||
21FE | |||
FF |
通过上面这张映射表我们可以将 code.bin 中的字节码反汇编为汇编语言
这一步可以让 ai 来,也可以写脚本,脚本已经放在文章结尾
code.bin
主程序入口
代码很长,就不完整展示了,我们只看开头的主程序入口
| ADDR | RAW | INSTRUCTION | ASCII |
|------|-----|-------------|-------|
| `0000` | `04 00 10 00 00` | PUSH32 0x00001000 | `.....` |
| `0005` | `04 2B 10 00 00` | PUSH32 0x0000102B | `.+...` |
| `000A` | `04 2A 00 00 00` | PUSH32 0x0000002A | `.*...` |
| `000F` | `1E 4F 00 00 00` | CALL 0x0000004F | `.O...` | 调用加密函数1:自定义 Base64
| `0014` | `04 2B 10 00 00` | PUSH32 0x0000102B | `.+...` |
| `0019` | `04 64 10 00 00` | PUSH32 0x00001064 | `.d...` |
| `001E` | `04 38 00 00 00` | PUSH32 0x00000038 | `.8...` |
| `0023` | `1E 68 03 00 00` | CALL 0x00000368 | `.h...` | 调用加密函数2:XOR 变换
| `0028` | `04 64 10 00 00` | PUSH32 0x00001064 | `.d...` | 加密结果存放地址
| `002D` | `04 9D 10 00 00` | PUSH32 0x0000109D | `.....` | 目标字符串地址
| `0032` | `04 38 00 00 00` | PUSH32 0x00000038 | `.8...` | 目标字符串长度 = 0x38
| `0037` | `1E 71 04 00 00` | CALL 0x00000471 | `.q...` | 将加密结果与目标字符串比较
| `003C` | `01 48 00 00 00` | JNZ 0x00000048 | `.H...` | 结果≠0 -> 失败
| `0041` | `04 D5 10 00 00` | PUSH32 0x000010D5 | `.....` | "Right!"
| `0046` | `20` | PRINT | ` ` |
| `0047` | `FF` | HALT | `.` |
| `0048` | `04 DC 10 00 00` | PUSH32 0x000010DC | `.....` | "Wrong!"
| `004D` | `20` | PRINT | ` ` |
| `004E` | `FF` | HALT | `.` |
首先就看到后面俩 PRINT,前面 PUSH 的地址分别是 0x10D5 和 0x10DC,分别对应 Right! 和 Wrong!
前面 0x3c 地址处的 JNZ 跳转说明若上面 CALL 调用的 0x471 地址处的函数返回值为 0 则失败
因此可以猜测 0x471 地址处的函数负责将密文与内置的目标字符串作比较
进而推测上面两个 PUSH 的参数 0x109D 和 0x38 分别是目标字符串的地址和长度
进一步猜测上面两个 CALL 调用的两个地址 0x4F 和 0x368 就是加密函数 1 和 2
加密函数 1(地址:0x4F)
| ADDR | RAW | INSTRUCTION | ASCII |
|------|-----|-------------|-------|
| `004F` | `04 00 00 00 00` | PUSH32 0x00000000 | `.....` |
| `0054` | `04 47 11 00 00` | PUSH32 0x00001147 | `.G...` |
| `0059` | `09` | STORE32 | `.` |
| `005A` | `00 5F 00 00 00` | JMP 0x0000005F | `._...` |
| `005F` | `04 47 11 00 00` | PUSH32 0x00001147 | `.G...` |
| `0064` | `06` | LOAD32 | `.` |
| `0065` | `04 00 00 00 00` | PUSH32 0x00000000 | `.....` |
| `006A` | `15` | EQ | `.` |
| `006B` | `02 DB 00 00 00` | JZ 0x000000DB | `.....` |
| `0070` | `04 47 11 00 00` | PUSH32 0x00001147 | `.G...` |
| `0075` | `06` | LOAD32 | `.` |
| `0076` | `04 01 00 00 00` | PUSH32 0x00000001 | `.....` |
| `007B` | `15` | EQ | `.` |
| `007C` | `02 20 01 00 00` | JZ 0x00000120 | `. ...` |
| `0081` | `04 47 11 00 00` | PUSH32 0x00001147 | `.G...` |
| `0086` | `06` | LOAD32 | `.` |
| `0087` | `04 02 00 00 00` | PUSH32 0x00000002 | `.....` |
| `008C` | `15` | EQ | `.` |
| `008D` | `02 52 01 00 00` | JZ 0x00000152 | `.R...` |
| `0092` | `04 47 11 00 00` | PUSH32 0x00001147 | `.G...` |
| `0097` | `06` | LOAD32 | `.` |
| `0098` | `04 03 00 00 00` | PUSH32 0x00000003 | `.....` |
| `009D` | `15` | EQ | `.` |
| `009E` | `02 7D 01 00 00` | JZ 0x0000017D | `.}...` |
| `00A3` | `04 47 11 00 00` | PUSH32 0x00001147 | `.G...` |
| `00A8` | `06` | LOAD32 | `.` |
| `00A9` | `04 04 00 00 00` | PUSH32 0x00000004 | `.....` |
| `00AE` | `15` | EQ | `.` |
| `00AF` | `02 A2 01 00 00` | JZ 0x000001A2 | `.....` |
| `00B4` | `04 47 11 00 00` | PUSH32 0x00001147 | `.G...` |
| `00B9` | `06` | LOAD32 | `.` |
| `00BA` | `04 05 00 00 00` | PUSH32 0x00000005 | `.....` |
| `00BF` | `15` | EQ | `.` |
| `00C0` | `02 B3 01 00 00` | JZ 0x000001B3 | `.....` |
| `00C5` | `04 47 11 00 00` | PUSH32 0x00001147 | `.G...` |
| `00CA` | `06` | LOAD32 | `.` |
| `00CB` | `04 06 00 00 00` | PUSH32 0x00000006 | `.....` |
| `00D0` | `15` | EQ | `.` |
| `00D1` | `02 61 03 00 00` | JZ 0x00000361 | `.a...` |
| `00D6` | `00 5F 00 00 00` | JMP 0x0000005F | `._...` |
| `00DB` | `04 23 11 00 00` | PUSH32 0x00001123 | `.#...` |
| `00E0` | `09` | STORE32 | `.` |
| `00E1` | `04 2F 11 00 00` | PUSH32 0x0000112F | `./...` |
| `00E6` | `09` | STORE32 | `.` |
| `00E7` | `04 2B 11 00 00` | PUSH32 0x0000112B | `.+...` |
| `00EC` | `09` | STORE32 | `.` |
| `00ED` | `04 27 11 00 00` | PUSH32 0x00001127 | `.'...` |
| `00F2` | `09` | STORE32 | `.` |
| `00F3` | `04 2F 11 00 00` | PUSH32 0x0000112F | `./...` |
| `00F8` | `06` | LOAD32 | `.` |
| `00F9` | `04 03 00 00 00` | PUSH32 0x00000003 | `.....` |
| `00FE` | `0D` | DIV | `.` |
| `00FF` | `04 37 11 00 00` | PUSH32 0x00001137 | `.7...` |
| `0104` | `09` | STORE32 | `.` |
| `0105` | `04 00 00 00 00` | PUSH32 0x00000000 | `.....` |
| `010A` | `04 33 11 00 00` | PUSH32 0x00001133 | `.3...` |
| `010F` | `09` | STORE32 | `.` |
| `0110` | `04 01 00 00 00` | PUSH32 0x00000001 | `.....` |
| `0115` | `04 47 11 00 00` | PUSH32 0x00001147 | `.G...` |
| `011A` | `09` | STORE32 | `.` |
| `011B` | `00 5F 00 00 00` | JMP 0x0000005F | `._...` |
| `0120` | `04 33 11 00 00` | PUSH32 0x00001133 | `.3...` |
| `0125` | `06` | LOAD32 | `.` |
| `0126` | `04 37 11 00 00` | PUSH32 0x00001137 | `.7...` |
| `012B` | `06` | LOAD32 | `.` |
| `012C` | `15` | EQ | `.` |
| `012D` | `02 42 01 00 00` | JZ 0x00000142 | `.B...` |
| `0132` | `04 02 00 00 00` | PUSH32 0x00000002 | `.....` |
| `0137` | `04 47 11 00 00` | PUSH32 0x00001147 | `.G...` |
| `013C` | `09` | STORE32 | `.` |
| `013D` | `00 5F 00 00 00` | JMP 0x0000005F | `._...` |
| `0142` | `04 06 00 00 00` | PUSH32 0x00000006 | `.....` |
| `0147` | `04 47 11 00 00` | PUSH32 0x00001147 | `.G...` |
| `014C` | `09` | STORE32 | `.` |
| `014D` | `00 5F 00 00 00` | JMP 0x0000005F | `._...` |
| `0152` | `04 01 00 00 00` | PUSH32 0x00000001 | `.....` |
| `0157` | `1C` | DUP | `.` |
| `0158` | `01 6D 01 00 00` | JNZ 0x0000016D | `.m...` |
| `015D` | `04 03 00 00 00` | PUSH32 0x00000003 | `.....` |
| `0162` | `04 47 11 00 00` | PUSH32 0x00001147 | `.G...` |
| `0167` | `09` | STORE32 | `.` |
| `0168` | `00 5F 00 00 00` | JMP 0x0000005F | `._...` |
| `016D` | `04 05 00 00 00` | PUSH32 0x00000005 | `.....` |
| `0172` | `04 47 11 00 00` | PUSH32 0x00001147 | `.G...` |
| `0177` | `09` | STORE32 | `.` |
| `0178` | `00 5F 00 00 00` | JMP 0x0000005F | `._...` |
| `017D` | `02 92 01 00 00` | JZ 0x00000192 | `.....` |
| `0182` | `04 04 00 00 00` | PUSH32 0x00000004 | `.....` |
| `0187` | `04 47 11 00 00` | PUSH32 0x00001147 | `.G...` |
| `018C` | `09` | STORE32 | `.` |
| `018D` | `00 5F 00 00 00` | JMP 0x0000005F | `._...` |
| `0192` | `04 05 00 00 00` | PUSH32 0x00000005 | `.....` |
| `0197` | `04 47 11 00 00` | PUSH32 0x00001147 | `.G...` |
| `019C` | `09` | STORE32 | `.` |
| `019D` | `00 5F 00 00 00` | JMP 0x0000005F | `._...` |
| `01A2` | `03 04` | PUSH8 0x04 | `..` |
| `01A4` | `05` | LOAD8 | `.` |
| `01A5` | `00 00 00 04 47` | JMP 0x47040000 | `....G` |
| `01AA` | `11` | NOT | `.` |
| `01AB` | `00 00 09 00 5F` | JMP 0x5F000900 | `...._` |
| `01B0` | `00 00 00 04 27` | JMP 0x27040000 | `....'` |
| `01B5` | `11` | NOT | `.` |
| `01B6` | `00 00 06 04 33` | JMP 0x33040600 | `....3` |
| `01BB` | `11` | NOT | `.` |
| `01BC` | `00 00 06 04 03` | JMP 0x03040600 | `.....` |
| `01C1` | `00 00 00 0C 0A` | JMP 0x0A0C0000 | `.....` |
| `01C6` | `04 3B 11 00 00` | PUSH32 0x0000113B | `.;...` |
| `01CB` | `09` | STORE32 | `.` |
| `01CC` | `04 2B 11 00 00` | PUSH32 0x0000112B | `.+...` |
| `01D1` | `06` | LOAD32 | `.` |
| `01D2` | `04 33 11 00 00` | PUSH32 0x00001133 | `.3...` |
| `01D7` | `06` | LOAD32 | `.` |
| `01D8` | `04 04 00 00 00` | PUSH32 0x00000004 | `.....` |
| `01DD` | `0C` | MUL | `.` |
| `01DE` | `0A` | ADD | `.` |
| `01DF` | `04 3F 11 00 00` | PUSH32 0x0000113F | `.?...` |
| `01E4` | `09` | STORE32 | `.` |
| `01E5` | `04 3B 11 00 00` | PUSH32 0x0000113B | `.;...` |
| `01EA` | `06` | LOAD32 | `.` |
| `01EB` | `05` | LOAD8 | `.` |
| `01EC` | `04 10 00 00 00` | PUSH32 0x00000010 | `.....` |
| `01F1` | `13` | SHL | `.` |
| `01F2` | `04 43 11 00 00` | PUSH32 0x00001143 | `.C...` |
| `01F7` | `09` | STORE32 | `.` |
| `01F8` | `04 43 11 00 00` | PUSH32 0x00001143 | `.C...` |
| `01FD` | `06` | LOAD32 | `.` |
| `01FE` | `04 3B 11 00 00` | PUSH32 0x0000113B | `.;...` |
| `0203` | `06` | LOAD32 | `.` |
| `0204` | `04 01 00 00 00` | PUSH32 0x00000001 | `.....` |
| `0209` | `0A` | ADD | `.` |
| `020A` | `05` | LOAD8 | `.` |
| `020B` | `04 08 00 00 00` | PUSH32 0x00000008 | `.....` |
| `0210` | `13` | SHL | `.` |
| `0211` | `10` | OR | `.` |
| `0212` | `04 43 11 00 00` | PUSH32 0x00001143 | `.C...` |
| `0217` | `09` | STORE32 | `.` |
| `0218` | `04 43 11 00 00` | PUSH32 0x00001143 | `.C...` |
| `021D` | `06` | LOAD32 | `.` |
| `021E` | `04 3B 11 00 00` | PUSH32 0x0000113B | `.;...` |
| `0223` | `06` | LOAD32 | `.` |
| `0224` | `04 02 00 00 00` | PUSH32 0x00000002 | `.....` |
| `0229` | `0A` | ADD | `.` |
| `022A` | `05` | LOAD8 | `.` |
| `022B` | `10` | OR | `.` |
| `022C` | `04 43 11 00 00` | PUSH32 0x00001143 | `.C...` |
| `0231` | `09` | STORE32 | `.` |
| `0232` | `04 43 11 00 00` | PUSH32 0x00001143 | `.C...` |
| `0237` | `06` | LOAD32 | `.` |
| `0238` | `04 05 00 00 00` | PUSH32 0x00000005 | `.....` |
| `023D` | `13` | SHL | `.` |
| `023E` | `04 43 11 00 00` | PUSH32 0x00001143 | `.C...` |
| `0243` | `06` | LOAD32 | `.` |
| `0244` | `04 13 00 00 00` | PUSH32 0x00000013 | `.....` |
| `0249` | `14` | SHR | `.` |
| `024A` | `10` | OR | `.` |
| `024B` | `04 FF FF FF 00` | PUSH32 0x00FFFFFF | `.....` |
| `0250` | `0F` | AND | `.` |
| `0251` | `04 7D 75 55 00` | PUSH32 0x0055757D | `.}uU.` |
| `0256` | `12` | XOR | `.` |
| `0257` | `04 43 11 00 00` | PUSH32 0x00001143 | `.C...` |
| `025C` | `09` | STORE32 | `.` |
| `025D` | `04 43 11 00 00` | PUSH32 0x00001143 | `.C...` |
| `0262` | `06` | LOAD32 | `.` |
| `0263` | `04 0B 00 00 00` | PUSH32 0x0000000B | `.....` |
| `0268` | `13` | SHL | `.` |
| `0269` | `04 43 11 00 00` | PUSH32 0x00001143 | `.C...` |
| `026E` | `06` | LOAD32 | `.` |
| `026F` | `04 0D 00 00 00` | PUSH32 0x0000000D | `.....` |
| `0274` | `14` | SHR | `.` |
| `0275` | `10` | OR | `.` |
| `0276` | `04 FF FF FF 00` | PUSH32 0x00FFFFFF | `.....` |
| `027B` | `0F` | AND | `.` |
| `027C` | `04 7D 75 55 00` | PUSH32 0x0055757D | `.}uU.` |
| `0281` | `12` | XOR | `.` |
| `0282` | `04 43 11 00 00` | PUSH32 0x00001143 | `.C...` |
| `0287` | `09` | STORE32 | `.` |
| `0288` | `04 43 11 00 00` | PUSH32 0x00001143 | `.C...` |
| `028D` | `06` | LOAD32 | `.` |
| `028E` | `04 14 00 00 00` | PUSH32 0x00000014 | `.....` |
| `0293` | `13` | SHL | `.` |
| `0294` | `04 43 11 00 00` | PUSH32 0x00001143 | `.C...` |
| `0299` | `06` | LOAD32 | `.` |
| `029A` | `04 04 00 00 00` | PUSH32 0x00000004 | `.....` |
| `029F` | `14` | SHR | `.` |
| `02A0` | `10` | OR | `.` |
| `02A1` | `04 FF FF FF 00` | PUSH32 0x00FFFFFF | `.....` |
| `02A6` | `0F` | AND | `.` |
| `02A7` | `04 7D 75 55 00` | PUSH32 0x0055757D | `.}uU.` |
| `02AC` | `12` | XOR | `.` |
| `02AD` | `04 43 11 00 00` | PUSH32 0x00001143 | `.C...` |
| `02B2` | `09` | STORE32 | `.` |
| `02B3` | `04 43 11 00 00` | PUSH32 0x00001143 | `.C...` |
| `02B8` | `06` | LOAD32 | `.` |
| `02B9` | `04 12 00 00 00` | PUSH32 0x00000012 | `.....` |
| `02BE` | `14` | SHR | `.` |
| `02BF` | `04 3F 00 00 00` | PUSH32 0x0000003F | `.?...` |
| `02C4` | `0F` | AND | `.` |
| `02C5` | `04 E3 10 00 00` | PUSH32 0x000010E3 | `.....` |
| `02CA` | `0A` | ADD | `.` |
| `02CB` | `05` | LOAD8 | `.` |
| `02CC` | `04 3F 11 00 00` | PUSH32 0x0000113F | `.?...` |
| `02D1` | `06` | LOAD32 | `.` |
| `02D2` | `08` | STORE8 | `.` |
| `02D3` | `04 43 11 00 00` | PUSH32 0x00001143 | `.C...` |
| `02D8` | `06` | LOAD32 | `.` |
| `02D9` | `04 0C 00 00 00` | PUSH32 0x0000000C | `.....` |
| `02DE` | `14` | SHR | `.` |
| `02DF` | `04 3F 00 00 00` | PUSH32 0x0000003F | `.?...` |
| `02E4` | `0F` | AND | `.` |
| `02E5` | `04 E3 10 00 00` | PUSH32 0x000010E3 | `.....` |
| `02EA` | `0A` | ADD | `.` |
| `02EB` | `05` | LOAD8 | `.` |
| `02EC` | `04 3F 11 00 00` | PUSH32 0x0000113F | `.?...` |
| `02F1` | `06` | LOAD32 | `.` |
| `02F2` | `04 01 00 00 00` | PUSH32 0x00000001 | `.....` |
| `02F7` | `0A` | ADD | `.` |
| `02F8` | `08` | STORE8 | `.` |
| `02F9` | `04 43 11 00 00` | PUSH32 0x00001143 | `.C...` |
| `02FE` | `06` | LOAD32 | `.` |
| `02FF` | `04 06 00 00 00` | PUSH32 0x00000006 | `.....` |
| `0304` | `14` | SHR | `.` |
| `0305` | `04 3F 00 00 00` | PUSH32 0x0000003F | `.?...` |
| `030A` | `0F` | AND | `.` |
| `030B` | `04 E3 10 00 00` | PUSH32 0x000010E3 | `.....` |
| `0310` | `0A` | ADD | `.` |
| `0311` | `05` | LOAD8 | `.` |
| `0312` | `04 3F 11 00 00` | PUSH32 0x0000113F | `.?...` |
| `0317` | `06` | LOAD32 | `.` |
| `0318` | `04 02 00 00 00` | PUSH32 0x00000002 | `.....` |
| `031D` | `0A` | ADD | `.` |
| `031E` | `08` | STORE8 | `.` |
| `031F` | `04 43 11 00 00` | PUSH32 0x00001143 | `.C...` |
| `0324` | `06` | LOAD32 | `.` |
| `0325` | `04 3F 00 00 00` | PUSH32 0x0000003F | `.?...` |
| `032A` | `0F` | AND | `.` |
| `032B` | `04 E3 10 00 00` | PUSH32 0x000010E3 | `.....` |
| `0330` | `0A` | ADD | `.` |
| `0331` | `05` | LOAD8 | `.` |
| `0332` | `04 3F 11 00 00` | PUSH32 0x0000113F | `.?...` |
| `0337` | `06` | LOAD32 | `.` |
| `0338` | `04 03 00 00 00` | PUSH32 0x00000003 | `.....` |
| `033D` | `0A` | ADD | `.` |
| `033E` | `08` | STORE8 | `.` |
| `033F` | `04 33 11 00 00` | PUSH32 0x00001133 | `.3...` |
| `0344` | `06` | LOAD32 | `.` |
| `0345` | `04 01 00 00 00` | PUSH32 0x00000001 | `.....` |
| `034A` | `0A` | ADD | `.` |
| `034B` | `04 33 11 00 00` | PUSH32 0x00001133 | `.3...` |
| `0350` | `09` | STORE32 | `.` |
| `0351` | `04 01 00 00 00` | PUSH32 0x00000001 | `.....` |
| `0356` | `04 47 11 00 00` | PUSH32 0x00001147 | `.G...` |
| `035B` | `09` | STORE32 | `.` |
| `035C` | `00 5F 00 00 00` | JMP 0x0000005F | `._...` |
| `0361` | `04 23 11 00 00` | PUSH32 0x00001123 | `.#...` |
| `0366` | `06` | LOAD32 | `.` |
| `0367` | `1F` | RET | `.` |
是个自定义的 base64 编码
注意:ROL() 是 24 位循环左移
加密函数 2(地址:0x368)
| ADDR | RAW | INSTRUCTION | ASCII |
|------|-----|-------------|-------|
| `0368` | `04 00 00 00 00` | PUSH32 0x00000000 | `.....` |
| `036D` | `04 4F 11 00 00` | PUSH32 0x0000114F | `.O...` |
| `0372` | `09` | STORE32 | `.` |
| `0373` | `00 78 03 00 00` | JMP 0x00000378 | `.x...` |
| `0378` | `04 4F 11 00 00` | PUSH32 0x0000114F | `.O...` |
| `037D` | `06` | LOAD32 | `.` |
| `037E` | `04 00 00 00 00` | PUSH32 0x00000000 | `.....` |
| `0383` | `15` | EQ | `.` |
| `0384` | `02 C1 03 00 00` | JZ 0x000003C1 | `.....` |
| `0389` | `04 4F 11 00 00` | PUSH32 0x0000114F | `.O...` |
| `038E` | `06` | LOAD32 | `.` |
| `038F` | `04 01 00 00 00` | PUSH32 0x00000001 | `.....` |
| `0394` | `15` | EQ | `.` |
| `0395` | `02 F4 03 00 00` | JZ 0x000003F4 | `.....` |
| `039A` | `04 4F 11 00 00` | PUSH32 0x0000114F | `.O...` |
| `039F` | `06` | LOAD32 | `.` |
| `03A0` | `04 02 00 00 00` | PUSH32 0x00000002 | `.....` |
| `03A5` | `15` | EQ | `.` |
| `03A6` | `02 26 04 00 00` | JZ 0x00000426 | `.&...` |
| `03AB` | `04 4F 11 00 00` | PUSH32 0x0000114F | `.O...` |
| `03B0` | `06` | LOAD32 | `.` |
| `03B1` | `04 03 00 00 00` | PUSH32 0x00000003 | `.....` |
| `03B6` | `15` | EQ | `.` |
| `03B7` | `02 6A 04 00 00` | JZ 0x0000046A | `.j...` |
| `03BC` | `00 78 03 00 00` | JMP 0x00000378 | `.x...` |
| `03C1` | `04 23 11 00 00` | PUSH32 0x00001123 | `.#...` |
| `03C6` | `09` | STORE32 | `.` |
| `03C7` | `04 2F 11 00 00` | PUSH32 0x0000112F | `./...` |
| `03CC` | `09` | STORE32 | `.` |
| `03CD` | `04 2B 11 00 00` | PUSH32 0x0000112B | `.+...` |
| `03D2` | `09` | STORE32 | `.` |
| `03D3` | `04 27 11 00 00` | PUSH32 0x00001127 | `.'...` |
| `03D8` | `09` | STORE32 | `.` |
| `03D9` | `04 00 00 00 00` | PUSH32 0x00000000 | `.....` |
| `03DE` | `04 33 11 00 00` | PUSH32 0x00001133 | `.3...` |
| `03E3` | `09` | STORE32 | `.` |
| `03E4` | `04 01 00 00 00` | PUSH32 0x00000001 | `.....` |
| `03E9` | `04 4F 11 00 00` | PUSH32 0x0000114F | `.O...` |
| `03EE` | `09` | STORE32 | `.` |
| `03EF` | `00 78 03 00 00` | JMP 0x00000378 | `.x...` |
| `03F4` | `04 33 11 00 00` | PUSH32 0x00001133 | `.3...` |
| `03F9` | `06` | LOAD32 | `.` |
| `03FA` | `04 2F 11 00 00` | PUSH32 0x0000112F | `./...` |
| `03FF` | `06` | LOAD32 | `.` |
| `0400` | `15` | EQ | `.` |
| `0401` | `02 16 04 00 00` | JZ 0x00000416 | `.....` |
| `0406` | `04 02 00 00 00` | PUSH32 0x00000002 | `.....` |
| `040B` | `04 4F 11 00 00` | PUSH32 0x0000114F | `.O...` |
| `0410` | `09` | STORE32 | `.` |
| `0411` | `00 78 03 00 00` | JMP 0x00000378 | `.x...` |
| `0416` | `04 03 00 00 00` | PUSH32 0x00000003 | `.....` |
| `041B` | `04 4F 11 00 00` | PUSH32 0x0000114F | `.O...` |
| `0420` | `09` | STORE32 | `.` |
| `0421` | `00 78 03 00 00` | JMP 0x00000378 | `.x...` |
| `0426` | `04 27 11 00 00` | PUSH32 0x00001127 | `.'...` |
| `042B` | `06` | LOAD32 | `.` |
| `042C` | `04 33 11 00 00` | PUSH32 0x00001133 | `.3...` |
| `0431` | `06` | LOAD32 | `.` |
| `0432` | `0A` | ADD | `.` |
| `0433` | `05` | LOAD8 | `.` |
| `0434` | `04 63 00 00 00` | PUSH32 0x00000063 | `.c...` |
| `0439` | `12` | XOR | `.` |
| `043A` | `04 2B 11 00 00` | PUSH32 0x0000112B | `.+...` |
| `043F` | `06` | LOAD32 | `.` |
| `0440` | `04 33 11 00 00` | PUSH32 0x00001133 | `.3...` |
| `0445` | `06` | LOAD32 | `.` |
| `0446` | `0A` | ADD | `.` |
| `0447` | `08` | STORE8 | `.` |
| `0448` | `04 33 11 00 00` | PUSH32 0x00001133 | `.3...` |
| `044D` | `06` | LOAD32 | `.` |
| `044E` | `04 01 00 00 00` | PUSH32 0x00000001 | `.....` |
| `0453` | `0A` | ADD | `.` |
| `0454` | `04 33 11 00 00` | PUSH32 0x00001133 | `.3...` |
| `0459` | `09` | STORE32 | `.` |
| `045A` | `04 01 00 00 00` | PUSH32 0x00000001 | `.....` |
| `045F` | `04 4F 11 00 00` | PUSH32 0x0000114F | `.O...` |
| `0464` | `09` | STORE32 | `.` |
| `0465` | `00 78 03 00 00` | JMP 0x00000378 | `.x...` |
| `046A` | `04 23 11 00 00` | PUSH32 0x00001123 | `.#...` |
| `046F` | `06` | LOAD32 | `.` |
| `0470` | `1F` | RET | `.` |
就是一个简单的逐字节异或变换

分析完加密算法就可以写脚本解密了
解密脚本
脚本可以自动从 code.bin 中提取密文(地址:0x109D:0x109D+56)
import base64
with open('code.bin', 'rb') as f:
data = f.read()
# 56字节预期密文
expected = bytes(data[0x109d:0x109d+56])
# 逆 XOR 0x63 → 得到自定义Base64
b64_bytes = bytes(b ^ 0x63for b in expected)
# 标准 Base64 字母表
alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
# 转为6位索引
indices = [alphabet.index(chr(b)) for b in b64_bytes]
# 24位循环移位辅助函数
def rol24(val, n):
val &= 0xFFFFFF
return ((val << n) | (val >> (24 - n))) & 0xFFFFFF
def ror24(val, n):
val &= 0xFFFFFF
return ((val >> n) | (val << (24 - n))) & 0xFFFFFF
# 分组解密
flag_bytes = []
for i in range(0, len(indices), 4):
# 4个6位索引 → 24位值
val = (indices[i] << 18) | (indices[i+1] << 12) | \
(indices[i+2] << 6) | indices[i+3]
# 逆推3轮混淆 (反向顺序)
val = ror24(val ^ 0x55757d, 20)
val = ror24(val ^ 0x55757d, 11)
val = ror24(val ^ 0x55757d, 5)
# 24位 → 3字节
flag_bytes.append((val >> 16) & 0xFF)
flag_bytes.append((val >> 8) & 0xFF)
flag_bytes.append(val & 0xFF)
flag = bytes(flag_bytes).decode('ascii')
print(f'Flag: {flag}')
'''
输出内容:
Flag: NCTF{1578be15-ad09-4859-9193-5d52585eb485}
'''
反汇编脚本
脚本已上传至 github,项目地址:
https://github.com/Lucien-404/VM-disassembler
其实整个项目都是 ai 生成的
首先将 vm_execute 发给 ai 生成映射表(这个应该一个本地的小模型就能实现)
接着脚本就能利用映射表自动将字节码反汇编为人能直接阅读的汇编代码
初衷是希望在离线的情况下也能解出虚拟机逆向题(主要是线下比赛),但是我们发现阅读汇编代码也并不是一件简单的事
脚本的使用说明和生成映射表的提示词模板也已经一并上传,目前脚本的普适性还没有得到有效验证,因此邀请大家一起来使用这个工具,如果有任何问题也欢迎各位私信联系我们,我们一起来维护改进这个项目