K3RN3L CTF 2021 Rev - `Recurso & Rasm ` writeups
Our Team zh3ro ended up at 9 th position in `K3RN3LCTF - 2021`.
These Reverse engineering challs are interesting
-> Both are based on one vm only (Recurso), different compiled scripts . (leFlag.recc , rasm.recc)
These Reverse engineering challs are interesting
-> Both are based on one vm only (Recurso), different compiled scripts . (leFlag.recc , rasm.recc)
Recurso
Given a Recurso Execuatable which can compile, run recurso sccrips.And a leFlag.recc (a recurso compiled file) containing a flag checking logic, can be run by given Recurso executable.
The Goal of the challenge is to get the flag checking logic in leFlag.recc and steal flag
Decompile and Analyse -> Recurso
First we have to get to know about how the Recurso is running this byte code in order to get the logic of leFlag.reccDecompiled the Code, changed the variable names based on code execuation, to ease my work.
Main function :
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
int __cdecl main(int argc, const char **argv, const char **envp) | |
{ | |
const char *v3; // rax | |
void *v5; // [rsp+18h] [rbp-18h] | |
__int64 v6; // [rsp+20h] [rbp-10h] | |
int *v7; // [rsp+28h] [rbp-8h] | |
if ( argc > 1 && strstr(argv[1], ".recc") ) | |
{ | |
v7 = initBytecodeFileWithFile(argv[1]); | |
runProgram(*((_QWORD *)v7 + 2), *((_QWORD *)v7 + 3)); | |
} | |
else if ( argc > 1 && strstr(argv[1], ".rec") ) | |
{ | |
fileData = (void *)readFile(argv[1], &fileSize); | |
v5 = fileData; | |
program = (__int64)initProgramNode(); | |
v6 = initFunctionNode("main"); | |
addElementToProgramNode(program, v6); | |
curFunction = v6; | |
parseFunction(program, &v5); | |
if ( argc == 4 && !strcmp(argv[2], "-s") ) | |
v3 = argv[3]; | |
else | |
v3 = (const char *)&unk_55B6B934B008; | |
compileBytecode(program, v3); | |
free(fileData); | |
freeProgramNode(program); | |
} | |
return 0; | |
} |
runProgram is the Function we need to focus
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
__int64 __fastcall runProgram(__int64 a1, __int64 code) | |
{ | |
int v2; // eax | |
int v3; // eax | |
int v4; // eax | |
int v5; // ecx | |
int v6; // eax | |
int v7; // eax | |
int v8; // eax | |
int v9; // eax | |
int v10; // eax | |
int v11; // eax | |
int v12; // eax | |
int v13; // eax | |
int v14; // eax | |
int v15; // eax | |
int v16; // eax | |
int v17; // eax | |
int v18; // ebx | |
int v19; // eax | |
int v20; // eax | |
int v21; // eax | |
int v22; // eax | |
__int64 v23; // rbx | |
int v24; // eax | |
int v25; // eax | |
int v26; // eax | |
int v27; // eax | |
int v28; // eax | |
int v29; // ecx | |
__int64 v30; // rax | |
int v31; // ebx | |
int v32; // eax | |
int v33; // eax | |
int v34; // eax | |
int v35; // eax | |
void **v36; // rbx | |
int v37; // eax | |
int v38; // eax | |
int v39; // eax | |
int v40; // eax | |
int v41; // eax | |
int v42; // eax | |
int v43; // eax | |
int v44; // eax | |
int v45; // eax | |
int v46; // eax | |
int v47; // eax | |
int v48; // eax | |
int v49; // eax | |
__int64 v50; // rcx | |
int v51; // eax | |
int v52; // eax | |
int v53; // eax | |
int v54; // eax | |
__int64 v55; // rcx | |
int v56; // eax | |
int v57; // eax | |
int v58; // eax | |
int v59; // eax | |
int v60; // ebx | |
int v61; // ecx | |
int v62; // eax | |
int v63; // eax | |
int v64; // eax | |
int v65; // eax | |
int v66; // eax | |
__int64 result; // rax | |
__int64 input_lld; // [rsp+28h] [rbp-138F8h] | |
char v69; // [rsp+34h] [rbp-138ECh] | |
char v70; // [rsp+35h] [rbp-138EBh] | |
char v71; // [rsp+36h] [rbp-138EAh] | |
char v72; // [rsp+37h] [rbp-138E9h] | |
char v73; // [rsp+38h] [rbp-138E8h] | |
char v74; // [rsp+39h] [rbp-138E7h] | |
char v75; // [rsp+3Ah] [rbp-138E6h] | |
char v76; // [rsp+3Bh] [rbp-138E5h] | |
char v77; // [rsp+3Ch] [rbp-138E4h] | |
char v78; // [rsp+3Dh] [rbp-138E3h] | |
char v79; // [rsp+3Eh] [rbp-138E2h] | |
char v80; // [rsp+3Fh] [rbp-138E1h] | |
__int64 stack[10001]; // [rsp+40h] [rbp-138E0h] | |
__int128 v82; // [rsp+138C8h] [rbp-58h] | |
char v83; // [rsp+138DFh] [rbp-41h] | |
_QWORD *funcs_ptr; // [rsp+138E0h] [rbp-40h] | |
int j; // [rsp+138E8h] [rbp-38h] | |
int i; // [rsp+138ECh] [rbp-34h] | |
void *call_stack; // [rsp+138F0h] [rbp-30h] | |
int v88_64; // [rsp+138FCh] [rbp-24h] | |
int cur_func; // [rsp+13900h] [rbp-20h] | |
int v90; // [rsp+13904h] [rbp-1Ch] | |
int v91; // [rsp+13908h] [rbp-18h] | |
int pc; // [rsp+1390Ch] [rbp-14h] | |
funcs_ptr = initializeFunctions((char *)a1); | |
pc = 0; | |
v91 = 0; | |
v90 = 0; | |
cur_func = 0; | |
v88_64 = 64; | |
call_stack = malloc(0x200uLL); | |
for ( i = 0; i < v88_64; ++i ) | |
*((_QWORD *)call_stack + i) = malloc(8uLL); | |
while ( 1 ) | |
{ | |
result = *(unsigned __int8 *)(pc + code); | |
if ( (_BYTE)result == 13 ) | |
return result; | |
v2 = pc++; | |
v83 = *(_BYTE *)(v2 + code); | |
switch ( v83 ) | |
{ | |
case 1: | |
*((_QWORD *)&v82 + 1) = stack[--v91]; | |
*(_QWORD *)&v82 = stack[--v91]; | |
v3 = v91++; | |
stack[v3] = *((_QWORD *)&v82 + 1) - v82; | |
break; | |
case 2: | |
*((_QWORD *)&v82 + 1) = stack[--v91]; | |
*(_QWORD *)&v82 = stack[--v91]; | |
v4 = v91++; | |
stack[v4] = v82 * *((_QWORD *)&v82 + 1); | |
break; | |
case 3: | |
*((_QWORD *)&v82 + 1) = stack[--v91]; | |
*(_QWORD *)&v82 = stack[--v91]; | |
v6 = v91++; | |
stack[v6] = *((_QWORD *)&v82 + 1) + v82; | |
break; | |
case 8: | |
v10 = pc++; | |
v73 = *(_BYTE *)(v10 + code); | |
v11 = pc++; | |
v74 = *(_BYTE *)(v11 + code); | |
v12 = pc++; | |
v75 = *(_BYTE *)(v12 + code); | |
v13 = pc++; | |
v76 = *(_BYTE *)(v13 + code); | |
v14 = pc++; | |
v77 = *(_BYTE *)(v14 + code); | |
v15 = pc++; | |
v78 = *(_BYTE *)(v15 + code); | |
v16 = pc++; | |
v79 = *(_BYTE *)(v16 + code); | |
v17 = pc++; | |
v80 = *(_BYTE *)(v17 + code); | |
v18 = v91++; | |
stack[v18] = bytesToLongLong((unsigned __int8 *)&v73); | |
break; | |
case 0xB: | |
v19 = pc++; | |
v69 = *(_BYTE *)(v19 + code); | |
v20 = pc++; | |
v70 = *(_BYTE *)(v20 + code); | |
v21 = pc++; | |
v71 = *(_BYTE *)(v21 + code); | |
v22 = pc++; | |
v72 = *(_BYTE *)(v22 + code); | |
v23 = stack[--v91]; | |
v24 = bytesToInt((unsigned __int8 *)&v69); | |
setLocal(funcs_ptr[cur_func], v24, v23); | |
break; | |
case 0xC: | |
v25 = pc++; | |
v69 = *(_BYTE *)(v25 + code); | |
v26 = pc++; | |
v70 = *(_BYTE *)(v26 + code); | |
v27 = pc++; | |
v71 = *(_BYTE *)(v27 + code); | |
v28 = pc++; | |
v72 = *(_BYTE *)(v28 + code); | |
v29 = bytesToInt((unsigned __int8 *)&v69); | |
v30 = funcs_ptr[cur_func]; | |
v31 = v91++; | |
stack[v31] = getLocal(v30, v29); | |
break; | |
case 0xE: | |
decrementFunction(funcs_ptr[cur_func]); | |
pc = **((_DWORD **)call_stack + --v90); | |
cur_func = *(_DWORD *)(*((_QWORD *)call_stack + v90) + 4LL); | |
break; | |
case 0xF: | |
printf("%lld\n", stack[--v91]); | |
break; | |
case 0x10: | |
--v91; | |
break; | |
case 0x13: | |
*((_QWORD *)&v82 + 1) = stack[--v91]; | |
*(_QWORD *)&v82 = stack[--v91]; | |
v5 = v91++; | |
stack[v5] = *((_QWORD *)&v82 + 1) / (__int64)v82; | |
break; | |
case 0x15: | |
v32 = pc++; | |
v69 = *(_BYTE *)(v32 + code); | |
v33 = pc++; | |
v70 = *(_BYTE *)(v33 + code); | |
v34 = pc++; | |
v71 = *(_BYTE *)(v34 + code); | |
v35 = pc++; | |
v72 = *(_BYTE *)(v35 + code); | |
if ( v90 >= v88_64 ) | |
{ | |
v88_64 *= 2; | |
call_stack = realloc(call_stack, 8LL * v88_64); | |
for ( j = v90; j < v88_64; ++j ) | |
{ | |
v36 = (void **)((char *)call_stack + 8 * j); | |
*v36 = malloc(8uLL); | |
} | |
} | |
*(_DWORD *)(*((_QWORD *)call_stack + v90) + 4LL) = cur_func; | |
**((_DWORD **)call_stack + v90++) = pc; | |
cur_func = bytesToInt((unsigned __int8 *)&v69); | |
pc = *(_DWORD *)funcs_ptr[cur_func]; | |
incrementFunction(funcs_ptr[cur_func]); | |
break; | |
case 0x16: | |
__isoc99_scanf("%lld", &input_lld); | |
v37 = v91++; | |
stack[v37] = input_lld; | |
break; | |
case 0x17: | |
*((_QWORD *)&v82 + 1) = stack[--v91]; | |
*(_QWORD *)&v82 = stack[--v91]; | |
if ( *((_QWORD *)&v82 + 1) != (_QWORD)v82 ) | |
{ | |
do | |
{ | |
v38 = pc++; | |
v83 = *(_BYTE *)(v38 + code); | |
} | |
while ( v83 != 14 ); | |
} | |
break; | |
case 0x18: | |
*((_QWORD *)&v82 + 1) = stack[--v91]; | |
*(_QWORD *)&v82 = stack[--v91]; | |
v7 = v91++; | |
stack[v7] = v82 | *((_QWORD *)&v82 + 1); | |
break; | |
case 0x19: | |
*((_QWORD *)&v82 + 1) = stack[--v91]; | |
*(_QWORD *)&v82 = stack[--v91]; | |
v8 = v91++; | |
stack[v8] = v82 & *((_QWORD *)&v82 + 1); | |
break; | |
case 0x1A: | |
*((_QWORD *)&v82 + 1) = stack[--v91]; | |
*(_QWORD *)&v82 = stack[--v91]; | |
v9 = v91++; | |
stack[v9] = v82 ^ *((_QWORD *)&v82 + 1); | |
break; | |
case 0x1B: | |
*((_QWORD *)&v82 + 1) = stack[--v91]; | |
*(_QWORD *)&v82 = stack[--v91]; | |
if ( *((_QWORD *)&v82 + 1) == (_QWORD)v82 ) | |
{ | |
do | |
{ | |
v39 = pc++; | |
v83 = *(_BYTE *)(v39 + code); | |
} | |
while ( v83 != 14 ); | |
} | |
break; | |
case 0x1C: | |
*((_QWORD *)&v82 + 1) = stack[--v91]; | |
*(_QWORD *)&v82 = stack[--v91]; | |
if ( *((_QWORD *)&v82 + 1) < (__int64)v82 ) | |
{ | |
do | |
{ | |
v40 = pc++; | |
v83 = *(_BYTE *)(v40 + code); | |
} | |
while ( v83 != 14 ); | |
} | |
break; | |
case 0x1D: | |
*((_QWORD *)&v82 + 1) = stack[--v91]; | |
*(_QWORD *)&v82 = stack[--v91]; | |
if ( *((_QWORD *)&v82 + 1) > (__int64)v82 ) | |
{ | |
do | |
{ | |
v41 = pc++; | |
v83 = *(_BYTE *)(v41 + code); | |
} | |
while ( v83 != 14 ); | |
} | |
break; | |
case 0x1E: | |
v42 = pc++; | |
v69 = *(_BYTE *)(v42 + code); | |
v43 = pc++; | |
v70 = *(_BYTE *)(v43 + code); | |
v44 = pc++; | |
v71 = *(_BYTE *)(v44 + code); | |
v45 = pc++; | |
v72 = *(_BYTE *)(v45 + code); | |
pc = bytesToInt((unsigned __int8 *)&v69); | |
break; | |
case 0x1F: | |
pc = stack[--v91]; | |
break; | |
case 0x20: | |
v46 = pc++; | |
v69 = *(_BYTE *)(v46 + code); | |
v47 = pc++; | |
v70 = *(_BYTE *)(v47 + code); | |
v48 = pc++; | |
v71 = *(_BYTE *)(v48 + code); | |
v49 = pc++; | |
v72 = *(_BYTE *)(v49 + code); | |
v50 = (int)bytesToInt((unsigned __int8 *)&v69); | |
++*(_BYTE *)(v50 + code); | |
break; | |
case 0x21: | |
v51 = pc++; | |
v69 = *(_BYTE *)(v51 + code); | |
v52 = pc++; | |
v70 = *(_BYTE *)(v52 + code); | |
v53 = pc++; | |
v71 = *(_BYTE *)(v53 + code); | |
v54 = pc++; | |
v72 = *(_BYTE *)(v54 + code); | |
v55 = (int)bytesToInt((unsigned __int8 *)&v69); | |
--*(_BYTE *)(v55 + code); | |
break; | |
case 0x22: | |
*((_QWORD *)&v82 + 1) = stack[--v91]; | |
*(_QWORD *)&v82 = stack[--v91]; | |
*(_BYTE *)(v82 + code) = *(_BYTE *)(*((_QWORD *)&v82 + 1) + code); | |
break; | |
case 0x23: | |
v56 = pc++; | |
v69 = *(_BYTE *)(v56 + code); | |
v57 = pc++; | |
v70 = *(_BYTE *)(v57 + code); | |
v58 = pc++; | |
v71 = *(_BYTE *)(v58 + code); | |
v59 = pc++; | |
v72 = *(_BYTE *)(v59 + code); | |
v60 = *(unsigned __int8 *)((int)bytesToInt((unsigned __int8 *)&v69) + code) << 8; | |
v61 = v60 + *(unsigned __int8 *)((int)bytesToInt((unsigned __int8 *)&v69) + 1LL + code); | |
v62 = v91++; | |
stack[v62] = v61; | |
break; | |
case 0x24: | |
v63 = pc++; | |
v69 = *(_BYTE *)(v63 + code); | |
v64 = pc++; | |
v70 = *(_BYTE *)(v64 + code); | |
v65 = pc++; | |
v71 = *(_BYTE *)(v65 + code); | |
v66 = pc++; | |
v72 = *(_BYTE *)(v66 + code); | |
*((_QWORD *)&v82 + 1) = stack[--v91]; | |
*(_QWORD *)&v82 = stack[--v91]; | |
if ( *((_QWORD *)&v82 + 1) == (_QWORD)v82 ) | |
pc = bytesToInt((unsigned __int8 *)&v69); | |
break; | |
default: | |
continue; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void *__fastcall initializeFunctions(char *a1) | |
{ | |
int v1; // eax | |
int v2; // eax | |
int v3; // eax | |
int v4; // eax | |
int v5; // eax | |
int v6; // eax | |
int v7; // eax | |
int v8; // eax | |
int v9; // eax | |
int v10; // eax | |
void **v11; // rbx | |
_DWORD *v12; // rbx | |
__int64 v13; // rbx | |
__int64 v14; // rbx | |
void **v15; // rbx | |
int v16; // eax | |
char v18; // [rsp+1Ch] [rbp-34h] | |
char v19; // [rsp+1Dh] [rbp-33h] | |
char v20; // [rsp+1Eh] [rbp-32h] | |
char v21; // [rsp+1Fh] [rbp-31h] | |
char v22; // [rsp+20h] [rbp-30h] | |
char v23; // [rsp+21h] [rbp-2Fh] | |
char v24; // [rsp+22h] [rbp-2Eh] | |
char v25; // [rsp+23h] [rbp-2Dh] | |
int j; // [rsp+24h] [rbp-2Ch] | |
char i; // [rsp+2Bh] [rbp-25h] | |
int v28; // [rsp+2Ch] [rbp-24h] | |
void *ptr; // [rsp+30h] [rbp-20h] | |
int v30; // [rsp+38h] [rbp-18h] | |
int v31; // [rsp+3Ch] [rbp-14h] | |
v31 = 2; | |
v30 = 1; | |
ptr = malloc(0x10uLL); | |
v28 = 1; | |
for ( i = *a1; i == 17; i = a1[v16] ) | |
{ | |
v1 = v28++; | |
for ( i = a1[v1]; i != 18; i = a1[v2] ) | |
v2 = v28++; | |
v3 = v28++; | |
v22 = a1[v3]; | |
v4 = v28++; | |
v23 = a1[v4]; | |
v5 = v28++; | |
v24 = a1[v5]; | |
v6 = v28++; | |
v25 = a1[v6]; | |
v7 = v28++; | |
v18 = a1[v7]; | |
v8 = v28++; | |
v19 = a1[v8]; | |
v9 = v28++; | |
v20 = a1[v9]; | |
v10 = v28++; | |
v21 = a1[v10]; | |
if ( v30 >= v31 ) | |
{ | |
v31 *= 2; | |
ptr = realloc(ptr, 8LL * v31); | |
} | |
v11 = (void **)((char *)ptr + 8 * v30 - 8); | |
*v11 = malloc(0x20uLL); | |
v12 = (_DWORD *)*((_QWORD *)ptr + v30 - 1); | |
*v12 = bytesToInt((unsigned __int8 *)&v18); | |
*(_DWORD *)(*((_QWORD *)ptr + v30 - 1) + 20LL) = 0; | |
v13 = *((_QWORD *)ptr + v30 - 1); | |
*(_DWORD *)(v13 + 16) = bytesToInt((unsigned __int8 *)&v22); | |
*(_DWORD *)(*((_QWORD *)ptr + v30 - 1) + 24LL) = v30 == 1; | |
v14 = *((_QWORD *)ptr + v30 - 1); | |
*(_QWORD *)(v14 + 8) = malloc(8LL * *(int *)(*((_QWORD *)ptr + v30 - 1) + 16LL)); | |
for ( j = 0; j < *(_DWORD *)(*((_QWORD *)ptr + v30 - 1) + 16LL); ++j ) | |
{ | |
v15 = (void **)(*(_QWORD *)(*((_QWORD *)ptr + v30 - 1) + 8LL) + 8LL * j); | |
*v15 = malloc(0xA0uLL); | |
} | |
++v30; | |
v16 = v28++; | |
} | |
return ptr; | |
} |
By analysing the initializeFunctions code, got to know the format of bytes in the .recc files
4 Bytes buffer size for function call stack record size (num of local variables).
4 Bytes function pointer for location of the function code in code bytes.
Each function is given a index, function call is handled by that index only
Code bytes are executed by switch case in runProgram function with 26 size instruction set.
By Analysing runProgram, initFunctions -> wrote the Disassembler, Emulator to make things easier on working with recurso sricpts(leFlag.recc)
class DisAssembler: stack = [] call_stack = [] funcs = [] current_func = 0 pc = 0 code = b'' completed = False def __init__(self, filename): data = open(filename, 'rb').read() self.funcs, sep = parse_funcs(data) self.code = data[sep:] self.init_opcodes() def init_opcodes(self): self.opcodes = { 0x1 : self.subtract, # 1 Byte 0x2 : self.muiltiply, # 1 Byte 0x3 : self.add, # 1 Byte 0x8 : self.pushInt64, # 1 + 8 Bytes 0xB : self.setLocal, # 1 + 4 Bytes 0xC : self.getLocal, # 1 + 4 Bytes 0xE : self.decFunction, # 1 + 4 Bytes 0xF : self.printf, # 1 Byte 0x10 : self.stackPop, # 1 Byte 0x13 : self.divide, # 1 Byte 0x15 : self.incFunction, # 1 Byte 0x16 : self.inputd, # 1 Byte 0x17 : self.jumpNotEqual, # 1 Byte 0x18 : self.bit_or, # 1 Byte 0x19 : self.bit_and, # 1 Byte 0x1A : self.bit_xor, # 1 Byte 0x1B : self.jumpEqual, # 1 Byte 0x1C : self.jumpLessThan, # 1 Byte 0x1D : self.jumpGreaterThan,# 1 Byte 0x1E : self.jump, # 1 + 4 Bytes 0x1F : self.jumpPop, # 1 Byte 0x20 : self.incCodeByte, # 1 + 4 Bytes 0x21 : self.decCodeByte, # 1 + 4 Bytes 0x22 : self.movCodeByte, # 1 Byte 0x23 : self.pushWord, # 1 + 4 Bytes 0x24 : self.jumpIfEqual, # 1 + 4 Bytes 0xD : self.terminate, # 1 Byte } def emulate(self): while not self.completed: pc = self.pc ins, param = self.get_instruction() if param != None: ins(param) else: ins() if param == None: print("{0:04x} -> {1:20}".format(pc, ins.__name__)) else: print("{0:04x} -> {1:20} 0x{2:x}".format(pc, ins.__name__, param)) def disassemble(self, pc = 0): self.pc = 0 while True: pc = self.pc try: ins, param = self.get_instruction() except Exception as e: if self.pc < len(self.code): print("Error occured while disassembling : ") print(e) if ins.__name__ == "incFunction": param = self.funcs[param].name for func in self.funcs: if func.ptr == pc: print("\n\n---------------------{}------------------------\n".format(func.name)) if param == None: print("{0:04x} -> {1:20}".format(pc, ins.__name__)) elif isinstance(param, str): print("{0:04x} -> {1:20} 0x{2}".format(pc, ins.__name__, param)) else: print("{0:04x} -> {1:20} 0x{2:x}".format(pc, ins.__name__, param)) def get_instruction(self): param_bytes = {0xB : 4, 0xC : 4, 0x15 : 4, 0x1E : 4, 0x20 : 4, 0x21 : 4, 0x23 : 4, 0x24 : 4, 0x8 : 8} byte = self.get_bytes() ; func = self.opcodes[byte] ; param = None if byte in param_bytes: param = self.get_bytes(param_bytes[byte]) return func, param def get_bytes(self, count=1): val = self.code[self.pc:self.pc+count] self.pc += count return bytes_to_long(val) def terminate(self): self.completed = True def subtract(self): # 0x1 p1 = self.stack.pop() p2 = self.stack.pop() self.stack.append(p1 - p2) def muiltiply(self): # 0x2 p1 = self.stack.pop() p2 = self.stack.pop() self.stack.append(p1 * p2) def add(self): # 0x3 p1 = self.stack.pop() p2 = self.stack.pop() self.stack.append(p1 + p2) def pushInt64(self, int64): # 0x8 self.stack.append(int64) def setLocal(self, int32): # 0xB (int 32 -> ind) val = self.stack.pop() self.funcs[self.current_func].setLocal(int32, val) def getLocal(self, int32): # 0xC (int 32 -> ind) val = self.funcs[self.current_func].getLocal(int32) self.stack.append(val) def decFunction(self): # 0xE self.funcs[self.current_func].decrementFunction() self.current_func, self.pc = self.call_stack.pop() def printf(self): # 0xF print(self.stack.pop()) def stackPop(self): # 0x10 self.stack.pop() def divide(self): # 0x13 p1 = self.stack.pop() p2 = self.stack.pop() self.stack.append(int(p1 / p2)) def incFunction(self, int32): # 0x15 (int 32 -> func ind) self.call_stack.append([self.current_func, self.pc]) self.current_func = int32 self.pc = self.funcs[self.current_func].ptr self.funcs[self.current_func].incrementFunction() def inputd(self): # 0x16 num = int(input("Enter a number (lld) : ")) self.stack.append(num) def jumpNotEqual(self): # 0x17 p1 = self.stack.pop() p2 = self.stack.pop() if (p1 != p2): self.pc = self.code.find(14, self.pc) + 1 def bit_or(self): # 0x18 p1 = self.stack.pop() p2 = self.stack.pop() self.stack.append(p2 | p1) def bit_and(self): # 0x19 p1 = self.stack.pop() p2 = self.stack.pop() self.stack.append(p2 | p1) def bit_xor(self): # 0x1A p1 = self.stack.pop() p2 = self.stack.pop() self.stack.append(p2 ^ p1) def jumpEqual(self): # 0x1B p1 = self.stack.pop() p2 = self.stack.pop() if (p1 == p2): self.pc = self.code.find(14, self.pc) + 1 def jumpLessThan(self): # 0x1C p1 = self.stack.pop() p2 = self.stack.pop() if (p1 < p2): self.pc = self.code.find(14, self.pc) + 1 def jumpGreaterThan(self): # 0x1D p1 = self.stack.pop() p2 = self.stack.pop() if (p1 > p2): self.pc = self.code.find(14, self.pc) + 1 def jump(self, int32): # 0x1E (int 32 -> address) self.pc = int32 def jumpPop(self): # 0x1F self.pc = self.stack.pop() def incCodeByte(self, int32): # 0x20 (int 32 -> byte off) temp = list(self.code) temp[int32] = (temp[int32] + 1) & 256 self.code = bytes(temp) def decCodeByte(self, int32): # 0x21 (int 32 -> byte off) temp = list(self.code) temp[int32] = (temp[int32] - 1) % 256 self.code = bytes(temp) def movCodeByte(self): # 0x22 p1 = self.stack.pop() p2 = self.stack.pop() temp = list(self.code) temp[p2] = temp[p1] self.code = bytes(temp) def pushWord(self, int32): # 0x23 (int 32 -> byte off) b1 = self.code[int32] << 8 b2 = self.code[int32 + 1] print("0x{:x} -> pushWord 0x{:x} | {:x}".format(self._temppc, int32, b1 + b2)) self.stack.append(b1 + b2) def jumpIfEqual(self, int32): # 0x24 (int32 -> address) p1 = self.stack.pop() p2 = self.stack.pop() if p1 == p2: self.pc = int32 class Function: buffer = [] buf_size = 0 def __init__(self, name, ptr, buff): self.name = name.decode() self.ptr = ptr self.buf_size = buff if (self.name == "main"): self.incrementFunction() def __str__(self): return "<Function {0} -> 0x{1:04x}>".format(self.name, self.ptr) def setLocal(self, ind, val): self.buffer[-1][ind] = val def getLocal(self, ind): return self.buffer[-1][ind] def incrementFunction(self): self.buffer.append([0 for _ in range(self.buf_size)]) def decrementFunction(self): self.buffer.pop() def bytes_to_long(stream): val = 0 for byte in stream: val = ( val << 8 ) | byte return val def parse_funcs(code): pc = 4 ; funcs = [] while code[pc] == 17: end = code.find(18, pc + 1) name = code[pc+1:end] buff = bytes_to_long(code[end+1:end+5]) ptr = bytes_to_long(code[end+5:end+9]) func = Function(name, ptr, buff) print(len(funcs), func) funcs.append(func) pc = end + 9 return funcs, pc
DisAssembled leFlag.recc
By using above disassembler-> disassembled code of leFlag.recc is
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
---------------------main------------------------ | |
0000 -> getLocal 0 | |
0005 -> inputd | |
0006 -> setLocal 0 | |
000b -> getLocal 0 | |
0010 -> incFunction check | |
0015 -> setLocal 1 | |
001a -> getLocal 1 | |
001f -> printf | |
0020 -> terminate | |
---------------------antidebug------------------------ | |
0021 -> setLocal 0 | |
0026 -> getLocal 0 | |
002b -> pushInt64 0 | |
0034 -> jumpNotEqual | |
0035 -> pushInt64 0 | |
003e -> decFunction | |
003f -> pushInt64 1 | |
0048 -> getLocal 0 | |
004d -> subtract | |
004e -> setLocal 1 | |
0053 -> pushInt64 1 | |
005c -> getLocal 0 | |
0061 -> add | |
0062 -> setLocal 0 | |
0067 -> pushInt64 1 | |
0070 -> getLocal 0 | |
0075 -> subtract | |
0076 -> setLocal 0 | |
007b -> pushInt64 1 | |
0084 -> getLocal 0 | |
0089 -> muiltiply | |
008a -> setLocal 0 | |
008f -> pushInt64 1 | |
0098 -> getLocal 0 | |
009d -> divide | |
009e -> setLocal 0 | |
00a3 -> pushInt64 1 | |
00ac -> getLocal 0 | |
00b1 -> bit_and | |
00b2 -> setLocal 0 | |
00b7 -> pushInt64 1 | |
00c0 -> getLocal 0 | |
00c5 -> bit_or | |
00c6 -> setLocal 0 | |
00cb -> pushInt64 0 | |
00d4 -> getLocal 0 | |
00d9 -> bit_xor | |
00da -> setLocal 0 | |
00df -> getLocal 1 | |
00e4 -> incFunction antidebug | |
00e9 -> pushInt64 0 | |
00f2 -> decFunction | |
---------------------itsATwap------------------------ | |
00f3 -> setLocal 0 | |
00f8 -> getLocal 0 | |
00fd -> pushInt64 3713 | |
0106 -> jumpNotEqual | |
0107 -> pushInt64 1 | |
0110 -> decFunction | |
0111 -> getLocal 1 | |
0116 -> inputd | |
0117 -> setLocal 1 | |
011c -> getLocal 1 | |
0121 -> incFunction antidebug | |
0126 -> getLocal 0 | |
012b -> incFunction itsATwap | |
0130 -> pushInt64 0 | |
0139 -> decFunction | |
---------------------oddCheck------------------------ | |
013a -> setLocal 3 | |
013f -> setLocal 2 | |
0144 -> setLocal 1 | |
0149 -> setLocal 0 | |
014e -> getLocal 0 | |
0153 -> pushInt64 30001 | |
015c -> jumpNotEqual | |
015d -> getLocal 1 | |
0162 -> pushInt64 26419 | |
016b -> jumpNotEqual | |
016c -> getLocal 2 | |
0171 -> pushInt64 62003745337707 | |
017a -> jumpNotEqual | |
017b -> getLocal 3 | |
0180 -> pushInt64 27955 | |
0189 -> jumpNotEqual | |
018a -> pushInt64 1 | |
0193 -> decFunction | |
0194 -> pushInt64 0 | |
019d -> decFunction | |
---------------------evenCheck------------------------ | |
019e -> setLocal 3 | |
01a3 -> setLocal 2 | |
01a8 -> setLocal 1 | |
01ad -> setLocal 0 | |
01b2 -> getLocal 0 | |
01b7 -> pushInt64 25695 | |
01c0 -> jumpEqual | |
01c1 -> getLocal 1 | |
01c6 -> pushInt64 928999216 | |
01cf -> jumpEqual | |
01d0 -> getLocal 2 | |
01d5 -> pushInt64 13151 | |
01de -> jumpEqual | |
01df -> getLocal 3 | |
01e4 -> pushInt64 125 | |
01ed -> jumpEqual | |
01ee -> pushInt64 0 | |
01f7 -> decFunction | |
01f8 -> pushInt64 1 | |
0201 -> decFunction | |
---------------------finalCheck------------------------ | |
0202 -> getLocal 0 | |
0207 -> getLocal 1 | |
020c -> getLocal 2 | |
0211 -> getLocal 3 | |
0216 -> getLocal 4 | |
021b -> getLocal 5 | |
0220 -> getLocal 6 | |
0225 -> getLocal 7 | |
022a -> inputd | |
022b -> setLocal 0 | |
0230 -> inputd | |
0231 -> setLocal 1 | |
0236 -> inputd | |
0237 -> setLocal 2 | |
023c -> inputd | |
023d -> setLocal 3 | |
0242 -> inputd | |
0243 -> setLocal 4 | |
0248 -> inputd | |
0249 -> setLocal 5 | |
024e -> inputd | |
024f -> setLocal 6 | |
0254 -> inputd | |
0255 -> setLocal 7 | |
025a -> getLocal 0 | |
025f -> getLocal 2 | |
0264 -> getLocal 4 | |
0269 -> getLocal 6 | |
026e -> incFunction oddCheck | |
0273 -> setLocal 8 | |
0278 -> getLocal 1 | |
027d -> getLocal 3 | |
0282 -> getLocal 5 | |
0287 -> getLocal 7 | |
028c -> incFunction evenCheck | |
0291 -> setLocal 9 | |
0296 -> getLocal 9 | |
029b -> getLocal 8 | |
02a0 -> bit_and | |
02a1 -> setLocal 10 | |
02a6 -> getLocal 10 | |
02ab -> decFunction | |
---------------------checkThemAll------------------------ | |
02ac -> setLocal 5 | |
02b1 -> setLocal 4 | |
02b6 -> setLocal 3 | |
02bb -> setLocal 2 | |
02c0 -> setLocal 1 | |
02c5 -> setLocal 0 | |
02ca -> getLocal 0 | |
02cf -> pushInt64 18446743885531466769 | |
02d8 -> jumpNotEqual | |
02d9 -> getLocal 1 | |
02de -> pushInt64 10593957610752 | |
02e7 -> jumpNotEqual | |
02e8 -> getLocal 2 | |
02ed -> pushInt64 118730899270 | |
02f6 -> jumpNotEqual | |
02f7 -> getLocal 3 | |
02fc -> pushInt64 1346493052268 | |
0305 -> jumpNotEqual | |
0306 -> getLocal 4 | |
030b -> pushInt64 409991082872 | |
0314 -> jumpNotEqual | |
0315 -> getLocal 5 | |
031a -> pushInt64 103082098739 | |
0323 -> jumpNotEqual | |
0324 -> pushInt64 1 | |
032d -> decFunction | |
032e -> pushInt64 0 | |
0337 -> decFunction | |
---------------------nextNextNextCheck------------------------ | |
0338 -> getLocal 0 | |
033d -> getLocal 1 | |
0342 -> getLocal 2 | |
0347 -> getLocal 3 | |
034c -> getLocal 4 | |
0351 -> inputd | |
0352 -> setLocal 0 | |
0357 -> inputd | |
0358 -> setLocal 1 | |
035d -> inputd | |
035e -> setLocal 2 | |
0363 -> inputd | |
0364 -> setLocal 3 | |
0369 -> inputd | |
036a -> setLocal 4 | |
036f -> getLocal 1 | |
0374 -> getLocal 0 | |
0379 -> subtract | |
037a -> setLocal 5 | |
037f -> getLocal 4 | |
0384 -> getLocal 0 | |
0389 -> muiltiply | |
038a -> setLocal 6 | |
038f -> getLocal 2 | |
0394 -> getLocal 5 | |
0399 -> add | |
039a -> setLocal 7 | |
039f -> getLocal 3 | |
03a4 -> getLocal 2 | |
03a9 -> add | |
03aa -> getLocal 1 | |
03af -> add | |
03b0 -> getLocal 0 | |
03b5 -> add | |
03b6 -> setLocal 8 | |
03bb -> getLocal 4 | |
03c0 -> getLocal 3 | |
03c5 -> bit_or | |
03c6 -> setLocal 9 | |
03cb -> getLocal 2 | |
03d0 -> getLocal 3 | |
03d5 -> subtract | |
03d6 -> setLocal 10 | |
03db -> getLocal 5 | |
03e0 -> getLocal 6 | |
03e5 -> getLocal 7 | |
03ea -> getLocal 8 | |
03ef -> getLocal 9 | |
03f4 -> getLocal 10 | |
03f9 -> incFunction checkThemAll | |
03fe -> setLocal 11 | |
0403 -> incFunction finalCheck | |
0408 -> setLocal 12 | |
040d -> getLocal 12 | |
0412 -> getLocal 11 | |
0417 -> bit_and | |
0418 -> setLocal 13 | |
041d -> getLocal 13 | |
0422 -> decFunction | |
---------------------checkity------------------------ | |
0423 -> setLocal 4 | |
0428 -> setLocal 3 | |
042d -> setLocal 2 | |
0432 -> setLocal 1 | |
0437 -> setLocal 0 | |
043c -> getLocal 0 | |
0441 -> pushInt64 489139534831 | |
044a -> jumpNotEqual | |
044b -> getLocal 1 | |
0450 -> pushInt64 1 | |
0459 -> jumpNotEqual | |
045a -> getLocal 2 | |
045f -> pushInt64 2 | |
0468 -> jumpNotEqual | |
0469 -> getLocal 3 | |
046e -> pushInt64 3 | |
0477 -> jumpNotEqual | |
0478 -> getLocal 4 | |
047d -> pushInt64 4 | |
0486 -> jumpNotEqual | |
0487 -> pushInt64 1 | |
0490 -> decFunction | |
0491 -> pushInt64 7331 | |
049a -> incFunction antidebug | |
049f -> pushInt64 0 | |
04a8 -> decFunction | |
---------------------midThree------------------------ | |
04a9 -> setLocal 0 | |
04ae -> getLocal 0 | |
04b3 -> pushInt64 892362496 | |
04bc -> jumpEqual | |
04bd -> pushInt64 0 | |
04c6 -> decFunction | |
04c7 -> pushInt64 1 | |
04d0 -> decFunction | |
---------------------topAndBottom------------------------ | |
04d1 -> setLocal 0 | |
04d6 -> getLocal 0 | |
04db -> pushInt64 7 | |
04e4 -> jumpNotEqual | |
04e5 -> pushInt64 1 | |
04ee -> decFunction | |
04ef -> pushInt64 0 | |
04f8 -> decFunction | |
---------------------checkTheBigs------------------------ | |
04f9 -> setLocal 1 | |
04fe -> setLocal 0 | |
0503 -> getLocal 0 | |
0508 -> getLocal 1 | |
050d -> jumpGreaterThan | |
050e -> getLocal 1 | |
0513 -> getLocal 1 | |
0518 -> jumpEqual | |
0519 -> pushInt64 0 | |
0522 -> decFunction | |
0523 -> getLocal 0 | |
0528 -> getLocal 1 | |
052d -> subtract | |
052e -> setLocal 2 | |
0533 -> getLocal 2 | |
0538 -> pushInt64 1 | |
0541 -> pushInt64 2 | |
054a -> pushInt64 3 | |
0553 -> pushInt64 4 | |
055c -> incFunction checkity | |
0561 -> setLocal 3 | |
0566 -> pushInt64 4294967040 | |
056f -> getLocal 1 | |
0574 -> bit_and | |
0575 -> setLocal 4 | |
057a -> getLocal 4 | |
057f -> incFunction midThree | |
0584 -> setLocal 5 | |
0589 -> pushInt64 255 | |
0592 -> getLocal 0 | |
0597 -> bit_and | |
0598 -> setLocal 6 | |
059d -> pushInt64 1095216660480 | |
05a6 -> getLocal 1 | |
05ab -> bit_and | |
05ac -> setLocal 7 | |
05b1 -> getLocal 7 | |
05b6 -> getLocal 6 | |
05bb -> bit_xor | |
05bc -> setLocal 8 | |
05c1 -> pushInt64 1 | |
05ca -> setLocal 9 | |
05cf -> incFunction nextNextNextCheck | |
05d4 -> setLocal 10 | |
05d9 -> getLocal 10 | |
05de -> getLocal 9 | |
05e3 -> bit_and | |
05e4 -> getLocal 5 | |
05e9 -> bit_and | |
05ea -> getLocal 3 | |
05ef -> bit_and | |
05f0 -> setLocal 11 | |
05f5 -> getLocal 11 | |
05fa -> decFunction | |
---------------------isItOr------------------------ | |
05fb -> setLocal 0 | |
0600 -> getLocal 0 | |
0605 -> pushInt64 99 | |
060e -> jumpNotEqual | |
060f -> pushInt64 1 | |
0618 -> decFunction | |
0619 -> pushInt64 0 | |
0622 -> decFunction | |
---------------------isItXor------------------------ | |
0623 -> setLocal 0 | |
0628 -> getLocal 0 | |
062d -> pushInt64 28 | |
0636 -> jumpEqual | |
0637 -> pushInt64 0 | |
0640 -> decFunction | |
0641 -> pushInt64 1 | |
064a -> decFunction | |
---------------------keepGoing------------------------ | |
064b -> pushInt64 7331 | |
0654 -> incFunction antidebug | |
0659 -> getLocal 0 | |
065e -> getLocal 1 | |
0663 -> inputd | |
0664 -> setLocal 0 | |
0669 -> inputd | |
066a -> setLocal 1 | |
066f -> getLocal 1 | |
0674 -> getLocal 0 | |
0679 -> bit_xor | |
067a -> setLocal 2 | |
067f -> getLocal 2 | |
0684 -> incFunction isItXor | |
0689 -> setLocal 3 | |
068e -> getLocal 1 | |
0693 -> getLocal 0 | |
0698 -> bit_and | |
0699 -> setLocal 2 | |
069e -> getLocal 2 | |
06a3 -> incFunction isItOr | |
06a8 -> setLocal 4 | |
06ad -> getLocal 5 | |
06b2 -> inputd | |
06b3 -> setLocal 5 | |
06b8 -> getLocal 5 | |
06bd -> incFunction itsATwap | |
06c2 -> getLocal 6 | |
06c7 -> getLocal 7 | |
06cc -> inputd | |
06cd -> setLocal 6 | |
06d2 -> inputd | |
06d3 -> setLocal 7 | |
06d8 -> getLocal 6 | |
06dd -> getLocal 7 | |
06e2 -> incFunction checkTheBigs | |
06e7 -> setLocal 8 | |
06ec -> getLocal 8 | |
06f1 -> getLocal 4 | |
06f6 -> bit_and | |
06f7 -> getLocal 3 | |
06fc -> bit_and | |
06fd -> setLocal 9 | |
0702 -> getLocal 9 | |
0707 -> decFunction | |
---------------------wowzaACheck2------------------------ | |
0708 -> setLocal 0 | |
070d -> getLocal 0 | |
0712 -> pushInt64 26960 | |
071b -> jumpGreaterThan | |
071c -> pushInt64 1 | |
0725 -> decFunction | |
0726 -> pushInt64 0 | |
072f -> decFunction | |
---------------------wowzaACheck------------------------ | |
0730 -> setLocal 0 | |
0735 -> getLocal 0 | |
073a -> pushInt64 269700 | |
0743 -> jumpLessThan | |
0744 -> pushInt64 1 | |
074d -> decFunction | |
074e -> pushInt64 0 | |
0757 -> decFunction | |
---------------------yetAnotherCheck------------------------ | |
0758 -> setLocal 0 | |
075d -> getLocal 0 | |
0762 -> pushInt64 28025 | |
076b -> jumpEqual | |
076c -> pushInt64 0 | |
0775 -> decFunction | |
0776 -> pushInt64 1 | |
077f -> decFunction | |
---------------------anotherCheck------------------------ | |
0780 -> setLocal 0 | |
0785 -> getLocal 0 | |
078a -> pushInt64 1057 | |
0793 -> jumpNotEqual | |
0794 -> pushInt64 1 | |
079d -> decFunction | |
079e -> pushInt64 0 | |
07a7 -> decFunction | |
---------------------check------------------------ | |
07a8 -> setLocal 0 | |
07ad -> getLocal 0 | |
07b2 -> pushInt64 102 | |
07bb -> jumpEqual | |
07bc -> pushInt64 0 | |
07c5 -> decFunction | |
07c6 -> getLocal 0 | |
07cb -> inputd | |
07cc -> setLocal 0 | |
07d1 -> pushInt64 1337 | |
07da -> getLocal 0 | |
07df -> bit_and | |
07e0 -> setLocal 2 | |
07e5 -> getLocal 2 | |
07ea -> incFunction anotherCheck | |
07ef -> setLocal 3 | |
07f4 -> pushInt64 1337 | |
07fd -> getLocal 0 | |
0802 -> bit_or | |
0803 -> setLocal 4 | |
0808 -> getLocal 4 | |
080d -> incFunction yetAnotherCheck | |
0812 -> setLocal 5 | |
0817 -> pushInt64 1337 | |
0820 -> getLocal 0 | |
0825 -> bit_xor | |
0826 -> setLocal 6 | |
082b -> getLocal 6 | |
0830 -> incFunction wowzaACheck | |
0835 -> setLocal 7 | |
083a -> getLocal 6 | |
083f -> incFunction wowzaACheck | |
0844 -> setLocal 8 | |
0849 -> incFunction keepGoing | |
084e -> setLocal 9 | |
0853 -> getLocal 9 | |
0858 -> getLocal 8 | |
085d -> bit_and | |
085e -> getLocal 7 | |
0863 -> bit_and | |
0864 -> getLocal 5 | |
0869 -> bit_and | |
086a -> getLocal 3 | |
086f -> bit_and | |
0870 -> setLocal 10 | |
0875 -> getLocal 10 | |
087a -> decFunction |
Based on that Reconstructed relevent python code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def int_input(string): | |
return int(input(string)) | |
def midThree(a0): | |
return a0 == 892362496 | |
def topAndBottom(a0): | |
return a0 == 7 | |
def checkity(a0, a1, a2, a3, a4): | |
if a0 == 489139534831 and a1 == 1 and a2 == 2 and a3 == 3 and a4 == 4: | |
return 1 | |
# antidebug(7331) | |
def itsATwap(a0): | |
if a0 == 3713: return 1 | |
a0 = int_input("itsATwap : ") | |
# antidebug(a0) | |
itsATwap(a0) | |
return 0 | |
def isItOr(a0): | |
return a0 == 99 | |
def isItXor(a0): | |
return a0 == 28 | |
def wowzaACheck2(a0): | |
return 26960 <= a0 | |
def wowzaACheck(a0): | |
return 269700 >= a0 | |
def yetAnotherCheck(a0): | |
return a0 == 28025 | |
def anotherCheck(a0): | |
return a0 == 1057 | |
def finalCheck(): | |
arr = [] | |
for i in range(8): | |
arr.append(int_input("i{} = ".format(i))) | |
t1 = oddCheck(arr[0], arr[2], arr[4], arr[6]) | |
t2 = evenCheck(arr[1], arr[3], arr[5], arr[7]) | |
return t1 & t2 | |
def oddCheck(a0, a1, a2, a3): | |
return a0 == 30001 & a1 == 26419 & a2 == 62003745337707 & a3 == 27955 | |
def evenCheck(a0, a1, a2, a3): | |
return a0 == 25695 & a1 == 928999216 & a2 == 13151 & a3 == 125 | |
def checkThemAll(a0, a1, a2, a3, a4, a5): | |
return a0 == 18446743885531466769 & a1 == 10593957610752 & a2 == 118730899270 &\ | |
a3 == 1346493052268 & a4 == 409991082872 & a5 == 103082098739 | |
def nextNextNextCheck(): | |
arr = [] | |
for i in range(5): | |
arr.append(int_input("i{} = ".format(i))) | |
arr.append(arr[0] - arr[1]) # i5 | |
arr.append(arr[0] * arr[4]) # i6 | |
arr.append(arr[2] + arr[5]) # i7 | |
arr.append(arr[3] + arr[2] + arr[1] + arr[0]) # i8 | |
arr.append(arr[3] | arr[4]) # i9 | |
arr.append(arr[3] - arr[2]) # i10 | |
t1 = checkThemAll(arr[5], arr[6], arr[7], arr[8], arr[9], arr[10]) | |
t2 = finalCheck() | |
return t1 & t2 | |
def checkTheBigs(a0, a1): | |
if a1 < a0: return 0 # no neccesarily | |
a2 = a1 - a0 | |
a3 = checkity(a2, 1, 2, 3, 4) | |
a4 = a1 & 4294967040 | |
a5 = midThree(a4) | |
a6 = a0 & 255 | |
a7 = a1 & 1095216660480 | |
a8 = a6 ^ a7 | |
a9 = 1 | |
a10 =nextNextNextCheck() | |
return a10 & a9 & a5 & a3 | |
def keepGoing(): | |
# antidebug(7331) | |
arr = [] | |
i0 = int_input("i0 = ") | |
i1 = int_input("i1 = ") | |
i3 = isItXor(i0 ^ i1) | |
i4 = isItOr(i0 & i1) | |
i5 = int_input("i5 = ") | |
itsATwap(i5) | |
i6 = int_input("i6 = ") | |
i7 = int_input("i7 = ") | |
i8 = checkTheBigs(i6, i7) | |
return i8 & i4 & i3 | |
def check(a0): | |
if a0 != 102: return 0 | |
i0 = int_input("i0 = ") | |
i3 = anotherCheck(i0 & 1337) | |
i5 = yetAnotherCheck(i0 | 1337) | |
i6 = 1337 ^ i0 ; i7 = wowzaACheck(i6) ; i8 = wowzaACheck2(i6) | |
i9 = keepGoing() | |
return i9 & i8 & i7 & i5 & i3 | |
def main(): | |
i0 = int_input("i0 = ") | |
print(check(i0)) |
Reversing the logic in leFlag.recc
There is nothing but number inputs and checks in the code.Finally removed all functions by focusing only on checks.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def int_input(string): | |
return int(input(string)) | |
i0 = int_input("i0 : ") | |
''' | |
i0 == 102 | |
''' | |
i1 = int_input("i1 : ") # 27745 | |
''' | |
i1 & 1337 == 1057 | |
i1 | 1337 == 28025 | |
i1 ^ 1337 >= 269700 | |
i1 ^ 1337 >= 26960 | |
''' | |
i2 = int_input("i2 : ") # 103 | |
i3 = int_input("i3 : ") # 123 | |
''' | |
i2 ^ i3 == 28 | |
i2 & i3 == 99 | |
''' | |
i4 = int_input("i4 : ") | |
''' not included in flag | |
i4 == 3713 | |
''' | |
i5 = int_input("i5 : ") # 1379099477 | |
i6 = int_input("i6 : ") # 490518634308 | |
''' | |
i6 - i5 == 489139534831 | |
i6 & 4294967040 == 892362496 | |
Extra checks : | |
every bytes in range 0x20 to 0xff | |
some bytes = guessed chars | |
''' | |
i7 = int_input("i7 : ") # 220707450224 | |
i8 = int_input("i8 : ") # 408885535071 | |
i9 = int_input("i9 : ") # 306908984117 | |
i10 = int_input("i10 : ") # 409991082856 | |
i11 = int_input("i11 : ") # 48 | |
''' | |
i7 - i8 == 18446743885531466769 | |
i7 * i11 == 10593957610752 | |
i9 + i7 - i8 == 118730899270 | |
i7 + i8 + i9 + i10 == 1346493052268 | |
i10 | i11 == 409991082872 | |
i10 - i9 == 103082098739 | |
''' | |
# Direct nums | |
i12 = int_input("i12 : ") # 30001 | |
i13 = int_input("i13 : ") # 25695 | |
i14 = int_input("i14 : ") # 26419 | |
i15 = int_input("i15 : ") # 928999216 | |
i16 = int_input("i16 : ") # 62003745337707 | |
i17 = int_input("i17 : ") # 13151 | |
i18 = int_input("i18 : ") # 27955 | |
i19 = int_input("i19 : ") # 125 | |
# All adjacent number of inputs, are required numbers calculated using z3 |
Based on the checks, written z3 script and got all the 20 input numbers.
Guessing part :( Especially for i5, i6 it became so difficult because of Too many possibilities.
My teammates helped me in this a lot, Placed all the character restrictions, guessed a last letter of i6 -> D based on i7, i8 number strings (3c0mp_3z!_).
Then seeing the possibilites noticed a string 'R3c' in i5, then it might be 'Recurso'. By going in that way got i5 -> R3cu and i6 -> r50_D
Finally by getting all the numbers
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from Crypto.Util.number import long_to_bytes as l2b | |
inputs = [102, 27745, 103, 123, 1379099477, 490518634308, 220707450224, 408885535071, 306908984117, 409991082856, 48, 30001, 25695, 26419, 928999216, 62003745337707, 13151, 27955, 125] | |
flag = b'' | |
for num in inputs: | |
flag += l2b(num) | |
print("[+] Flag is : ", flag) |
Flag : flag{R3cUr50_D3c0mp_3z!_Gu3s5_u_sh0u1d_g37_g08d_71k3_m3}
Rasm
Given the Same Recurso Execuatable with recurso compiled file rasm.recc containing a flag checking logic.The Goal of the challenge is to get the flag checking logic in rasm.recc and steal flag
Disassembling
Tried to run the code took an input and given segmentation error. Then tried decompiling using the old script -> given error due to (Invalid Opcode)It seems like there is an error in Code bytes, just to know all the instructions, skipped all the errors. Then found interesting at the end of the disassembly
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
---------------------main------------------------ | |
0000 -> pushInt64 319 | |
0009 -> inputd | |
000a -> pushInt64 265 | |
0013 -> add | |
0014 -> jumpPop | |
0015 -> jumpPop | |
0016 -> subtract | |
0018 -> subtract | |
. | |
. | |
. | |
0236 -> decFunction | |
0237 -> pushInt64 0x200 0100 0015 | |
0240 -> pushInt64 0x238 | |
0249 -> setLocal 0x0 | |
024e -> getLocal 0x0 | |
0253 -> pushWord 0x23e | |
0258 -> movCodeByte | |
0259 -> decCodeByte 0x238 | |
025e -> pushWord 0x23e | |
0263 -> getLocal 0x0 | |
0268 -> movCodeByte | |
0269 -> incCodeByte 0x23f | |
026e -> pushInt64 0x0 | |
0277 -> pushWord 0x23e | |
027c -> jumpIfEqual 0x286 | |
0281 -> jump 0x24e | |
0286 -> getLocal 0x0 | |
028b -> pushWord 0x23c | |
0290 -> movCodeByte | |
0291 -> decCodeByte 0x238 | |
0296 -> pushWord 0x23c | |
029b -> getLocal 0x0 | |
02a0 -> movCodeByte | |
02a1 -> incCodeByte 0x23d | |
02a6 -> pushInt64 0x100 | |
02af -> pushWord 0x23c | |
02b4 -> jumpIfEqual 0x2be | |
02b9 -> jump 0x286 | |
02be -> getLocal 0x0 | |
02c3 -> pushWord 0x23a | |
02c8 -> movCodeByte | |
02c9 -> decCodeByte 0x238 | |
02ce -> pushWord 0x23a | |
02d3 -> getLocal 0x0 | |
02d8 -> movCodeByte | |
02d9 -> incCodeByte 0x23b | |
02de -> pushInt64 0x238 | |
02e7 -> pushWord 0x23a | |
02ec -> jumpIfEqual 0x2f6 | |
02f1 -> jump 0x2be | |
02f6 -> pushInt64 0x2 | |
02ff -> printf | |
0300 -> jump 0x9 |
Code from 0x0237 to 0x0300 makes sense now, The assembly code is encoded some how, the code below is to decode that above code bytes and jump there.
There are some instructions in Recurso lang which can modify the execution code bytes at run time. So Rasm is having self modifying logic.
Decoding the Bytecode
The code below (0x237 to 0x300) is decoding the above code (0x015 to 0x237) by decrementing every byte by 1.And found a code at above (0x0 to 0x14) which is causing Segmentation fault .
The code above is to , take an input and jump to (265 + input_val)
Jump address should be 0x237. So input = 0x237 - 265 = 302 (in decimal)
If we give the input 302, segmentation fault won't come, It decodes above code and prints(2) and jump to above. Asks again a input address to jump.
Analyzing Decoded Bytecode
Decoded the rasm.recc into drasm.recc by a script and then disassembled.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
---------------------main------------------------ | |
0000 -> pushInt64 0x13f | |
0009 -> inputd | |
000a -> pushInt64 0x109 | |
0013 -> add | |
0014 -> jumpPop | |
0015 -> jump 0x25 | |
001a -> inputd | |
001b -> setLocal 0x0 | |
0020 -> jump 0x33 | |
0025 -> pushInt64 0x3e8 | |
002e -> setLocal 0x0 | |
0033 -> pushWord 0x7 | |
0038 -> pushWord 0x7 | |
003d -> pushInt64 0x7 | |
0046 -> add | |
0047 -> movCodeByte | |
0048 -> incCodeByte 0x8 | |
004d -> pushWord 0x7 | |
0052 -> pushInt64 0x6 | |
005b -> add | |
005c -> pushWord 0x7 | |
0061 -> movCodeByte | |
0062 -> pushWord 0x7 | |
0067 -> pushWord 0x7 | |
006c -> pushInt64 0x5 | |
0075 -> add | |
0076 -> movCodeByte | |
0077 -> incCodeByte 0x8 | |
007c -> pushWord 0x7 | |
0081 -> pushInt64 0x4 | |
008a -> add | |
008b -> pushWord 0x7 | |
0090 -> movCodeByte | |
0091 -> pushWord 0x7 | |
0096 -> pushWord 0x7 | |
009b -> pushInt64 0x3 | |
00a4 -> add | |
00a5 -> movCodeByte | |
00a6 -> incCodeByte 0x8 | |
00ab -> pushWord 0x7 | |
00b0 -> pushInt64 0x2 | |
00b9 -> add | |
00ba -> pushWord 0x7 | |
00bf -> movCodeByte | |
00c0 -> pushWord 0x7 | |
00c5 -> incCodeByte 0x8 | |
00ca -> pushWord 0x7 | |
00cf -> movCodeByte | |
00d0 -> pushWord 0x7 | |
00d5 -> pushInt64 0x3 | |
00de -> movCodeByte | |
00df -> incCodeByte 0x8 | |
00e4 -> incCodeByte 0x8 | |
00e9 -> incCodeByte 0x8 | |
00ee -> incCodeByte 0x8 | |
00f3 -> incCodeByte 0x8 | |
00f8 -> incCodeByte 0x8 | |
00fd -> incCodeByte 0x8 | |
0102 -> incCodeByte 0x8 | |
0107 -> incCodeByte 0x8 | |
010c -> incCodeByte 0x8 | |
0111 -> incCodeByte 0x8 | |
0116 -> incCodeByte 0x8 | |
011b -> incCodeByte 0x8 | |
0120 -> incCodeByte 0x8 | |
0125 -> incCodeByte 0x6 | |
012a -> pushWord 0x5 | |
012f -> getLocal 0x0 | |
0134 -> jumpIfEqual 0x13e | |
0139 -> jump 0x33 | |
013e -> pushInt64 0x617b7b67616c66 | |
0147 -> pushInt64 0x4142434445464748 | |
0150 -> pushInt64 0x735773215f6d35 | |
0159 -> pushInt64 0x494a4b4c4d4e4f50 | |
0162 -> pushInt64 0x5f6b7733635f30 | |
016b -> pushInt64 0x5152535455565758 | |
0174 -> pushInt64 0x6e376b5f545562 | |
017d -> pushInt64 0x595a303132333435 | |
0186 -> pushInt64 0x723163355f3462 | |
018f -> pushInt64 0x363738397b7d5b5d | |
0198 -> pushInt64 0x6d5b3768775f79 | |
01a1 -> pushInt64 0x2d3d5f2b21402324 | |
01aa -> pushInt64 0x5f34215f745355 | |
01b3 -> pushInt64 0x255e262a28292f3f | |
01bc -> pushInt64 0x5f377961776c34 | |
01c5 -> pushInt64 0x2c2e3c3e3b3a2722 | |
01ce -> pushInt64 0x2132476e346863 | |
01d7 -> pushInt64 0x0 | |
01e0 -> pushInt64 0x7d2131 | |
01e9 -> pushWord 0x2 | |
01ee -> inputd | |
01ef -> bit_xor | |
01f0 -> incCodeByte 0x2 | |
01f5 -> jumpIfEqual 0x1ff | |
01fa -> jump 0x22c | |
01ff -> stackPop | |
0200 -> decCodeByte 0x6 | |
0205 -> pushWord 0x5 | |
020a -> pushInt64 0x0 | |
0213 -> jumpIfEqual 0x21d | |
0218 -> jump 0x1e9 | |
021d -> pushInt64 0x1 | |
0226 -> printf | |
0227 -> jump 0x236 | |
022c -> pushInt64 0x0 | |
0235 -> printf | |
0236 -> terminate | |
0237 -> pushInt64 0x20001000015 | |
0240 -> pushInt64 0x238 | |
0249 -> setLocal 0x0 | |
024e -> getLocal 0x0 | |
0253 -> pushWord 0x23e | |
0258 -> movCodeByte | |
0259 -> decCodeByte 0x238 | |
025e -> pushWord 0x23e | |
0263 -> getLocal 0x0 | |
0268 -> movCodeByte | |
0269 -> incCodeByte 0x23f | |
026e -> pushInt64 0x0 | |
0277 -> pushWord 0x23e | |
027c -> jumpIfEqual 0x286 | |
0281 -> jump 0x24e | |
0286 -> getLocal 0x0 | |
028b -> pushWord 0x23c | |
0290 -> movCodeByte | |
0291 -> decCodeByte 0x238 | |
0296 -> pushWord 0x23c | |
029b -> getLocal 0x0 | |
02a0 -> movCodeByte | |
02a1 -> incCodeByte 0x23d | |
02a6 -> pushInt64 0x100 | |
02af -> pushWord 0x23c | |
02b4 -> jumpIfEqual 0x2be | |
02b9 -> jump 0x286 | |
02be -> getLocal 0x0 | |
02c3 -> pushWord 0x23a | |
02c8 -> movCodeByte | |
02c9 -> decCodeByte 0x238 | |
02ce -> pushWord 0x23a | |
02d3 -> getLocal 0x0 | |
02d8 -> movCodeByte | |
02d9 -> incCodeByte 0x23b | |
02de -> pushInt64 0x238 | |
02e7 -> pushWord 0x23a | |
02ec -> jumpIfEqual 0x2f6 | |
02f1 -> jump 0x2be | |
02f6 -> pushInt64 0x2 | |
02ff -> printf | |
0300 -> jump 0x9 |
- 0x013e to 0x01e0 : Pushing a 8 byte numbers (Alternatively a flag number and a dummy number) to the stack
- On each flag number : by doing long_to_bytes -> 7 bytes of flag is coming, in reverse order and one char is wrong.
- 0x0033 to 0x0139 : A loop, in each iteration, it can update one flag num and move to other flag num address.
- On each flag number : reverse one number (flag 7 bytes , in same space of 8 bytes) which leads to 5th byte null (0).
- loop variables, other variables are maintained on code bytes only, they are accessed and modified using the instructions
- No of times the above loop will run depends on local var 0. we can set that varible by input, at address 0x001a
- So second input (used for second jump) is input + 265 = 0x001a. So input = 0x1a - 265 = -239
- Third input (no of iterations of the loop) has to be 10. As there are 10 such flag numbers
- 0x01e9 to 0x0236 : A loop to take numbers (which are combined together can form flag) and check them and return 1
- On each iteration (i) : It checks input ^ i*0x100 == stackTop(flag number), and pops dummy number once.
Taking those 10 flag numbers in disassembly from 0x013e alternatively in the instructions.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from Crypto.Util.number import long_to_bytes as l2b | |
from Crypto.Util.number import bytes_to_long as b2l | |
flag_nums = [0x617b7b67616c66, 0x735773215f6d35, 0x5f6b7733635f30, 0x6e376b5f545562, 0x723163355f3462, 0x6d5b3768775f79, 0x5f34215f745355, 0x5f377961776c34, 0x2132476e346863, 0x7d2131] | |
flag = b'' | |
for i in range(10): | |
num = b2l( l2b(flag_nums[i])[::-1] ) | |
num ^= (9-i)*0x100 | |
flag += l2b(num) | |
print("[+] Flag is : ", flag.decode()) |
Flag : flag{ra5m_!s_s0_c3wl_bUT_k1nb4_5c4ry_wh7_mUSt_!7_4lway5_ch4nG3!1!}
Comments
Post a Comment