[CTF] DEF CON CTF Qualifier 2024 - pass-it-on analysis : deep dive into swift virtual machine

The Orange·2024년 5월 21일
0

CTF

목록 보기
7/7
Overview
1. Analysis of Binary
2. Analysis of Goal
3. Solving Problems
	3-1. read the first bit of the random constant (be44)
	3-2. construct the random constant using wait instruction and after_op_func

Overview


This challenge is from DEFCON CTF 32 Qualifier (reversing).

This post contains my approach of how I tried to solve it and failed before seeing writeup, and analysis of payload from writeup.

I'm writing this post for the following reasons.

  1. This challenge is the most interesting challenge that I've ever faced.
  2. I hope this post can help others learn how to do analysis, and the process of recognizing problems and solutions for them. (most of this post is about the detailed process of analyzing the binary)

1. Analysis of Binary


Before getting into the analysis, sorry for my terrible sense in naming things :(

And if you only wanna see the main problem of this challenge, start reading from Analysis of Goal.

binary:

➜  passiton file challenge
challenge: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 3.2.0, stripped

run.sh:

LD_LIBRARY_PATH=./lib/ ./challenge

execution:

➜  passiton ./run.sh
asdf
Swift/ErrorType.swift:200: Fatal error: Error raised at top level: Error Domain=NSCocoaErrorDomain Code=3840 "The data is not in the correct format."
Current stack trace:
0    libswiftCore.so                    0x00007f12e97f60d0 _swift_stdlib_reportFatalErrorInFile + 109
1    libswiftCore.so                    0x00007f12e94c57e8 <unavailable> + 1464296
2    libswiftCore.so                    0x00007f12e94c5687 <unavailable> + 1463943
3    libswiftCore.so                    0x00007f12e94c44c0 _assertionFailure(_:_:file:line:flags:) + 339
4    libswiftCore.so                    0x00007f12e952b3de <unavailable> + 1881054
5    challenge                          0x000055ce9e4906ed <unavailable> + 22253
6    libc.so.6                          0x00007f12e84dad90 <unavailable> + 171408
7    libc.so.6                          0x00007f12e84dadc0 __libc_start_main + 128
8    challenge                          0x000055ce9e48fdd5 <unavailable> + 19925
Illegal instruction

It seems like it has a correct format of data.

gdb-peda$ bt
#0  0x00007ffff6bb17e2 in read () from /lib/x86_64-linux-gnu/libc.so.6
#1  0x00007ffff6b29c36 in _IO_file_underflow () from /lib/x86_64-linux-gnu/libc.so.6
#2  0x00007ffff6b1d308 in getdelim () from /lib/x86_64-linux-gnu/libc.so.6
#3  0x00007ffff7de29e4 in swift_stdlib_readLine_stdin () from ./lib/libswiftCore.so
#4  0x00007ffff7b5c042 in $ss8readLine16strippingNewlineSSSgSb_tF () from ./lib/libswiftCore.so
#5  0x0000555555560961 in ?? ()
#6  0x0000555555559ace in ?? ()
#7  0x00005555555591d1 in ?? ()
#8  0x00007ffff6ac6d90 in ?? () from /lib/x86_64-linux-gnu/libc.so.6
#9  0x00007ffff6ac6e40 in __libc_start_main () from /lib/x86_64-linux-gnu/libc.so.6
#10 0x0000555555558dd5 in ?? ()
gdb-peda$ 

The readLine function is called from 0x0000555555560961 (sub_C940).

 	v2 = (char *)_ss8readLine16strippingNewlineSSSgSb_tF(1LL); // readLine
  if ( !v3 )
    BUG();
  v4 = (__int64)v3;
  v43[0] = v2;
  v43[1] = v3;
  v5 = *(_QWORD *)_sSS10FoundationE8EncodingV5asciiACvau();
  v6 = sub_DBD0();
  v8 = _sSy10FoundationE4data5using20allowLossyConversionAA4DataVSgSSAAE8EncodingV_SbtF(v5, 0LL, &_sSSN, v6);
  if ( (unsigned int)HIBYTE(v7) > 0xFE )
    BUG();
  v9 = v7;
  _s10Foundation17JSONSerializationCMa(0LL);
  v10 = (_QWORD *)_s10Foundation17JSONSerializationC14ReadingOptionsV17mutableContainersAEvau(); // JSON
  _s10Foundation17JSONSerializationC10jsonObject4with7optionsypAA4DataV_AC14ReadingOptionsVtKFZ(v8, v9, *v10);
  if ( v1 )
  {
    swift_bridgeObjectRelease(v4);
    return sub_DC00(v8, v9);
  }
  v52 = 0LL;
  v48 = (char *)v4;
  sub_DC00(v8, v9);
  v12 = sub_5720(&qword_13248);
  if ( !(unsigned __int8)swift_dynamicCast(v43, v46, (char *)&_sypN + 8, v12, 6LL) )
    BUG();
  v13 = 1LL << v43[0][32];
  v14 = ~(-1LL << v13);
  if ( v13 >= 64 )
    v14 = -1LL;
  _RBP = *((_QWORD *)v43[0] + 8) & v14;
  v51 = (unsigned __int64)(v13 + 63) >> 6;
  v45 = v43[0];
  swift_bridgeObjectRetain(v43[0]);
  ...

As the word “JSON” is visible, it is quite sure that it reads input and parses it as json.

        v24 = *(_QWORD *)(v45 + 48);
        v25 = *(_QWORD *)(v24 + 16 * v18);
        v26 = *(_QWORD *)(v24 + 16 * v18 + 8);
        v27 = *(_QWORD *)(*(_QWORD *)(v45 + 56) + 8 * v18);
        if ( v25 == 106 && v26 == 0xE100000000000000LL
          || (_ss27_stringCompareWithSmolCheck__9expectingSbs11_StringGutsV_ADs01_G16ComparisonResultOtF(
                'j',
                0xE100000000000000LL,
                v25,
                v26,
                0LL) & 1) != 0 )
        {
          v46[0] = v27;
          swift_retain_n(v27, 2LL);
          swift_bridgeObjectRetain(v26);
          swift_dynamicCast(v43, v46, v44, &_ss6UInt32VN, 7LL);
          (*(void (__fastcall **)(_QWORD))(*(_QWORD *)a1 + 576LL))(LODWORD(v43[0]));
          goto LABEL_10;
        }
        if ( v25 == 6583145 && v26 == 0xE300000000000000LL
          || (_ss27_stringCompareWithSmolCheck__9expectingSbs11_StringGutsV_ADs01_G16ComparisonResultOtF(
                'dsi',
                0xE300000000000000LL,
                v25,
                v26,
                0LL) & 1) != 0 )
        {
          v46[0] = v27;
          swift_retain_n(v27, 2LL);
          swift_bridgeObjectRetain(v26);
          swift_dynamicCast(v43, v46, v44, &_sSbN, 7LL);
          (*(void (__fastcall **)(_QWORD))(*(_QWORD *)a1 + 600LL))(LODWORD(v43[0]));
          goto LABEL_10;
        }
        if ( v25 == 6583151 && v26 == 0xE300000000000000LL
          || (_ss27_stringCompareWithSmolCheck__9expectingSbs11_StringGutsV_ADs01_G16ComparisonResultOtF(
                'dso',
                0xE300000000000000LL,
                v25,
                v26,
                0LL) & 1) != 0 )
        {
          v46[0] = v27;
          swift_retain_n(v27, 2LL);
          swift_bridgeObjectRetain(v26);
          swift_dynamicCast(v43, v46, v44, &_sSbN, 7LL);
          (*(void (__fastcall **)(_QWORD))(*(_QWORD *)a1 + 624LL))(LODWORD(v43[0]));
          goto LABEL_10;
        }
        ...

The stringCompare functions are called with the string argument like ‘j’, ‘isd’, ‘osd’.

You can guess that they are json keys to be parsed.

For the keys “i” and “j” are parsed differently.

      if ( v25 == 102 && v26 == 0xE100000000000000LL
        || (_ss27_stringCompareWithSmolCheck__9expectingSbs11_StringGutsV_ADs01_G16ComparisonResultOtF(
              'f',
              0xE100000000000000LL,
              v25,
              v26,
              0LL) & 1) != 0 )
      {
        v46[0] = v27;
        swift_retain_n(v27, 2LL);
        swift_bridgeObjectRetain(v26);
        v35 = sub_5720(&unk_13250);
        swift_dynamicCast(v43, v46, v44, v35, 7LL);
        v49 = (__int64 (*)(void))v43[0];
        v54 = *(void (__fastcall **)(__int64 *, _QWORD))(v43[0] + 16);
        if ( v54 )
        {
          v53 = *(__int64 (**)(void))(*(_QWORD *)a1 + 976LL);
          v36 = 0LL;
          do
          {
            LODWORD(v50) = *((_DWORD *)v49 + v36 + 8);
            v47 = v36 + 1;
            v37 = v53();
            (*(void (__fastcall **)(_QWORD))(*(_QWORD *)v37 + 128LL))((unsigned int)v50);
            swift_release(v37);
            v36 = v47;
          }
          while ( v54 != (void (__fastcall *)(__int64 *, _QWORD))v47 );
        }
        swift_release(v27);
        swift_release(v49);
        swift_bridgeObjectRelease(v26);
      }
      ...

It has a loop, so it is possible to guess that the value of key “f” is array.

    v46[0] = v27;                               // parsing for the key "i"
    swift_retain_n(v27, 2LL);
    swift_bridgeObjectRetain(v26);
    v28 = sub_5720(&unk_13258);
    swift_dynamicCast(v43, v46, v44, v28, 7LL);
    v29 = v43[0];
    v30 = v52;
    v50 = sub_C310(v43[0]); // acutal parsing
    v52 = v30;
    if ( v30 )
    {
      swift_bridgeObjectRelease(v48);
      swift_bridgeObjectRelease(v26);
      swift_release(v27);
      swift_release(v29);
      v23 = v45;
      swift_release(v45);
      return swift_bridgeObjectRelease(v23);
    }
    swift_release(v29);
    v49 = *(__int64 (**)(void))(*(_QWORD *)a1 + 1072LL);
    v31 = v49();
    v47 = (*(__int64 (**)(void))(*(_QWORD *)v31 + 136LL))();
    swift_release(v31);
    v32 = *(_QWORD *)(v47 + 16);
    swift_release(v47);
    v19 = __OFADD__(*(_QWORD *)(v50 + 16), v32);
    v47 = *(_QWORD *)(v50 + 16) + v32;
    if ( v19 )
      BUG();
    v19 = __OFSUB__(v47--, 1LL);
    if ( v19 )
      BUG();
    if ( v47 >= 32 )
      break;
    v49 = (__int64 (*)(void))v49();
    v54 = (void (__fastcall *)(__int64 *, _QWORD))(*(__int64 (__fastcall **)(__int64 *))(*(_QWORD *)v49 + 152LL))(v46);
    v53 = v33;
   
------------------------------------------------------------------------------------------
    
   // sub_C310
  result = swiftEmptyArrayStorage;
  v2 = *(_QWORD *)(a1 + 16);
  if ( v2 )
  {
    v3 = 0LL;
    v19 = *(_QWORD *)(a1 + 16);
    while ( 2 )
    {
      if ( v3 + 1 >= v2 )
        BUG();
      v4 = *(unsigned __int8 *)(a1 + v3 + 32);
      v5 = *(_BYTE *)(a1 + v3 + 33) & 0x1F;
      switch ( (unsigned __int64)*(unsigned __int8 *)(a1 + v3 + 33) >> 5 )
      {
        case 0uLL:
          v6 = swift_allocObject(&unk_13410, 56LL, 7LL);
          *(_OWORD *)(v6 + 40) = 0LL;
          *(_QWORD *)(v6 + 16) = 'pmJ'; // opcode name
          *(_QWORD *)(v6 + 24) = 0xE300000000000000LL;
          *(_WORD *)(v6 + 32) = v5;
          swift_beginAccess(v6 + 48, v22, 1LL, 0LL);
          *(_DWORD *)(v6 + 48) = v4 & 0x1F; // operand value
          v7 = v4 >> 5;
          v8 = v6 + 52;
          v9 = &v21;
          goto LABEL_18;
        case 1uLL:
          v6 = swift_allocObject(&unk_13528, 60LL, 7LL);
          *(_OWORD *)(v6 + 40) = 0LL;
          *(_DWORD *)(v6 + 56) = 0;
          *(_QWORD *)(v6 + 16) = 'tiaW';
          *(_QWORD *)(v6 + 24) = 0xE400000000000000LL;
          *(_WORD *)(v6 + 32) = v5;
          swift_beginAccess(v6 + 48, v25, 1LL, 0LL);
          *(_DWORD *)(v6 + 48) = v4 & 0x1F;
          swift_beginAccess(v6 + 52, v24, 1LL, 0LL);
          *(_DWORD *)(v6 + 52) = (v4 >> 5) & 3;
          v10 = v4 >> 7;
          v11 = v6 + 56;
          v12 = &v23;
          goto LABEL_16;
          
          ...
          
          v3 += 2LL;
          _sSa034_makeUniqueAndReserveCapacityIfNotB0yyFyXl_Ts5();
          v18 = swiftEmptyArrayStorage[2];
          if ( swiftEmptyArrayStorage[3] >> 1 <= v18 )
            _sSa16_createNewBuffer14bufferIsUnique15minimumCapacity13growForAppendySb_SiSbtFyXl_Ts5(
              swiftEmptyArrayStorage[3] >= 2uLL,
              v18 + 1,
              1LL);
          _sSa37_appendElementAssumeUniqueAndCapacity_03newB0ySi_xntFyXl_Ts5(v18, v6);
          _sSa12_endMutationyyFyXl_Ts5();
          v2 = v19;
          if ( v3 < v19 )
            continue;
          result = swiftEmptyArrayStorage;
          break;

It looks like it parses “i” as array for crafting instructions for virtual machine.

It fills each structure with opcode name and operand values, and appends it to the array.

The function for emulating specific instruction can be found by setting watchpoint on written addresses. (where operand values reside)

  // sub_8B10 (for mov instruction)
  v3 = v2;
  LODWORD(v4) = 0;
  switch ( (*(unsigned __int16 (**)(void))(*(_QWORD *)v2 + 256LL))() ) // operand read here
  {
    case 0u: // operand decides what to do
      v5 = (*(__int64 (**)(void))(*(_QWORD *)a2 + 184LL))();
      v6 = *(_QWORD *)(qword_14610 + 16);
      if ( v6 )
      {
        for ( i = 0LL; i != v6; ++i )
        {
          v8 = *(_DWORD *)(qword_14610 + 4 * i + 32);
          v9 = 1LL << v8;
          if ( v8 >= 0x40 )
            v9 = 0LL;
          if ( __OFSUB__(0xFFFFFFFFLL, v9) )
            BUG();
          if ( 0xFFFFFFFFLL - v9 < 0 )
            BUG();
          v5 &= -1 - v9;
        }
      }
      v10 = 0x100000001LL * v5;
      v11 = (*(__int64 (**)(void))(*a1 + 832))();
      v4 = v10 >> v11;
      if ( v11 >= 0x40 )
        LODWORD(v4) = 0;
      goto LABEL_19;
    case 1u:
      v12 = (*(__int64 (**)(void))(*a1 + 472))();
      goto LABEL_18;
    case 2u:
      v12 = (*(__int64 (**)(void))(*a1 + 496))();
      goto LABEL_18;
    case 3u:
      goto LABEL_19;
    case 5u:
      v13 = (*(__int64 (**)(void))(*a1 + 1024))();
      v14 = *a1;
      ...

In this way, behaviors of every instruction can be analyzed.

(From now on, I call the function for emulating specific instruction as the instruction function)

Following is the code for crafting “i” array from user instruction.

def Jmp(a1, a2):
    return f'{(a1 & 0x1f) | (a2 << 5)}, {0 << 5}'
def Wait(a1, a2, a3):
    assert a2 < 4
    assert a3 < 2
    return f'{(a1 & 0x1f) | (a2 << 5) | (a3 << 7)}, {1 << 5}'
def In(src, shift):
    assert src in [0,1,2,3,6,7]
    return f'{(src << 5) | (shift & 0x1f)}, {2 << 5}'
def Out(dest, shift):
    assert dest in [0,1,2,3,4,5,6]
    return f'{(dest << 5) | (shift & 0x1f)}, {3 << 5}'
def Pull(a1, a2):
    assert a1 < 2 and a2 < 2
    return f'{(a1 << 6) | (a2 << 5) | 0x80}, {4 << 5}'
def Push(a1, a2):
    assert a1 < 2 and a2 < 2
    return f'{(a1 << 6) | (a2 << 5)}, {4 << 5}'
def Mov(src, cal, dest):
    assert src in [0,1,2,3,5,6,7]
    assert cal in [0,2,1]
    assert dest in [0,1,2,5,6,7]
    return f'{src | (cal << 3) | (dest << 5)}, {5 << 5}'
def Irq(a1, a2, a3):
    return f'{(a1 << 6) | (a2 << 5) | (a3 & 0x1f)}, {6 << 5}'
def Set(a1, a2):
    return f'{(a1 << 5) | (a2 & 0x1f)}, {7 << 5}'
   
   
inst = ''
inst += Irq(0, 0, 0) + ', '
inst += In(1, 0) + ', '
inst = inst[:-2]
payload = '{"j":1,"isd":1,"osd":1,"pt":1,"ps":1,"at":1,"as":1,"sc":1,"se":1,"sd":1,"ib":0,"ob":1,"seb":1,"sb":1,"st":1,"sn":1,"f":[1,2,3,4],'+f'"i":[{inst}]'+'}'

For efficient analysis, I wrote and used many gdb scripts below.

The function for parsing instruction (sub_C310) is called twice.

So it is easy to recognize that init instruction exists.

Followings are the gdb script for parsing init instruction and the result.

  • gdb script
    import gdb
    
    ge = gdb.execute
    gp = gdb.parse_and_eval
    
    ge('file challenge')
    ge('set environment LD_LIBRARY_PATH ./lib/')
    
    with open('./init.txt', 'wt') as f:
        f.write('')
    
    def out(string):
        with open('./init.txt', 'at') as f:
            f.write(string + '\n')
    
    class BP(gdb.Breakpoint):
        def stop(self):
            ebx = int(gp('$ebx'))
            eax = int(gp('$eax'))
            match eax >> 5:
                case 0:
                    out(f'Jmp {hex(ebx & 0x1f)} {hex(ebx >> 5)}')
                case 1:
                    out(f'Wait {hex(ebx & 0x1f)} {hex((ebx >> 5) & 3)} {hex(ebx >> 7)}')
                case 2:
                    out(f'In {hex(ebx >> 5)} {hex(ebx & 0x1f if (ebx & 0x1f) != 0 else 32)}')
                case 3:
                    out(f'Out {hex(ebx >> 5)} {hex(ebx & 0x1f if (ebx & 0x1f) != 0 else 32)}')
                case 4:
                    v15 = (ebx >> 6) & 1
                    if ebx & 0x80 != 0:
                        out(f'Pull {hex(v15)} {hex((ebx >> 5) & 1)}')
                    else:
                        out(f'Push {hex(v15)} {hex((ebx >> 5) & 1)}')
                case 5:
                    out(f'Mov {hex(ebx >> 5)} {hex((ebx >> 3) & 3)} {hex(ebx & 7)}')
                case 6:
                    out(f'Irq {hex((ebx >> 6) & 1)} {hex((ebx >> 5) & 1)} {hex(ebx & 0x1f)}')
                case 7:
                    out(f'Set {hex(ebx >> 5)} {hex(ebx & 0x1f)}')
                case _:
                    assert False
            return False
    
    BP(f'*{0x0000555555554000+0xC376}')
    
    payload = '{"j":1,"isd":1,"osd":1,"pt":1,"ps":1,"at":1,"as":1,"sc":1,"se":1,"sd":1,"ib":1,"ob":1,"seb":1,"sb":1,"st":1,"sn":1,"f":[1,2,3,4],'+f'"i":[]'+'}'
    ge(f'r <<< \'{payload}\'')
  • result
    Pull 0x0 0x1
    Set 0x1 0xf
    Out 0x0 0x1
    Jmp 0x2 0x2

(The role of each instruction will be handled later)

For every instruction function, it can be easily seen that many dynamic calls are from a1 and a2.

      v11 = (*(__int64 (**)(void))(*a1 + 832))();
      v4 = v10 >> v11;
      if ( v11 >= 0x40 )
        LODWORD(v4) = 0;
      goto LABEL_19;
    case 1u:
      v12 = (*(__int64 (**)(void))(*a1 + 472))();
      goto LABEL_18;
    case 2u:
      v12 = (*(__int64 (**)(void))(*a1 + 496))();
      goto LABEL_18;
    case 3u:
      goto LABEL_19;
    case 5u:
      v13 = (*(__int64 (**)(void))(*a1 + 1024))();
      v14 = *a1;
      if ( v13 == 1 )
        v15 = (*(__int64 (**)(void))(v14 + 1000))();
      else
        v15 = (*(__int64 (**)(void))(v14 + 976))();
      v37 = v15;
      v39 = (*(__int64 (**)(void))(*(_QWORD *)v15 + 144LL))();
      swift_release(v37);
      LODWORD(v4) = -(v39 < (*(unsigned int (**)(void))(*a1 + 1048))());
      goto LABEL_19;
    case 6u:
      v12 = (*(__int64 (**)(void))(*a1 + 400))();
      goto LABEL_18;
    case 7u:
      v12 = (*(__int64 (**)(void))(*a1 + 376))();
LABEL_18:

It can be figured out that there are about 2 types of functions while debugging callee functions.

Type 1. function for reading

__int64 __fastcall sub_B890()
{
  __int64 v0; // r13
  __int64 v1; // rbx
  char v3[32]; // [rsp+8h] [rbp-20h] BYREF

  swift_beginAccess(v0 + 24, v3, 0LL, 0LL);
  v1 = *(_QWORD *)(v0 + 24);
  swift_retain(v1);
  return v1;
}

Type 2. function for writing

__int64 __fastcall sub_B8C0(__int64 a1)
{
  __int64 v1; // r13
  __int64 v3; // rdi
  char v5[32]; // [rsp+8h] [rbp-20h] BYREF

  swift_beginAccess(v1 + 24, v5, 1LL, 0LL);
  v3 = *(_QWORD *)(v1 + 24);
  *(_QWORD *)(v1 + 24) = a1;
  return swift_release(v3);
}

It looks like they use r13 as base address like this of class in c++.

https://github.com/apple/swift/blob/main/docs/ABI/CallConvSummary.rst

Following the link, r13 is used as self in swift.

text:0000000000008B27                 mov     r15, rdi // rdi: a1
...
.text:0000000000008BBD                 mov     rax, [r15]
.text:0000000000008BC0                 mov     r13, r15
.text:0000000000008BC3                 call    qword ptr [rax+340h] // dynamic call from *a1

It uses a1 as self and calls function from *a1.

So a1 (so as a2) must be some memory for class.

To see a1 and a2 values, I used following gdb script.

  • gdb script for logging arguments.
    import gdb
    import re
    
    ge = gdb.execute
    gp = gdb.parse_and_eval
    
    ge('file challenge')
    ge('set environment LD_LIBRARY_PATH ./lib/')
    
    with open('./sub_his.txt', 'wt') as f:
        f.write('')
    
    def out(string):
        with open('./sub_his.txt', 'at') as f:
            f.write(string + '\n')
    
    class BP(gdb.Breakpoint):
        def stop(self):
            rip = int(gp('$rip')) - 0x0000555555554000
            name = ''
            if rip == 0x6F60:
                name = 'wait'
            elif rip == 0x8b10:
                name = 'mov'
            elif rip == 0x73C0:
                name = 'in'
            elif rip == 0x7A20:
                name = 'out'
            elif rip == 0x8310:
                name = 'pull'
            elif rip == 0x8670:
                name = 'push'
            elif rip == 0x91d0:
                name = 'irq'
            elif rip == 0x9560:
                name = 'set'
            elif rip == 0x6A90:
                name = 'jmp'
            r13 = int(gp('$r13'))
            rdi = int(gp('$rdi'))
            rsi = int(gp('$rsi'))
            be44 = int(gp('*(unsigned char*)0x55555557be44'))
            out(name+f'(self={hex(r13)},arg1={hex(rdi)},arg2={hex(rsi)}) be44={hex(be44)}')
            return False
        
    for i in [0x73C0, 0x8b10, 0x6F60, 0x7A20, 0x8310, 0x8670, 0x91d0, 0x9560, 0x6A90]:
        BP(f'*{0x0000555555554000+i}')
    
    def Jmp(a1, a2):
        return f'{(a1 & 0x1f) | (a2 << 5)}, {0 << 5}'
    def Wait(a1, a2, a3):
        assert a2 < 4
        assert a3 < 2
        return f'{(a1 & 0x1f) | (a2 << 5) | (a3 << 7)}, {1 << 5}'
    def In(src, shift):
        assert src in [0,1,2,3,6,7]
        return f'{(src << 5) | (shift & 0x1f)}, {2 << 5}'
    def Out(dest, shift):
        assert dest in [0,1,2,3,4,5,6]
        return f'{(dest << 5) | (shift & 0x1f)}, {3 << 5}'
    def Pull(a1, a2):
        assert a1 < 2 and a2 < 2
        return f'{(a1 << 6) | (a2 << 5) | 0x80}, {4 << 5}'
    def Push(a1, a2):
        assert a1 < 2 and a2 < 2
        return f'{(a1 << 6) | (a2 << 5)}, {4 << 5}'
    def Mov(src, cal, dest):
        assert src in [0,1,2,3,5,6,7]
        assert cal in [0,2,1]
        assert dest in [0,1,2,5,6,7]
        return f'{src | (cal << 3) | (dest << 5)}, {5 << 5}'
    def Irq(a1, a2, a3):
        return f'{(a1 << 6) | (a2 << 5) | (a3 & 0x1f)}, {6 << 5}'
    def Set(a1, a2):
        return f'{(a1 << 5) | (a2 & 0x1f)}, {7 << 5}'
    
    inst = ''
    inst += Mov(6, 0, 6) + ', '
    inst = inst[:-2]
    
    payload = '{"j":1,"isd":1,"osd":1,"pt":1,"ps":1,"at":1,"as":1,"sc":1,"se":1,"sd":1,"ib":0,"ob":1,"seb":1,"sb":1,"st":1,"sn":1,"f":[1,2,3,4],'+f'"i":[{inst}]'+'}'
    
    ge(f'r <<< \'{payload}\'')
    print(payload)
    exit()
    
  • result
    pull(self=0x55555557ba50,arg1=0x55555557bf40,arg2=0x55555557be20) be44=0x2
    mov(self=0x55555557fbd0,arg1=0x55555557c020,arg2=0x55555557be20) be44=0x2
    mov(self=0x55555557fbd0,arg1=0x55555557c020,arg2=0x55555557be20) be44=0x2
    mov(self=0x55555557fbd0,arg1=0x55555557c020,arg2=0x55555557be20) be44=0x2
    mov(self=0x55555557fbd0,arg1=0x55555557c020,arg2=0x55555557be20) be44=0x2
    mov(self=0x55555557fbd0,arg1=0x55555557c020,arg2=0x55555557be20) be44=0x2
    mov(self=0x55555557fbd0,arg1=0x55555557c020,arg2=0x55555557be20) be44=0x2
    mov(self=0x55555557fbd0,arg1=0x55555557c020,arg2=0x55555557be20) be44=0x2
    mov(self=0x55555557fbd0,arg1=0x55555557c020,arg2=0x55555557be20) be44=0x2
    set(self=0x55555557ba10,arg1=0x55555557bf40,arg2=0x55555557be20) be44=0x2
    mov(self=0x55555557fbd0,arg1=0x55555557c020,arg2=0x55555557be20) be44=0x0
    mov(self=0x55555557fbd0,arg1=0x55555557c020,arg2=0x55555557be20) be44=0x0
    mov(self=0x55555557fbd0,arg1=0x55555557c020,arg2=0x55555557be20) be44=0x0
    mov(self=0x55555557fbd0,arg1=0x55555557c020,arg2=0x55555557be20) be44=0x0
    mov(self=0x55555557fbd0,arg1=0x55555557c020,arg2=0x55555557be20) be44=0x0
    mov(self=0x55555557fbd0,arg1=0x55555557c020,arg2=0x55555557be20) be44=0x0
    mov(self=0x55555557fbd0,arg1=0x55555557c020,arg2=0x55555557be20) be44=0x0
    mov(self=0x55555557fbd0,arg1=0x55555557c020,arg2=0x55555557be20) be44=0x0
    out(self=0x55555557be60,arg1=0x55555557bf40,arg2=0x55555557be20) be44=0x0
    mov(self=0x55555557fbd0,arg1=0x55555557c020,arg2=0x55555557be20) be44=0x2
    mov(self=0x55555557fbd0,arg1=0x55555557c020,arg2=0x55555557be20) be44=0x2
    mov(self=0x55555557fbd0,arg1=0x55555557c020,arg2=0x55555557be20) be44=0x2
    mov(self=0x55555557fbd0,arg1=0x55555557c020,arg2=0x55555557be20) be44=0x2
    mov(self=0x55555557fbd0,arg1=0x55555557c020,arg2=0x55555557be20) be44=0x2
    mov(self=0x55555557fbd0,arg1=0x55555557c020,arg2=0x55555557be20) be44=0x2
    mov(self=0x55555557fbd0,arg1=0x55555557c020,arg2=0x55555557be20) be44=0x2
    jmp(self=0x55555557bea0,arg1=0x55555557bf40,arg2=0x55555557be20) be44=0x2
    mov(self=0x55555557fbd0,arg1=0x55555557c020,arg2=0x55555557be20) be44=0x0
    mov(self=0x55555557fbd0,arg1=0x55555557c020,arg2=0x55555557be20) be44=0x0
    out(self=0x55555557be60,arg1=0x55555557bf40,arg2=0x55555557be20) be44=0x0
    mov(self=0x55555557fbd0,arg1=0x55555557c020,arg2=0x55555557be20) be44=0x2
    mov(self=0x55555557fbd0,arg1=0x55555557c020,arg2=0x55555557be20) be44=0x2
    mov(self=0x55555557fbd0,arg1=0x55555557c020,arg2=0x55555557be20) be44=0x2
    mov(self=0x55555557fbd0,arg1=0x55555557c020,arg2=0x55555557be20) be44=0x2
    ...

There are a few things to recognize seeing above result. (ignore be44 for now)

  1. self points to the instruction structure where operand value resides.
  2. arg1 (which is a1) points to the structure for who added the instruction.
  3. arg2 points to the structure that doesn’t change.
  4. the rule for the order of executing instructions exists (init inst x1 + user inst x8 + init inst x1 + ..)
gdb-peda$ x/xg 0x55555557bf40
0x55555557bf40: 0x0000555555567e48
gdb-peda$ x/xg 0x55555557c020
0x55555557c020: 0x0000555555567e48
gdb-peda$ vmmap 0x0000555555567e48
Start              End                Perm      Name
0x0000555555567000 0x0000555555569000 rw-p      /home/deayzl/ctf/defcon2024/passiton/challenge
gdb-peda$ x/xg 0x55555557be20
0x55555557be20: 0x0000555555568300
gdb-peda$ vmmap 0x0000555555568300
Start              End                Perm      Name
0x0000555555567000 0x0000555555569000 rw-p      /home/deayzl/ctf/defcon2024/passiton/challenge

Many dynamic calls in each instruction function are from 0x0000555555567e48 (which resides in *a1).

Then, 0x0000555555567e48 is vtable for 0x55555557c020 and 0x55555557bf40.

0x55555557c020 is a class for user, and 0x55555557bf40 is for init instructions’.

From now on, I call 0x55555557c020 as my_context, 0x55555557bf40 as init_context, and the class of both is vm_context.

a2 is accessible from both context, so let’s just call it middle_context.

vm_contextvtableownername
0x55555557c0200x0000555555567e48usermy_context
0x55555557bf400x0000555555567e48init instructionsinit_context
0x55555557be200x0000555555568300middle (neutrality)middle_context

Following is the gdb script for parsing vtable.

It is easy to analyze instruction functions after defining the parsed structure in ida.

  • gdb script for parsing structure
    import gdb
    
    ge = gdb.execute
    gp = gdb.parse_and_eval
    
    ge('file challenge')
    ge('set environment LD_LIBRARY_PATH ./lib/')
    
    ge('b *0x0000555555554000+0x8310')
    
    def Jmp(a1, a2):
        return f'{(a1 & 0x1f) | (a2 << 5)}, {0 << 5}'
    def Wait(a1, a2, a3):
        assert a2 < 4
        assert a3 < 2
        return f'{(a1 & 0x1f) | (a2 << 5) | (a3 << 7)}, {1 << 5}'
    def In(src, shift):
        assert src in [0,1,2,3,6,7]
        return f'{(src << 5) | (shift & 0x1f)}, {2 << 5}'
    def Out(dest, shift):
        assert dest in [0,1,2,3,4,5,6]
        return f'{(dest << 5) | (shift & 0x1f)}, {3 << 5}'
    def Pull(a1, a2):
        assert a1 < 2 and a2 < 2
        return f'{(a1 << 6) | (a2 << 5) | 0x80}, {4 << 5}'
    def Push(a1, a2):
        assert a1 < 2 and a2 < 2
        return f'{(a1 << 6) | (a2 << 5)}, {4 << 5}'
    def Mov(src, cal, dest):
        assert src in [0,1,2,3,5,6,7]
        assert cal in [0,2,1]
        assert dest in [0,1,2,5,6,7]
        return f'{src | (cal << 3) | (dest << 5)}, {5 << 5}'
    def Irq(a1, a2, a3):
        return f'{(a1 << 6) | (a2 << 5) | (a3 & 0x1f)}, {6 << 5}'
    def Set(a1, a2):
        return f'{(a1 << 5) | (a2 & 0x1f)}, {7 << 5}'
    
    inst = ''
    inst += Wait(0x10, 2, 1) + ', '
    inst = inst[:-2]
    
    payload = '{"j":1,"isd":1,"osd":1,"pt":1,"ps":1,"at":1,"as":1,"sc":1,"se":1,"sd":1,"ib":1,"ob":1,"seb":1,"sb":1,"st":1,"sn":1,"f":[1,2,3,4],'+f'"i":[{inst}]'+'}'
    
    ge(f'r <<< \'{payload}\'')
    
    funcs = {}
    struct_def = 'struct vm_context {'
    counter = 0
    addr = 0x0000555555554000+0x13e48
    while addr < 0x0000555555554000+0x13e48+1000:
        value = int(gp(f'*(unsigned long*){addr}'))
        if 0x0000555555554000 <= value <= 0x0000555555565000:
            if funcs.get(str(value)) == None:
                struct_def += f'\n\tunsigned int (__fastcall *sub_{hex(value - 0x0000555555554000)[2:]})();'
                funcs[str(value)] = 1
            else:
                funcs[str(value)] += 1
                struct_def += f'\n\tunsigned int (__fastcall *sub_{hex(value - 0x0000555555554000)[2:]}_{funcs[str(value)]})();'
        else:
            struct_def += f'\n\tunsigned long idk{counter};'
            counter += 1
        addr += 8
    
    struct_def += '\n}'
    
    print(struct_def)
    exit()
  • result
    struct vm_vtable {
            unsigned long idk0;
            unsigned long idk1;
            unsigned long idk2;
            unsigned long idk3;
            unsigned long idk4;
            unsigned int (__fastcall *sub_f688)();
            unsigned long idk5;
            unsigned long idk6;
            unsigned long idk7;
            unsigned long idk8;
            unsigned long idk9;
            unsigned long idk10;
            unsigned long idk11;
            unsigned long idk12;
            unsigned long idk13;
            unsigned long idk14;
            unsigned long idk15;
            unsigned long idk16;
            unsigned long idk17;
            unsigned long idk18;
            unsigned long idk19;
            unsigned long idk20;
            unsigned long idk21;
            unsigned long idk22;
            unsigned long idk23;
            unsigned long idk24;
            unsigned long idk25;
            unsigned long idk26;
            unsigned long idk27;
            unsigned long idk28;
            unsigned long idk29;
            unsigned long idk30;
            unsigned long idk31;
            unsigned long idk32;
            unsigned long idk33;
            unsigned long idk34;
            unsigned long idk35;
            unsigned long idk36;
            unsigned long idk37;
            unsigned long idk38;
            unsigned long idk39;
            unsigned int (__fastcall *sub_9b80)();
            unsigned int (__fastcall *sub_9ba0)();
            unsigned int (__fastcall *sub_9bd0)();
            unsigned int (__fastcall *sub_9c00)();
            unsigned int (__fastcall *sub_9c20)();
            unsigned int (__fastcall *sub_9c50)();
            unsigned int (__fastcall *sub_9c90)();
            unsigned int (__fastcall *sub_9cb0)();
            unsigned int (__fastcall *sub_9ce0)();
            unsigned int (__fastcall *sub_9d20)();
            unsigned int (__fastcall *sub_9d40)();
            unsigned int (__fastcall *sub_9d70)();
            unsigned int (__fastcall *sub_9db0)();
            unsigned int (__fastcall *sub_9dd0)();
            unsigned int (__fastcall *sub_9e00)();
            unsigned int (__fastcall *sub_9e40)();
            unsigned int (__fastcall *sub_9e60)();
            unsigned int (__fastcall *sub_9e90)();
            unsigned int (__fastcall *sub_9ed0)();
            unsigned int (__fastcall *sub_9ef0)();
            unsigned int (__fastcall *sub_9f20)();
            unsigned int (__fastcall *sub_9f60)();
            unsigned int (__fastcall *sub_9f80)();
            unsigned int (__fastcall *sub_9fb0)();
            unsigned int (__fastcall *sub_9ff0)();
            unsigned int (__fastcall *sub_a010)();
            unsigned int (__fastcall *sub_a040)();
            unsigned int (__fastcall *sub_a080)();
            unsigned int (__fastcall *sub_a0a0)();
            unsigned int (__fastcall *sub_a0d0)();
            unsigned int (__fastcall *sub_a110)();
            unsigned int (__fastcall *sub_a130)();
            unsigned int (__fastcall *sub_a160)();
            unsigned int (__fastcall *sub_a1a0)();
            unsigned int (__fastcall *sub_a1c0)();
            unsigned int (__fastcall *sub_a1f0)();
            unsigned int (__fastcall *sub_a230)();
            unsigned int (__fastcall *sub_a250)();
            unsigned int (__fastcall *sub_a280)();
            unsigned int (__fastcall *sub_a2c0)();
            unsigned int (__fastcall *sub_a2e0)();
            unsigned int (__fastcall *sub_a310)();
            unsigned int (__fastcall *sub_a350)();
            unsigned int (__fastcall *sub_a370)();
            unsigned int (__fastcall *sub_a3a0)();
            unsigned int (__fastcall *sub_a3e0)();
            unsigned int (__fastcall *sub_a400)();
            unsigned int (__fastcall *sub_a430)();
            unsigned int (__fastcall *sub_a470)();
            unsigned int (__fastcall *sub_a490)();
            unsigned int (__fastcall *sub_a4c0)();
            unsigned int (__fastcall *sub_a500)();
            unsigned int (__fastcall *sub_a520)();
            unsigned int (__fastcall *sub_a550)();
            unsigned int (__fastcall *sub_a590)();
            unsigned int (__fastcall *sub_a5b0)();
            unsigned int (__fastcall *sub_a5e0)();
            unsigned int (__fastcall *sub_a620)();
            unsigned int (__fastcall *sub_a640)();
            unsigned int (__fastcall *sub_a670)();
            unsigned int (__fastcall *sub_a6b0)();
            unsigned int (__fastcall *sub_a6d0)();
            unsigned int (__fastcall *sub_a700)();
            unsigned int (__fastcall *sub_a740)();
            unsigned int (__fastcall *sub_a760)();
            unsigned int (__fastcall *sub_a790)();
            unsigned int (__fastcall *sub_a7d0)();
            unsigned int (__fastcall *sub_a7f0)();
            unsigned int (__fastcall *sub_a820)();
            unsigned int (__fastcall *sub_a860)();
            unsigned int (__fastcall *sub_a880)();
            unsigned int (__fastcall *sub_a8b0)();
            unsigned int (__fastcall *sub_a8f0)();
            unsigned int (__fastcall *sub_a910)();
            unsigned int (__fastcall *sub_a940)();
            unsigned int (__fastcall *sub_a980)();
            unsigned int (__fastcall *sub_a9a0)();
            unsigned int (__fastcall *sub_a9d0)();
            unsigned int (__fastcall *sub_aa10)();
            unsigned int (__fastcall *sub_aa30)();
            unsigned int (__fastcall *sub_aa60)();
            unsigned int (__fastcall *sub_aa90)();
            unsigned int (__fastcall *sub_aac0)();
            unsigned int (__fastcall *sub_aaf0)();
    }
  • analyzed instruction function example (in instruction)
    __int64 __fastcall in_op_sub_73C0(vm_context **a1, middle_context **a2)
    {
      __int64 v2; // r13
      char *op2; // rbp
      unsigned int op2_2; // eax
      __int64 _1_shl_op2; // rbx
      unsigned __int64 v7; // r15
      bool v8; // cf
      __int64 _1_shl_op2_neg_1; // rbx
      unsigned int (*get_be44)(void); // r15
      unsigned __int64 v11; // rbp
      unsigned int ib; // eax
      unsigned __int64 v13; // rbp
      unsigned __int64 v14; // r15
      unsigned int v15; // eax
      __int64 v16; // rax
      __int64 v17; // rdx
      char isd; // bl
      unsigned int (__fastcall *get_c03c_raw_1)(); // rax
      void (__fastcall *end_access)(char *, _QWORD); // rax
      _DWORD *c03c_1; // rdx
      int v22; // esi
      unsigned int op2_1; // eax
      unsigned int _32_op2; // ecx
      int v25; // r15d
      void (__fastcall *end_access_1)(char *, _QWORD); // rax
      _DWORD *c03c; // rdx
      unsigned int (__fastcall *v28)(); // rbx
      void (__fastcall *v29)(char *, _QWORD); // rax
      _DWORD *v30; // rdx
      int v31; // esi
      _DWORD *v32; // rdx
      unsigned int v33; // ebx
      int v34; // eax
      unsigned int v35; // eax
      __int64 v36; // rdi
      unsigned int c044; // ebx
      __int64 (*get_ps)(void); // r15
      unsigned int ps; // eax
      unsigned int v40; // ebx
      array_context **array_context; // r13
      vm_context *_a1; // rax
      __int64 be44; // [rsp+8h] [rbp-60h]
      unsigned int (__fastcall *get_c03c_raw)(); // [rsp+8h] [rbp-60h]
      __int64 (*get_op2)(void); // [rsp+18h] [rbp-50h]
      char v47[72]; // [rsp+20h] [rbp-48h] BYREF
    
      LODWORD(op2) = (_DWORD)a2;
      if ( (((__int64 (__fastcall *)(vm_context **))(*a1)->get_c072)(a1) & 1) == 0 )// 0x55555557c072 (sub_a500)
      {
        get_op2 = *(__int64 (**)(void))(*(_QWORD *)v2 + 224LL);
        op2_2 = get_op2();                          // op2
        _1_shl_op2 = 1LL << op2_2;
        LODWORD(v7) = 0;
        if ( op2_2 >= 0x40 )
          _1_shl_op2 = 0LL;
        v8 = _1_shl_op2 == 0;
        _1_shl_op2_neg_1 = _1_shl_op2 - 1;
        if ( !v8 )
        {
          switch ( (*(unsigned int (**)(void))(*(_QWORD *)v2 + 200LL))() )// op1
          {
            case 0u:
              get_be44 = (*a2)->get_be44;
              be44 = get_be44();
              v11 = be44 + ((unsigned __int64)get_be44() << 32);
              ib = (*a1)->get_ib();
              v13 = v11 >> ib;
              v14 = 0LL;
              if ( ib < 64 )
                v14 = v13;
              v7 = _1_shl_op2_neg_1 & v14;
              if ( HIDWORD(v7) )
                BUG();
              goto LABEL_16;
            case 1u:
              v15 = (*a1)->get_c048();              // 0x55555557c048 (sub_9ed0)
              goto LABEL_15;
            case 2u:
              v15 = (*a1)->get_c04c();              // 0x55555557c04c
              goto LABEL_15;
            case 3u:
              goto LABEL_16;
            case 6u:
              v15 = (*a1)->get_c03c();              // 0x55555557c03c (sub_9d20)
              goto LABEL_15;
            case 7u:
              v15 = (*a1)->get_c038();              // 0x55555557c038 (sub_9c90)
    LABEL_15:
              LODWORD(v7) = v15 & _1_shl_op2_neg_1;
    LABEL_16:
              isd = (*a1)->get_isd();               // isd 0x55555557c064
              LODWORD(op2) = get_op2();
              get_c03c_raw_1 = (*a1)->get_c03c_raw;
              if ( (isd & 1) != 0 )
              {
                get_c03c_raw = (*a1)->get_c03c_raw;
                end_access = (void (__fastcall *)(char *, _QWORD))((__int64 (__fastcall *)(char *))get_c03c_raw_1)(v47);
                v22 = 0;
                if ( (unsigned int)op2 < 0x20 )
                  v22 = *c03c_1 >> (char)op2;
                *c03c_1 = v22;
                end_access(v47, 0LL);               // sub_e740
                op2_1 = get_op2();                  // 0x55555557fda4
                _32_op2 = 32 - op2_1;
                if ( op2_1 > 0x20 )
                  BUG();
                v25 = (_DWORD)v7 << _32_op2;
                if ( _32_op2 >= 0x20 )
                  v25 = 0;
                end_access_1 = (void (__fastcall *)(char *, _QWORD))((__int64 (__fastcall *)(char *))get_c03c_raw)(v47);
                *c03c |= v25;                       // 0x55555557c03c
              }
              else
              {
                v28 = (*a1)->get_c03c_raw;
                v29 = (void (__fastcall *)(char *, _QWORD))((__int64 (__fastcall *)(char *))get_c03c_raw_1)(v47);
                v31 = 0;
                if ( (unsigned int)op2 < 0x20 )
                  v31 = *v30 << (char)op2;
                *v30 = v31;
                v29(v47, 0LL);
                op2 = v47;
                end_access_1 = (void (__fastcall *)(char *, _QWORD))((__int64 (__fastcall *)(char *))v28)(v47);
                *v32 |= v7;
              }
              end_access_1(v47, 0LL);
              v33 = (*a1)->get_c044();
              v34 = get_op2();
              v8 = __CFADD__(v33, v34);
              v35 = v33 + v34;
              if ( v8 )
                BUG();
              v36 = 32LL;
              if ( v35 < 0x20 )
                v36 = v35;
              ((void (__fastcall *)(__int64))(*a1)->write_c044)(v36);// 0x55555557c044 (sub_9e60)
              goto LABEL_30;
            default:
              v16 = sub_DA00();
              swift_allocError(&unk_12BA0, v16, 0LL, 0LL);
              *(_QWORD *)v17 = 2LL;
              *(_QWORD *)(v17 + 8) = 0LL;
              *(_BYTE *)(v17 + 16) = 2;
              swift_willThrow(&unk_12BA0);
              return (unsigned int)op2;
          }
        }
        BUG();
      }
    LABEL_30:
      if ( (((__int64 (*)(void))(*a1)->get_as)() & 1) != 0 )// as 0x55555557c071 (sub_a470)
      {
        c044 = (*a1)->get_c044();                   // 0x55555557c044 (sub_9e40)
        get_ps = (__int64 (*)(void))(*a1)->get_ps;
        if ( c044 >= (unsigned int)get_ps() )       // ps 0x55555557c06c (sub_a350)
        {
          ps = get_ps();                            // ps 0x55555557c06c (sub_a350)
          v40 = ((__int64 (__fastcall *)(_QWORD))(*a1)->sub_b470)(ps);// 0x55555557c020 (sub_b470)
          array_context = (array_context **)((__int64 (*)(void))(*a1)->get_array_context2)();
          LOBYTE(v40) = ((__int64 (__fastcall *)(_QWORD))(*array_context)->insert)(v40);// insert 0x55555557c100
          swift_release(array_context);
          _a1 = *a1;
          if ( (v40 & 1) != 0 )
          {
            LODWORD(op2) = 0;
            ((void (__fastcall *)(_QWORD))_a1->write_c03c)(0LL);
            ((void (__fastcall *)(_QWORD))(*a1)->write_c044)(0LL);
          }
          else
          {
            ((void (__fastcall *)(__int64))_a1->write_c072)(1LL);
            LOBYTE(op2) = 1;
          }
        }
        else
        {
          LODWORD(op2) = 0;
        }
      }
      else
      {
        LODWORD(op2) = 0;
      }
      return (unsigned int)op2;
    }

If you follow the xrefs of the instruction function, there are 2 more functions executed before and after the instruction function is exeucted.

.data:00000000000136D8                 dq offset sub_6300
.data:00000000000136E0                 dq offset sub_6340
.data:00000000000136E8                 dq offset sub_6360
.data:00000000000136F0                 dq offset sub_6390
.data:00000000000136F8                 dq offset sub_77F0
.data:0000000000013700                 dq offset in_op_sub_73C0
.data:0000000000013708                 dq offset in_op_validate_sub_76C0 // 1
.data:0000000000013710                 dq offset after_op_func_sub_64B0 // 2
.data:0000000000013718                 db  30h ; 0
.data:0000000000013719                 db    0
.data:000000000001371A                 db    0
.data:000000000001371B                 db    0
.data:000000000001371C                 db    0
.data:000000000001371D                 db    0

First one is for validation.

      // sub_B4D0
      ...
      if ( v10 + 1 == v4 )
      {
LABEL_10:
        swift_release(v8);
        v13 = (*vm_context)->get_sc();
        v14 = ((__int64 (*)(void))(*vm_context)->get_se)() & 1;
        v15 = __CFADD__(v13, v14);
        v16 = v13 + v14;
        if ( v15 )
          BUG();
        if ( v16 < 6
          && (*vm_context)->get_sb() < 0x20 // validate json values
          && (*vm_context)->get_ib() < 0x20
          && (*vm_context)->get_ob() < 0x20
          && (*vm_context)->get_seb() < 0x20
          && v22() < 0x20
          && (*vm_context)->get_pt() < 0x21
          && (*vm_context)->get_ps() < 0x21
          && (*vm_context)->get_j() < 0x20
          && (*vm_context)->get_sn() < 0x20 )
        {
          return ((__int64 (__fastcall *)(__int64))(*vm_context)->sub_adf0)(1LL);
        }
        else
        {
          v17 = sub_DA00();
          swift_allocError(&unk_12BA0, v17, 0LL, 0LL);
          *(_QWORD *)v18 = 3LL;
          *(_QWORD *)(v18 + 8) = 0LL;
          *(_BYTE *)(v18 + 16) = 2;
          return swift_willThrow(&unk_12BA0);
        }
      }
      else
      {
        while ( 1 )
        {
          if ( v7 > v10 )
            BUG();
          inst_structure = *(inst_structure ***)(v8 + 8 * v7 + 32);
          swift_retain(inst_structure);
          v12 = get_middle_context_c0b0();
          ((void (__fastcall *)(vm_context **, __int64))(*inst_structure)->op_validate_func)(vm_context, v12); // this is where validation function is executed
          if ( v0 )
            break;
          ++v7;
          swift_release(inst_structure);
          swift_release(v12);
          if ( v20 == v7 )
            goto LABEL_10;
        }
        swift_release(inst_structure);
        swift_release(v12);
        return swift_release(v8);
      }
    }
  }
  return result;
}

------------------------------------------------------------------------------------------
 
__int64 __fastcall in_op_validate_sub_76C0(vm_context **a1)
{
  __int64 v1; // r13
  __int64 ib_plus_op2; // rax
  __int64 (*get_ib)(void); // rbx
  unsigned int ib; // ebp
  int ib_1; // r15d
  int op2; // eax
  bool v7; // cf
  unsigned __int64 one; // rdx
  unsigned int v9; // esi
  __int64 v10; // rdi
  __int64 v11; // r8
  __int64 v12; // rax
  __int64 v13; // rdx

  ib_plus_op2 = (*(__int64 (**)(void))(*(_QWORD *)v1 + 200LL))();// op1
  if ( !(_DWORD)ib_plus_op2 )
  {
    get_ib = (__int64 (*)(void))(*a1)->get_ib;
    ib = get_ib();
    ib_1 = get_ib();
    op2 = (*(__int64 (**)(void))(*(_QWORD *)v1 + 224LL))();// op2
    v7 = __CFADD__(ib_1, op2);
    ib_plus_op2 = (unsigned int)(ib_1 + op2);
    if ( v7 )
      BUG();
    if ( (unsigned int)ib_plus_op2 < ib )
      BUG();
    if ( (_DWORD)ib_plus_op2 != ib )
    {
      one = qword_14610->one;
      while ( 1 )
      {
        if ( ib >= (unsigned int)ib_plus_op2 )
          BUG();
        v9 = ib - 32;
        if ( ib < 32 )
          v9 = ib;
        if ( one )
        {
          if ( LODWORD(qword_14610->zero) == v9 )
            goto error;
          if ( one != 1 )
          {
            if ( HIDWORD(qword_14610->zero) == v9 )
              goto error;
            if ( one != 2 )
              break;
          }
        }
LABEL_7:
        if ( ++ib == (_DWORD)ib_plus_op2 )
          return ib_plus_op2;
      }
      v10 = 10LL;
      while ( 1 )
      {
        v11 = v10 - 8 + 1;
        if ( __OFADD__(1LL, v10 - 8) )
          BUG();
        if ( *((_DWORD *)&qword_14610->idk0 + v10) == v9 )
          break;
        ++v10;
        if ( v11 == one )
          goto LABEL_7;
      }
error:
      v12 = sub_DA00();
      swift_allocError(&unk_12BA0, v12, 0LL, 0LL);
      *(_QWORD *)v13 = 3LL;
      *(_QWORD *)(v13 + 8) = 0LL;
      *(_BYTE *)(v13 + 16) = 2;
      return swift_willThrow(&unk_12BA0);
    }
  }
  return ib_plus_op2;
}

For “in” instruction, the validation function checks if “ib” is zero and “ib” + operand2 is over 32.

If validation fails, it throws error.

So it is important to satisfy the validation when crafting instruction.

(the validation functions exists when the opcode is jmp, wait, in, out, and set)

Second one is executed after the instruction function.

It depends on c072 value whether it’ll be executed or not.

And the c072 value is decided inside the instruction function.

(I call this function as after_op_func, and as op_end)

__int64 __fastcall execute_op_func_sub_B010()
{
  __int64 v0; // r12
  vm_context **vm_context; // r13
  vm_context **vm_context_; // r14
  __int64 (*get_c072)(void); // rbx
  __int64 (__fastcall *end_access)(char *, _QWORD); // rax
  _QWORD *c058; // rdx
  unsigned int user_inst_idx_1; // ebp
  middle_context **middle_context; // r13
  unsigned int be40; // r15d
  __int64 v10; // rax
  __int64 v11; // rdx
  middle_context **v12; // r15
  unsigned __int64 user_inst_idx; // rbp
  __int64 be38; // r13
  inst_structure **inst_structure; // r15
  char c072; // bl
  middle_context **v17; // rbp
  char ret; // al
  void *v19; // rdi
  char ret_; // r13
  unsigned int user_inst_idx__; // ebp
  unsigned int last_idx; // eax
  vm_context *v23; // rcx
  unsigned int first_idx_of_user_inst; // eax
  void (__fastcall *v25)(char *, _QWORD); // rax
  _DWORD *user_inst_idx_; // rdx
  unsigned int v27; // ebp
  array_context **v28; // rbp
  __int64 v29; // r13
  __int64 v30; // rbp
  __int64 (*get_middle_context_c0b0)(void); // [rsp+10h] [rbp-58h]
  unsigned int (*get_user_inst_idx_c050)(void); // [rsp+18h] [rbp-50h]
  char v33[72]; // [rsp+20h] [rbp-48h] BYREF

  vm_context_ = vm_context;
  get_c072 = (__int64 (*)(void))(*vm_context)->get_c072;
  if ( (get_c072() & 1) != 0 || ((__int64 (*)(void))(*vm_context)->get_c058)() <= 0 )
  {
    if ( (((__int64 (*)(void))(*vm_context)->get_c0b9)() & 1) == 0 )
    {
      user_inst_idx_1 = (*vm_context)->get_user_inst_idx_c050();
      middle_context = (middle_context **)((__int64 (*)(void))(*vm_context)->get_middle_context_c0b0)();
      be40 = (*middle_context)->get_be40();
      swift_release(middle_context);
      if ( user_inst_idx_1 < be40 )
      {
        v10 = sub_DA00();
        swift_allocError(&unk_12BA0, v10, 0LL, 0LL);
        *(_QWORD *)v11 = 4LL;
        *(_QWORD *)(v11 + 8) = 0LL;
        *(_BYTE *)(v11 + 16) = 2;
        return swift_willThrow(&unk_12BA0);
      }
    }
    get_middle_context_c0b0 = (__int64 (*)(void))(*vm_context_)->get_middle_context_c0b0;
    v12 = (middle_context **)get_middle_context_c0b0();
    get_user_inst_idx_c050 = (*vm_context_)->get_user_inst_idx_c050;
    user_inst_idx = get_user_inst_idx_c050();
    be38 = ((__int64 (*)(void))(*v12)->get_be38)();
    swift_release(v12);
    if ( *(_QWORD *)(be38 + 16) <= user_inst_idx )
      BUG();
    inst_structure = *(inst_structure ***)(be38 + 8 * user_inst_idx + 32);
    swift_retain(inst_structure);
    swift_release(be38);
    c072 = get_c072();
    ((void (__fastcall *)(_QWORD))(*vm_context_)->write_c072)(0LL);
    v17 = (middle_context **)get_middle_context_c0b0();
    ret = ((__int64 (__fastcall *)(vm_context **, middle_context **))(*inst_structure)->op_func)(vm_context_, v17);
    if ( v0 )
    {
      swift_release(inst_structure);
      v19 = v17;
    }
    else
    {
      ret_ = ret;
      swift_release(v17);
      if ( (ret_ & 1) == 0 )                    // goto next instruction
      {
        user_inst_idx__ = get_user_inst_idx_c050();
        last_idx = (*vm_context_)->get_last_idx_c08c();
        v23 = *vm_context_;
        if ( user_inst_idx__ == last_idx )
        {
          first_idx_of_user_inst = v23->get_first_idx_of_user_inst_c090();
          ((void (__fastcall *)(_QWORD))(*vm_context_)->write_user_inst_idx_c050)(first_idx_of_user_inst);
        }
        else
        {
          v25 = (void (__fastcall *)(char *, _QWORD))((__int64 (__fastcall *)(char *))v23->sub_a040)(v33);
          if ( *user_inst_idx_ == -1 )
            BUG();
          ++*user_inst_idx_;
          v25(v33, 0LL);
        }
      }
      if ( (((__int64 (*)(void))(*vm_context_)->get_at)() & 1) != 0 )
      {
        v27 = (*vm_context_)->get_c040();
        if ( v27 >= (*vm_context_)->get_pt() )
        {
          v28 = (array_context **)((__int64 (*)(void))(*vm_context_)->get_array_context1)();
          v29 = ((__int64 (*)(void))(*v28)->pop)();
          swift_release(v28);
          if ( (v29 & 0x100000000LL) == 0 )
          {
            ((void (__fastcall *)(_QWORD))(*vm_context_)->write_c038)((unsigned int)v29);
            ((void (__fastcall *)(_QWORD))(*vm_context_)->write_c040)(0LL);
          }
        }
      }
      if ( (c072 & 1) == 0 )
      {
        v30 = get_middle_context_c0b0();
        ((void (__fastcall *)(vm_context **, __int64))(*inst_structure)->after_op_func)(vm_context_, v30); // executed here
        swift_release(v30);
        return swift_release(inst_structure);
      }
      v19 = inst_structure;
    }
    return swift_release(v19);
  }
  end_access = (__int64 (__fastcall *)(char *, _QWORD))((__int64 (__fastcall *)(char *))(*vm_context)->get_c058_raw)(v33);
  if ( __OFSUB__(*c058, 1LL) )
    BUG();
  --*c058;
  return end_access(v33, 0LL);
}

Followings are the analyzed instruction functions.

  • jmp
    __int64 __fastcall jmp_op_sub_6A90(vm_context **a1, middle_context **a2)
    {
      __int64 v2; // r13
      unsigned int v3; // ebp
      unsigned int v4; // eax
      __int64 v5; // rax
      __int64 v6; // rdx
      void (__fastcall *end_access)(char *, _QWORD); // rax
      _DWORD *raw_ptr; // rdx
      unsigned int v9; // eax
      unsigned int v10; // eax
      unsigned int v12; // [rsp+Ch] [rbp-4Ch]
      char v13[72]; // [rsp+10h] [rbp-48h] BYREF
    
      v3 = (unsigned int)a2;
      switch ( (*(unsigned int (**)(void))(*(_QWORD *)v2 + 224LL))() )// op2
      {
        case 0u:
          goto LABEL_15;
        case 1u:
          v4 = (*a1)->get_c048();
          goto LABEL_6;
        case 2u:
          v12 = (*a1)->get_c048();
          end_access = (void (__fastcall *)(char *, _QWORD))((__int64 (__fastcall *)(char *))(*a1)->get_c048_raw)(v13);
          goto LABEL_9;
        case 3u:
          v4 = (*a1)->get_c04c();
    LABEL_6:
          if ( !v4 )
            goto LABEL_15;
          goto LABEL_17;
        case 4u:
          v12 = (*a1)->get_c04c();
          end_access = (void (__fastcall *)(char *, _QWORD))((__int64 (__fastcall *)(char *))(*a1)->get_c04c_raw)(v13);
    LABEL_9:
          --*raw_ptr;
          v3 = 0;
          end_access(v13, 0LL);
          if ( !v12 )
            return v3;
          goto LABEL_15;
        case 5u:
          v3 = (*a1)->get_c048();
          if ( v3 == ((unsigned int (__fastcall *)(vm_context **))(*a1)->get_c04c)(a1) )
            goto LABEL_17;
          goto LABEL_15;
        case 6u:
          v3 = (*a2)->get_be44();
          v9 = (*a1)->get_j();
          if ( v9 < 0x20 && _bittest((const int *)&v3, v9) )
            goto LABEL_15;
          goto LABEL_17;
        case 7u:
          v3 = (*a1)->get_c040();
          if ( v3 < ((unsigned int (__fastcall *)(vm_context **))(*a1)->get_pt)(a1) )
          {
    LABEL_15:
            v10 = (*(__int64 (**)(void))(*(_QWORD *)v2 + 200LL))();// op1
            ((void (__fastcall *)(_QWORD))(*a1)->write_user_inst_idx_c050)(v10);
            LOBYTE(v3) = 1;
          }
          else
          {
    LABEL_17:
            v3 = 0;
          }
          break;
        default:
          v5 = sub_DA00();
          swift_allocError(&unk_12BA0, v5, 0LL, 0LL);
          *(_QWORD *)v6 = 1LL;
          *(_QWORD *)(v6 + 8) = 0LL;
          *(_BYTE *)(v6 + 16) = 2;
          swift_willThrow(&unk_12BA0);
          break;
      }
      return v3;
    }
  • wait
    __int64 __fastcall wait_op_sub_6F60(vm_context **a1, middle_context **a2)
    {
      unsigned int v2; // r12d
      __int64 v3; // r13
      unsigned int ret; // ebx
      unsigned int v5; // ebx
      unsigned int op1_2; // eax
      int v7; // ebp
      __int64 v8; // rax
      __int64 v9; // rdx
      int op1_1; // r14d
      unsigned int ib; // eax
      unsigned int v12; // eax
      int v13; // ebp
      __int64 (*get_op1)(void); // r14
      char op1; // bl
      __int64 v16; // rax
      int op1_and_3; // ebx
      bool v18; // cf
      char v19; // bl
      __int64 (*get_op3)(void); // r14
      int op3; // eax
      int _be4c; // ecx
      void (__fastcall *end_access)(char *, _QWORD); // rax
      _BYTE *be4c_1; // rdx
      unsigned int c034; // [rsp+14h] [rbp-54h]
      unsigned __int8 be4c; // [rsp+14h] [rbp-54h]
      vm_context **v28; // [rsp+18h] [rbp-50h]
      char v29[72]; // [rsp+20h] [rbp-48h] BYREF
    
      ret = v2;
      switch ( (*(unsigned int (**)(void))(*(_QWORD *)v3 + 232LL))() )// op2
      {
        case 0u:
          v28 = a1;
          v5 = (*a2)->get_be44();                   // 0x55555557be44
          op1_2 = (*(__int64 (**)(void))(*(_QWORD *)v3 + 208LL))();// op1
          v7 = _bittest((const int *)&v5, op1_2);
          ret = 0;
          if ( op1_2 >= 0x20 )
            v7 = 0;
          if ( v7 != (*(unsigned int (**)(void))(*(_QWORD *)v3 + 256LL))() )// op3
            goto return_1;
          return ret;
        case 1u:
          op1_1 = (*(__int64 (**)(void))(*(_QWORD *)v3 + 208LL))();// op1
          v28 = a1;
          ib = (*a1)->get_ib();                     // ib 0x55555557c07c
          ret = op1_1 + ib;
          if ( __CFADD__(op1_1, ib) )
            BUG();
          v12 = (*a2)->get_be44();                  // 0x55555557be44
          v13 = _bittest((const int *)&v12, ret);
          if ( v13 != (*(unsigned int (**)(void))(*(_QWORD *)v3 + 256LL))() )// op3
            goto return_1;
          return 0;
        case 2u:
          v28 = a1;
          get_op1 = *(__int64 (**)(void))(*(_QWORD *)v3 + 208LL);
          op1 = get_op1();                          // op1
          if ( (get_op1() & 0x10) != 0 )
          {
            c034 = (*a1)->get_c034();               // 0x55555557c034
            op1_and_3 = get_op1() & 3;
            v18 = __CFADD__(c034, op1_and_3);
            v19 = c034 + op1_and_3;
            if ( v18 )
              BUG();
            ret = ((get_op1() & 4) != 0) + (v19 & 3);
          }
          else
          {
            ret = op1 & 7;
          }
          be4c = (*a2)->get_be4c();                 // 0x55555557be4c (sub_b9f0)
          get_op3 = *(__int64 (**)(void))(*(_QWORD *)v3 + 256LL);
          op3 = get_op3();                          // op3
          _be4c = be4c;
          if ( op3 == _bittest(&_be4c, ret) )
          {
            if ( (unsigned int)get_op3() == 1 )
            {
              end_access = (void (__fastcall *)(char *, _QWORD))((__int64 (__fastcall *)(char *))(*a2)->get_be4c_raw)(v29);
              *be4c_1 &= (0xFF << ret) - 1;
              ret = 0;
              end_access(v29, 0LL);
            }
            else
            {
              return 0;
            }
          }
          else
          {
    return_1:
            ((void (__fastcall *)(__int64))(*v28)->write_c072)(1LL);// 0x55555557c072
            LOBYTE(ret) = 1;
          }
          return ret;
        case 3u:
          v16 = sub_DA00();
          swift_allocError(&unk_12BA0, v16, 0LL, 0LL);
          *(_QWORD *)v9 = 2LL;
          goto LABEL_13;
        default:
          v8 = sub_DA00();
          swift_allocError(&unk_12BA0, v8, 0LL, 0LL);
          *(_QWORD *)v9 = 1LL;
    LABEL_13:
          *(_QWORD *)(v9 + 8) = 0LL;
          *(_BYTE *)(v9 + 16) = 2;
          swift_willThrow(&unk_12BA0);
          return ret;
      }
    }
  • in
    __int64 __fastcall in_op_sub_73C0(vm_context **a1, middle_context **a2)
    {
      __int64 v2; // r13
      char *op2; // rbp
      unsigned int op2_2; // eax
      __int64 _1_shl_op2; // rbx
      unsigned __int64 v7; // r15
      bool v8; // cf
      __int64 _1_shl_op2_neg_1; // rbx
      unsigned int (*get_be44)(void); // r15
      unsigned __int64 v11; // rbp
      unsigned int ib; // eax
      unsigned __int64 v13; // rbp
      unsigned __int64 v14; // r15
      unsigned int v15; // eax
      __int64 v16; // rax
      __int64 v17; // rdx
      char isd; // bl
      unsigned int (__fastcall *get_c03c_raw_1)(); // rax
      void (__fastcall *end_access)(char *, _QWORD); // rax
      _DWORD *c03c_1; // rdx
      int v22; // esi
      unsigned int op2_1; // eax
      unsigned int _32_op2; // ecx
      int v25; // r15d
      void (__fastcall *end_access_1)(char *, _QWORD); // rax
      _DWORD *c03c; // rdx
      unsigned int (__fastcall *v28)(); // rbx
      void (__fastcall *v29)(char *, _QWORD); // rax
      _DWORD *v30; // rdx
      int v31; // esi
      _DWORD *v32; // rdx
      unsigned int v33; // ebx
      int v34; // eax
      unsigned int v35; // eax
      __int64 v36; // rdi
      unsigned int c044; // ebx
      __int64 (*get_ps)(void); // r15
      unsigned int ps; // eax
      unsigned int v40; // ebx
      array_context **array_context; // r13
      vm_context *_a1; // rax
      __int64 be44; // [rsp+8h] [rbp-60h]
      unsigned int (__fastcall *get_c03c_raw)(); // [rsp+8h] [rbp-60h]
      __int64 (*get_op2)(void); // [rsp+18h] [rbp-50h]
      char v47[72]; // [rsp+20h] [rbp-48h] BYREF
    
      LODWORD(op2) = (_DWORD)a2;
      if ( (((__int64 (__fastcall *)(vm_context **))(*a1)->get_c072)(a1) & 1) == 0 )// 0x55555557c072 (sub_a500)
      {
        get_op2 = *(__int64 (**)(void))(*(_QWORD *)v2 + 224LL);
        op2_2 = get_op2();                          // op2
        _1_shl_op2 = 1LL << op2_2;
        LODWORD(v7) = 0;
        if ( op2_2 >= 0x40 )
          _1_shl_op2 = 0LL;
        v8 = _1_shl_op2 == 0;
        _1_shl_op2_neg_1 = _1_shl_op2 - 1;
        if ( !v8 )
        {
          switch ( (*(unsigned int (**)(void))(*(_QWORD *)v2 + 200LL))() )// op1
          {
            case 0u:
              get_be44 = (*a2)->get_be44;
              be44 = get_be44();
              v11 = be44 + ((unsigned __int64)get_be44() << 32);
              ib = (*a1)->get_ib();
              v13 = v11 >> ib;
              v14 = 0LL;
              if ( ib < 64 )
                v14 = v13;
              v7 = _1_shl_op2_neg_1 & v14;
              if ( HIDWORD(v7) )
                BUG();
              goto LABEL_16;
            case 1u:
              v15 = (*a1)->get_c048();              // 0x55555557c048 (sub_9ed0)
              goto LABEL_15;
            case 2u:
              v15 = (*a1)->get_c04c();              // 0x55555557c04c
              goto LABEL_15;
            case 3u:
              goto LABEL_16;
            case 6u:
              v15 = (*a1)->get_c03c();              // 0x55555557c03c (sub_9d20)
              goto LABEL_15;
            case 7u:
              v15 = (*a1)->get_c038();              // 0x55555557c038 (sub_9c90)
    LABEL_15:
              LODWORD(v7) = v15 & _1_shl_op2_neg_1;
    LABEL_16:
              isd = (*a1)->get_isd();               // isd 0x55555557c064
              LODWORD(op2) = get_op2();
              get_c03c_raw_1 = (*a1)->get_c03c_raw;
              if ( (isd & 1) != 0 )
              {
                get_c03c_raw = (*a1)->get_c03c_raw;
                end_access = (void (__fastcall *)(char *, _QWORD))((__int64 (__fastcall *)(char *))get_c03c_raw_1)(v47);
                v22 = 0;
                if ( (unsigned int)op2 < 0x20 )
                  v22 = *c03c_1 >> (char)op2;
                *c03c_1 = v22;
                end_access(v47, 0LL);               // sub_e740
                op2_1 = get_op2();                  // 0x55555557fda4
                _32_op2 = 32 - op2_1;
                if ( op2_1 > 0x20 )
                  BUG();
                v25 = (_DWORD)v7 << _32_op2;
                if ( _32_op2 >= 0x20 )
                  v25 = 0;
                end_access_1 = (void (__fastcall *)(char *, _QWORD))((__int64 (__fastcall *)(char *))get_c03c_raw)(v47);
                *c03c |= v25;                       // 0x55555557c03c
              }
              else
              {
                v28 = (*a1)->get_c03c_raw;
                v29 = (void (__fastcall *)(char *, _QWORD))((__int64 (__fastcall *)(char *))get_c03c_raw_1)(v47);
                v31 = 0;
                if ( (unsigned int)op2 < 0x20 )
                  v31 = *v30 << (char)op2;
                *v30 = v31;
                v29(v47, 0LL);
                op2 = v47;
                end_access_1 = (void (__fastcall *)(char *, _QWORD))((__int64 (__fastcall *)(char *))v28)(v47);
                *v32 |= v7;
              }
              end_access_1(v47, 0LL);
              v33 = (*a1)->get_c044();
              v34 = get_op2();
              v8 = __CFADD__(v33, v34);
              v35 = v33 + v34;
              if ( v8 )
                BUG();
              v36 = 32LL;
              if ( v35 < 0x20 )
                v36 = v35;
              ((void (__fastcall *)(__int64))(*a1)->write_c044)(v36);// 0x55555557c044 (sub_9e60)
              goto LABEL_30;
            default:
              v16 = sub_DA00();
              swift_allocError(&unk_12BA0, v16, 0LL, 0LL);
              *(_QWORD *)v17 = 2LL;
              *(_QWORD *)(v17 + 8) = 0LL;
              *(_BYTE *)(v17 + 16) = 2;
              swift_willThrow(&unk_12BA0);
              return (unsigned int)op2;
          }
        }
        BUG();
      }
    LABEL_30:
      if ( (((__int64 (*)(void))(*a1)->get_as)() & 1) != 0 )// as 0x55555557c071 (sub_a470)
      {
        c044 = (*a1)->get_c044();                   // 0x55555557c044 (sub_9e40)
        get_ps = (__int64 (*)(void))(*a1)->get_ps;
        if ( c044 >= (unsigned int)get_ps() )       // ps 0x55555557c06c (sub_a350)
        {
          ps = get_ps();                            // ps 0x55555557c06c (sub_a350)
          v40 = ((__int64 (__fastcall *)(_QWORD))(*a1)->sub_b470)(ps);// 0x55555557c020 (sub_b470)
          array_context = (array_context **)((__int64 (*)(void))(*a1)->get_array_context2)();
          LOBYTE(v40) = ((__int64 (__fastcall *)(_QWORD))(*array_context)->insert)(v40);// insert 0x55555557c100
          swift_release(array_context);
          _a1 = *a1;
          if ( (v40 & 1) != 0 )
          {
            LODWORD(op2) = 0;
            ((void (__fastcall *)(_QWORD))_a1->write_c03c)(0LL);
            ((void (__fastcall *)(_QWORD))(*a1)->write_c044)(0LL);
          }
          else
          {
            ((void (__fastcall *)(__int64))_a1->write_c072)(1LL);
            LOBYTE(op2) = 1;
          }
        }
        else
        {
          LODWORD(op2) = 0;
        }
      }
      else
      {
        LODWORD(op2) = 0;
      }
      return (unsigned int)op2;
    }
  • out
    __int64 __fastcall out_op_sub_7A20(vm_context **a1, middle_context **a2)
    {
      __int64 v2; // r13
      vm_context **a1_; // r14
      unsigned int (__fastcall *get_at)(); // rbp
      unsigned int v5; // ebx
      array_context **v6; // r13
      __int64 v7; // rbx
      unsigned int c038_1; // ebx
      char osd; // bp
      __int64 v10; // r15
      __int64 (*get_op2)(void); // r14
      unsigned int op2; // eax
      __int64 (*get_op2_1)(void); // rsi
      vm_context **v14; // r14
      __int64 v15; // rbx
      bool v16; // cf
      unsigned __int64 v17; // rbx
      unsigned int op2_1; // ebp
      void (__fastcall *end_access)(__int128 *, _QWORD); // rax
      _DWORD *c038; // rdx
      int v21; // esi
      unsigned __int64 v22; // rbx
      __int64 v23; // rbp
      unsigned int op2_2; // eax
      __int64 v25; // rbp
      void (*v26)(void); // rbx
      __int64 (*get_ob)(void); // rbx
      int v28; // eax
      unsigned int v29; // ebp
      unsigned int v30; // eax
      int v31; // ebx
      unsigned int v32; // ebp
      unsigned int ob; // eax
      int v34; // edx
      int v35; // ebx
      int v36; // edi
      unsigned int (__fastcall *write_be44)(); // rbx
      void (__fastcall *v38)(__int128 *, _QWORD); // rax
      int v39; // eax
      unsigned int v40; // ebp
      unsigned int v41; // ebp
      int v42; // ebx
      int v43; // ebx
      unsigned int v44; // eax
      unsigned int v45; // eax
      __int64 v46; // rdx
      __int64 v47; // rax
      __int64 v48; // rdx
      __int64 (*v49)(void); // rbx
      int v50; // eax
      unsigned int v51; // ebp
      unsigned int v52; // eax
      int v53; // ebx
      unsigned int v54; // ebp
      unsigned int v55; // eax
      int v56; // edx
      int v57; // ebx
      int v58; // edi
      unsigned int (__fastcall *write_be48)(); // rbx
      void (__fastcall *v60)(__int128 *, _QWORD); // rax
      int v61; // eax
      unsigned int v62; // ebp
      unsigned int v63; // ebp
      int v64; // ebx
      unsigned int v65; // eax
      unsigned int v66; // ecx
      unsigned int v67; // eax
      int v68; // ebx
      int v69; // r15d
      unsigned int be44_1; // ebp
      unsigned int v71; // eax
      int v72; // ecx
      int v73; // ebp
      int v74; // ebx
      int v75; // r15d
      unsigned int v76; // ebp
      unsigned int v77; // eax
      int v78; // ecx
      int v79; // ebp
      __int64 (*get_c040)(void); // rbp
      int c040; // ebx
      int op2_3; // eax
      unsigned int c040_op2; // eax
      __int64 v84; // rdi
      unsigned int (__fastcall *write_c040)(); // r15
      unsigned int c040_1; // ebx
      array_context **v87; // r13
      vm_context **a1__; // [rsp+8h] [rbp-A0h]
      int a1__b; // [rsp+8h] [rbp-A0h]
      __int64 (*get_ob_1)(void); // [rsp+8h] [rbp-A0h]
      int v92; // [rsp+8h] [rbp-A0h]
      int a1__c; // [rsp+8h] [rbp-A0h]
      __int64 (*a1__a)(void); // [rsp+8h] [rbp-A0h]
      unsigned int c038_2; // [rsp+10h] [rbp-98h]
      unsigned __int64 c083_and_v17; // [rsp+10h] [rbp-98h]
      __int64 v98; // [rsp+20h] [rbp-88h]
      int be44; // [rsp+20h] [rbp-88h]
      int selfb; // [rsp+20h] [rbp-88h]
      unsigned int (__fastcall *self)(); // [rsp+20h] [rbp-88h]
      __int128 selfc; // [rsp+20h] [rbp-88h]
      int selfa; // [rsp+20h] [rbp-88h]
      int selfd; // [rsp+20h] [rbp-88h]
      __int64 (*get_c038)(void); // [rsp+38h] [rbp-70h]
      __int64 (*v106)(void); // [rsp+38h] [rbp-70h]
      __int64 (*get_c038a)(void); // [rsp+38h] [rbp-70h]
      __int64 (*get_be44)(void); // [rsp+48h] [rbp-60h]
      __int64 (*get_be48)(void); // [rsp+48h] [rbp-60h]
      __int64 (*get_at_1)(void); // [rsp+58h] [rbp-50h]
      __int128 v111[4]; // [rsp+60h] [rbp-48h] BYREF
    
      v98 = v2;
      a1_ = a1;
      get_at = (*a1)->get_at;
      if ( (((__int64 (__fastcall *)(vm_context **))get_at)(a1) & 1) != 0 )// at 0x55555557c070 (sub_a3e0)
      {
        v5 = (*a1)->get_c040();                     // 0x55555557c040 (sub_9db0)
        if ( v5 >= ((unsigned int (__fastcall *)(vm_context **))(*a1)->get_pt)(a1) )// pt 0x55555557c068 (sub_a2c0)
        {
          v6 = (array_context **)((__int64 (*)(void))(*a1)->get_array_context1)();// 0x55555557c098 (sub_aa90)
          v7 = ((__int64 (*)(void))(*v6)->pop)();   // 0x55555557c0d0 (sub_60c0)
          swift_release(v6);
          if ( (v7 & 0x100000000LL) != 0 )
          {
            ((void (__fastcall *)(__int64))(*a1)->write_c072)(1LL);
            LOBYTE(v7) = 1;
            return (unsigned int)v7;
          }
          ((void (__fastcall *)(_QWORD))(*a1)->write_c038)((unsigned int)v7);// 0x55555557c038 (sub_9cb0)
          a1 = 0LL;
          ((void (__fastcall *)(_QWORD))(*a1_)->write_c040)(0LL);// 0x55555557c040 (sub_9dd0)
        }
      }
      get_at_1 = (__int64 (*)(void))get_at;
      get_c038 = (__int64 (*)(void))(*a1_)->get_c038;
      c038_1 = get_c038();                          // 0x55555557c038 (sub_9c90)
      osd = (*a1_)->sub_a230();                     // osd 0x55555557c065 (sub_a230)
      v10 = v98;
      a1__ = a1_;
      get_op2 = *(__int64 (**)(void))(*(_QWORD *)v98 + 224LL);
      op2 = get_op2();                              // op2
      get_op2_1 = get_op2;
      if ( (osd & 1) != 0 )
      {
        c038_2 = c038_1;
        v14 = a1__;
        v15 = 0LL;
        if ( op2 < 0x40 )
          v15 = 1LL << op2;
        v16 = v15 == 0;
        v17 = v15 - 1;
        if ( v16 )
          BUG();
        if ( HIDWORD(v17) )
          BUG();
        op2_1 = get_op2_1();                        // op2
        end_access = (void (__fastcall *)(__int128 *, _QWORD))((__int64 (__fastcall *)(__int128 *))(*a1__)->get_c038_raw)(v111);// (sub_9ce0)
        v21 = 0;
        if ( op2_1 < 0x20 )
          v21 = *c038 >> op2_1;
        c083_and_v17 = (unsigned int)v17 & c038_2;
        *c038 = v21;
        end_access(v111, 0LL);                      // (sub_e730)
        v10 = v98;
      }
      else
      {
        v22 = (unsigned __int64)c038_1 << op2 >> 32;
        if ( op2 >= 0x40 )
          v22 = 0LL;
        c083_and_v17 = v22;
        v14 = a1__;
        v23 = (unsigned int)get_c038();             // 0x55555557c038 (sub_9c90)
        op2_2 = ((__int64 (__fastcall *)(vm_context **, __int64 (*)(void)))get_op2_1)(a1, get_op2_1);// op2
        v25 = v23 << op2_2;
        if ( op2_2 >= 0x40 )
          LODWORD(v25) = 0;
        ((void (__fastcall *)(_QWORD))(*a1__)->write_c038)((unsigned int)v25);// 0x55555557c038 (sub_9cb0)
      }
      v26 = *(void (**)(void))(*(_QWORD *)v10 + 200LL);
      switch ( ((unsigned int (*)(void))v26)() )    // dest (op1)
      {
        case 0u:
          get_ob = (__int64 (*)(void))(*v14)->get_ob;
          a1__b = get_ob();                         // ob 0x55555557c080 (sub_a7d0)
          v106 = *(__int64 (**)(void))(*(_QWORD *)v10 + 224LL);
          v28 = v106();                             // op2
          v29 = a1__b + v28;
          if ( __CFADD__(a1__b, v28) )
            BUG();
          get_ob_1 = get_ob;
          v30 = get_ob();                           // ob 0x55555557c080 (sub_a7d0)
          v31 = -31 << v30;
          if ( v29 >= 0x20 )
          {
            v32 = v30;
            get_be44 = (__int64 (*)(void))(*a2)->get_be44;
            be44 = get_be44();
            ob = get_ob_1();
            v34 = (_DWORD)c083_and_v17 << ob;
            if ( ob >= 0x20 )
              v34 = 0;
            v35 = v31 - 1;
            v36 = 0x7FFFFFFF;
            if ( v32 < 0x20 )
              v36 = v35;
            write_be44 = (*a2)->write_be44;
            ((void (__fastcall *)(_QWORD))write_be44)(v34 | be44 & (unsigned int)v36);
            v38 = (void (__fastcall *)(__int128 *, _QWORD))((__int64 (__fastcall *)(__int128 *))(*a2)->end_access)(v111);
            v38(v111, 0LL);
            selfb = get_ob_1();
            v39 = v106();
            v40 = selfb + v39;
            if ( __CFADD__(selfb, v39) )
              BUG();
            self = write_be44;
            v16 = v40 < 0x20;
            v41 = v40 - 32;
            if ( v16 )
              BUG();
            v42 = 0;
            if ( v41 < 0x20 )
              v42 = 1 << v41;
            v16 = v42 == 0;
            v43 = v42 - 1;
            if ( v16 )
              BUG();
            v92 = get_be44();
            v44 = v106();
            v16 = v44 < v41;
            v45 = v44 - v41;
            if ( v16 )
              BUG();
            goto LABEL_48;
          }
          v68 = v31 - 1;
          v69 = -1;
          if ( v30 < 0x20 )
            v69 = v68;
          be44_1 = (*a2)->get_be44();               // 0x55555557be44 (sub_e2a0)
          v71 = get_ob_1();                         // ob 0x55555557c080 (sub_a7d0)
          v72 = 0;
          if ( v71 < 0x20 )
            v72 = (_DWORD)c083_and_v17 << v71;
          v73 = v69 & be44_1;
          v10 = v98;
          ((void (__fastcall *)(_QWORD))(*a2)->write_be44)(v72 | (unsigned int)v73);// 0x55555557be44 (sub_e470)
          goto LABEL_63;
        case 1u:
          ((void (__fastcall *)(unsigned __int64))(*v14)->write_c048)(c083_and_v17);// 0x55555557c048 (sub_9ef0)
          goto LABEL_63;
        case 2u:
          ((void (__fastcall *)(unsigned __int64))(*v14)->write_c04c)(c083_and_v17);
          goto LABEL_63;
        case 3u:
          goto LABEL_63;
        case 4u:
          v49 = (__int64 (*)(void))(*v14)->get_ob;
          a1__c = v49();
          get_c038a = *(__int64 (**)(void))(*(_QWORD *)v10 + 224LL);
          v50 = get_c038a();
          v51 = a1__c + v50;
          if ( __CFADD__(a1__c, v50) )
            BUG();
          a1__a = v49;
          v52 = v49();
          v53 = -31 << v52;
          if ( v51 < 0x20 )
          {
            v74 = v53 - 1;
            v75 = -1;
            if ( v52 < 0x20 )
              v75 = v74;
            v76 = (*a2)->get_be48();
            v77 = a1__a();
            v78 = 0;
            if ( v77 < 0x20 )
              v78 = (_DWORD)c083_and_v17 << v77;
            v79 = v75 & v76;
            v10 = v98;
            ((void (__fastcall *)(_QWORD))(*a2)->write_be48)(v78 | (unsigned int)v79);
          }
          else
          {
            v54 = v52;
            get_be48 = (__int64 (*)(void))(*a2)->get_be48;
            selfa = get_be48();
            v55 = a1__a();
            v56 = (_DWORD)c083_and_v17 << v55;
            if ( v55 >= 0x20 )
              v56 = 0;
            v57 = v53 - 1;
            v58 = 0x7FFFFFFF;
            if ( v54 < 0x20 )
              v58 = v57;
            write_be48 = (*a2)->write_be48;
            ((void (__fastcall *)(_QWORD))write_be48)(v56 | selfa & (unsigned int)v58);
            v60 = (void (__fastcall *)(__int128 *, _QWORD))((__int64 (__fastcall *)(__int128 *))(*a2)->end_access2)(v111);
            v60(v111, 0LL);
            selfd = a1__a();
            v61 = get_c038a();
            v62 = selfd + v61;
            if ( __CFADD__(selfd, v61) )
              BUG();
            self = write_be48;
            v16 = v62 < 0x20;
            v63 = v62 - 32;
            if ( v16 )
              BUG();
            v64 = 0;
            if ( v63 < 0x20 )
              v64 = 1 << v63;
            v16 = v64 == 0;
            v43 = v64 - 1;
            if ( v16 )
              BUG();
            v92 = get_be48();
            v65 = get_c038a();
            v16 = v65 < v63;
            v45 = v65 - v63;
            if ( v16 )
              BUG();
    LABEL_48:
            v66 = 0;
            if ( v45 < 0x20 )
              v66 = (unsigned int)c083_and_v17 >> v45;
            ((void (__fastcall *)(_QWORD))self)(v66 | ~v43 & v92);
          }
          goto LABEL_63;
        case 5u:
          ((void (__fastcall *)(unsigned __int64))(*v14)->write_user_inst_idx_c050)(c083_and_v17);
          goto LABEL_63;
        case 6u:
          ((void (__fastcall *)(unsigned __int64))(*v14)->write_c03c)(c083_and_v17);
          v67 = (*(__int64 (**)(void))(*(_QWORD *)v10 + 224LL))();
          ((void (__fastcall *)(_QWORD))(*v14)->write_c044)(v67);
    LABEL_63:
          get_c040 = (__int64 (*)(void))(*v14)->get_c040;
          c040 = get_c040();                        // 0x55555557c040 (sub_9db0)
          op2_3 = (*(__int64 (**)(void))(*(_QWORD *)v10 + 224LL))();// op2
          v16 = __CFADD__(c040, op2_3);
          c040_op2 = c040 + op2_3;
          if ( v16 )
            BUG();
          v84 = 32LL;
          if ( c040_op2 < 0x20 )
            v84 = c040_op2;
          write_c040 = (*v14)->write_c040;
          ((void (__fastcall *)(__int64))write_c040)(v84);// 0x55555557c040 (sub_9dd0)
          if ( (get_at_1() & 1) == 0                // at 0x55555557c070 (sub_a3e0)
            || (c040_1 = get_c040(), c040_1 < (*v14)->get_pt())// 0x55555557c040, pt 0x55555557c068
            || (v87 = (array_context **)((__int64 (*)(void))(*v14)->get_array_context1)(),// 0x55555557c098
                v7 = ((__int64 (*)(void))(*v87)->pop)(),// 0x55555557c0d0
                swift_release(v87),
                (v7 & 0x100000000LL) != 0) )
          {
            LODWORD(v7) = 0;
          }
          else
          {
            ((void (__fastcall *)(_QWORD))(*v14)->write_c038)((unsigned int)v7);// 0x55555557c038 (sub_9cb0)
            LODWORD(v7) = 0;
            ((void (__fastcall *)(_QWORD))write_c040)(0LL);
          }
          break;
        default:
          *(_QWORD *)&v111[0] = 'tsed dab';
          *((_QWORD *)&v111[0] + 1) = 0xE900000000000020LL;
          v26();
          _ss23CustomStringConvertibleP11descriptionSSvgTj(&_ss6UInt32VN, &_ss6UInt32Vs23CustomStringConvertiblesWP);
          v7 = v46;
          _sSS6appendyySSF();
          swift_bridgeObjectRelease(v7);
          selfc = v111[0];
          v47 = sub_DA00();
          swift_allocError(&unk_12BA0, v47, 0LL, 0LL);
          *(_OWORD *)v48 = selfc;
          *(_BYTE *)(v48 + 16) = 1;
          swift_willThrow(&unk_12BA0);
          break;
      }
      return (unsigned int)v7;
    }
  • pull
    __int64 __fastcall pull_op_sub_8310(vm_context **a1)
    {
      __int64 self; // r13
      __int64 self_; // r15
      unsigned int v3; // ebp
      array_context **array_context; // rbp
      __int64 v5; // r13
      __int16 v6; // ax
      vm_context *v7; // rcx
    
      self_ = self;
      if ( (((__int64 (__fastcall *)(vm_context **))(*a1)->get_at)(a1) & 1) != 0 )// at 0x55555557c070 (sub_a3e0) (0x55555557bf90)
      {
        v3 = (*a1)->get_c040();                     // 0x55555557c040 (sub_9db0)
        if ( v3 >= ((unsigned int (__fastcall *)(vm_context **))(*a1)->get_pt)(a1) )// pt 0x55555557c068 (sub_a2c0)
          goto LABEL_10;
      }
      if ( (*(unsigned __int16 (**)(void))(*(_QWORD *)self + 200LL))() != 1// op1 0x55555557fda0 (sub_e210) (0x55555557ba80)
        || (LODWORD(array_context) = (*a1)->get_c040(),// 0x55555557c040 (sub_9db0)
            (unsigned int)array_context >= ((unsigned int (__fastcall *)(vm_context **))(*a1)->get_pt)(a1)) )// pt 0x55555557c068 (sub_a2c0)
      {
        array_context = (array_context **)((__int64 (*)(void))(*a1)->get_array_context1)();// 0x55555557bfb8 (sub_aa90)
        v5 = ((__int64 (*)(void))(*array_context)->pop)();// 0x55555557c3c0 (sub_60c0)
        swift_release(array_context);
        if ( (v5 & 0x100000000LL) != 0 )
        {
          v6 = (*(__int64 (**)(void))(*(_QWORD *)self_ + 224LL))();// op2
          v7 = *a1;
          if ( v6 )
          {
            ((void (__fastcall *)(__int64))v7->write_c072)(1LL);
            LOBYTE(array_context) = 1;
            return (unsigned int)array_context;
          }
          LODWORD(v5) = v7->get_c048();
        }
        ((void (__fastcall *)(_QWORD))(*a1)->write_c038)((unsigned int)v5);// 0x55555557c038 (sub_9cb0) (0x55555557bf58)
        LODWORD(array_context) = 0;
        ((void (__fastcall *)(_QWORD))(*a1)->write_c040)(0LL);// 0x55555557c040 (sub_9dd0) (0x55555557bf60)
        return (unsigned int)array_context;
      }
      if ( !(*(unsigned __int16 (**)(void))(*(_QWORD *)self + 224LL))() )// op2 0x55555557fda2 (sub_e220)
      {
    LABEL_10:
        LODWORD(array_context) = 0;
        return (unsigned int)array_context;
      }
      ((void (__fastcall *)(__int64))(*a1)->write_c072)(1LL);// 0x55555557c072 (sub_a520)
      LOBYTE(array_context) = 1;
      return (unsigned int)array_context;
    }
  • push
    __int64 __fastcall push_op_sub_8670(vm_context **a1)
    {
      unsigned int (__fastcall *get_array_context2)(); // rbp
      __int64 self; // r13
      __int64 self_; // r15
      unsigned int v4; // ebx
      array_context **array_context2; // r13
      char v6; // bl
      array_context **v7; // rbx
      unsigned int c03c; // eax
      __int64 v10; // rax
      __int64 v11; // rdx
    
      self_ = self;
      if ( !(*(unsigned __int16 (**)(void))(*(_QWORD *)self + 200LL))()// op1
        || (v4 = (*a1)->get_ps(),
            LOBYTE(get_array_context2) = 1,
            v4 == ((unsigned int (__fastcall *)(vm_context **))(*a1)->get_c044)(a1)) )
      {
        get_array_context2 = (*a1)->get_array_context2;
        array_context2 = (array_context **)((__int64 (*)(void))get_array_context2)();
        v6 = (*array_context2)->is_len_capacity_equal();
        swift_release(array_context2);
        if ( (v6 & 1) == 0 )
        {
          v7 = (array_context **)((__int64 (*)(void))get_array_context2)();
          c03c = (*a1)->get_c03c();
          LODWORD(get_array_context2) = ((__int64 (__fastcall *)(_QWORD))(*v7)->insert)(c03c);
          swift_release(v7);
          if ( ((unsigned __int8)get_array_context2 & 1) == 0 )
          {
            v10 = sub_DA00();
            swift_allocError(&unk_12BA0, v10, 0LL, 0LL);
            *(_QWORD *)v11 = 2LL;
            *(_QWORD *)(v11 + 8) = 0LL;
            *(_BYTE *)(v11 + 16) = 2;
            swift_willThrow(&unk_12BA0);
            return (unsigned int)get_array_context2;
          }
          goto LABEL_7;
        }
        LOBYTE(get_array_context2) = 1;
        if ( !(*(unsigned __int16 (**)(void))(*(_QWORD *)self_ + 224LL))() )// op2
        {
    LABEL_7:
          LODWORD(get_array_context2) = 0;
          ((void (__fastcall *)(_QWORD))(*a1)->write_c03c)(0LL);
          ((void (__fastcall *)(_QWORD))(*a1)->write_c044)(0LL);
        }
      }
      return (unsigned int)get_array_context2;
    }
  • mov
    __int64 __fastcall mov_op_sub_8B10(vm_context **a1, middle_context **a2)
    {
      __int64 v2; // r13
      __int64 v3; // r14
      unsigned __int64 src_value; // rbp
      unsigned int be44_1; // eax
      unsigned __int64 one; // rsi
      __int64 i; // r8
      unsigned int v8; // ecx
      __int64 v9; // r9
      unsigned __int64 v10; // rbp
      unsigned int v11; // eax
      unsigned int v12; // eax
      unsigned int st; // eax
      vm_context *a1_; // rcx
      array_context **array_context; // rax
      __int16 v16; // ax
      unsigned __int32 v17; // ebp
      unsigned int v18; // ebp
      unsigned int v19; // eax
      bool v20; // cf
      char v21; // al
      char v22; // cl
      unsigned __int64 v23; // r14
      unsigned int ob; // eax
      int v25; // edx
      __int64 v26; // rdi
      void (__fastcall *v27)(char *, _QWORD); // rax
      unsigned int ob_1; // r14d
      int _1_shl_ob; // r15d
      int _1_shl_ob_neg_1; // r15d
      int v31; // eax
      unsigned int v32; // ecx
      unsigned int v33; // ebp
      __int64 v34; // rax
      __int64 v35; // rdx
      array_context **v37; // r13
      __int64 (*get_ob_1)(void); // [rsp+8h] [rbp-70h]
      __int64 get_ob; // [rsp+8h] [rbp-70h]
      int be44; // [rsp+10h] [rbp-68h]
      unsigned int (__fastcall *write_be44)(); // [rsp+10h] [rbp-68h]
      __int64 (*get_be44)(void); // [rsp+28h] [rbp-50h]
      char v44[72]; // [rsp+30h] [rbp-48h] BYREF
    
      v3 = v2;
      LODWORD(src_value) = 0;
      switch ( (*(unsigned __int16 (**)(void))(*(_QWORD *)v2 + 256LL))() )// src
      {
        case 0u:
          be44_1 = (*a2)->get_be44();               // 0x55555557be44 (sub_e2a0)
          one = qword_14610->one;
          if ( one )
          {
            for ( i = 0LL; i != one; ++i )
            {
              v8 = *((_DWORD *)&qword_14610->zero + i);
              v9 = 1LL << v8;
              if ( v8 >= 0x40 )
                v9 = 0LL;
              if ( __OFSUB__(0xFFFFFFFFLL, v9) )
                BUG();
              if ( 0xFFFFFFFFLL - v9 < 0 )
                BUG();
              be44_1 &= 0xFFFFFFFF - v9;
            }
          }
          v10 = 0x100000001LL * be44_1;
          v11 = (*a1)->get_ib();                    // ib 0x55555557c07c (sub_a740)
          src_value = v10 >> v11;
          if ( v11 >= 64 )
            LODWORD(src_value) = 0;
          goto LABEL_19;
        case 1u:
          v12 = (*a1)->get_c048();                  // 0x55555557c048 (sub_8910)
          goto LABEL_18;
        case 2u:
          v12 = (*a1)->get_c04c();                  // 0x55555557c04c (sub_9f60)
          goto LABEL_18;
        case 3u:
          goto LABEL_19;
        case 5u:
          st = (*a1)->get_st();                     // st 0x55555557c0a8 (sub_abe0)
          a1_ = *a1;
          if ( st == 1 )
            array_context = (array_context **)((__int64 (*)(void))a1_->get_array_context2)();// 0x55555557c0a0 (sub_ab20)
          else
            array_context = (array_context **)((__int64 (*)(void))a1_->get_array_context1)();// 0x55555557c098 (sub_aa90)
          v37 = array_context;
          get_ob = ((__int64 (*)(void))(*array_context)->get_len)();// 0x55555557c0d0 (sub_6160)
          swift_release(v37);
          LODWORD(src_value) = -(get_ob < (*a1)->get_sn());// sn 0x55555557c0ac (sub_ac80)
          goto LABEL_19;
        case 6u:
          v12 = (*a1)->get_c03c();                  // 0x55555557c03c (sub_9d20)
          goto LABEL_18;
        case 7u:
          v12 = (*a1)->get_c038();                  // 0x55555557c038 (sub_9c90)
    LABEL_18:
          LODWORD(src_value) = v12;
    LABEL_19:
          v16 = (*(__int64 (**)(void))(*(_QWORD *)v3 + 232LL))();// cal
          switch ( v16 )
          {
            case 0:
              break;
            case 2:
              v17 = _byteswap_ulong(src_value);
              v18 = (16 * (v17 & 0xF0F0F0F)) | (v17 >> 4) & 0xF0F0F0F;
              LODWORD(src_value) = (((((v18 >> 2) & 0x33333333) + 4 * (v18 & 0x33333333)) >> 1) & 0x55555555)
                                 + 2 * ((((v18 >> 2) & 0x33333333) + 4 * (v18 & 0x33333333)) & 0x55555555);
              break;
            case 1:
              LODWORD(src_value) = ~(_DWORD)src_value;
              break;
            default:
    LABEL_36:
              v34 = sub_DA00();
              swift_allocError(&unk_12BA0, v34, 0LL, 0LL);
              *(_QWORD *)v35 = 2LL;
              *(_QWORD *)(v35 + 8) = 0LL;
              *(_BYTE *)(v35 + 16) = 2;
              swift_willThrow(&unk_12BA0);
              return (unsigned int)v3;
          }
          switch ( (*(unsigned __int16 (**)(void))(*(_QWORD *)v3 + 208LL))() )// dest
          {
            case 0u:
              get_ob_1 = (__int64 (*)(void))(*a1)->get_ob;
              v19 = get_ob_1();                     // ob 0x55555557c080 (sub_a7d0)
              v20 = v19 < 0x20;
              v21 = v19 & 0x3F;
              v22 = 31;
              if ( v20 )
                v22 = v21;
              v23 = 0xFFFFFFFF00000001LL << v22;
              get_be44 = (__int64 (*)(void))(*a2)->get_be44;
              be44 = get_be44();                    // 0x55555557be44 (sub_e2a0)
              ob = get_ob_1();                      // SIGSEGV?
              v25 = (_DWORD)src_value << ob;
              if ( ob >= 0x20 )
                v25 = 0;
              v26 = v25 | be44 & (unsigned int)(v23 - 1);
              write_be44 = (*a2)->write_be44;
              ((void (__fastcall *)(__int64))write_be44)(v26);
              v27 = (void (__fastcall *)(char *, _QWORD))((__int64 (__fastcall *)(char *))(*a2)->end_access)(v44);
              v27(v44, 0LL);
              ob_1 = get_ob_1();
              _1_shl_ob = 1 << ob_1;
              if ( ob_1 >= 0x20 )
                _1_shl_ob = 0;
              v20 = _1_shl_ob == 0;
              _1_shl_ob_neg_1 = _1_shl_ob - 1;
              if ( v20 )
                BUG();
              v31 = get_be44();
              v32 = 32 - ob_1;
              if ( ob_1 > 0x20 )
                BUG();
              v33 = (unsigned int)src_value >> v32;
              LODWORD(v3) = 0;
              if ( v32 >= 0x20 )
                v33 = 0;
              ((void (__fastcall *)(_QWORD))write_be44)(v33 | ~_1_shl_ob_neg_1 & v31);
              break;
            case 1u:
              ((void (__fastcall *)(_QWORD))(*a1)->write_c048)((unsigned int)src_value);// 0x55555557c048 (sub_9ef0)
              LODWORD(v3) = 0;
              break;
            case 2u:
              ((void (__fastcall *)(_QWORD))(*a1)->write_c04c)((unsigned int)src_value);// 0x55555557c04c (sub_9f80)
              LODWORD(v3) = 0;
              break;
            case 5u:
              ((void (__fastcall *)(_QWORD))(*a1)->write_user_inst_idx_c050)((unsigned int)src_value);// 0x55555557c050 (sub_a010)
              LOBYTE(v3) = 1;
              break;
            case 6u:
              ((void (__fastcall *)(_QWORD))(*a1)->write_c03c)((unsigned int)src_value);// 0x55555557c03c (sub_9d40)
              LODWORD(v3) = 0;
              ((void (__fastcall *)(_QWORD))(*a1)->write_c044)(0LL);// 0x55555557c044 (sub_9e60)
              break;
            case 7u:
              ((void (__fastcall *)(_QWORD))(*a1)->write_c038)((unsigned int)src_value);// 0x55555557c038 (sub_9cb0)
              LODWORD(v3) = 0;
              ((void (__fastcall *)(_QWORD))(*a1)->write_c040)(0LL);// 0x55555557c040 (sub_9dd0)
              break;
            default:
              goto LABEL_36;
          }
          return (unsigned int)v3;
        default:
          goto LABEL_36;
      }
    }
  • irq
    __int64 __fastcall irq_op_sub_91D0(vm_context **a1, middle_context **a2)
    {
      __int64 v2; // r13
      unsigned int v3; // ebp
      __int64 (*get_op3)(void); // r14
      char op3; // r15
      unsigned int v6; // r15d
      __int64 v7; // rax
      __int64 v8; // rdx
      unsigned int c034; // r15d
      int v10; // ebx
      bool v11; // cf
      char v12; // bl
      void (__fastcall *end_access)(char *, _QWORD); // rax
      _BYTE *be4c_1; // rdx
      int be4c; // eax
      _BYTE *be4c_2; // rdx
      char v18[72]; // [rsp+20h] [rbp-48h] BYREF
    
      v3 = v2;
      get_op3 = *(__int64 (**)(void))(*(_QWORD *)v2 + 256LL);// op3
      if ( (get_op3() & 8) != 0 )
      {
        v7 = sub_DA00();
        swift_allocError(&unk_12BA0, v7, 0LL, 0LL);
        *(_QWORD *)v8 = 2LL;
        *(_QWORD *)(v8 + 8) = 0LL;
        *(_BYTE *)(v8 + 16) = 2;
        swift_willThrow(&unk_12BA0);
      }
      else
      {
        op3 = get_op3();
        if ( (get_op3() & 0x10) != 0 )
        {
          c034 = (*a1)->get_c034();
          v10 = get_op3() & 3;
          v11 = __CFADD__(c034, v10);
          v12 = c034 + v10;
          if ( v11 )
            BUG();
          v6 = v12 & 3 | get_op3() & 4;
        }
        else
        {
          v6 = op3 & 7;
        }
        if ( (*(unsigned int (**)(void))(*(_QWORD *)v2 + 208LL))() == 1 )// op1
        {
          end_access = (void (__fastcall *)(char *, _QWORD))((__int64 (__fastcall *)(char *))(*a2)->get_be4c_raw)(v18);
          *be4c_1 &= (-1 << v6) - 1;
    LABEL_13:
          v3 = 0;
          end_access(v18, 0LL);
          return v3;
        }
        if ( (*(unsigned int (**)(void))(*(_QWORD *)v2 + 232LL))() != 1 )// op2
        {
          end_access = (void (__fastcall *)(char *, _QWORD))((__int64 (__fastcall *)(char *))(*a2)->get_be4c_raw)(v18);
          *be4c_2 |= 1 << v6;
          goto LABEL_13;
        }
        be4c = (unsigned __int8)(*a2)->get_be4c();
        if ( _bittest(&be4c, v6) )
        {
          ((void (__fastcall *)(__int64))(*a1)->write_c072)(1LL);
          LOBYTE(v3) = 1;
        }
        else
        {
          return 0;
        }
      }
      return v3;
    }
  • set
    __int64 __fastcall set_op_sub_9560(vm_context **a1, middle_context **a2)
    {
      __int64 v2; // r13
      void (*v4)(void); // rbx
      __int64 (*get_seb)(void); // rbx
      unsigned int seb_1; // eax
      unsigned int v7; // r14d
      unsigned int seb; // eax
      int v9; // ebx
      int v10; // r14d
      unsigned int v11; // eax
      int v12; // r14d
      int v13; // ebx
      int v14; // edi
      void (__fastcall *v15)(__int128 *, _QWORD); // rax
      int seb_2; // eax
      bool v17; // cf
      char v18; // al
      unsigned int seb_3; // eax
      unsigned int v20; // r14d
      unsigned int v21; // ebx
      unsigned int v22; // ebp
      unsigned int v23; // eax
      unsigned int v24; // esi
      unsigned int op2; // eax
      unsigned int op2_1; // eax
      __int64 v27; // rdx
      __int64 v28; // rbx
      __int64 v29; // rax
      __int64 v30; // rdx
      __int64 (*v31)(void); // rbx
      unsigned int v32; // eax
      unsigned int v33; // r14d
      unsigned int v34; // eax
      int v35; // ebx
      int v36; // r14d
      unsigned int v37; // eax
      int v38; // r14d
      int v39; // ebx
      int v40; // edi
      void (__fastcall *v41)(__int128 *, _QWORD); // rax
      int v42; // eax
      char v43; // al
      unsigned int v44; // eax
      unsigned int v45; // eax
      int v46; // edx
      unsigned int v47; // ebp
      unsigned int v48; // eax
      int v49; // ebx
      int v50; // eax
      unsigned int v51; // ebx
      int v52; // ebp
      unsigned int v53; // eax
      int v54; // ebp
      int v55; // ecx
      void (__fastcall *v56)(__int128 *, _QWORD); // rax
      int *c084; // rdx
      int v58; // ecx
      int v59; // ebx
      int v60; // eax
      unsigned int v61; // ebx
      int op2_2; // ebp
      unsigned int v63; // eax
      int v64; // ebp
      int v65; // ecx
      unsigned int v67; // [rsp+8h] [rbp-90h]
      unsigned int (__fastcall *write_be44)(); // [rsp+8h] [rbp-90h]
      unsigned int v69; // [rsp+8h] [rbp-90h]
      int v70; // [rsp+8h] [rbp-90h]
      int v71; // [rsp+8h] [rbp-90h]
      __int64 (*get_seb_)(void); // [rsp+10h] [rbp-88h]
      __int64 (*v73)(void); // [rsp+10h] [rbp-88h]
      int be44_1; // [rsp+1Ch] [rbp-7Ch]
      int be44; // [rsp+1Ch] [rbp-7Ch]
      __int64 (*get_op2_1)(void); // [rsp+38h] [rbp-60h]
      __int64 (*get_op2)(void); // [rsp+38h] [rbp-60h]
      __int64 (*get_be44_1)(void); // [rsp+40h] [rbp-58h]
      __int64 (*get_be44)(void); // [rsp+40h] [rbp-58h]
      __int128 v80[4]; // [rsp+50h] [rbp-48h] BYREF
    
      v4 = *(void (**)(void))(*(_QWORD *)v2 + 200LL);
      switch ( ((unsigned int (*)(void))v4)() )     // op1
      {
        case 0u:
          get_seb = (__int64 (*)(void))(*a1)->get_seb;
          seb_1 = get_seb();
          v7 = seb_1 + 5;
          if ( seb_1 >= 0xFFFFFFFB )
            BUG();
          get_seb_ = get_seb;
          seb = get_seb();
          v9 = -31 << seb;
          if ( v7 >= 0x20 )
          {
            v67 = seb;
            get_be44_1 = (__int64 (*)(void))(*a2)->get_be44;
            be44_1 = get_be44_1();
            get_op2_1 = *(__int64 (**)(void))(*(_QWORD *)v2 + 224LL);// op2
            v10 = get_op2_1();
            v11 = get_seb_();
            v12 = v10 << v11;
            if ( v11 >= 0x20 )
              v12 = 0;
            v13 = v9 - 1;
            v14 = 0x7FFFFFFF;
            if ( v67 < 0x20 )
              v14 = v13;
            write_be44 = (*a2)->write_be44;
            ((void (__fastcall *)(_QWORD))write_be44)(v12 | be44_1 & (unsigned int)v14);
            v15 = (void (__fastcall *)(__int128 *, _QWORD))((__int64 (__fastcall *)(__int128 *))(*a2)->end_access)(v80);
            v15(v80, 0LL);
            seb_2 = get_seb_();
            v17 = __CFADD__(seb_2, 5);
            v18 = seb_2 + 5;
            if ( v17 )
              BUG();
            ((void (__fastcall *)(_QWORD))(*a1)->write_seb)(v18 & 0x1F);
            seb_3 = get_seb_();
            v20 = 5 - seb_3;
            if ( seb_3 > 5 )
              BUG();
            v21 = get_be44_1();
            v22 = get_op2_1();
            v23 = get_seb_();
            v24 = 5 - v23;
            if ( v23 > 5 )
              BUG();
            goto LABEL_24;
          }
          v49 = v9 - 1;
          v17 = seb < 0x20;
          v50 = -1;
          if ( v17 )
            v50 = v49;
          v70 = v50;
          v51 = (*a2)->get_be44();
          v52 = (*(__int64 (**)(void))(*(_QWORD *)v2 + 224LL))();// op2
          v53 = get_seb_();
          v54 = v52 << v53;
          v55 = 0;
          if ( v53 < 0x20 )
            v55 = v54;
          ((void (__fastcall *)(_QWORD))(*a2)->write_be44)(v55 | v70 & v51);
          v56 = (void (__fastcall *)(__int128 *, _QWORD))((__int64 (__fastcall *)(__int128 *))(*a1)->get_c084_raw)(v80);
          v58 = *c084 + 5;
          if ( (unsigned int)*c084 >= 0xFFFFFFFB )
            BUG();
          goto LABEL_40;
        case 1u:
          op2 = (*(__int64 (**)(void))(*(_QWORD *)v2 + 224LL))();// op2
          ((void (__fastcall *)(_QWORD))(*a1)->write_c048)(op2);
          break;
        case 2u:
          op2_1 = (*(__int64 (**)(void))(*(_QWORD *)v2 + 224LL))();// op2
          ((void (__fastcall *)(_QWORD))(*a1)->write_c04c)(op2_1);
          break;
        case 4u:
          v31 = (__int64 (*)(void))(*a1)->get_seb;
          v32 = v31();
          v33 = v32 + 5;
          if ( v32 >= 0xFFFFFFFB )
            BUG();
          v73 = v31;
          v34 = v31();
          v35 = -31 << v34;
          if ( v33 < 0x20 )
          {
            v59 = v35 - 1;
            v17 = v34 < 0x20;
            v60 = -1;
            if ( v17 )
              v60 = v59;
            v71 = v60;
            v61 = (*a2)->get_be48();
            op2_2 = (*(__int64 (**)(void))(*(_QWORD *)v2 + 224LL))();// op2
            v63 = v73();
            v64 = op2_2 << v63;
            v65 = 0;
            if ( v63 < 0x20 )
              v65 = v64;
            ((void (__fastcall *)(_QWORD))(*a2)->write_be48)(v65 | v71 & v61);
            v56 = (void (__fastcall *)(__int128 *, _QWORD))((__int64 (__fastcall *)(__int128 *))(*a1)->get_c084_raw)(v80);
            v58 = *c084 + 5;
            if ( (unsigned int)*c084 >= 0xFFFFFFFB )
              BUG();
    LABEL_40:
            *c084 = v58;
            v56(v80, 0LL);
          }
          else
          {
            v69 = v34;
            get_be44 = (__int64 (*)(void))(*a2)->get_be48;
            be44 = get_be44();
            get_op2 = *(__int64 (**)(void))(*(_QWORD *)v2 + 224LL);
            v36 = get_op2();
            v37 = v73();
            v38 = v36 << v37;
            if ( v37 >= 0x20 )
              v38 = 0;
            v39 = v35 - 1;
            v40 = 0x7FFFFFFF;
            if ( v69 < 0x20 )
              v40 = v39;
            write_be44 = (*a2)->write_be48;
            ((void (__fastcall *)(_QWORD))write_be44)(v38 | be44 & (unsigned int)v40);
            v41 = (void (__fastcall *)(__int128 *, _QWORD))((__int64 (__fastcall *)(__int128 *))(*a2)->end_access2)(v80);
            v41(v80, 0LL);
            v42 = v73();
            v17 = __CFADD__(v42, 5);
            v43 = v42 + 5;
            if ( v17 )
              BUG();
            ((void (__fastcall *)(_QWORD))(*a1)->write_seb)(v43 & 0x1F);
            v44 = v73();
            v20 = 5 - v44;
            if ( v44 > 5 )
              BUG();
            v21 = get_be44();
            v22 = get_op2();
            v45 = v73();
            v24 = 5 - v45;
            if ( v45 > 5 )
              BUG();
    LABEL_24:
            v46 = -1;
            if ( v20 < 0x20 )
              v46 = -32 >> v20;
            v47 = v22 >> v24;
            v48 = 0;
            if ( v24 < 0x20 )
              v48 = v47;
            ((void (__fastcall *)(_QWORD))write_be44)(v48 | v46 & v21);
          }
          break;
        default:
          *(_QWORD *)&v80[0] = 'tsed dab';
          *((_QWORD *)&v80[0] + 1) = 0xE900000000000020LL;
          v4();
          _ss23CustomStringConvertibleP11descriptionSSvgTj(&_ss6UInt32VN, &_ss6UInt32Vs23CustomStringConvertiblesWP);
          v28 = v27;
          _sSS6appendyySSF();
          swift_bridgeObjectRelease(v28);
          v29 = sub_DA00();
          swift_allocError(&unk_12BA0, v29, 0LL, 0LL);
          *(_OWORD *)v30 = v80[0];
          *(_BYTE *)(v30 + 16) = 1;
          swift_willThrow(&unk_12BA0);
          break;
      }
      return 0LL;
    }
  • after_op_func
    __int64 __fastcall after_op_func_sub_64B0(vm_context **a1, middle_context **a2)
    {
      __int64 self; // r13
      __int64 self_; // rbx
      __int64 (*get_se)(void); // r15
      int v6; // ebx
      int v7; // ebp
      bool v8; // cf
      unsigned int v9; // ebp
      char self_104; // bl
      char se_1; // al
      unsigned int v12; // ecx
      int v13; // edx
      int v14; // ebp
      unsigned int sc_1; // ebx
      unsigned int se; // eax
      unsigned int sc_neg_se; // ebx
      int v18; // ebp
      __int64 (*get_sb)(void); // r15
      unsigned int sb; // eax
      int v21; // ebp
      int v22; // ebx
      int sb_2; // ebp
      int sc; // eax
      unsigned int sb_sc; // eax
      unsigned int v26; // eax
      __int64 (*v27)(void); // rdx
      int v28; // r15d
      int v29; // ebx
      int v30; // eax
      unsigned int v31; // eax
      unsigned int v32; // eax
      int v33; // ebx
      int v34; // ebx
      char v35; // al
      middle_context *v36; // rcx
      unsigned int v37; // eax
      unsigned int v38; // edx
      void (__fastcall *v39)(char *, _QWORD); // rax
      int be48_1; // eax
      unsigned int v41; // edx
      unsigned int new_be44_; // ebx
      middle_context *v43; // rax
      __int64 new_be44; // rdi
      char sd; // al
      middle_context *v46; // rcx
      unsigned int v47; // eax
      unsigned int v48; // ecx
      unsigned int sb_1; // eax
      unsigned int v50; // ecx
      unsigned int v51; // eax
      unsigned int v52; // edx
      __int64 v53; // rdi
      unsigned int (__fastcall *write_be44)(); // r15
      void (__fastcall *v55)(char *, _QWORD); // rax
      int v56; // eax
      unsigned int v57; // edx
      __int64 (*get_self_104)(void); // r15
      __int64 self_104__; // rax
      int v60; // ebx
      int v61; // eax
      unsigned int v62; // eax
      unsigned int v63; // ecx
      int v64; // ebx
      __int16 v65; // bx
      unsigned int v66; // ebx
      unsigned int v67; // [rsp+0h] [rbp-88h]
      int be48; // [rsp+4h] [rbp-84h]
      int be44_1; // [rsp+4h] [rbp-84h]
      __int64 (*v70)(void); // [rsp+8h] [rbp-80h]
      unsigned int v71; // [rsp+8h] [rbp-80h]
      unsigned int be44; // [rsp+8h] [rbp-80h]
      __int64 (*get_be48)(void); // [rsp+18h] [rbp-70h]
      __int64 (*get_be44)(void); // [rsp+18h] [rbp-70h]
      __int64 (*get_sc)(void); // [rsp+20h] [rbp-68h]
      char v76; // [rsp+28h] [rbp-60h]
      unsigned int v77; // [rsp+2Ch] [rbp-5Ch]
      char v78[72]; // [rsp+40h] [rbp-48h] BYREF
    
      self_ = self;
      get_sc = (__int64 (*)(void))(*a1)->get_sc;
      if ( ((unsigned int (__fastcall *)(vm_context **))get_sc)(a1) )
      {
        get_se = (__int64 (*)(void))(*a1)->get_se;
        if ( (get_se() & 1) == 0 || ((*(__int64 (**)(void))(*(_QWORD *)self + 104LL))() & 0xFFF0) == 16 )
        {
          if ( (unsigned int)get_sc() )
          {
            v6 = get_sc();
            v7 = get_se() & 1;
            v8 = __CFADD__(v6, v7);
            v9 = v6 + v7;
            self_ = self;
            if ( v8 )
              BUG();
          }
          else
          {
            v9 = 0;
          }
          self_104 = (*(__int64 (**)(void))(*(_QWORD *)self_ + 104LL))();
          se_1 = get_se();
          v12 = 5 - v9;
          if ( v9 > 5 )
            BUG();
          v13 = (unsigned __int8)(((16 * ((se_1 & 1) == 0)) | 0xF) & self_104) >> v12;
          v14 = 0;
          if ( v12 >= 0x20 )
            v13 = 0;
          v67 = v13;
          sc_1 = get_sc();
          se = get_se() & 1;
          v8 = sc_1 < se;
          sc_neg_se = sc_1 - se;
          if ( v8 )
            BUG();
          if ( sc_neg_se < 0x20 )
            v14 = 1 << sc_neg_se;
          v8 = v14 == 0;
          v18 = v14 - 1;
          if ( v8 )
            BUG();
          get_sb = (__int64 (*)(void))(*a1)->get_sb;
          sb = get_sb();
          v21 = v18 << sb;
          v22 = 0;
          if ( sb < 0x20 )
            v22 = v21;
          sb_2 = get_sb();
          sc = get_sc();
          v8 = __CFADD__(sb_2, sc);
          sb_sc = sb_2 + sc;
          if ( v8 )
            BUG();
          if ( sb_sc < 0x20 )
          {
            sd = (*a1)->get_sd();
            v46 = *a2;
            if ( (sd & 1) != 0 )
            {
              v71 = v46->get_be48();
              v47 = get_sb();
              v48 = 0;
              if ( v47 < 0x20 )
                v48 = v67 << v47;
              ((void (__fastcall *)(_QWORD))(*a2)->write_be48)(v48 | v71 & ~v22);
              goto LABEL_45;
            }
            be44 = v46->get_be44();
            sb_1 = get_sb();
            v50 = 0;
            if ( sb_1 < 32 )
              v50 = v67 << sb_1;
            v43 = *a2;
            new_be44 = v50 | be44 & ~v22;
          }
          else
          {
            v26 = get_sb();
            v27 = get_sb;
            if ( v26 >= 0x1F )
              LOBYTE(v26) = 31;
            v28 = 31 << v26;
            v70 = v27;
            v29 = v27();
            v30 = get_sc();
            v8 = __CFADD__(v29, v30);
            v31 = v29 + v30;
            if ( v8 )
              BUG();
            v8 = v31 < 0x20;
            v32 = v31 - 32;
            if ( v8 )
              BUG();
            v33 = 0;
            if ( v32 < 0x20 )
              v33 = 1 << (v32 & 0x1F);
            v8 = v33 == 0;
            v34 = v33 - 1;
            if ( v8 )
              BUG();
            v76 = v32 & 0x1F;
            v77 = v32;
            v35 = (*a1)->get_sd();
            v36 = *a2;
            if ( (v35 & 1) == 0 )
            {
              get_be44 = (__int64 (*)(void))v36->get_be44;
              be44_1 = get_be44();
              v51 = v70();
              v52 = v67 << v51;
              if ( v51 >= 0x20 )
                v52 = 0;
              v53 = v52 | be44_1 & ~v28;
              write_be44 = (*a2)->write_be44;
              ((void (__fastcall *)(__int64))write_be44)(v53);
              v55 = (void (__fastcall *)(char *, _QWORD))((__int64 (__fastcall *)(char *))(*a2)->end_access)(v78);
              v55(v78, 0LL);
              v56 = get_be44();
              v57 = v67 >> v76;
              if ( v77 >= 0x20 )
                v57 = 0;
              ((void (__fastcall *)(_QWORD))write_be44)(v57 | v56 & ~v34);
              goto LABEL_45;
            }
            get_be48 = (__int64 (*)(void))v36->get_be48;
            be48 = get_be48();
            v37 = v70();
            v38 = v67 << v37;
            if ( v37 >= 0x20 )
              v38 = 0;
            ((void (__fastcall *)(_QWORD))(*a2)->write_be48)(v38 | be48 & ~v28);
            v39 = (void (__fastcall *)(char *, _QWORD))((__int64 (__fastcall *)(char *))(*a2)->end_access2)(v78);
            v39(v78, 0LL);
            be48_1 = get_be48();
            v41 = v67 >> v76;
            if ( v77 >= 0x20 )
              v41 = 0;
            new_be44_ = v41 | be48_1 & ~v34;
            v43 = *a2;
            new_be44 = new_be44_;
          }
          ((void (__fastcall *)(__int64))v43->write_be44)(new_be44);
    LABEL_45:
          self_ = self;
        }
      }
      get_self_104 = *(__int64 (**)(void))(*(_QWORD *)self_ + 104LL);
      self_104__ = get_self_104();                  // sub_62B0
      if ( (_WORD)self_104__ )
      {
        if ( (unsigned int)get_sc() )
        {
          v60 = get_sc();
          v61 = ((__int64 (*)(void))(*a1)->get_se)() & 1;
          v8 = __CFADD__(v60, v61);
          v62 = v60 + v61;
          if ( v8 )
            BUG();
        }
        else
        {
          v62 = 0;
        }
        v63 = 5 - v62;
        if ( v62 > 5 )
          BUG();
        v64 = 0;
        if ( v63 < 0x20 )
          v64 = 1 << v63;
        v8 = v64 == 0;
        v65 = v64 - 1;
        if ( v8 )
          BUG();
        self_104__ = (unsigned __int16)get_self_104();
        v66 = (unsigned __int16)(self_104__ & v65);
        if ( v66 )
          return ((__int64 (__fastcall *)(_QWORD))(*a1)->write_c058)(v66);
      }
      return self_104__;
    }

Following is the gdb script for debugging read/write addresses. (op_end is after_op_func)

  • gdb script for debugging
    import gdb
    import re
    
    ge = gdb.execute
    gp = gdb.parse_and_eval
    
    ge('file challenge')
    ge('set environment LD_LIBRARY_PATH ./lib/')
    
    keys = {0x55555557c060:"j",0x55555557c064:"isd",0x55555557c065:"osd",0x55555557c068:"pt",0x55555557c06c:"ps",0x55555557c070:"at",0x55555557c071:"as",0x55555557c074:"sc",0x55555557c078:"se",0x55555557c079:"sd",0x55555557c07c:"ib",0x55555557c080:"ob",0x55555557c084:"seb",0x55555557c088:"sb",0x55555557c0a8:"st",0x55555557c0ac:"sn"}
    keys_f = {0x55555557c0f0:"f[0]",0x55555557c0f4:"f[1]",0x55555557c0f8:"f[2]",0x55555557c0fc:"f[3]"}
    
    pull = 0x0000555555554000+0x8310
    set_1 = 0x0000555555554000+0x9560
    out_1 = 0x0000555555554000+0x7A20
    jmp_1 = 0x0000555555554000+0x6A90
    in_1 = 0x0000555555554000+0x73C0
    wait_1 = 0x0000555555554000+0x6F60
    wait_2 = 0x0000555555554000+0x71B0
    mov_1 = 0x0000555555554000+0x8B10
    op_end = 0x0000555555554000+0x64B0
    irq = 0x0000555555554000+0x91D0
    push = 0x0000555555554000+0x8670
    for i in [push, mov_1, pull, set_1, out_1, jmp_1, wait_1, in_1, op_end, irq]:
        ge(f'b *{i}')
    
    def Jmp(a1, a2):
        return f'{(a1 & 0x1f) | (a2 << 5)}, {0 << 5}'
    def Wait(a1, a2, a3):
        assert a2 < 4
        assert a3 < 2
        return f'{(a1 & 0x1f) | (a2 << 5) | (a3 << 7)}, {1 << 5}'
    def In(src, shift):
        assert src in [0,1,2,3,6,7]
        return f'{(src << 5) | (shift & 0x1f)}, {2 << 5}'
    def Out(dest, shift):
        assert dest in [0,1,2,3,4,5,6]
        return f'{(dest << 5) | (shift & 0x1f)}, {3 << 5}'
    def Pull(a1, a2):
        assert a1 < 2 and a2 < 2
        return f'{(a1 << 6) | (a2 << 5) | 0x80}, {4 << 5}'
    def Push(a1, a2):
        assert a1 < 2 and a2 < 2
        return f'{(a1 << 6) | (a2 << 5)}, {4 << 5}'
    def Mov(src, cal, dest):
        assert src in [0,1,2,3,5,6,7]
        assert cal in [0,2,1]
        assert dest in [0,1,2,5,6,7]
        return f'{src | (cal << 3) | (dest << 5)}, {5 << 5}'
    def Irq(a1, a2, a3):
        return f'{(a1 << 6) | (a2 << 5) | (a3 & 0x1f)}, {6 << 5}'
    def Set(a1, a2):
        return f'{(a1 << 5) | (a2 & 0x1f)}, {7 << 5}'
    
    inst = ''
    inst += Push(0, 0) + ', '
    inst = inst[:-2]
    print(inst)
    
    payload = '{"j":0,"se":0,"sd":0,"sc":2,"sb":1,"isd":0,'+f'"i":[{inst}]'+'}'
    
    ge(f'r <<< \'{payload}\'')
    print(payload)
    
    with open('./out.txt', 'wt') as f:
        f.write('')
    
    def out(string):
        with open('./out.txt', 'at') as f:
            f.write(string + '\n')
    
    with open('./get_calls_log.txt', 'wt') as f:
        f.write('')
    
    def log(string):
        with open('./get_calls_log.txt', 'at') as f:
            f.write(string + '\n')
    
    while True:
        try:
            rip = int(gp('$rip'))
        except:
            break
    
        if rip == pull:
            out('pull')
        elif rip == set_1:
            out('set')
            # ge('c')
            # continue
        elif rip == out_1:
            out('out')
        elif rip == jmp_1:
            out('jmp')
            # ge('c')
            # continue
        elif rip == wait_1:
            out('wait_1')
        elif rip == wait_2:
            out('wait_2')
        elif rip == in_1:
            out('in_1')
        elif rip == op_end:
            out('op_end')
            # ge('c')
            # continue
        elif rip == mov_1:
            out('mov_1')
            # ge('c')
            # continue
        elif rip == irq:
            out('irq')
        elif rip == push:
            out('push')
            ge('c')
            continue
    
        isFirst = True
        r13 = int(gp('$r13'))
        out(f'self: {hex(r13)}')
        # value = int(gp('*(unsigned char*)0x55555557c072'))
        # out(f'0x55555557c072: {hex(value)}')
    
        while True:
            if isFirst:
                out('-' * 100)
                isFirst = False
            inst = ge('x/i $rip', to_string=True)
            log(inst)
            rip = int(gp('$rip'))
            if rip == 0x0000555555554000+0x7B5B:
                esi = int(gp('$esi'))
                cl = int(gp('$cl'))
                out(f'{hex(esi)} >> {hex(cl)}')
            elif rip == 0x0000555555554000+0x7B69:
                rdx = int(gp('$rdx'))
                esi = int(gp('$esi'))
                out(f'*{hex(rdx)} = {hex(esi)}')
            elif rip == 0x0000555555554000+0x7BAB:
                rbp = int(gp('$rbp'))
                cl = int(gp('$cl'))
                out(f'{hex(rbp)} << {hex(cl)}')
            elif rip == 0x0000555555554000+0x6B66:
                rdx = int(gp('$rdx'))
                value = int(gp(f'*(unsigned int*){rdx}'))
                out(f'--*{hex(rdx)} ({value} -> {value - 1})')
            elif rip == 0x0000555555554000+0x754B or rip == 0x0000555555554000+0x75A1:
                rdx = int(gp('$rdx'))
                value = int(gp(f'*(unsigned int*){rdx}'))
                out(f'*{hex(rdx)} ({hex(value)})')
            elif rip == 0x0000555555554000+0x754F:
                esi = int(gp('$esi'))
                cl = int(gp('$cl'))
                out(f'{hex(esi)} >> {hex(cl)}')
            elif rip == 0x0000555555554000+0x7551 or rip == 0x0000555555554000+0x75A7:
                rdx = int(gp('$rdx'))
                esi = int(gp('$esi'))
                out(f'*{hex(rdx)} = {hex(esi)}')
            elif rip == 0x0000555555554000+0x7574:
                r15d = int(gp('$r15d'))
                cl = int(gp('$cl'))
                out(f'{hex(r15d)} >> {hex(cl)}')
            elif rip == 0x0000555555554000+0x758D or rip == 0x0000555555554000+0x75BF:
                rdx = int(gp('$rdx'))
                r15d = int(gp('$r15d'))
                out(f'*{hex(rdx)} |= {hex(r15d)}')
            elif rip == 0x0000555555554000+0x75A5:
                esi = int(gp('$esi'))
                cl = int(gp('$cl'))
                out(f'{hex(esi)} << {hex(cl)}')
            elif rip == 0x0000555555554000+0x6769 or rip == 0x0000555555554000+0x66E3:
                ebx = int(gp('(unsigned int)$ebx'))
                out(f'not {hex(ebx)}')
                ge('si')
                ebx = int(gp('(unsigned int)$ebx'))
                if rip == 0x0000555555554000+0x6769:
                    rsp = int(gp('$rsp'))
                    value = int(gp(f'*(unsigned int*){rsp+0x88-0x80}'))
                else:
                    value = int(gp('(unsigned int)$eax'))
                out(f'and {hex(ebx)}, {hex(value)}')
                ge('si')
                ebx = int(gp('(unsigned int)$ebx'))
                if rip == 0x0000555555554000+0x6769:
                    value = int(gp('(unsigned int)$ecx'))
                else:
                    value = int(gp('(unsigned int)$edx'))
                out(f'or {hex(ebx)}, {hex(value)} ({hex(ebx | value)})')
            elif rip == 0x0000555555554000+0x747C:
                rbp = int(gp('(unsigned long)$rbp'))
                cl = int(gp('$cl'))
                out(f'{hex(rbp)} >> {hex(cl)} ({hex(rbp >> cl)})')
            elif rip == 0x0000555555554000+0x7489:
                r15 = int(gp('$r15'))
                rbx = int(gp('$rbx'))
                out(f'{hex(r15)} & {hex(rbx)}')
            
            # if 'call' in inst and ('rax' in inst or 'rcx' in inst or 'rsp' in inst):
            if 'call' in inst and re.search(r'call   0x[a-f0-9]+', inst) == None:
                r13 = int(gp('$r13'))
                pc = int(gp('$rip'))
                end_pc = int(re.findall(r'0x[0-9a-f]+\:', ge('x/2i $rip', to_string=True))[1][:-1], 16)
                ge('si')
                addr = int(gp('$rip'))
                if addr == 0x0000555555554000+0x5FE0:
                    rdi = int(gp('$rdi'))
                    out(f'{hex(pc-0x0000555555554000)}: sub_{hex(addr-0x0000555555554000)[2:]} self: {hex(r13)} (insert {hex(rdi)})')
                    ge('finish')
                    continue
                write = []
                read = []
                inst = ge('x/i $rip', to_string=True)
                while 'jmp' in inst or 'push' in inst:
                    ge('si')
                    inst = ge('x/i $rip', to_string=True)
                # if addr == 0x555555562470:
                #     ge('si 2')
                while end_pc != int(gp('$rip')):
                    inst = ge('x/i $rip', to_string=True).split(':')[-1].strip()
                    log(inst)
                    if (r:=re.search(r'mov[a-z]*[ ]+.*\[r13.+\]\,', inst)) != None: # write
                        expr = r.group()
                        expr = expr[expr.find('[')+1:-2]
                        write.append((int(gp('$'+expr)), int(gp('$'+inst[inst.find(',')+1:]))))
                    elif (r:=re.search(r'mov[a-z]*[ ]+.*\,.+\[r13.+\]', inst)) != None: # read
                        expr = r.group()
                        expr = expr[expr.find('[')+1:-1]
                        read.append(int(gp('$'+expr)))
                    if 'call' in inst:
                        ge('ni')
                    else:
                        ge('si')
                # if end_pc == 0x0000555555554000+0x7BC7:
                    # exit()
                rw_str = ''
                if len(read) > 0 or len(write) > 0:
                    rw_str = '(read:'
                    for i in read:
                        rw_str += ' ' + hex(i)
                        if keys.get(i) != None:
                            rw_str += f'({keys[i]})'
                        elif keys_f.get(i) != None:
                            rw_str += f'({keys_f[i]})'
                    rw_str += ', write:'
                    for i in write:
                        rw_str += ' ' + f'{hex(i[0])}({hex(i[1])})'
                    rw_str += ')'
                ret = int(gp('$rax'))
                out(f'{hex(pc-0x0000555555554000)}: sub_{hex(addr-0x0000555555554000)[2:]} self: {hex(r13)} retrun {hex(ret)} ' + rw_str)
            elif 'ret' in inst:
                out('-' * 100)
                break
            else:
                ge('ni')
        ge('c')
    
    print(payload)
    exit()
  • result example
    pull
    self: 0x55555557ba50
    ----------------------------------------------------------------------------------------------------
    0x8327: sub_a3e0 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bf90, write:)
    0x8356: sub_e210 self: 0x55555557ba50 retrun 0x0 (read: 0x55555557ba80, write:)
    0x83ad: sub_aa90 self: 0x55555557bf40 retrun 0x55555557c3c0 (read: 0x55555557bfb8, write:)
    0x83bc: sub_60c0 self: 0x55555557c3c0 retrun 0x96e5 (read: 0x55555557c3c0 0x55555557c3c0, write:)
    0x8414: sub_9cb0 self: 0x55555557bf40 retrun 0x0 (read:, write: 0x55555557bf58(0x96e5))
    0x8421: sub_9dd0 self: 0x55555557bf40 retrun 0x0 (read:, write: 0x55555557bf60(0x0))
    ----------------------------------------------------------------------------------------------------
    op_end
    self: 0x55555557ba50
    ----------------------------------------------------------------------------------------------------
    0x64dc: sub_a590 self: 0x55555557bf40 retrun 0x2 (read: 0x55555557bf94, write:)
    0x64f8: sub_a620 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bf98, write:)
    0x6524: sub_a590 self: 0x55555557bf40 retrun 0x2 (read: 0x55555557bf94, write:)
    0x652d: sub_a590 self: 0x55555557bf40 retrun 0x2 (read: 0x55555557bf94, write:)
    0x6531: sub_a620 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bf98, write:)
    0x654d: sub_62b0 self: 0x55555557ba50 retrun 0xf (read: 0x55555557ba70, write:)
    0x6555: sub_a620 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bf98, write:)
    0x6588: sub_a590 self: 0x55555557bf40 retrun 0x2 (read: 0x55555557bf94, write:)
    0x658e: sub_a620 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bf98, write:)
    0x65c4: sub_a8f0 self: 0x55555557bf40 retrun 0x1 (read: 0x55555557bfa8, write:)
    0x65d3: sub_a8f0 self: 0x55555557bf40 retrun 0x1 (read: 0x55555557bfa8, write:)
    0x65d8: sub_a590 self: 0x55555557bf40 retrun 0x2 (read: 0x55555557bf94, write:)
    0x66fd: sub_a6b0 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bf99, write:)
    0x674b: sub_e2a0 self: 0x55555557be20 retrun 0x2 (read: 0x55555557be44, write:)
    0x6758: sub_a8f0 self: 0x55555557bf40 retrun 0x1 (read: 0x55555557bfa8, write:)
    not 0x6
    and 0xfffffff9, 0x2
    or 0x0, 0x2 (0x2)
    0x6779: sub_e470 self: 0x55555557be20 retrun 0x0 (read:, write: 0x55555557be44(0x2))
    0x6823: sub_62b0 self: 0x55555557ba50 retrun 0xf (read: 0x55555557ba70, write:)
    0x6833: sub_a590 self: 0x55555557bf40 retrun 0x2 (read: 0x55555557bf94, write:)
    0x683c: sub_a590 self: 0x55555557bf40 retrun 0x2 (read: 0x55555557bf94, write:)
    0x6843: sub_a620 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bf98, write:)
    0x6879: sub_62b0 self: 0x55555557ba50 retrun 0xf (read: 0x55555557ba70, write:)
    0x688b: sub_a0a0 self: 0x55555557bf40 retrun 0x0 (read:, write: 0x55555557bf78(0x7))
    ----------------------------------------------------------------------------------------------------
    wait_1
    self: 0x55555557ba90
    ----------------------------------------------------------------------------------------------------
    0x6f7c: sub_e1a0 self: 0x55555557ba90 retrun 0x0 (read: 0x55555557bac4, write:)
    0x6faa: sub_e2a0 self: 0x55555557be20 retrun 0x2 (read: 0x55555557be44, write:)
    0x6fb8: sub_e190 self: 0x55555557ba90 retrun 0x1 (read: 0x55555557bac0, write:)
    0x6fd5: sub_e250 self: 0x55555557ba90 retrun 0x0 (read: 0x55555557bac8, write:)
    0x717f: sub_a520 self: 0x55555557c020 retrun 0x0 (read:, write: 0x55555557c072(0x1))
    ----------------------------------------------------------------------------------------------------
    op_end
    self: 0x55555557ba90
    ----------------------------------------------------------------------------------------------------
    0x64dc: sub_a590 self: 0x55555557c020 retrun 0x1 (read: 0x55555557c074(sc), write:)
    0x64f8: sub_a620 self: 0x55555557c020 retrun 0x1 (read: 0x55555557c078(se), write:)
    0x6505: sub_62b0 self: 0x55555557ba90 retrun 0x0 (read: 0x55555557bab0, write:)
    0x6823: sub_62b0 self: 0x55555557ba90 retrun 0x0 (read: 0x55555557bab0, write:)
    ----------------------------------------------------------------------------------------------------
    wait_1
    self: 0x55555557ba90
    ----------------------------------------------------------------------------------------------------
    0x6f7c: sub_e1a0 self: 0x55555557ba90 retrun 0x0 (read: 0x55555557bac4, write:)
    0x6faa: sub_e2a0 self: 0x55555557be20 retrun 0x2 (read: 0x55555557be44, write:)
    0x6fb8: sub_e190 self: 0x55555557ba90 retrun 0x1 (read: 0x55555557bac0, write:)
    0x6fd5: sub_e250 self: 0x55555557ba90 retrun 0x0 (read: 0x55555557bac8, write:)
    0x717f: sub_a520 self: 0x55555557c020 retrun 0x0 (read:, write: 0x55555557c072(0x1))
    ----------------------------------------------------------------------------------------------------
    ...

