运行程序

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}