运行程序
D:\TRY\CTF\PCL\RE\gocode\copy\gocode>chall
input the flag:
aaa
something error
查壳
无壳, 64位
分析
使用IDA打开, 找到main_main函数, 为go语言编写
主要通过调试一点一点分析, 找到规律以后, 可以大致猜测后面字节码的功能
// main.main
void __cdecl main_main()
{
__int64 _IP; // rax
unsigned __int64 v1; // rcx
__int64 Slice; // rdx
unsigned __int64 script; // rsi
unsigned __int64 ______op1; // rsi
unsigned __int64 ______op2; // r8
unsigned __int64 __op1; // rsi
unsigned __int64 _op1; // rsi
unsigned __int64 _op2; // r8
unsigned __int64 _____op1; // rsi
unsigned __int64 _____op2; // r8
unsigned __int64 ____op1; // rsi
unsigned __int64 ____op2; // r8
unsigned __int64 v13; // rsi
unsigned __int64 v14; // r8
unsigned __int64 v15; // r8
unsigned __int64 ___op1; // rsi
__int64 v17; // rsi
unsigned __int64 ___op2; // rdi
unsigned __int64 op2; // rsi
__int64 Slice_op2; // rsi
unsigned __int64 op1; // rdi
__int64 v22; // [rsp+40h] [rbp-C90h]
unsigned __int64 v23; // [rsp+58h] [rbp-C78h]
__int64 old_IP; // [rsp+68h] [rbp-C68h]
__int64 v25; // [rsp+80h] [rbp-C50h] BYREF
__int128 regs_Array[2]; // [rsp+88h] [rbp-C48h] BYREF
__int64 some_Data[374]; // [rsp+A8h] [rbp-C28h] BYREF
__int64 old_Slice; // [rsp+C58h] [rbp-78h]
__int64 v29[2]; // [rsp+C68h] [rbp-68h] BYREF
__int64 output[2]; // [rsp+C78h] [rbp-58h] BYREF
__int64 v31[2]; // [rsp+C98h] [rbp-38h] BYREF
__int64 v32[2]; // [rsp+CA8h] [rbp-28h] BYREF
__int64 v33[2]; // [rsp+CB8h] [rbp-18h] BYREF
while ( (unsigned __int64)&v25 <= *(_QWORD *)(*(_QWORD *)NtCurrentTeb()->NtTib.ArbitraryUserPointer + 16LL) )
runtime_morestack_noctxt();
qmemcpy(some_Data, &unk_A73EA0, sizeof(some_Data));
memset(regs_Array, 0, sizeof(regs_Array));
_IP = 0LL;
v1 = 0LL;
Slice = 0LL;
while ( 1 )
{
if ( (unsigned __int64)_IP >= 0x176 )
runtime_panicIndex();
v23 = v1;
old_Slice = Slice;
old_IP = _IP;
script = some_Data[_IP];// 更新IP寄存器
if ( script > 0xC )
{
if ( script > 0xE )
{
switch ( script )
{
case 0xFuLL:
if ( (unsigned __int64)(_IP + 1) >= 0x176 )
runtime_panicIndex();
v13 = some_Data[_IP + 1];
if ( v13 >= 4 )
runtime_panicIndexU();
if ( (unsigned __int64)(_IP + 2) >= 0x176 )
runtime_panicIndex();
v14 = some_Data[_IP + 2];
if ( v14 >= 4 )
goto LABEL_89;
v15 = *((_QWORD *)regs_Array + v14);
if ( !v15 )
{
runtime_panicdivide();
LABEL_89:
runtime_panicIndexU();
}
*((_QWORD *)regs_Array + v13) /= v15;
_IP += 3LL; // 可以看到_IP加上了3
break;
case 0xAAuLL:
if ( (unsigned __int64)(_IP + 1) >= 0x176 )// 检查当前IP位置
runtime_panicIndex();
___op1 = some_Data[_IP + 1];
if ( ___op1 >= 4 ) // 检查操作数, 该操作数为regs的下标
runtime_panicIndexU();
v17 = *((_QWORD *)regs_Array + ___op1);
if ( (unsigned __int64)(_IP + 2) >= 0x176 )// 检查当前IP位置
runtime_panicIndex();
___op2 = some_Data[_IP + 2];
if ( ___op2 >= 4 ) // 该操作数为regs的下标, 检查操作数
runtime_panicIndexU();
if ( *((_QWORD *)regs_Array + ___op2) != v17 )// 查看二者是否相等
{
output[0] = (__int64)&len_output; // 这里是go对字符串的操作
output[1] = (__int64)&p_output; // 指向的是error字符串
fmt_Fprintln((__int64)&go_itab__ptr_os_File_comma__ptr_io_Writer, qword_AF3428, (__int64)output, 1LL, 1LL);// 输出错误消息
os_Exit(0LL); // 退出程序
_IP = old_IP;
v1 = v23;
Slice = old_Slice;
}
_IP += 3LL;
break;
case 0xBBuLL:
if ( (unsigned __int64)(_IP + 2) >= 0x176 )// 检查IP位置
runtime_panicIndex();
op2 = some_Data[_IP + 2];
if ( op2 >= v1 ) // 检查操作数, 因为Slice中只有0x10个数, 所以这里导入要小于0x10
runtime_panicIndexU();
Slice_op2 = *(_QWORD *)(Slice + 8 * op2);// 导入Slice中的值到寄存器数组中
if ( (unsigned __int64)(_IP + 1) >= 0x176 )// 检查IP位置
runtime_panicIndex();
op1 = some_Data[_IP + 1];
if ( op1 >= 4 ) // 寄存器的下标
runtime_panicIndexU();
*((_QWORD *)regs_Array + op1) = Slice_op2;// 将Slice中的数据导入到寄存器中
_IP += 3LL;
break;
}
}
else if ( script == 0xD )
{
if ( (unsigned __int64)(_IP + 1) >= 0x176 )// 检查IP位置
runtime_panicIndex();
_____op1 = some_Data[_IP + 1];
if ( _____op1 >= 4 ) // 操作数1为regs的下标
runtime_panicIndexU();
if ( (unsigned __int64)(_IP + 2) >= 0x176 )// 检查IP位置
runtime_panicIndex();
_____op2 = some_Data[_IP + 2];
if ( _____op2 >= 4 ) // 操作数2为regs的下标
runtime_panicIndexU();
*((_QWORD *)regs_Array + _____op1) -= *((_QWORD *)regs_Array + _____op2);
_IP += 3LL;
}
else // 操作码0xE
{
if ( (unsigned __int64)(_IP + 1) >= 0x176 )// 检查IP位置
runtime_panicIndex();
____op1 = some_Data[_IP + 1]; // 操作数1为regs的下标
if ( ____op1 >= 4 )
runtime_panicIndexU();
if ( (unsigned __int64)(_IP + 2) >= 0x176 )// 检查操作数
runtime_panicIndex();
____op2 = some_Data[_IP + 2]; // 操作数2为regs下标
if ( ____op2 >= 4 )
runtime_panicIndexU();
*((_QWORD *)regs_Array + ____op1) *= *((_QWORD *)regs_Array + ____op2);// 乘法操作
_IP += 3LL; // 指令长度为3
}
goto LABEL_12;
}
if ( script <= 2 )
{
if ( script == 1 )
{
if ( (unsigned __int64)(_IP + 1) >= 0x176 )// 检查IP位置
runtime_panicIndex();
______op1 = some_Data[_IP + 1];
if ( ______op1 >= 4 ) // op1为regs的下标
runtime_panicIndexU();
if ( (unsigned __int64)(_IP + 2) >= 0x176 )
runtime_panicIndex();
______op2 = some_Data[_IP + 2]; // op2为regs的下标
if ( ______op2 >= 4 )
runtime_panicIndexU();
*((_QWORD *)regs_Array + ______op1) ^= *((_QWORD *)regs_Array + ______op2);
_IP += 3LL;
}
else if ( script == 2 )
{
if ( (unsigned __int64)(_IP + 2) >= 0x176 )// 检查IP位置
runtime_panicIndex();
if ( (unsigned __int64)(_IP + 1) >= 0x176 )// 检查IP位置
runtime_panicIndex();
__op1 = some_Data[_IP + 1];
if ( __op1 >= 4 ) // 操作数1 将作为regs的下标
runtime_panicIndexU();
*((_QWORD *)regs_Array + __op1) = some_Data[_IP + 2];// 给寄存器传输一个立即数(操作数2)
_IP += 3LL; // 指令长度为3
}
goto LABEL_12;
}
if ( script != 0xA )
{
if ( script == 0xB )
{
if ( len > 0 )
JUMPOUT(0xA25B49LL);
++_IP; // 这个指令码长度为1字节
}
else if ( script == 0xC )
{
if ( (unsigned __int64)(_IP + 1) >= 0x176 )// 检查IP位置
runtime_panicIndex();
_op1 = some_Data[_IP + 1]; // 操作数1 将用来作为regs的下标
if ( _op1 >= 4 ) // 只有4个寄存器
runtime_panicIndexU();
if ( (unsigned __int64)(_IP + 2) >= 0x176 )// 检查IP位置
runtime_panicIndex();
_op2 = some_Data[_IP + 2];
if ( _op2 >= 4 ) // 操作数2 同样作为regs下标
runtime_panicIndexU();
*((_QWORD *)regs_Array + _op1) += *((_QWORD *)regs_Array + _op2);// regs[op1] += regs[op2]
_IP += 3LL; // 指令长度为3
}
goto LABEL_12;
}
v33[0] = (__int64)&len_output;
v33[1] = (__int64)&off_A70B48;
fmt_Fprintln((__int64)&go_itab__ptr_os_File_comma__ptr_io_Writer, qword_AF3428, (__int64)v33, 1LL, 1LL);// 输入提示
v32[0] = (__int64)&RTYPE__ptr_string;
v32[1] = (__int64)&p_input;
fmt_Fscanf( // 输入
(__int64)&go_itab__ptr_os_File_comma__ptr_io_Reader,
qword_AF3420,
(__int64)"%37s",
4LL,
(__int64)v32,
1LL,
1LL);
if ( v22 )
return; // 检查开头是否是PCL{, 结尾是否是}
if ( len != 37 || *(_DWORD *)p_input != 0x7B4C4350 || *(_BYTE *)(p_input + 36) != 0x7D )
break;
len = 32LL;
if ( dword_B36C60 )
runtime_gcWriteBarrierBX();
else
p_input += 4LL; // 跳过开头的PCL{, 直接对括号中的内容进行操作
_IP = old_IP + 1;
v1 = v23;
Slice = old_Slice;
LABEL_12:
if ( _IP >= 0x176 ) // 检查虚拟机运行的程序是否结束
{
v29[0] = (__int64)&len_output;
v29[1] = (__int64)&off_A70B78;
fmt_Fprintln((__int64)&go_itab__ptr_os_File_comma__ptr_io_Writer, qword_AF3428, (__int64)v29, 1LL, 1LL);
return;
}
}
v31[0] = (__int64)&len_output;
v31[1] = (__int64)&p_output;
fmt_Fprintln((__int64)&go_itab__ptr_os_File_comma__ptr_io_Writer, qword_AF3428, (__int64)v31, 1LL, 1LL);
} // PCL{11908B11111111111111111111111111}
/* Orphan comments:
将扩展为DWORD的两个十六进制值存入新的Slice数组中
实现数据类型的转换, 返回第一个和第二个参数描述字符串, 第三个参数表示返回的进制为16位, 第四个参数表示返回unsigned int的长度为32位
检查格式
扩展slice的容量
返回一个地址
输出错误提示: input format is error
*/
程序为虚拟机, 通过调试知道了字节存储在some_Data数组中, 第53行就是更新IP的操作script = some_Data[_IP];
下面就是通过switch和if来根据字节码进行不同的操作, 其中开头的两个字节码对应的是输入和数据转换.
输入进行的操作: 输入并检查开头是否为"PCL{", 结尾是否为"{", 长度是否为37, 并改变了len的值从37改为32, 推测应该是去掉了开头和结尾的5个长度, 并给int_p_input加上了4, 也就是跳过了开头
数据转换的操作: 以两个字节为单位, 将输入字符(括号中的)转换为十六进制数. 并放入一个新的数组中, 新数组的单个元素长度为8个字节.
接下来就是对输入数据进行验证.
得到的字节码(去掉了开头的两个操作码):(注意: 一开始写这道题的时候, 以为字节码个操作都是单字节的, 但是操作数是多字节的, 比如下面的第6行和第13行, 操作数是直接数的是多字节小端排序)
0xbb, 0x0, 0x0,
0xbb, 0x1, 0x1,
0xbb, 0x2, 0x2,
0xbb, 0x3, 0x3,
0xc, 0x1, 0x2,
0x2, 0x2, 0x11b,
0xaa, 0x1, 0x2,
0xbb, 0x1, 0x1,
0xbb, 0x2, 0x2,
0xc, 0x0, 0x1,
0xe, 0x0, 0x2,
0xd, 0x0, 0x3,
0x2, 0x2, 0x7901,
0xaa, 0x0, 0x2,
0xbb, 0x2, 0x2,
0x2, 0x0, 0x63,
0x1, 0x2, 0x0,
0xbb, 0x0, 0x0,
0xe, 0x0, 0x2,
0xd, 0x0, 0x1,
0xc, 0x0, 0x3,
0x2, 0x1, 0x1ff6,
0xaa, 0x0, 0x1,
0xbb, 0x1, 0x1,
0xbb, 0x0, 0x0,
0xbb, 0x2, 0x2,
0xc, 0x1, 0x0,
0xc, 0x1, 0x2,
0xc, 0x1, 0x3,
0x2, 0x0, 0x21e,
0xaa, 0x1, 0x0,
0xbb, 0x1, 0x1,
0xbb, 0x0, 0x0,
0xe, 0x0, 0x3,
0xd, 0x0, 0x1,
0xc, 0x0, 0x2,
0x2, 0x3, 0x3331,
0xaa, 0x0, 0x3,
0xbb, 0x0, 0x4,
0xbb, 0x1, 0x5,
0xbb, 0x2, 0x6,
0x2, 0x3, 0x63,
0xc, 0x0, 0x3,
0x2, 0x3, 0x68,
0x1, 0x0, 0x3,
0x2, 0x3, 0x152,
0xaa, 0x0, 0x3,
0x2, 0x3, 0x33,
0xd, 0x1, 0x3,
0x2, 0x3, 0x63,
0xe, 0x1, 0x3,
0x2, 0x0, 0x441,
0xaa, 0x0, 0x1,
0x2, 0x3, 0x63,
0x1, 0x2, 0x3,
0x2, 0x3, 0x6b,
0xc, 0x2, 0x3,
0x2, 0x1, 0x10e,
0xaa, 0x2, 0x1,
0x2, 0x1, 0x9e,
0xbb, 0x0, 0x7,
0xaa, 0x0, 0x1,
0xbb, 0x0, 0x8,
0xbb, 0x1, 0x9,
0xbb, 0x2, 0xa,
0xbb, 0x3, 0xb,
0xe, 0x0, 0x3,
0x2, 0x3, 0x36ce,
0xaa, 0x0, 0x3,
0xbb, 0x0, 0x8,
0xbb, 0x3, 0xb,
0xc, 0x0, 0x1,
0xe, 0x0, 0x2,
0xd, 0x0, 0x3,
0x2, 0x2, 0x682d,
0xaa, 0x0, 0x2,
0xbb, 0x2, 0xa,
0x2, 0x0, 0x63,
0x1, 0x2, 0x0,
0xbb, 0x0, 0x8,
0xe, 0x0, 0x2,
0xd, 0x0, 0x1,
0xc, 0x0, 0x3,
0x2, 0x1, 0x15,
0xaa, 0x0, 0x1,
0xbb, 0x1, 0x9,
0xbb, 0x0, 0x8,
0xbb, 0x2, 0xa,
0xc, 0x1, 0x0,
0xc, 0x1, 0x2,
0xc, 0x1, 0x3,
0x2, 0x0, 0x1ae,
0xaa, 0x1, 0x0,
0xbb, 0x1, 0x9,
0xbb, 0x0, 0x8,
0xe, 0x0, 0x3,
0xd, 0x0, 0x1,
0xc, 0x0, 0x2,
0x2, 0x3, 0x3709,
0xaa, 0x0, 0x3,
0xbb, 0x0, 0xc,
0xbb, 0x1, 0xd,
0xbb, 0x2, 0xe,
0x2, 0x3, 0x63,
0xc, 0x0, 0x3,
0x2, 0x3, 0x68,
0x1, 0x0, 0x3,
0x2, 0x3, 0xfa,
0xaa, 0x0, 0x3,
0x2, 0x3, 0x1e,
0xd, 0x1, 0x3,
0x2, 0x3, 0x63,
0xe, 0x1, 0x3,
0x2, 0x0, 0x18c,
0xaa, 0x0, 0x1,
0x2, 0x3, 0x63,
0x1, 0x2, 0x3,
0x2, 0x3, 0x6b,
0xc, 0x2, 0x3,
0x2, 0x1, 0x83,
0xaa, 0x2, 0x1,
0x2, 0x1, 0x47,
0xbb, 0x0, 0xf,
0xaa, 0x0, 0x1
通过分析每个字节码对应的功能, 对其进行转换, 以下是转换的代码:
public class GoCode {
public static void main(String[] args) {
int[] code = {
0xbb, 0x0, 0x0,
0xbb, 0x1, 0x1,
0xbb, 0x2, 0x2,
0xbb, 0x3, 0x3,
0xc, 0x1, 0x2,
0x2, 0x2, 0x11b,
0xaa, 0x1, 0x2,
0xbb, 0x1, 0x1,
0xbb, 0x2, 0x2,
0xc, 0x0, 0x1,
0xe, 0x0, 0x2,
0xd, 0x0, 0x3,
0x2, 0x2, 0x7901,
0xaa, 0x0, 0x2,
0xbb, 0x2, 0x2,
0x2, 0x0, 0x63,
0x1, 0x2, 0x0,
0xbb, 0x0, 0x0,
0xe, 0x0, 0x2,
0xd, 0x0, 0x1,
0xc, 0x0, 0x3,
0x2, 0x1, 0x1ff6,
0xaa, 0x0, 0x1,
0xbb, 0x1, 0x1,
0xbb, 0x0, 0x0,
0xbb, 0x2, 0x2,
0xc, 0x1, 0x0,
0xc, 0x1, 0x2,
0xc, 0x1, 0x3,
0x2, 0x0, 0x21e,
0xaa, 0x1, 0x0,
0xbb, 0x1, 0x1,
0xbb, 0x0, 0x0,
0xe, 0x0, 0x3,
0xd, 0x0, 0x1,
0xc, 0x0, 0x2,
0x2, 0x3, 0x3331,
0xaa, 0x0, 0x3,
0xbb, 0x0, 0x4,
0xbb, 0x1, 0x5,
0xbb, 0x2, 0x6,
0x2, 0x3, 0x63,
0xc, 0x0, 0x3,
0x2, 0x3, 0x68,
0x1, 0x0, 0x3,
0x2, 0x3, 0x152,
0xaa, 0x0, 0x3,
0x2, 0x3, 0x33,
0xd, 0x1, 0x3,
0x2, 0x3, 0x63,
0xe, 0x1, 0x3,
0x2, 0x0, 0x441,
0xaa, 0x0, 0x1,
0x2, 0x3, 0x63,
0x1, 0x2, 0x3,
0x2, 0x3, 0x6b,
0xc, 0x2, 0x3,
0x2, 0x1, 0x10e,
0xaa, 0x2, 0x1,
0x2, 0x1, 0x9e,
0xbb, 0x0, 0x7,
0xaa, 0x0, 0x1,
0xbb, 0x0, 0x8,
0xbb, 0x1, 0x9,
0xbb, 0x2, 0xa,
0xbb, 0x3, 0xb,
0xe, 0x0, 0x3,
0x2, 0x3, 0x36ce,
0xaa, 0x0, 0x3,
0xbb, 0x0, 0x8,
0xbb, 0x3, 0xb,
0xc, 0x0, 0x1,
0xe, 0x0, 0x2,
0xd, 0x0, 0x3,
0x2, 0x2, 0x682d,
0xaa, 0x0, 0x2,
0xbb, 0x2, 0xa,
0x2, 0x0, 0x63,
0x1, 0x2, 0x0,
0xbb, 0x0, 0x8,
0xe, 0x0, 0x2,
0xd, 0x0, 0x1,
0xc, 0x0, 0x3,
0x2, 0x1, 0x15,
0xaa, 0x0, 0x1,
0xbb, 0x1, 0x9,
0xbb, 0x0, 0x8,
0xbb, 0x2, 0xa,
0xc, 0x1, 0x0,
0xc, 0x1, 0x2,
0xc, 0x1, 0x3,
0x2, 0x0, 0x1ae,
0xaa, 0x1, 0x0,
0xbb, 0x1, 0x9,
0xbb, 0x0, 0x8,
0xe, 0x0, 0x3,
0xd, 0x0, 0x1,
0xc, 0x0, 0x2,
0x2, 0x3, 0x3709,
0xaa, 0x0, 0x3,
0xbb, 0x0, 0xc,
0xbb, 0x1, 0xd,
0xbb, 0x2, 0xe,
0x2, 0x3, 0x63,
0xc, 0x0, 0x3,
0x2, 0x3, 0x68,
0x1, 0x0, 0x3,
0x2, 0x3, 0xfa,
0xaa, 0x0, 0x3,
0x2, 0x3, 0x1e,
0xd, 0x1, 0x3,
0x2, 0x3, 0x63,
0xe, 0x1, 0x3,
0x2, 0x0, 0x18c,
0xaa, 0x0, 0x1,
0x2, 0x3, 0x63,
0x1, 0x2, 0x3,
0x2, 0x3, 0x6b,
0xc, 0x2, 0x3,
0x2, 0x1, 0x83,
0xaa, 0x2, 0x1,
0x2, 0x1, 0x47,
0xbb, 0x0, 0xf,
0xaa, 0x0, 0x1};
for (int i = 0; i < code.length; i += 3) {
//导入Slice数组的数据
if (code[i] == 0xBB) {
System.out.println("mov regs[" + code[i + 1] + "] Slice[" + code[i + 2] + "]");
}
//add指令, 针对两个寄存器
else if (code[i] == 0xC) {
System.out.println("add regs[" + code[i + 1] + "] regs[" + code[i + 2] + "]");
}
//一个立即数的mov指令
else if (code[i] == 0x2) {
System.out.printf("mov regs[%d] %#x\n", code[i + 1], code[i + 2]);
}
//cmp指令, 只不过不一样直接跳到exit
else if (code[i] == 0xAA) {
System.out.println("cmp regs[" + code[i + 1] + "] regs[" + code[i + 2] + "]");
System.out.println(" jnz exit\n");
}
//mul乘法指令
else if (code[i] == 0xE) {
System.out.println("mul regs[" + code[i + 1] + "] regs[" + code[i + 2] + "]");
}
//sub减法指令
else if (code[i] == 0xD) {
System.out.println("sub regs[" + code[i + 1] + "] regs[" + code[i + 2] + "]");
}
//xor异或指令
else if (code[i] == 0x1) {
System.out.println("xor regs[" + code[i + 1] + "] regs[" + code[i + 2] + "]");
}
//用于打印还未处理的指令
else {
System.out.printf("%3x %3x %3x\n", code[i], code[i + 1], code[i + 2]);
}
}
转换后得到伪汇编代码, 为了方便查看, jnz用了缩进
mov regs[0] Slice[0]
mov regs[1] Slice[1]
mov regs[2] Slice[2]
mov regs[3] Slice[3]
add regs[1] regs[2]
mov regs[2] 0x11b
cmp regs[1] regs[2]
jnz exit
mov regs[1] Slice[1]
mov regs[2] Slice[2]
add regs[0] regs[1]
mul regs[0] regs[2]
sub regs[0] regs[3]
mov regs[2] 0x7901
cmp regs[0] regs[2]
jnz exit
mov regs[2] Slice[2]
mov regs[0] 0x63
xor regs[2] regs[0]
mov regs[0] Slice[0]
mul regs[0] regs[2]
sub regs[0] regs[1]
add regs[0] regs[3]
mov regs[1] 0x1ff6
cmp regs[0] regs[1]
jnz exit
mov regs[1] Slice[1]
mov regs[0] Slice[0]
mov regs[2] Slice[2]
add regs[1] regs[0]
add regs[1] regs[2]
add regs[1] regs[3]
mov regs[0] 0x21e
cmp regs[1] regs[0]
jnz exit
mov regs[1] Slice[1]
mov regs[0] Slice[0]
mul regs[0] regs[3]
sub regs[0] regs[1]
add regs[0] regs[2]
mov regs[3] 0x3331
cmp regs[0] regs[3]
jnz exit
mov regs[0] Slice[4]
mov regs[1] Slice[5]
mov regs[2] Slice[6]
mov regs[3] 0x63
add regs[0] regs[3]
mov regs[3] 0x68
xor regs[0] regs[3]
mov regs[3] 0x152
cmp regs[0] regs[3]
jnz exit
mov regs[3] 0x33
sub regs[1] regs[3]
mov regs[3] 0x63
mul regs[1] regs[3]
mov regs[0] 0x441
cmp regs[0] regs[1]
jnz exit
mov regs[3] 0x63
xor regs[2] regs[3]
mov regs[3] 0x6b
add regs[2] regs[3]
mov regs[1] 0x10e
cmp regs[2] regs[1]
jnz exit
mov regs[1] 0x9e
mov regs[0] Slice[7]
cmp regs[0] regs[1]
jnz exit
mov regs[0] Slice[8]
mov regs[1] Slice[9]
mov regs[2] Slice[10]
mov regs[3] Slice[11]
mul regs[0] regs[3]
mov regs[3] 0x36ce
cmp regs[0] regs[3]
jnz exit
mov regs[0] Slice[8]
mov regs[3] Slice[11]
add regs[0] regs[1]
mul regs[0] regs[2]
sub regs[0] regs[3]
mov regs[2] 0x682d
cmp regs[0] regs[2]
jnz exit
mov regs[2] Slice[10]
mov regs[0] 0x63
xor regs[2] regs[0]
mov regs[0] Slice[8]
mul regs[0] regs[2]
sub regs[0] regs[1]
add regs[0] regs[3]
mov regs[1] 0x15
cmp regs[0] regs[1]
jnz exit
mov regs[1] Slice[9]
mov regs[0] Slice[8]
mov regs[2] Slice[10]
add regs[1] regs[0]
add regs[1] regs[2]
add regs[1] regs[3]
mov regs[0] 0x1ae
cmp regs[1] regs[0]
jnz exit
mov regs[1] Slice[9]
mov regs[0] Slice[8]
mul regs[0] regs[3]
sub regs[0] regs[1]
add regs[0] regs[2]
mov regs[3] 0x3709
cmp regs[0] regs[3]
jnz exit
mov regs[0] Slice[12]
mov regs[1] Slice[13]
mov regs[2] Slice[14]
mov regs[3] 0x63
add regs[0] regs[3]
mov regs[3] 0x68
xor regs[0] regs[3]
mov regs[3] 0xfa
cmp regs[0] regs[3]
jnz exit
mov regs[3] 0x1e
sub regs[1] regs[3]
mov regs[3] 0x63
mul regs[1] regs[3]
mov regs[0] 0x18c
cmp regs[0] regs[1]
jnz exit
mov regs[3] 0x63
xor regs[2] regs[3]
mov regs[3] 0x6b
add regs[2] regs[3]
mov regs[1] 0x83
cmp regs[2] regs[1]
jnz exit
mov regs[1] 0x47
mov regs[0] Slice[15]
cmp regs[0] regs[1]
jnz exit
然后我们使用字节码生成表达式
//创建一个regs寄存器数组, 因为要输出的是表达式所以使用String类型
String[] regs = new String[4];
for (int i = 0; i < code.length; i += 3) {
//导入Slice数组的数据
if (code[i] == 0xBB) {
regs[code[i + 1]] = "Slice[" + code[i + 2] + "]";
}
//加法运算
else if (code[i] == 0xC) {
regs[code[i + 1]] = "(" + regs[code[i + 1]] + " + " + regs[code[i + 2]] + ")";
}
//立即数mov
else if (code[i] == 0x2) {
regs[code[i + 1]] = code[i + 2] + "";
}
//乘法
else if (code[i] == 0xE) {
regs[code[i + 1]] = "(" + regs[code[i + 1]] + " * " + regs[code[i + 2]] + ")";
}
//sub减法指令
else if (code[i] == 0xD) {
regs[code[i + 1]] = "(" + regs[code[i + 1]] + " - " + regs[code[i + 2]] + ")";
}
else if (code[i] == 0x1) {
regs[code[i + 1]] = "(" + regs[code[i + 1]] + " ^ " + regs[code[i + 2]] + ")";
}
else if (code[i] == 0xAA) {
System.out.println("s.add(" + regs[code[i + 1]] + " == " + regs[code[i + 2]] + ")");
}
得到了表达后, 使用z3求解, 注意去掉无用的括号, 并且修改一些算式的顺序.
from z3 import *
s = Solver()
Slice = [BitVec('%d' % i, 8) for i in range(16)]
s.add(Slice[1] + Slice[2] == 283)
s.add(((Slice[0] + Slice[1]) * Slice[2]) - Slice[3] == 30977)
s.add(((Slice[2] ^ 99) * Slice[0]) - Slice[1] + Slice[3] == 8182)
s.add(Slice[0] + Slice[1] + Slice[2] + Slice[3] == 542)
s.add(Slice[0] * Slice[3] - Slice[1] + Slice[2] == 13105)
s.add((Slice[4]+99)^104 == 338)
s.add((Slice[5]-51)*99 == 1089)
s.add((Slice[6] ^ 99) + 107 == 270)
s.add(Slice[7] == 158)
s.add(Slice[8] * Slice[11] == 14030)
s.add(((Slice[8] + Slice[9]) * Slice[10]) - Slice[11] == 26669)
s.add(((Slice[8] * (Slice[10] ^ 99)) - Slice[9]) + Slice[11] == 21)
s.add(Slice[8] + Slice[9] + Slice[10] + Slice[11] == 430)
s.add(((Slice[8] * Slice[11]) - Slice[9]) + Slice[10] == 14089)
s.add((Slice[12] + 99) ^ 104 == 250)
s.add((Slice[13] - 30) * 99 == 396)
s.add((Slice[14] ^ 99) + 107 == 131)
s.add(Slice[15] == 71)
if s.check() == sat:
sm = s.model()
flag_ = [(sm[Slice[i]].as_long().real) for i in range(16)]
for i in flag_:
print(hex(i)[2:], end = '')
else:
print("error")
#bdcc4f46d73ec09ee628633d2f227b47
最后修改格式得到flag
flag
PCL{bdcc4f46d73ec09ee628633d2f227b47}