Now it is clear that the binary gets input, parses it as json, crafts properties and instructions for virtual machine, and runs init instructions and user instructions.

2. Analysis of Goal


“/flag” string can be found in main function.

  // main
  swift_release(v12);
  v14 = *(_QWORD *)(qword_14618 + 16); // length
  if ( v14 )
  {
    v15 = 0LL;
    while ( 1 )
    {
      if ( !*(_QWORD *)(qword_14620 + 16) )
        BUG();
      v16 = *(_QWORD *)(qword_14620 + 32);
      v17 = *(__int64 (**)(void))(*(_QWORD *)v16 + 112LL);
      swift_retain(v16);
      v18 = v17();
      swift_release(v16);
      if ( *(_QWORD *)(v18 + 16) < 2uLL )
        BUG();
      v19 = *(_QWORD *)(v18 + 40);
      swift_retain(v19);
      swift_release(v18);
      v20 = (*(__int64 (**)(void))(*(_QWORD *)v19 + 1000LL))();
      swift_release(v19);
      v21 = (*(__int64 (**)(void))(*(_QWORD *)v20 + 136LL))();
      swift_release(v20);
      if ( (v21 & 0x100000000LL) != 0 )
        break;
      if ( v15 >= *(_QWORD *)(qword_14618 + 16) )
        BUG();
      if ( *(_DWORD *)(qword_14618 + 4 * v15 + 32) != (_DWORD)v21 ) // compare
      {
        v31 = sub_5720(&qword_13228);
        v30 = swift_allocObject(v31, 64LL, 7LL);
        *(_QWORD *)(v30 + 16) = 1LL;
        *(_QWORD *)(v30 + 24) = 2LL;
        *(_QWORD *)&v39 = 543449442LL;
        *((_QWORD *)&v39 + 1) = 0xE400000000000000LL;
        v32 = _ss23CustomStringConvertibleP11descriptionSSvgTj(&_ss6UInt32VN, &_ss6UInt32Vs23CustomStringConvertiblesWP);
        v34 = v33;
        _sSS6appendyySSF(v32, v33);
        swift_bridgeObjectRelease(v34);
        _sSS6appendyySSF(540877088LL, 0xE400000000000000LL);
        if ( v15 >= *(_QWORD *)(qword_14618 + 16) )
          BUG();
        v35 = _ss23CustomStringConvertibleP11descriptionSSvgTj(&_ss6UInt32VN, &_ss6UInt32Vs23CustomStringConvertiblesWP);
        v37 = v36;
        _sSS6appendyySSF(v35, v36);
        swift_bridgeObjectRelease(v37);
        *(_QWORD *)(v30 + 56) = &_sSSN;
        *(_OWORD *)(v30 + 32) = v39;
LABEL_23:
        _ss5print_9separator10terminatoryypd_S2StF(v30, 32LL, 0xE100000000000000LL, 10LL, 0xE100000000000000LL);
        swift_release(v30);
        exit(1);
      }
      if ( v14 == ++v15 ) // compare iterator with length
        goto LABEL_16;
    }
    v29 = sub_5720(&qword_13228);
    v30 = swift_allocObject(v29, 64LL, 7LL);
    *(_QWORD *)(v30 + 16) = 1LL;
    *(_QWORD *)(v30 + 24) = 2LL;
    *(_QWORD *)(v30 + 56) = &_sSSN;
    *(_QWORD *)(v30 + 32) = 'dab';
    *(_QWORD *)(v30 + 40) = 0xE300000000000000LL;
    goto LABEL_23;
  }
