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
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.
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.
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}\'')
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.
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()
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)
self
points to the instruction structure where operand value resides.arg1
(which is a1) points to the structure for who added the instruction.arg2
points to the structure that doesn’t change.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_context | vtable | owner | name |
---|---|---|---|
0x55555557c020 | 0x0000555555567e48 | user | my_context |
0x55555557bf40 | 0x0000555555567e48 | init instructions | init_context |
0x55555557be20 | 0x0000555555568300 | middle (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.
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()
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)();
}
__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.
__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;
}
__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;
}
}
__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;
}
__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;
}
__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;
}
__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;
}
__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;
}
}
__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;
}
__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;
}
__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)
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()
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.
“/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.
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]
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.
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;
}
*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.
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:)
----------------------------------------------------------------------------------------------------
...
*be44 |= 0x2
by op_end right after out instruction (*be44 is 3)bittest(be44, 1) == 1
is True by the first wait instructionbittest(be44, 0) == 1
is True by the second wait instruction*c03c >>= 1; *c03c |= (((*be44 >> 1) & 1) << 31);
by the in instruction*be44 |= 0x2
by op_end right after out instruction (*be44 is 2)bittest(be44, 1) == 1
is True by the first wait instructionbittest(be44, 0) == 1
is False by the second wait instruction (repeat)*be44 &= 0xffffffff; *be44 |= 1;
by op_end right after the wait instruction (*be44 is now 3)bittest(be44, 0) == 1
is True by the second wait instruction*be44 &= 0xfffffff9; *be44 |= 0x1;
by op_end right after the init_context’s jmp instruction (*be44 is now 1)*c03c >>= 1; *c03c |= 0;
by the in instructionThe 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
Sprunki Retake is a fan-made adaptation of the music game Incredibox, enhancing the original experience with new sounds, characters, and visual effects.
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.