LABEL_16:
  v22 = sub_5720(&qword_13228);
  v23 = swift_allocObject(v22, 64LL, 7LL);
  *(_QWORD *)(v23 + 16) = 1LL;
  *(_QWORD *)(v23 + 24) = 2LL;
  *(_QWORD *)&v38 = ' :ser';
  *((_QWORD *)&v38 + 1) = 0xE500000000000000LL;
  v24 = _s10Foundation3URLV15fileURLWithPathACSS_tcfC('galf/'); // "/flag"
  v25 = _sSS10FoundationE10contentsOfSSAA3URLVh_tKcfC(v24);
  v27 = v26;
  sub_D9C0(v24);
  _sSS6appendyySSF(v25, v27);
  swift_bridgeObjectRelease(v27);
  *(_QWORD *)(v23 + 56) = &_sSSN;
  *(_OWORD *)(v23 + 32) = v38;
  _ss5print_9separator10terminatoryypd_S2StF(v23, 32LL, 0xE100000000000000LL, 10LL, 0xE100000000000000LL);
  swift_release(v23);
  return 0LL;
}

It looks like it compares value from qword_14618 with value from qword_14620.

If added iterator is equal to v14 (which is guessed as length), it goes to the LABEL_16 which executes functions related to “/flag” string.

  • stdout when did nothing
    For help, type "help".
    Type "apropos word" to search for commands related to "word".
    [Thread debugging using libthread_db enabled]
    Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
    bad
    [Inferior 1 (process 603033) exited with code 01]
  • stdout when added push instruction
    For help, type "help".
    Type "apropos word" to search for commands related to "word".
    [Thread debugging using libthread_db enabled]
    Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
    bad 0 != 20603
    [Inferior 1 (process 603192) exited with code 01]

It is more clearer after adding push instruction.

    get_array_context2 = (*a1)->get_array_context2;
    array_context2 = (array_context **)((__int64 (*)(void))get_array_context2)();
    v6 = (*array_context2)->is_len_capacity_equal();
    swift_release(array_context2);
    if ( (v6 & 1) == 0 )
    {
      array_context2 = (array_context **)((__int64 (*)(void))get_array_context2)();
      c03c = (*a1)->get_c03c();
      LODWORD(get_array_context2) = ((__int64 (__fastcall *)(_QWORD))(*array_context2)->insert)(c03c);
      swift_release(v7);

Push instruction inserts value to array2. (there are 2 array_contexts in 1 vm_context)

Then, it means that the value from qword_14620 is equal to the value inside array2.

The goal is to insert values to array2, make it equal, get passed, and get flag.

The problem is that the values from qword_14618 are changed everytime the binary is exeucted.

For help, type "help".
Type "apropos word" to search for commands related to "word".
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
bad 0 != 17152
[Inferior 1 (process 607535) exited with code 01]

For help, type "help".
Type "apropos word" to search for commands related to "word".
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
bad 0 != 56335
[Inferior 1 (process 607652) exited with code 01]

...

So it is impossible to just push static constant to array2 and make it equal.

And the constant compared with 0 can be found in pull instruction.

...
pull
self: 0x55555557ba50
----------------------------------------------------------------------------------------------------
0x8327: sub_a3e0 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bf90, write:)
0x8356: sub_e210 self: 0x55555557ba50 retrun 0x0 (read: 0x55555557ba80, write:)
0x83ad: sub_aa90 self: 0x55555557bf40 retrun 0x55555557c3c0 (read: 0x55555557bfb8, write:)
0x83bc: sub_60c0 self: 0x55555557c3c0 retrun 0x4259 (read: 0x55555557c3c0 0x55555557c3c0, write:)
0x8414: sub_9cb0 self: 0x55555557bf40 retrun 0x0 (read:, write: 0x55555557bf58(0x4259))
0x8421: sub_9dd0 self: 0x55555557bf40 retrun 0x0 (read:, write: 0x55555557bf60(0x0))
----------------------------------------------------------------------------------------------------
pull
self: 0x55555557ba50
----------------------------------------------------------------------------------------------------
0x8327: sub_a3e0 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bf90, write:)
0x8356: sub_e210 self: 0x55555557ba50 retrun 0x0 (read: 0x55555557ba80, write:)
0x83ad: sub_aa90 self: 0x55555557bf40 retrun 0x55555557c3c0 (read: 0x55555557bfb8, write:)
0x83bc: sub_60c0 self: 0x55555557c3c0 retrun 0x37ec (read: 0x55555557c3c0 0x55555557c3c0, write:) // 14316
0x8414: sub_9cb0 self: 0x55555557bf40 retrun 0x0 (read:, write: 0x55555557bf58(0x37ec))
0x8421: sub_9dd0 self: 0x55555557bf40 retrun 0x0 (read:, write: 0x55555557bf60(0x0))
----------------------------------------------------------------------------------------------------
...

Continuing.
bad 0 != 14316
[Inferior 1 (process 723932) exited with code 01]

14316 is 0x37ec in hex.

It means that the pull instruction from init instructions pops the constant from array1 of init_context.

Following shows the loop of the init instructions. (without op_end)

pull
self: 0x55555557ba50
----------------------------------------------------------------------------------------------------
0x8327: sub_a3e0 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bf90, write:)
0x8356: sub_e210 self: 0x55555557ba50 retrun 0x0 (read: 0x55555557ba80, write:)
0x83ad: sub_aa90 self: 0x55555557bf40 retrun 0x55555557c3c0 (read: 0x55555557bfb8, write:)
0x83bc: sub_60c0 self: 0x55555557c3c0 retrun 0x5c61 (read: 0x55555557c3c0 0x55555557c3c0, write:)
0x8414: sub_9cb0 self: 0x55555557bf40 retrun 0x0 (read:, write: 0x55555557bf58(0x5c61))
0x8421: sub_9dd0 self: 0x55555557bf40 retrun 0x0 (read:, write: 0x55555557bf60(0x0))
----------------------------------------------------------------------------------------------------
set
self: 0x55555557ba10
----------------------------------------------------------------------------------------------------
0x9585: sub_e260 self: 0x55555557ba10 retrun 0x1 (read: 0x55555557ba40, write:)
0x96d8: sub_e270 self: 0x55555557ba10 retrun 0xf (read: 0x55555557ba44, write:)
0x96e6: sub_9ef0 self: 0x55555557bf40 retrun 0x0 (read:, write: 0x55555557bf68(0xf))
----------------------------------------------------------------------------------------------------
out
self: 0x55555557be60
----------------------------------------------------------------------------------------------------
0x7a4c: sub_a3e0 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bf90, write:)
0x7ad0: sub_9c90 self: 0x55555557bf40 retrun 0x5c61 (read: 0x55555557bf58, write:)
0x7ad7: sub_a230 self: 0x55555557bf40 retrun 0x1 (read: 0x55555557bf85, write:)
0x7af6: sub_e1e0 self: 0x55555557be60 retrun 0x1 (read: 0x55555557be94, write:)
0x7b3b: sub_e1e0 self: 0x55555557be60 retrun 0x1 (read: 0x55555557be94, write:)
0x7b4a: sub_9ce0 self: 0x55555557bf40 retrun 0x555555562730 
0x5c61 >> 0x1
*0x55555557bf58 = 0x2e30
0x7b72: sub_e730 self: 0x55555557bf40 retrun 0x7ffff47bfd28 
0x7bd4: sub_e1d0 self: 0x55555557be60 retrun 0x0 (read: 0x55555557be90, write:)
0x7bfe: sub_a7d0 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bfa0, write:)
0x7c16: sub_e1e0 self: 0x55555557be60 retrun 0x1 (read: 0x55555557be94, write:)
0x7c2c: sub_a7d0 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bfa0, write:)
0x7fa4: sub_e2a0 self: 0x55555557be20 retrun 0x0 (read: 0x55555557be44, write:)
0x7faf: sub_a7d0 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bfa0, write:)
0x7fd6: sub_e470 self: 0x55555557be20 retrun 0x0 (read:, write: 0x55555557be44(0x1))
0x803d: sub_9db0 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bf60, write:)
0x8047: sub_e1e0 self: 0x55555557be60 retrun 0x1 (read: 0x55555557be94, write:)
0x806d: sub_9dd0 self: 0x55555557bf40 retrun 0x0 (read:, write: 0x55555557bf60(0x1))
0x8070: sub_a3e0 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bf90, write:)
----------------------------------------------------------------------------------------------------
jmp
self: 0x55555557bea0
----------------------------------------------------------------------------------------------------
0x6aac: sub_e1c0 self: 0x55555557bea0 retrun 0x2 (read: 0x55555557bed4, write:)
0x6b18: sub_9ed0 self: 0x55555557bf40 retrun 0xf (read: 0x55555557bf68, write:)
0x6b2a: sub_9f20 self: 0x55555557bf40 retrun 0x555555562770 
--*0x55555557bf68 (15 -> 14)
0x6b71: sub_e770 self: 0x55555557bf40 retrun 0x7ffff47bfd28 
0x6bc4: sub_e1b0 self: 0x55555557bea0 retrun 0x2 (read: 0x55555557bed0, write:)
0x6bd2: sub_a010 self: 0x55555557bf40 retrun 0x0 (read:, write: 0x55555557bf70(0x2))
----------------------------------------------------------------------------------------------------
out
self: 0x55555557be60
----------------------------------------------------------------------------------------------------
0x7a4c: sub_a3e0 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bf90, write:)
0x7ad0: sub_9c90 self: 0x55555557bf40 retrun 0x2e30 (read: 0x55555557bf58, write:)
...

It looks like it extracts the first bit from constant, and writes it to 0x55555557be44 which is some address of middle_context.

It means that the first bit of the random constant is written to be44 while executing init instructions and user instructions must read it, make value same with it, push it to array2, eventually get passed in the main loop which compares the random constant with the pushed value, and get flag.

Now the main problems are coming to the surface.

3. Solving Problems


3-1. read the first bit of the random constant (be44)

To read the first bit of the random constant, it is necessary to locate which instruction can read be44.

Followings are the candidates for it.

in(0, ?) -> src = ((*be44 << 32 | *be44) >> ib) & ((1 << op2) - 1), validate: ib != 0 and ib + op2 <= 32
mov(0, ?, ?) -> src = 0x100000001LL * (*be44 & 0xfffffffe)
set(0, ?) -> write_be44((op2 << seb) | (*be44 & 0x7FFFFFFF))
jmp(?, 6) -> if bittest(be44, j) == 1: pc = op1, validate: j != 0
wait(?, 0 or 1, ?) -> bittest(be44, op1) or bittest(be44, ib + op1), validate: ib + op1 != 0

As you can see, almost every validation prevents reading the first bit of be44.

But, there’s only one way to access the first bit of be44 in the case of “wait” instruction.

It is possible to call bittest(be44, 0) with “ib” 1. (0 + 1 ≠ 0)

          // in instruction function
          if ( (isd & 1) != 0 )
          {
            get_c03c_raw = (*a1)->get_c03c_raw;
            end_access = (void (__fastcall *)(char *, _QWORD))((__int64 (__fastcall *)(char *))get_c03c_raw_1)(v47);
            v22 = 0;
            if ( (unsigned int)op2 < 0x20 )
              v22 = *c03c_1 >> (char)op2;
            *c03c_1 = v22;
            end_access(v47, 0LL);               // sub_e740
            op2_1 = get_op2();                  // 0x55555557fda4
            _32_op2 = 32 - op2_1;
            if ( op2_1 > 0x20 )
              BUG();
            v25 = (_DWORD)v7 << _32_op2;
            if ( _32_op2 >= 0x20 )
              v25 = 0;
            end_access_1 = (void (__fastcall *)(char *, _QWORD))((__int64 (__fastcall *)(char *))get_c03c_raw)(v47);
            *c03c |= v25;                       // 0x55555557c03c
          }
          else
          {
            v28 = (*a1)->get_c03c_raw;
            v29 = (void (__fastcall *)(char *, _QWORD))((__int64 (__fastcall *)(char *))get_c03c_raw_1)(v47);
            v31 = 0;
            if ( (unsigned int)op2 < 0x20 )
              v31 = *c03c_2 << (char)op2;
            *c03c_2 = v31;
            v29(v47, 0LL);
            op2 = v47;
            end_access_1 = (void (__fastcall *)(char *, _QWORD))((__int64 (__fastcall *)(char *))v28)(v47);
            *c03c_3 |= v7;
          }
  1. Right after out instruction executed by init_context, execute wait instruction to bittest the first bit of be44 and return 0 if it is 1 or return 1.
  2. If returned value is 1, re-execute wait instruction and repeat.
  3. Through in instruction, *c03c |= 0x10000 and *c03c = *c03c >> 1.

But, the wait instruction only checks if it is 1 and returns 0 or 1.

It just keeps repeating itself when returning 1.

It doesn’t make it execute *c03c |= 0 and *c03c = *c03c >> 1 when it needs to be filled with 0 at specific index of the value.

So, it is impossible to make the same value with the random constant.

Now it is the second problem of this challenge which can be the most important part.

3-2. construct the random constant using wait instruction and after_op_func

I kept thinking about the possible way to solve this problem after DEFCON CTF ended.

    // sub_B010
    ((void (__fastcall *)(_QWORD))(*vm_context_)->write_c072)(0LL);
    v17 = (middle_context **)get_middle_context_c0b0();
    ret = ((__int64 (__fastcall *)(vm_context **, middle_context **))(*inst_structure)->op_func)(vm_context_, v17);
    if ( v0 )
    {
      swift_release(inst_structure);
      v19 = v17;
    }
    else
    {
      ret_ = ret;
      swift_release(v17);
      if ( (ret_ & 1) == 0 )                    // goto next instruction
      {
        user_inst_idx__ = get_user_inst_idx_c050();
        last_idx = (*vm_context_)->get_last_idx_c08c();
        v23 = *vm_context_;
        if ( user_inst_idx__ == last_idx )
        {
          first_idx_of_user_inst = v23->get_first_idx_of_user_inst_c090();
          ((void (__fastcall *)(_QWORD))(*vm_context_)->write_user_inst_idx_c050)(first_idx_of_user_inst);
        }
        else
        {
          v25 = (void (__fastcall *)(char *, _QWORD))((__int64 (__fastcall *)(char *))v23->sub_a040)(v33);
          if ( *user_inst_idx_ == -1 )
            BUG();
          ++*user_inst_idx_;
          v25(v33, 0LL);
        }
      }
      if ( (((__int64 (*)(void))(*vm_context_)->get_at)() & 1) != 0 ) // array1.pop()
      {
        v27 = (*vm_context_)->get_c040();
        if ( v27 >= (*vm_context_)->get_pt() )
        {
          v28 = (array_context **)((__int64 (*)(void))(*vm_context_)->get_array_context1)();
          v29 = ((__int64 (*)(void))(*v28)->pop)();
          swift_release(v28);
          if ( (v29 & 0x100000000LL) == 0 )
          {
            ((void (__fastcall *)(_QWORD))(*vm_context_)->write_c038)((unsigned int)v29);
            ((void (__fastcall *)(_QWORD))(*vm_context_)->write_c040)(0LL);
          }
        }
      }
      if ( (c072 & 1) == 0 ) // after_op_func
      {
        v30 = get_middle_context_c0b0();
        ((void (__fastcall *)(vm_context **, __int64))(*inst_structure)->after_op_func)(vm_context_, v30);
        swift_release(v30);
        return swift_release(inst_structure);
      }
      v19 = inst_structure;
    }
    return swift_release(v19);
  }

I could think that utilizing array1.pop and after_op_func is the only way to know how many wait instruction returned 1.

But it looked hard to execute different behaviors depending on the length of array1 or c038, or c040.

It also looked hard to do something with after_op_func, because it can only use and, or bit operations, not add or subtract.

I couldn’t make a detailed scenario.

Here’s the instructions and json values from writeup.

Wait 0x1 0x0 0x0 # check bittest(be44, 1) == 0 (wait until init_context's set instruction is executed)
Set 0x1 0xf # set iterator
Wait 0x1 0x0 0x1 # check bittest(be44, 1) == 1 (wait until init_context's out instruction is executed)
Mov 0x2 0x0 0x2 # nop
Wait 0x0 0x0 0x1 # check bittest(be44, 0) == 1 (wait until *be44 & 1 == 1)
In 0x0 0x1 # *c03c |= (((*be44 >> 1) & 1) << 31)
Jmp 0x6 0x2 # if --iterator is not 0, jump to idx 6
Wait 0x1 0x0 0x1

"ib": 1,"sb": 0,"se": 1,"sc": 1,"isd": 1,"as": 1,"ps": 16

And the following is a part of executing instructions from writeup which shows the solution of this problem.

when the first bit of be44 is 1:

out
self: 0x55555557be60
----------------------------------------------------------------------------------------------------
0x7a4c: sub_a3e0 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bf90, write:)
0x7ad0: sub_9c90 self: 0x55555557bf40 retrun 0x96e5 (read: 0x55555557bf58, write:)
0x7ad7: sub_a230 self: 0x55555557bf40 retrun 0x1 (read: 0x55555557bf85, write:)
0x7af6: sub_e1e0 self: 0x55555557be60 retrun 0x1 (read: 0x55555557be94, write:)
0x7b3b: sub_e1e0 self: 0x55555557be60 retrun 0x1 (read: 0x55555557be94, write:)
0x7b4a: sub_9ce0 self: 0x55555557bf40 retrun 0x555555562730 
0x96e5 >> 0x1
*0x55555557bf58 = 0x4b72
0x7b72: sub_e730 self: 0x55555557bf40 retrun 0x7ffff47bfd28 
0x7bd4: sub_e1d0 self: 0x55555557be60 retrun 0x0 (read: 0x55555557be90, write:)
0x7bfe: sub_a7d0 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bfa0, write:)
0x7c16: sub_e1e0 self: 0x55555557be60 retrun 0x1 (read: 0x55555557be94, write:)
0x7c2c: sub_a7d0 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bfa0, write:)
0x7fa4: sub_e2a0 self: 0x55555557be20 retrun 0x0 (read: 0x55555557be44, write:)
0x7faf: sub_a7d0 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bfa0, write:)
0x7fd6: sub_e470 self: 0x55555557be20 retrun 0x0 (read:, write: 0x55555557be44(0x1))
0x803d: sub_9db0 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bf60, write:)
0x8047: sub_e1e0 self: 0x55555557be60 retrun 0x1 (read: 0x55555557be94, write:)
0x806d: sub_9dd0 self: 0x55555557bf40 retrun 0x0 (read:, write: 0x55555557bf60(0x1))
0x8070: sub_a3e0 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bf90, write:)
----------------------------------------------------------------------------------------------------
op_end
self: 0x55555557be60
----------------------------------------------------------------------------------------------------
0x64dc: sub_a590 self: 0x55555557bf40 retrun 0x2 (read: 0x55555557bf94, write:)
0x64f8: sub_a620 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bf98, write:)
0x6524: sub_a590 self: 0x55555557bf40 retrun 0x2 (read: 0x55555557bf94, write:)
0x652d: sub_a590 self: 0x55555557bf40 retrun 0x2 (read: 0x55555557bf94, write:)
0x6531: sub_a620 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bf98, write:)
0x654d: sub_62b0 self: 0x55555557be60 retrun 0xe (read: 0x55555557be80, write:)
0x6555: sub_a620 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bf98, write:)
0x6588: sub_a590 self: 0x55555557bf40 retrun 0x2 (read: 0x55555557bf94, write:)
0x658e: sub_a620 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bf98, write:)
0x65c4: sub_a8f0 self: 0x55555557bf40 retrun 0x1 (read: 0x55555557bfa8, write:)
0x65d3: sub_a8f0 self: 0x55555557bf40 retrun 0x1 (read: 0x55555557bfa8, write:)
0x65d8: sub_a590 self: 0x55555557bf40 retrun 0x2 (read: 0x55555557bf94, write:)
0x66fd: sub_a6b0 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bf99, write:)
0x674b: sub_e2a0 self: 0x55555557be20 retrun 0x1 (read: 0x55555557be44, write:)
0x6758: sub_a8f0 self: 0x55555557bf40 retrun 0x1 (read: 0x55555557bfa8, write:)
not 0x6
and 0xfffffff9, 0x1
or 0x1, 0x2 (0x3)
0x6779: sub_e470 self: 0x55555557be20 retrun 0x0 (read:, write: 0x55555557be44(0x3))
0x6823: sub_62b0 self: 0x55555557be60 retrun 0xe (read: 0x55555557be80, write:)
0x6833: sub_a590 self: 0x55555557bf40 retrun 0x2 (read: 0x55555557bf94, write:)
0x683c: sub_a590 self: 0x55555557bf40 retrun 0x2 (read: 0x55555557bf94, write:)
0x6843: sub_a620 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bf98, write:)
0x6879: sub_62b0 self: 0x55555557be60 retrun 0xe (read: 0x55555557be80, write:)
0x688b: sub_a0a0 self: 0x55555557bf40 retrun 0x0 (read:, write: 0x55555557bf78(0x6))
----------------------------------------------------------------------------------------------------
wait_1
self: 0x5555555802d0
----------------------------------------------------------------------------------------------------
0x6f7c: sub_e1a0 self: 0x5555555802d0 retrun 0x0 (read: 0x555555580304, write:)
0x6faa: sub_e2a0 self: 0x55555557be20 retrun 0x3 (read: 0x55555557be44, write:)
0x6fb8: sub_e190 self: 0x5555555802d0 retrun 0x1 (read: 0x555555580300, write:)
0x6fd5: sub_e250 self: 0x5555555802d0 retrun 0x1 (read: 0x555555580308, write:)
----------------------------------------------------------------------------------------------------
mov_1
self: 0x55555557f700
----------------------------------------------------------------------------------------------------
0x8b2e: sub_8910 self: 0x55555557f700 retrun 0x2 (read: 0x55555557f734, write:)
0x8bec: sub_9f60 self: 0x55555557c020 retrun 0x0 (read: 0x55555557c04c, write:)
0x8c39: sub_8880 self: 0x55555557f700 retrun 0x0 (read: 0x55555557f732, write:)
0x8c9c: sub_87f0 self: 0x55555557f700 retrun 0x2 (read: 0x55555557f730, write:)
0x8e2d: sub_9f80 self: 0x55555557c020 retrun 0x0 (read:, write: 0x55555557c04c(0x0))
----------------------------------------------------------------------------------------------------
op_end
self: 0x55555557f700
----------------------------------------------------------------------------------------------------
0x64dc: sub_a590 self: 0x55555557c020 retrun 0x1 (read: 0x55555557c074(sc), write:)
0x64f8: sub_a620 self: 0x55555557c020 retrun 0x1 (read: 0x55555557c078(se), write:)
0x6505: sub_62b0 self: 0x55555557f700 retrun 0x3 (read: 0x55555557f720, write:)
0x6823: sub_62b0 self: 0x55555557f700 retrun 0x3 (read: 0x55555557f720, write:)
0x6833: sub_a590 self: 0x55555557c020 retrun 0x1 (read: 0x55555557c074(sc), write:)
0x683c: sub_a590 self: 0x55555557c020 retrun 0x1 (read: 0x55555557c074(sc), write:)
0x6843: sub_a620 self: 0x55555557c020 retrun 0x1 (read: 0x55555557c078(se), write:)
0x6879: sub_62b0 self: 0x55555557f700 retrun 0x3 (read: 0x55555557f720, write:)
0x688b: sub_a0a0 self: 0x55555557c020 retrun 0x0 (read:, write: 0x55555557c058(0x3))
----------------------------------------------------------------------------------------------------
wait_1
self: 0x5555555801e0
----------------------------------------------------------------------------------------------------
0x6f7c: sub_e1a0 self: 0x5555555801e0 retrun 0x0 (read: 0x555555580214, write:)
0x6faa: sub_e2a0 self: 0x55555557be20 retrun 0x3 (read: 0x55555557be44, write:)
0x6fb8: sub_e190 self: 0x5555555801e0 retrun 0x0 (read: 0x555555580210, write:)
0x6fd5: sub_e250 self: 0x5555555801e0 retrun 0x1 (read: 0x555555580218, write:)
----------------------------------------------------------------------------------------------------
op_end
self: 0x5555555801e0
----------------------------------------------------------------------------------------------------
0x64dc: sub_a590 self: 0x55555557c020 retrun 0x1 (read: 0x55555557c074(sc), write:)
0x64f8: sub_a620 self: 0x55555557c020 retrun 0x1 (read: 0x55555557c078(se), write:)
0x6505: sub_62b0 self: 0x5555555801e0 retrun 0x18 (read: 0x555555580200, write:)
0x6524: sub_a590 self: 0x55555557c020 retrun 0x1 (read: 0x55555557c074(sc), write:)
0x652d: sub_a590 self: 0x55555557c020 retrun 0x1 (read: 0x55555557c074(sc), write:)
0x6531: sub_a620 self: 0x55555557c020 retrun 0x1 (read: 0x55555557c078(se), write:)
0x654d: sub_62b0 self: 0x5555555801e0 retrun 0x18 (read: 0x555555580200, write:)
0x6555: sub_a620 self: 0x55555557c020 retrun 0x1 (read: 0x55555557c078(se), write:)
0x6588: sub_a590 self: 0x55555557c020 retrun 0x1 (read: 0x55555557c074(sc), write:)
0x658e: sub_a620 self: 0x55555557c020 retrun 0x1 (read: 0x55555557c078(se), write:)
0x65c4: sub_a8f0 self: 0x55555557c020 retrun 0x0 (read: 0x55555557c088(sb), write:)
0x65d3: sub_a8f0 self: 0x55555557c020 retrun 0x0 (read: 0x55555557c088(sb), write:)
0x65d8: sub_a590 self: 0x55555557c020 retrun 0x1 (read: 0x55555557c074(sc), write:)
0x66fd: sub_a6b0 self: 0x55555557c020 retrun 0x0 (read: 0x55555557c079(sd), write:)
0x674b: sub_e2a0 self: 0x55555557be20 retrun 0x3 (read: 0x55555557be44, write:)
0x6758: sub_a8f0 self: 0x55555557c020 retrun 0x0 (read: 0x55555557c088(sb), write:)
not 0x0
and 0xffffffff, 0x3
or 0x3, 0x1 (0x3)
0x6779: sub_e470 self: 0x55555557be20 retrun 0x0 (read:, write: 0x55555557be44(0x3))
0x6823: sub_62b0 self: 0x5555555801e0 retrun 0x18 (read: 0x555555580200, write:)
0x6833: sub_a590 self: 0x55555557c020 retrun 0x1 (read: 0x55555557c074(sc), write:)
0x683c: sub_a590 self: 0x55555557c020 retrun 0x1 (read: 0x55555557c074(sc), write:)
0x6843: sub_a620 self: 0x55555557c020 retrun 0x1 (read: 0x55555557c078(se), write:)
0x6879: sub_62b0 self: 0x5555555801e0 retrun 0x18 (read: 0x555555580200, write:)
----------------------------------------------------------------------------------------------------
in_1
self: 0x555555580640
----------------------------------------------------------------------------------------------------
0x73de: sub_a500 self: 0x55555557c020 retrun 0x0 (read: 0x55555557c072, write:)
0x7402: sub_7300 self: 0x555555580640 retrun 0x1 (read: 0x555555580674, write:)
0x742b: sub_e280 self: 0x555555580640 retrun 0x0 (read: 0x555555580670, write:)
0x7456: sub_e2a0 self: 0x55555557be20 retrun 0x3 (read: 0x55555557be44, write:)
0x7460: sub_e2a0 self: 0x55555557be20 retrun 0x3 (read: 0x55555557be44, write:)
0x7474: sub_a740 self: 0x55555557c020 retrun 0x1 (read: 0x55555557c07c(ib), write:)
0x300000003 >> 0x1 (0x180000001)
0x180000001 & 0x1
0x7513: sub_a1a0 self: 0x55555557c020 retrun 0x1 (read: 0x55555557c064(isd), write:)
0x7520: sub_7300 self: 0x555555580640 retrun 0x1 (read: 0x555555580674, write:)
0x7542: sub_9d70 self: 0x55555557c020 retrun 0x555555562740 
*0x55555557c03c (0x0)
0x0 >> 0x1
*0x55555557c03c = 0x0
0x755c: sub_e740 self: 0x55555557c020 retrun 0x7ffff47bfd28 
0x7563: sub_7300 self: 0x555555580640 retrun 0x1 (read: 0x555555580674, write:)
0x1 >> 0x1f
0x7589: sub_9d70 self: 0x55555557c020 retrun 0x555555562740 
*0x55555557c03c |= -0x80000000
0x75c7: sub_e740 self: 0x55555557c020 retrun 0x7ffff47bfd28 
0x75cf: sub_9e40 self: 0x55555557c020 retrun 0x0 (read: 0x55555557c044, write:)
0x75dc: sub_7300 self: 0x555555580640 retrun 0x1 (read: 0x555555580674, write:)
0x75f9: sub_9e60 self: 0x55555557c020 retrun 0x0 (read:, write: 0x55555557c044(0x1))
0x7609: sub_a470 self: 0x55555557c020 retrun 0x1 (read: 0x55555557c071(as), write:)
0x7619: sub_9e40 self: 0x55555557c020 retrun 0x1 (read: 0x55555557c044, write:)
0x762b: sub_a350 self: 0x55555557c020 retrun 0x10 (read: 0x55555557c06c(ps), write:)
----------------------------------------------------------------------------------------------------
...

when the first bit of be44 is 0:

out
self: 0x55555557be60
----------------------------------------------------------------------------------------------------
0x7a4c: sub_a3e0 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bf90, write:)
0x7ad0: sub_9c90 self: 0x55555557bf40 retrun 0x4b72 (read: 0x55555557bf58, write:)
0x7ad7: sub_a230 self: 0x55555557bf40 retrun 0x1 (read: 0x55555557bf85, write:)
0x7af6: sub_e1e0 self: 0x55555557be60 retrun 0x1 (read: 0x55555557be94, write:)
0x7b3b: sub_e1e0 self: 0x55555557be60 retrun 0x1 (read: 0x55555557be94, write:)
0x7b4a: sub_9ce0 self: 0x55555557bf40 retrun 0x555555562730 
0x4b72 >> 0x1
*0x55555557bf58 = 0x25b9
0x7b72: sub_e730 self: 0x55555557bf40 retrun 0x7ffff47bfd28 
0x7bd4: sub_e1d0 self: 0x55555557be60 retrun 0x0 (read: 0x55555557be90, write:)
0x7bfe: sub_a7d0 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bfa0, write:)
0x7c16: sub_e1e0 self: 0x55555557be60 retrun 0x1 (read: 0x55555557be94, write:)
0x7c2c: sub_a7d0 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bfa0, write:)
0x7fa4: sub_e2a0 self: 0x55555557be20 retrun 0x1 (read: 0x55555557be44, write:)
0x7faf: sub_a7d0 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bfa0, write:)
0x7fd6: sub_e470 self: 0x55555557be20 retrun 0x0 (read:, write: 0x55555557be44(0x0))
0x803d: sub_9db0 self: 0x55555557bf40 retrun 0x1 (read: 0x55555557bf60, write:)
0x8047: sub_e1e0 self: 0x55555557be60 retrun 0x1 (read: 0x55555557be94, write:)
0x806d: sub_9dd0 self: 0x55555557bf40 retrun 0x0 (read:, write: 0x55555557bf60(0x2))
0x8070: sub_a3e0 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bf90, write:)
----------------------------------------------------------------------------------------------------
op_end
self: 0x55555557be60
----------------------------------------------------------------------------------------------------
0x64dc: sub_a590 self: 0x55555557bf40 retrun 0x2 (read: 0x55555557bf94, write:)
0x64f8: sub_a620 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bf98, write:)
0x6524: sub_a590 self: 0x55555557bf40 retrun 0x2 (read: 0x55555557bf94, write:)
0x652d: sub_a590 self: 0x55555557bf40 retrun 0x2 (read: 0x55555557bf94, write:)
0x6531: sub_a620 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bf98, write:)
0x654d: sub_62b0 self: 0x55555557be60 retrun 0xe (read: 0x55555557be80, write:)
0x6555: sub_a620 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bf98, write:)
0x6588: sub_a590 self: 0x55555557bf40 retrun 0x2 (read: 0x55555557bf94, write:)
0x658e: sub_a620 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bf98, write:)
0x65c4: sub_a8f0 self: 0x55555557bf40 retrun 0x1 (read: 0x55555557bfa8, write:)
0x65d3: sub_a8f0 self: 0x55555557bf40 retrun 0x1 (read: 0x55555557bfa8, write:)
0x65d8: sub_a590 self: 0x55555557bf40 retrun 0x2 (read: 0x55555557bf94, write:)
0x66fd: sub_a6b0 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bf99, write:)
0x674b: sub_e2a0 self: 0x55555557be20 retrun 0x0 (read: 0x55555557be44, write:)
0x6758: sub_a8f0 self: 0x55555557bf40 retrun 0x1 (read: 0x55555557bfa8, write:)
not 0x6
and 0xfffffff9, 0x0
or 0x0, 0x2 (0x2)
0x6779: sub_e470 self: 0x55555557be20 retrun 0x0 (read:, write: 0x55555557be44(0x2))
0x6823: sub_62b0 self: 0x55555557be60 retrun 0xe (read: 0x55555557be80, write:)
0x6833: sub_a590 self: 0x55555557bf40 retrun 0x2 (read: 0x55555557bf94, write:)
0x683c: sub_a590 self: 0x55555557bf40 retrun 0x2 (read: 0x55555557bf94, write:)
0x6843: sub_a620 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bf98, write:)
0x6879: sub_62b0 self: 0x55555557be60 retrun 0xe (read: 0x55555557be80, write:)
0x688b: sub_a0a0 self: 0x55555557bf40 retrun 0x0 (read:, write: 0x55555557bf78(0x6))
----------------------------------------------------------------------------------------------------
wait_1
self: 0x5555555802d0
----------------------------------------------------------------------------------------------------
0x6f7c: sub_e1a0 self: 0x5555555802d0 retrun 0x0 (read: 0x555555580304, write:)
0x6faa: sub_e2a0 self: 0x55555557be20 retrun 0x2 (read: 0x55555557be44, write:)
0x6fb8: sub_e190 self: 0x5555555802d0 retrun 0x1 (read: 0x555555580300, write:)
0x6fd5: sub_e250 self: 0x5555555802d0 retrun 0x1 (read: 0x555555580308, write:)
----------------------------------------------------------------------------------------------------
mov_1
self: 0x55555557f700
----------------------------------------------------------------------------------------------------
0x8b2e: sub_8910 self: 0x55555557f700 retrun 0x2 (read: 0x55555557f734, write:)
0x8bec: sub_9f60 self: 0x55555557c020 retrun 0x0 (read: 0x55555557c04c, write:)
0x8c39: sub_8880 self: 0x55555557f700 retrun 0x0 (read: 0x55555557f732, write:)
0x8c9c: sub_87f0 self: 0x55555557f700 retrun 0x2 (read: 0x55555557f730, write:)
0x8e2d: sub_9f80 self: 0x55555557c020 retrun 0x0 (read:, write: 0x55555557c04c(0x0))
----------------------------------------------------------------------------------------------------
op_end
self: 0x55555557f700
----------------------------------------------------------------------------------------------------
0x64dc: sub_a590 self: 0x55555557c020 retrun 0x1 (read: 0x55555557c074(sc), write:)
0x64f8: sub_a620 self: 0x55555557c020 retrun 0x1 (read: 0x55555557c078(se), write:)
0x6505: sub_62b0 self: 0x55555557f700 retrun 0x3 (read: 0x55555557f720, write:)
0x6823: sub_62b0 self: 0x55555557f700 retrun 0x3 (read: 0x55555557f720, write:)
0x6833: sub_a590 self: 0x55555557c020 retrun 0x1 (read: 0x55555557c074(sc), write:)
0x683c: sub_a590 self: 0x55555557c020 retrun 0x1 (read: 0x55555557c074(sc), write:)
0x6843: sub_a620 self: 0x55555557c020 retrun 0x1 (read: 0x55555557c078(se), write:)
0x6879: sub_62b0 self: 0x55555557f700 retrun 0x3 (read: 0x55555557f720, write:)
0x688b: sub_a0a0 self: 0x55555557c020 retrun 0x0 (read:, write: 0x55555557c058(0x3))
----------------------------------------------------------------------------------------------------
wait_1
self: 0x5555555801e0
----------------------------------------------------------------------------------------------------
0x6f7c: sub_e1a0 self: 0x5555555801e0 retrun 0x0 (read: 0x555555580214, write:)
0x6faa: sub_e2a0 self: 0x55555557be20 retrun 0x2 (read: 0x55555557be44, write:)
0x6fb8: sub_e190 self: 0x5555555801e0 retrun 0x0 (read: 0x555555580210, write:)
0x6fd5: sub_e250 self: 0x5555555801e0 retrun 0x1 (read: 0x555555580218, write:)
0x717f: sub_a520 self: 0x55555557c020 retrun 0x0 (read:, write: 0x55555557c072(0x1))
----------------------------------------------------------------------------------------------------
op_end
self: 0x5555555801e0
----------------------------------------------------------------------------------------------------
0x64dc: sub_a590 self: 0x55555557c020 retrun 0x1 (read: 0x55555557c074(sc), write:)
0x64f8: sub_a620 self: 0x55555557c020 retrun 0x1 (read: 0x55555557c078(se), write:)
0x6505: sub_62b0 self: 0x5555555801e0 retrun 0x18 (read: 0x555555580200, write:)
0x6524: sub_a590 self: 0x55555557c020 retrun 0x1 (read: 0x55555557c074(sc), write:)
0x652d: sub_a590 self: 0x55555557c020 retrun 0x1 (read: 0x55555557c074(sc), write:)
0x6531: sub_a620 self: 0x55555557c020 retrun 0x1 (read: 0x55555557c078(se), write:)
0x654d: sub_62b0 self: 0x5555555801e0 retrun 0x18 (read: 0x555555580200, write:)
0x6555: sub_a620 self: 0x55555557c020 retrun 0x1 (read: 0x55555557c078(se), write:)
0x6588: sub_a590 self: 0x55555557c020 retrun 0x1 (read: 0x55555557c074(sc), write:)
0x658e: sub_a620 self: 0x55555557c020 retrun 0x1 (read: 0x55555557c078(se), write:)
0x65c4: sub_a8f0 self: 0x55555557c020 retrun 0x0 (read: 0x55555557c088(sb), write:)
0x65d3: sub_a8f0 self: 0x55555557c020 retrun 0x0 (read: 0x55555557c088(sb), write:)
0x65d8: sub_a590 self: 0x55555557c020 retrun 0x1 (read: 0x55555557c074(sc), write:)
0x66fd: sub_a6b0 self: 0x55555557c020 retrun 0x0 (read: 0x55555557c079(sd), write:)
0x674b: sub_e2a0 self: 0x55555557be20 retrun 0x2 (read: 0x55555557be44, write:)
0x6758: sub_a8f0 self: 0x55555557c020 retrun 0x0 (read: 0x55555557c088(sb), write:)
not 0x0
and 0xffffffff, 0x2
or 0x2, 0x1 (0x3)
0x6779: sub_e470 self: 0x55555557be20 retrun 0x0 (read:, write: 0x55555557be44(0x3))
0x6823: sub_62b0 self: 0x5555555801e0 retrun 0x18 (read: 0x555555580200, write:)
0x6833: sub_a590 self: 0x55555557c020 retrun 0x1 (read: 0x55555557c074(sc), write:)
0x683c: sub_a590 self: 0x55555557c020 retrun 0x1 (read: 0x55555557c074(sc), write:)
0x6843: sub_a620 self: 0x55555557c020 retrun 0x1 (read: 0x55555557c078(se), write:)
0x6879: sub_62b0 self: 0x5555555801e0 retrun 0x18 (read: 0x555555580200, write:)
----------------------------------------------------------------------------------------------------
wait_1
self: 0x5555555801e0
----------------------------------------------------------------------------------------------------
0x6f7c: sub_e1a0 self: 0x5555555801e0 retrun 0x0 (read: 0x555555580214, write:)
0x6faa: sub_e2a0 self: 0x55555557be20 retrun 0x3 (read: 0x55555557be44, write:)
0x6fb8: sub_e190 self: 0x5555555801e0 retrun 0x0 (read: 0x555555580210, write:)
0x6fd5: sub_e250 self: 0x5555555801e0 retrun 0x1 (read: 0x555555580218, write:)
----------------------------------------------------------------------------------------------------
jmp
self: 0x55555557bea0
----------------------------------------------------------------------------------------------------
0x6aac: sub_e1c0 self: 0x55555557bea0 retrun 0x2 (read: 0x55555557bed4, write:)
0x6b18: sub_9ed0 self: 0x55555557bf40 retrun 0xe (read: 0x55555557bf68, write:)
0x6b2a: sub_9f20 self: 0x55555557bf40 retrun 0x555555562770 
--*0x55555557bf68 (14 -> 13)
0x6b71: sub_e770 self: 0x55555557bf40 retrun 0x7ffff47bfd28 
0x6bc4: sub_e1b0 self: 0x55555557bea0 retrun 0x2 (read: 0x55555557bed0, write:)
0x6bd2: sub_a010 self: 0x55555557bf40 retrun 0x0 (read:, write: 0x55555557bf70(0x2))
----------------------------------------------------------------------------------------------------
op_end
self: 0x55555557bea0
----------------------------------------------------------------------------------------------------
0x64dc: sub_a590 self: 0x55555557bf40 retrun 0x2 (read: 0x55555557bf94, write:)
0x64f8: sub_a620 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bf98, write:)
0x6524: sub_a590 self: 0x55555557bf40 retrun 0x2 (read: 0x55555557bf94, write:)
0x652d: sub_a590 self: 0x55555557bf40 retrun 0x2 (read: 0x55555557bf94, write:)
0x6531: sub_a620 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bf98, write:)
0x654d: sub_62b0 self: 0x55555557bea0 retrun 0x1 (read: 0x55555557bec0, write:)
0x6555: sub_a620 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bf98, write:)
0x6588: sub_a590 self: 0x55555557bf40 retrun 0x2 (read: 0x55555557bf94, write:)
0x658e: sub_a620 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bf98, write:)
0x65c4: sub_a8f0 self: 0x55555557bf40 retrun 0x1 (read: 0x55555557bfa8, write:)
0x65d3: sub_a8f0 self: 0x55555557bf40 retrun 0x1 (read: 0x55555557bfa8, write:)
0x65d8: sub_a590 self: 0x55555557bf40 retrun 0x2 (read: 0x55555557bf94, write:)
0x66fd: sub_a6b0 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bf99, write:)
0x674b: sub_e2a0 self: 0x55555557be20 retrun 0x3 (read: 0x55555557be44, write:)
0x6758: sub_a8f0 self: 0x55555557bf40 retrun 0x1 (read: 0x55555557bfa8, write:)
not 0x6
and 0xfffffff9, 0x3
or 0x1, 0x0 (0x1)
0x6779: sub_e470 self: 0x55555557be20 retrun 0x0 (read:, write: 0x55555557be44(0x1))
0x6823: sub_62b0 self: 0x55555557bea0 retrun 0x1 (read: 0x55555557bec0, write:)
0x6833: sub_a590 self: 0x55555557bf40 retrun 0x2 (read: 0x55555557bf94, write:)
0x683c: sub_a590 self: 0x55555557bf40 retrun 0x2 (read: 0x55555557bf94, write:)
0x6843: sub_a620 self: 0x55555557bf40 retrun 0x0 (read: 0x55555557bf98, write:)
0x6879: sub_62b0 self: 0x55555557bea0 retrun 0x1 (read: 0x55555557bec0, write:)
0x688b: sub_a0a0 self: 0x55555557bf40 retrun 0x0 (read:, write: 0x55555557bf78(0x1))
----------------------------------------------------------------------------------------------------
in_1
self: 0x555555580640
----------------------------------------------------------------------------------------------------
0x73de: sub_a500 self: 0x55555557c020 retrun 0x0 (read: 0x55555557c072, write:)
0x7402: sub_7300 self: 0x555555580640 retrun 0x1 (read: 0x555555580674, write:)
0x742b: sub_e280 self: 0x555555580640 retrun 0x0 (read: 0x555555580670, write:)
0x7456: sub_e2a0 self: 0x55555557be20 retrun 0x1 (read: 0x55555557be44, write:)
0x7460: sub_e2a0 self: 0x55555557be20 retrun 0x1 (read: 0x55555557be44, write:)
0x7474: sub_a740 self: 0x55555557c020 retrun 0x1 (read: 0x55555557c07c(ib), write:)
0x100000001 >> 0x1 (0x80000000)
0x80000000 & 0x1
0x7513: sub_a1a0 self: 0x55555557c020 retrun 0x1 (read: 0x55555557c064(isd), write:)
0x7520: sub_7300 self: 0x555555580640 retrun 0x1 (read: 0x555555580674, write:)
0x7542: sub_9d70 self: 0x55555557c020 retrun 0x555555562740 
*0x55555557c03c (0x80000000)
-0x80000000 >> 0x1
*0x55555557c03c = 0x40000000
0x755c: sub_e740 self: 0x55555557c020 retrun 0x7ffff47bfd28 
0x7563: sub_7300 self: 0x555555580640 retrun 0x1 (read: 0x555555580674, write:)
0x0 >> 0x1f
0x7589: sub_9d70 self: 0x55555557c020 retrun 0x555555562740 
*0x55555557c03c |= 0x0
0x75c7: sub_e740 self: 0x55555557c020 retrun 0x7ffff47bfd28 
0x75cf: sub_9e40 self: 0x55555557c020 retrun 0x1 (read: 0x55555557c044, write:)
0x75dc: sub_7300 self: 0x555555580640 retrun 0x1 (read: 0x555555580674, write:)
0x75f9: sub_9e60 self: 0x55555557c020 retrun 0x0 (read:, write: 0x55555557c044(0x2))
0x7609: sub_a470 self: 0x55555557c020 retrun 0x1 (read: 0x55555557c071(as), write:)
0x7619: sub_9e40 self: 0x55555557c020 retrun 0x2 (read: 0x55555557c044, write:)
0x762b: sub_a350 self: 0x55555557c020 retrun 0x10 (read: 0x55555557c06c(ps), write:)
----------------------------------------------------------------------------------------------------
...
  • when be44 is 1 after out instruction
    1. *be44 |= 0x2 by op_end right after out instruction (*be44 is 3)
    2. bittest(be44, 1) == 1 is True by the first wait instruction
    3. nop (mov)
    4. bittest(be44, 0) == 1 is True by the second wait instruction
    5. *c03c >>= 1; *c03c |= (((*be44 >> 1) & 1) << 31); by the in instruction
    6. go back to 1 by the jmp instruction
  • when be44 is 0 after out instruction
    1. *be44 |= 0x2 by op_end right after out instruction (*be44 is 2)
    2. bittest(be44, 1) == 1 is True by the first wait instruction
    3. nop (mov)
    4. bittest(be44, 0) == 1 is False by the second wait instruction (repeat)
    5. *be44 &= 0xffffffff; *be44 |= 1; by op_end right after the wait instruction (*be44 is now 3)
    6. bittest(be44, 0) == 1 is True by the second wait instruction
    7. *be44 &= 0xfffffff9; *be44 |= 0x1; by op_end right after the init_context’s jmp instruction (*be44 is now 1)
    8. *c03c >>= 1; *c03c |= 0; by the in instruction
    9. go back to 1 by the jmp instruction

The role of op_end (what I introduced as after_op_func) is to do *be44 |= 1 to force the next wait instruction to return 0.

So, the second wait instruction that checks the first bit of be44 eventually passes but the order of executing instructions changed (delayed) and that leads to executing jmp instruction of init_context and op_end of it before executing in instruction.

Then, the op_end of jmp_instruction makes be44 to 1, and the in instruction extracts the second bit of be44 (which is 0) and use it.

It can be seen as the second bit of be44 is used as the alias of the first bit.

(The in instruction can insert value to array2 so the compares can be passed)

At first glance, the instructions from writeup does look simple.

But, it has a lot to think of.

It was fun to write, happy hacking :)

Written by deayzl

2개의 댓글

comment-user-thumbnail
2024년 9월 26일

The Pass-It-On challenge from DEF CON CTF Qualifiers 2024 requires a deep understanding of the Swift Virtual Machine's internal workings, incredibox sprunki including its custom instruction set, memory model, and control flow.

답글 달기
comment-user-thumbnail
2024년 11월 27일

Sprunki Retake is a fan-made adaptation of the music game Incredibox, enhancing the original experience with new sounds, characters, and visual effects.

답글 달기