Analysis
IDA로 열어보면, libc PLT/GOT 주소가 사라져있음.


심볼 찾기
main에서 처음 호출되는 sub_71840 함수
→ _dl_runtime_resolve
→ jmp r11
→ sigemptyset
심볼 복구 결과 (희미한 XREF 문구 참고):

sub_71247
1. 입력받은 문자열 a1의 길이가 0x23, 35바이트인지 확인함.
_BOOL8 __fastcall sub_71247(__int64 a1) { int v1; // eax int v3; // eax int v4; // [rsp+14h] [rbp-FCh] int v5; // [rsp+18h] [rbp-F8h] int i; // [rsp+1Ch] [rbp-F4h] int v7; // [rsp+20h] [rbp-F0h] int j; // [rsp+24h] [rbp-ECh] int k; // [rsp+28h] [rbp-E8h] int m; // [rsp+2Ch] [rbp-E4h] __int64 v11; // [rsp+30h] [rbp-E0h] __int64 v12; // [rsp+38h] [rbp-D8h] _OWORD v13[2]; // [rsp+40h] [rbp-D0h] BYREF __int64 v14; // [rsp+60h] [rbp-B0h] _DWORD v15[38]; // [rsp+70h] [rbp-A0h] unsigned __int64 v16; // [rsp+108h] [rbp-8h] v16 = __readfsqword(0x28u); v12 = _strlen_avx2(a1); memset(v13, 0, sizeof(v13)); v14 = 0; v4 = 0; v5 = 2; LABEL_7: while ( v4 <= 9 ) { ++v5; for ( i = 2; i < v5; ++i ) { if ( !(v5 % i) ) goto LABEL_7; } v1 = v4++; *((_DWORD *)v13 + v1) = v5; } ...
C언어 재현 코드
- check1.c
#include <stdio.h> #include <stdint.h> int main(void) { int v1; int v5 = 2; int v4 = 0; int i; int v13[8]; LABEL_7: while ( v4 <= 9 ) { ++v5; for ( i = 2; i < v5; ++i ) { if ( !(v5 % i) ) goto LABEL_7; } v1 = v4++; // *((_DWORD *)v13 + v1) = v5; v13[v1] = v5; } int v12 = (v13[1]) * (v13[2]); printf("v12 should be: %d\n", v12); return 0; }
seo@seo:~/study/LACTF2024/rbp$ gcc -o check1 check1.c && ./check1 v12 should be: 35
2. 입력받은 문자열이 “lactf{”
로 시작하는지 확인.
- 입력받은 문자열은 문자들 서로 XOR 검사를 통해
v15
1바이트씩 검사. input[0] * input[1] * input[2] * input[3] * input[4] * input[5] == 0x15F6D1945A0LL
성립 필요.
v15[0] = 0; v15[1] = 13; v15[2] = 15; v15[3] = 24; v15[4] = 10; v15[5] = 23; v15[6] = 13; v15[7] = 0; v15[8] = 2; v15[9] = 21; v15[10] = 7; v15[11] = 26; v15[12] = 15; v15[13] = 2; v15[14] = 0; v15[15] = 23; v15[16] = 5; v15[17] = 24; v15[18] = 24; v15[19] = 21; v15[20] = 23; v15[21] = 0; v15[22] = 18; v15[23] = 15; v15[24] = 10; v15[25] = 7; v15[26] = 5; v15[27] = 18; v15[28] = 0; v15[29] = 29; v15[30] = 23; v15[31] = 26; v15[32] = 24; v15[33] = 15; v15[34] = 29; v15[35] = 0; v11 = 1; v7 = 0; for ( j = 0; j <= 5; ++j ) { for ( k = 0; k <= 5; ++k ) { v3 = v7++; if ( (char)(*(_BYTE *)(j + a1) ^ *(_BYTE *)(k + a1)) != v15[v3] ) return 0; } v11 *= *(char *)(j + a1); } if ( v11 != 0x15F6D1945A0LL ) return 0;
- 1바이트씩 검사는 아래와 같이 수행한다 볼 수 있음
- 총 36번 사이클
input[0] ^ input[0] == v15[0] input[0] ^ input[1] == v15[2] input[0] ^ input[2] == v15[3] input[0] ^ input[3] == v15[4] input[0] ^ input[4] == v15[5] input[0] ^ input[5] == v15[6] input[1] ^ input[0] == v15[0] ... input[5] ^ input[5] == v15[35]
- check2.py
z3 솔버로 문자열 구하기 가능 (GPT ㄳ)
import z3 # v15 매트릭스는 그대로 v15 = [ 0, 0xD, 0xF, 0x18, 0xA, 0x17, 0xD, 0, 2, 0x15, 7, 26, 15, 2, 0, 23, 5, 24, 24, 21, 23, 0, 18, 15, 10, 7, 5, 18, 0, 29, 23, 26, 24, 15, 29, 0, ] # 1) BitVec 변수 6개를 64비트로 선언 a1 = [z3.BitVec(f'input_{i}', 64) for i in range(6)] solver = z3.Solver() # 2) XOR 제약 v7 = 0 for j in range(6): for k in range(6): solver.add(a1[j] ^ a1[k] == v15[v7]) v7+=1 # 3) (선택) 만약 이 값들이 printable ASCII라면 범위 제한 for v in a1: solver.add(z3.UGE(v, z3.BitVecVal(32, 64)), z3.ULE(v, z3.BitVecVal(126, 64))) # 4) 곱셈 제약: input_0 * input_1 * … * input_5 == 1509363893664 prod = a1[0] for v in a1[1:]: prod = prod * v solver.add(prod == z3.BitVecVal(1509363893664, 64)) # 5) 풀어보기 if solver.check() == z3.sat: m = solver.model() res = [m[v].as_long() for v in a1] print("solution:", res) print("as chars:", ''.join(chr(x) for x in res)) else: print("unsat")
seo@seo:~/study/LACTF2024/rbp$ python3 check2.py solution: [108, 97, 99, 116, 102, 123] as chars: lactf{
3. 맨 마지막 문자가 ‘}’
인지 확인
if ( *(_BYTE *)(a1 + 34) != '}' ) return 0;
4. 시행 착오 시작
sub_71247
일부 코드sub_68000
,sub_69000
,sub_70000
함수 모두 리턴값 1 성립 필요.
for ( m = 6; m <= 33; ++m ) { if ( dword_70AE8 != -1 ) { sub_711A1(dword_70AE8); dword_70AE8 = -1; } if ( (unsigned __int8)sub_68000(*(_BYTE *)(m + a1)) != 1 || (unsigned __int8)sub_69000(*(_BYTE *)(m + a1)) != 1 || (unsigned __int8)sub_70000(*(_BYTE *)(m + a1)) != 1 ) { return 0; } }
임의로 lactf{a0_JKLMNOPQRSTUVWXYZabcdefgh}
문자열을 넣었을때를 살펴봄.
sub_711A1
dword_70AE8
는 곧 a1
, 0이므로, sub_68000
→ RWX sub_69000
→ RW sub_70000
→ RW
__int64 __fastcall sub_711A1(char a1) { unsigned int v1; // eax unsigned int v2; // eax unsigned int v3; // eax __int64 result; // rax if ( a1 ) v1 = 3; // PROT_READ | PROT_WRITE else v1 = 7; // PROT_READ | PROT_WRITE | PROT_EXEC if ( (unsigned int)mprotect(sub_68000, 4096, v1) == -1 ) abort(); if ( a1 == 1 ) v2 = 7; // PROT_READ | PROT_WRITE | PROT_EXEC else v2 = 3; // PROT_READ | PROT_WRITE if ( (unsigned int)mprotect(sub_69000, 4096, v2) == -1 ) abort(); if ( a1 == 2 ) v3 = 7; // PROT_READ | PROT_WRITE | PROT_EXEC else v3 = 3; // PROT_READ | PROT_WRITE result = mprotect(sub_70000, 4096, v3); if ( (_DWORD)result == -1 ) abort(); return result; }
a1은 0, 1, 2 이 셋 중 하나만 되므로, 항상 2번씩은 exception_hander로 넘어감.

sub_68000
a1에는 a 문자 들어감.
수행전: dword_70AE8 = 0
dword_70AEC = 0
수행후: dword_70AE4 = 1
__int64 __fastcall sub_68000(char a1) { int v2; // eax if ( a1 <= 0x60 || a1 > 0x7A ) // abcdefghijklmnopqrstuvwxyz return 0; v2 = dword_70AE4++; byte_70B00[v2] = a1; if ( (a1 == 'b' || a1 == 'c' || a1 == 'h' || a1 == 's' || a1 == 't') && ++dword_70AEC != 2 && dword_70AEC != 8 && dword_70AEC != 9 && dword_70AEC != 12 ) { dword_70AE8 = 1; } if ( a1 == 'd' ) dword_70AE8 = 2; return 1; }
exception_hander (sub_710F9)
sub_69000
함수는 수행 X. exception_hander인 sub_710F9로 넘어감.
수행전: dword_70AE4 = 1
dword_70AE8 = -1
dword_70AEC = 0
.bss:0000000000070B00 byte_70B00 db ‘a’, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 .bss:0000000000070B00 ; DATA XREF: sub_68000+30↑o .bss:0000000000070B00 ; exception_handler+1D↓o … .bss:0000000000070B16 db 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
a3: 00007FFFFFFFD340 → dq 7
수행시: a = 97 = 0x61
byte_70B00[i] = (byte_70B00[i] – 96) % 26 + 97;
= (97 – 96) % 26 + 97 = 98 = ‘b’
수행 후: 첫문자인 a → b 변환, 항상 1을 리턴함.
마찬가지로, sub_70000
가 수행되지 않고, exception_hander
로 넘어감.
따라서 b → c 변환.
총 오른쪽으로 2번 시프트 연산.
ucontext_t *__fastcall exception_handler(__int64 a1, siginfo_t *a2, ucontext_t *a3) { ucontext_t *result; // rax int i; // [rsp+1Ch] [rbp-Ch] for ( i = 0; i < dword_70AE4; ++i ) byte_70B00[i] = (byte_70B00[i] - 96) % 26 + 97; a3->uc_mcontext.gregs[13] = 1; // 13 = REG_RAX result = a3; a3->uc_mcontext.gregs[16] = *(_QWORD *)a3->uc_mcontext.gregs[15]; // 16 = REG_RIP, 15 = REG_RSP return result; }
sub_68000
- 소문자 알파벳 범위인지 확인
__int64 __fastcall check3_small_ascii(char a1) { int v2; // eax if ( a1 <= 0x60 || a1 > 0x7A ) // 'abcdefghijklmnopqrstuvwxyz' return 0; v2 = dword_70AE4++; byte_70B00[v2] = a1; if ( (a1 == 'b' || a1 == 'c' || a1 == 'h' || a1 == 's' || a1 == 't') && ++dword_70AEC != 2 && dword_70AEC != 8 && dword_70AEC != 9 && dword_70AEC != 12 ) { dword_70AE8 = 1; } if ( a1 == 'd' ) dword_70AE8 = 2; return 1; }
sub_69000
- 숫자 범위인지 확인
__int64 __fastcall sub_69000(char a1) { if ( a1 <= 0x2F || a1 > 0x39 ) // 0123456789 return 0; if ( a1 - 48 != dword_70824 % 10 ) return 0; dword_70824 /= 10; if ( dword_70AEC == 3 ) dword_70AE8 = 2; else dword_70AE8 = 0; return 1; }
sub_70000
- 문자를 아스키코드로 변환후, 서로 곱했을때 9024로 나눈 나머지가 0만 아니면 됨.
__int64 __fastcall sub_70000(char a1) { if ( !(a1 * a1 % 9024) ) return 0; dword_70AE8 = 0; return 1; }
- 9024의 제곱근 = 94.99473669630333
95 = ‘_’
seo@seo:~/study/LACTF2024/rbp$ cat tmp3.py import math number = 9024 sqrt_number = math.sqrt(number) print(sqrt_number) print(chr(95)) seo@seo:~/study/LACTF2024/rbp$ python3 tmp3.py 94.99473669630333 _
간략히 살펴봤을때,
sub_68000
는 작은 알파벳 범위인지 확인, 따라서 check3_small_ascii
로 함수 이름 명명sub_69000
은 숫자 범위인지 확인, 따라서 check4_number
명명sub_70000
은 ‘_’
인지 확인, 따라서 check5_underbar
명명sub_710F9
이하 exception_hander
는, shift_right
명명
결과값을 쉽게 알아보기 위해
해당 4개의 함수와 strcmp
함수 후킹 적용.
- hook.c
#define _GNU_SOURCE #include <link.h> #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <string.h> #include <signal.h> #include <sys/mman.h> #include <dobby.h> #include <funchook.h> bool has_exec(uintptr_t addr) { FILE *fp = fopen("/proc/self/maps", "r"); if (!fp) { perror("fopen"); return false; } char line[256]; while (fgets(line, sizeof(line), fp)) { uintptr_t start, end; char perms[5]; // e.g. "r-xp" if (sscanf(line, "%lx-%lx %4s", &start, &end, perms) != 3) continue; if (addr >= start && addr < end) { fclose(fp); return (perms[2] == 'x'); // perms[2]이 'x'면 실행 권한 } } fclose(fp); return false; } void check3_small_ascii_handler(void *address, DobbyRegisterContext *reg_ctx) { uint64_t rax = (uint64_t)(reg_ctx->general.regs.rax); uint64_t rdi = (uint64_t)(reg_ctx->general.regs.rdi); printf("[hook.so] check3_small_ascii: rax = 0x%lx, rdi = %c\n", rax, rdi); } void check4_number_handler(void *address, DobbyRegisterContext *reg_ctx) { uint64_t rax = (uint64_t)(reg_ctx->general.regs.rax); uint64_t rdi = (uint64_t)(reg_ctx->general.regs.rdi); printf("[hook.so] check4_number: rax = 0x%lx, rdi = %c, dword_70824 = %u\n", rax, rdi, *(uint32_t*)(0x70824)); } void check5_underbar_handler(void *address, DobbyRegisterContext *reg_ctx) { uint64_t rax = (uint64_t)(reg_ctx->general.regs.rax); uint64_t rdi = (uint64_t)(reg_ctx->general.regs.rdi); // uint32_t dword_70AE8 = *(uint32_t*)(0x70AE8); bool _has_exec = has_exec(0x70000); // printf("dword_70AE8: %u, has_exec: %d\n", dword_70AE8, _has_exec); if(_has_exec) { printf("[hook.so] Called check5_underbar: rax = 0x%lx, rdi = %c\n", rax, rdi); if(rdi != '_') { printf("[hook.so] check5_underbar mismatch!\n"); exit(1); } } } void shift_right_handler(void *address, DobbyRegisterContext *reg_ctx) { printf("[hook.so] shift_right: \n"); } static int (*orig_strcmp)(const char *p1, const char *p2); static int hook_strcmp(const char *p1, const char *p2) { printf("[hook.so] strcmp p1: %s, p2: %s\n", p1, p2); return orig_strcmp(p1, p2); } // static int64_t (*orig_check5_underbar)(char a1); // static int64_t hook_check5_underbar(char a1) // { // int64_t rv; // printf("!!!\n"); // rv = orig_check5_underbar(a1); // return rv; // } // static int64_t (*orig_main)(int a1, char **a2, char **a3); // static int64_t hook_main(int a1, char **a2, char **a3) { // printf("[hook.so] Called main!\n"); // funchook_t *funchook = funchook_create(); // int rv; // printf("rv: %d\n", rv); // // void *res = mmap(0x70000, 4096, PROT_READ | PROT_WRITE, // // MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0); // // printf("res: %p\n", res); // // printf("mprotect: %d\n", mprotect(0x70000, 4096, 7)); // orig_check5_underbar = (void *)(0x70000); // rv = funchook_prepare(funchook, (void**)&orig_check5_underbar, hook_check5_underbar); // rv = funchook_install(funchook, 0); // int64_t ret = orig_main(a1, a2, a3); // return ret; // } __attribute__((constructor)) void initialize() { printf("[hook.so] Successfully Loaded!\n"); dobby_enable_near_branch_trampoline(); DobbyInstrument((void *)(0x680B6), (dobby_instrument_callback_t)check3_small_ascii_handler); DobbyInstrument((void *)(0x690A8), (dobby_instrument_callback_t)check4_number_handler); DobbyInstrument((void *)(0x715FD), (dobby_instrument_callback_t)check5_underbar_handler); DobbyInstrument((void *)(0x71197), (dobby_instrument_callback_t)shift_right_handler); DobbyHook((void*)(strcmp), (void*)hook_strcmp, (void**)&orig_strcmp); dobby_disable_near_branch_trampoline(); // DobbyHook((void*)(0x7165e), (void*)hook_main, (void**)&orig_main); }
- build.sh
#!/bin/bash gcc -shared -fPIC -o hook.so hook.c -ldl -L. -ldobby -lfunchook
lactf{aaaaaaaaaaaaaaaaaaaaaaaaaaaa}
문자열을 넣었을때 결과 살펴봄.
맨 마지막 단계인 strcmp
함수에서 막힘.
shift_right
연산은 총 56번 수행.

[hook.so] strcmp p1: ecaywusqomkigecaywusqomkigec, p2: vwbowpcjrhpkobfryu
seo@seo:~/study/LACTF2024/rbp$ LD_PRELOAD=./hook/hook.so ./rbp [hook.so] Successfully Loaded! she r on my b till I p > lactf{aaaaaaaaaaaaaaaaaaaaaaaaaaaa} [hook.so] check3_small_ascii: rax = 0x1, rdi = a [hook.so] shift_right: [hook.so] shift_right: [hook.so] check5_underbar: rax = 0x1, rdi = a [hook.so] check3_small_ascii: rax = 0x1, rdi = a [hook.so] shift_right: [hook.so] shift_right: ... [hook.so] check5_underbar: rax = 0x1, rdi = a [hook.so] strcmp p1: ecaywusqomkigecaywusqomkigec, p2: vwbowpcjrhpkobfryu extremely loud incorrect buzzer
살펴봤을때, aaa...
문자열이 ecaywusqomkigecaywusqomkigec
로 최종 변환되었음.
역연산 코드를 짜면
def left_shift(_chr, cnt): _chr = ord(_chr) for i in range(cnt): _chr = (_chr - 97) while(_chr <= 0): _chr += 26 _chr += 96 return chr(_chr) enc = "ecaywusqomkigecaywusqomkigec" dec = "" loopcnt_7155B = 33-6 + 1 print(len(enc)) for i in range(len(enc)): dec += left_shift(enc[i], loopcnt_7155B*2) loopcnt_7155B -= 1 print(dec)
- Result
seo@seo:~/study/LACTF2024/rbp/hook$ python3 ../tmp2.py 28 aaaaaaaaaaaaaaaaaaaaaaaaaaaa
“vwbowpcjrhpkobfryu”
문자열을 역연산 코드에 넣었을때 rubqavktdvfcixdray
seo@seo:~/study/LACTF2024/rbp/hook$ python3 ../tmp2.py 18 rubqavktdvfcixdray
해당 문자열에다 a 더미를 채웠을때 → lactf{rubqavktdvfcixdrayaaaaaaaaaa}
프로그램 결과:
check4_number
에서 막힘- 4번째 문자부터는 0~9가 들어가야할 것.
seo@seo:~/study/LACTF2024/rbp$ LD_PRELOAD=./hook/hook.so ./rbp [hook.so] Successfully Loaded! she r on my b till I p > lactf{rubqavktdvfcixdrayaaaaaaaaaa} [hook.so] check3_small_ascii: rax = 0x1, rdi = r [hook.so] shift_right: [hook.so] shift_right: [hook.so] check5_underbar: rax = 0x1, rdi = r [hook.so] check3_small_ascii: rax = 0x1, rdi = u [hook.so] shift_right: [hook.so] shift_right: [hook.so] check5_underbar: rax = 0x1, rdi = u [hook.so] check3_small_ascii: rax = 0x1, rdi = b [hook.so] shift_right: [hook.so] shift_right: [hook.so] check5_underbar: rax = 0x1, rdi = b [hook.so] shift_right: [hook.so] check4_number: rax = 0x0, rdi = q extremely loud incorrect buzzer
check4_number
dword_70824 = 13003401
- a1 =
dword_70824 % 10 + 0x30
- a1 =
13003401
% 10 + 0x30 - a1 = 49 =
‘1’
- 4번쨰 문자 =
‘1’
- dword_70824/=10,
dword_70824 = 1300340
__int64 __fastcall check4_number(char a1) { if ( a1 <= 0x2F || a1 > 0x39 ) return 0; if ( a1 - 0x30 != dword_70824 % 10 ) return 0; dword_70824 /= 10; if ( dword_70AEC == 3 ) dword_70AE8 = 2; else dword_70AE8 = 0; return 1; }
5번째 문자부터 다시 복호화 시작.
lactf{rub1scxmvfxhekzftcaaaaaaaaaa}
def left_shift(_chr, cnt): _chr = ord(_chr) for i in range(cnt): _chr = (_chr - 97) while(_chr <= 0): _chr += 26 _chr += 96 return chr(_chr) enc = "vwbowpcjrhpkobfryu" dec = "" loopcnt_7155B = 33-6 + 1 print(len(enc)) # r dec += left_shift(enc[0], loopcnt_7155B*2) loopcnt_7155B -= 1 # u dec += left_shift(enc[1], loopcnt_7155B*2) loopcnt_7155B -= 1 # b dec += left_shift(enc[2], loopcnt_7155B*2) loopcnt_7155B -= 1 # 1 loopcnt_7155B -= 1 dec += "1" for i in range(3, len(enc)): dec += left_shift(enc[i], loopcnt_7155B*2) loopcnt_7155B -= 1 dec = dec.ljust(28, "a") print("lactf{" + dec + "}")
seo@seo:~/study/LACTF2024/rbp$ python3 tmp2.py 18 lactf{rub1scxmvfxhekzftcaaaaaaaaaa}
lactf{rub1scxmvfxhekzftcaaaaaaaaaa}
프로그램 결과:
check4_number
에서 막힘‘x’
문자 대신‘0’
이 들어가야할 것.
[hook.so] check4_number: rax = 0x0, rdi = x, dword_70824 = 1300340 extremely loud incorrect buzzer
lactf{rub1sc0mvfxhekzftcaaaaaaaaaa}
프로그램 결과:
‘m’
대신에‘_’
[hook.so] Called check5_underbar: rax = 0x1, rdi = m [hook.so] check5_underbar mismatch!
def left_shift(_chr, cnt): _chr = ord(_chr) for i in range(cnt): _chr = (_chr - 97) while(_chr <= 0): _chr += 26 _chr += 96 return chr(_chr) enc = "vwbowpcjrhpkobfryu" dec = "" loopcnt_7155B = 33-6 + 1 print(len(enc)) # r dec += left_shift(enc[0], loopcnt_7155B*2) loopcnt_7155B -= 1 # u dec += left_shift(enc[1], loopcnt_7155B*2) loopcnt_7155B -= 1 # b dec += left_shift(enc[2], loopcnt_7155B*2) loopcnt_7155B -= 1 # 1 loopcnt_7155B -= 1 dec += "1" # s dec += left_shift(enc[3], loopcnt_7155B*2) loopcnt_7155B -= 1 # c dec += left_shift(enc[4], loopcnt_7155B*2) loopcnt_7155B -= 1 # 0 loopcnt_7155B -= 1 dec += "0" # _ loopcnt_7155B -= 1 dec += "_" for i in range(5, len(enc)): dec += left_shift(enc[i], loopcnt_7155B*2) loopcnt_7155B -= 1 dec = dec.ljust(28, "a") print("lactf{" + dec + "}")
seo@seo:~/study/LACTF2024/rbp$ python3 tmp2.py 18 lactf{rub1sc0_bqzjbliodjxgeaaaaaaa}
lactf{rub1sc0_bqzjbliodjxgeaaaaaaa}
프로그램 결과:
q 대신 4
[hook.so] check4_number: rax = 0x0, rdi = q, dword_70824 = 130034 extremely loud incorrect buzzer
def left_shift(_chr, cnt): _chr = ord(_chr) for i in range(cnt): _chr = (_chr - 97) while(_chr <= 0): _chr += 26 _chr += 96 return chr(_chr) enc = "vwbowpcjrhpkobfryu" dec = "" loopcnt_7155B = 33-6 + 1 print(len(enc)) # r dec += left_shift(enc[0], loopcnt_7155B*2) loopcnt_7155B -= 1 # u dec += left_shift(enc[1], loopcnt_7155B*2) loopcnt_7155B -= 1 # b dec += left_shift(enc[2], loopcnt_7155B*2) loopcnt_7155B -= 1 # 1 loopcnt_7155B -= 1 dec += "1" # s dec += left_shift(enc[3], loopcnt_7155B*2) loopcnt_7155B -= 1 # c dec += left_shift(enc[4], loopcnt_7155B*2) loopcnt_7155B -= 1 # 0 loopcnt_7155B -= 1 dec += "0" # _ loopcnt_7155B -= 1 dec += "_" # b dec += left_shift(enc[5], loopcnt_7155B*2) loopcnt_7155B -= 1 # 4 loopcnt_7155B -= 1 dec += "4" for i in range(6, len(enc)): dec += left_shift(enc[i], loopcnt_7155B*2) loopcnt_7155B -= 1 dec = dec.ljust(28, "a") print("lactf{" + dec + "}")
seo@seo:~/study/LACTF2024/rbp$ python3 tmp2.py 18 lactf{rub1sc0_b4sbldnkqflzigaaaaaa}
lactf{rub1sc0_b4sbldnkqflzigaaaaaa}
프로그램 결과:
b 대신 3
[hook.so] check4_number: rax = 0x0, rdi = b, dword_70824 = 13003 extremely loud incorrect buzzer
def left_shift(_chr, cnt): _chr = ord(_chr) for i in range(cnt): _chr = (_chr - 97) while(_chr <= 0): _chr += 26 _chr += 96 return chr(_chr) enc = "vwbowpcjrhpkobfryu" dec = "" loopcnt_7155B = 33-6 + 1 print(len(enc)) # r dec += left_shift(enc[0], loopcnt_7155B*2) loopcnt_7155B -= 1 # u dec += left_shift(enc[1], loopcnt_7155B*2) loopcnt_7155B -= 1 # b dec += left_shift(enc[2], loopcnt_7155B*2) loopcnt_7155B -= 1 # 1 loopcnt_7155B -= 1 dec += "1" # s dec += left_shift(enc[3], loopcnt_7155B*2) loopcnt_7155B -= 1 # c dec += left_shift(enc[4], loopcnt_7155B*2) loopcnt_7155B -= 1 # 0 loopcnt_7155B -= 1 dec += "0" # _ loopcnt_7155B -= 1 dec += "_" # b dec += left_shift(enc[5], loopcnt_7155B*2) loopcnt_7155B -= 1 # 4 loopcnt_7155B -= 1 dec += "4" # s dec += left_shift(enc[6], loopcnt_7155B*2) loopcnt_7155B -= 1 # 3 loopcnt_7155B -= 1 dec += "3" for i in range(7, len(enc)): dec += left_shift(enc[i], loopcnt_7155B*2) loopcnt_7155B -= 1 dec = dec.ljust(28, "a") print("lactf{" + dec + "}")
seo@seo:~/study/LACTF2024/rbp$ python3 tmp2.py 18 lactf{rub1sc0_b4s3dnfpmshnbkiaaaaa}
lactf{rub1sc0_b4s3dnfpmshnbkiaaaaa}
프로그램 결과:
n 대신 ‘_’
[hook.so] Called check5_underbar: rax = 0x1, rdi = n [hook.so] check5_underbar mismatch!
def left_shift(_chr, cnt): _chr = ord(_chr) for i in range(cnt): _chr = (_chr - 97) while(_chr <= 0): _chr += 26 _chr += 96 return chr(_chr) enc = "vwbowpcjrhpkobfryu" dec = "" loopcnt_7155B = 33-6 + 1 print(len(enc)) # r dec += left_shift(enc[0], loopcnt_7155B*2) loopcnt_7155B -= 1 # u dec += left_shift(enc[1], loopcnt_7155B*2) loopcnt_7155B -= 1 # b dec += left_shift(enc[2], loopcnt_7155B*2) loopcnt_7155B -= 1 # 1 loopcnt_7155B -= 1 dec += "1" # s dec += left_shift(enc[3], loopcnt_7155B*2) loopcnt_7155B -= 1 # c dec += left_shift(enc[4], loopcnt_7155B*2) loopcnt_7155B -= 1 # 0 loopcnt_7155B -= 1 dec += "0" # _ loopcnt_7155B -= 1 dec += "_" # b dec += left_shift(enc[5], loopcnt_7155B*2) loopcnt_7155B -= 1 # 4 loopcnt_7155B -= 1 dec += "4" # s dec += left_shift(enc[6], loopcnt_7155B*2) loopcnt_7155B -= 1 # 3 loopcnt_7155B -= 1 dec += "3" # d dec += left_shift(enc[7], loopcnt_7155B*2) loopcnt_7155B -= 1 # _ loopcnt_7155B -= 1 dec += "_" for i in range(8, len(enc)): dec += left_shift(enc[i], loopcnt_7155B*2) loopcnt_7155B -= 1 dec = dec.ljust(28, "a") print("lactf{" + dec + "}")
18 lactf{rub1sc0_b4s3d_phroujpdmkaaaa}
lactf{rub1sc0_b4s3d_phroujpdmkaaaa}
프로그램 결과:
r 대신에 ‘0’
[hook.so] check4_number: rax = 0x0, rdi = r, dword_70824 = 1300 extremely loud incorrect buzzer
def left_shift(_chr, cnt): _chr = ord(_chr) for i in range(cnt): _chr = (_chr - 97) while(_chr <= 0): _chr += 26 _chr += 96 return chr(_chr) enc = "vwbowpcjrhpkobfryu" dec = "" loopcnt_7155B = 33-6 + 1 print(len(enc)) # r dec += left_shift(enc[0], loopcnt_7155B*2) loopcnt_7155B -= 1 # u dec += left_shift(enc[1], loopcnt_7155B*2) loopcnt_7155B -= 1 # b dec += left_shift(enc[2], loopcnt_7155B*2) loopcnt_7155B -= 1 # 1 loopcnt_7155B -= 1 dec += "1" # s dec += left_shift(enc[3], loopcnt_7155B*2) loopcnt_7155B -= 1 # c dec += left_shift(enc[4], loopcnt_7155B*2) loopcnt_7155B -= 1 # 0 loopcnt_7155B -= 1 dec += "0" # _ loopcnt_7155B -= 1 dec += "_" # b dec += left_shift(enc[5], loopcnt_7155B*2) loopcnt_7155B -= 1 # 4 loopcnt_7155B -= 1 dec += "4" # s dec += left_shift(enc[6], loopcnt_7155B*2) loopcnt_7155B -= 1 # 3 loopcnt_7155B -= 1 dec += "3" # d dec += left_shift(enc[7], loopcnt_7155B*2) loopcnt_7155B -= 1 # _ loopcnt_7155B -= 1 dec += "_" # p dec += left_shift(enc[8], loopcnt_7155B*2) loopcnt_7155B -= 1 # h dec += left_shift(enc[9], loopcnt_7155B*2) loopcnt_7155B -= 1 # 0 loopcnt_7155B -= 1 dec += "0" for i in range(10, len(enc)): dec += left_shift(enc[i], loopcnt_7155B*2) loopcnt_7155B -= 1 dec = dec.ljust(28, "a") print("lactf{" + dec + "}")
seo@seo:~/study/LACTF2024/rbp$ python3 tmp2.py 18 lactf{rub1sc0_b4s3d_ph0tqwlrfomaaa}
lactf{rub1sc0_b4s3d_ph0tqwlrfomaaa}
프로그램 결과:
q 대신 0
[hook.so] check4_number: rax = 0x0, rdi = q, dword_70824 = 130 extremely loud incorrect buzzer
def left_shift(_chr, cnt): _chr = ord(_chr) for i in range(cnt): _chr = (_chr - 97) while(_chr <= 0): _chr += 26 _chr += 96 return chr(_chr) enc = "vwbowpcjrhpkobfryu" dec = "" loopcnt_7155B = 33-6 + 1 print(len(enc)) # r dec += left_shift(enc[0], loopcnt_7155B*2) loopcnt_7155B -= 1 # u dec += left_shift(enc[1], loopcnt_7155B*2) loopcnt_7155B -= 1 # b dec += left_shift(enc[2], loopcnt_7155B*2) loopcnt_7155B -= 1 # 1 loopcnt_7155B -= 1 dec += "1" # s dec += left_shift(enc[3], loopcnt_7155B*2) loopcnt_7155B -= 1 # c dec += left_shift(enc[4], loopcnt_7155B*2) loopcnt_7155B -= 1 # 0 loopcnt_7155B -= 1 dec += "0" # _ loopcnt_7155B -= 1 dec += "_" # b dec += left_shift(enc[5], loopcnt_7155B*2) loopcnt_7155B -= 1 # 4 loopcnt_7155B -= 1 dec += "4" # s dec += left_shift(enc[6], loopcnt_7155B*2) loopcnt_7155B -= 1 # 3 loopcnt_7155B -= 1 dec += "3" # d dec += left_shift(enc[7], loopcnt_7155B*2) loopcnt_7155B -= 1 # _ loopcnt_7155B -= 1 dec += "_" # p dec += left_shift(enc[8], loopcnt_7155B*2) loopcnt_7155B -= 1 # h dec += left_shift(enc[9], loopcnt_7155B*2) loopcnt_7155B -= 1 # 0 loopcnt_7155B -= 1 dec += "0" # t dec += left_shift(enc[10], loopcnt_7155B*2) loopcnt_7155B -= 1 # 0 loopcnt_7155B -= 1 dec += "0" for i in range(11, len(enc)): dec += left_shift(enc[i], loopcnt_7155B*2) loopcnt_7155B -= 1 dec = dec.ljust(28, "a") print("lactf{" + dec + "}")
seo@seo:~/study/LACTF2024/rbp$ python3 tmp2.py 18 lactf{rub1sc0_b4s3d_ph0t0synthqoaa}
lactf{rub1sc0_b4s3d_ph0t0synthqoaa}
프로그램 결과:
q 대신 3
[hook.so] check4_number: rax = 0x0, rdi = q, dword_70824 = 13 extremely loud incorrect buzzer
def left_shift(_chr, cnt): _chr = ord(_chr) for i in range(cnt): _chr = (_chr - 97) while(_chr <= 0): _chr += 26 _chr += 96 return chr(_chr) enc = "vwbowpcjrhpkobfryu" dec = "" loopcnt_7155B = 33-6 + 1 print(len(enc)) # r dec += left_shift(enc[0], loopcnt_7155B*2) loopcnt_7155B -= 1 # u dec += left_shift(enc[1], loopcnt_7155B*2) loopcnt_7155B -= 1 # b dec += left_shift(enc[2], loopcnt_7155B*2) loopcnt_7155B -= 1 # 1 loopcnt_7155B -= 1 dec += "1" # s dec += left_shift(enc[3], loopcnt_7155B*2) loopcnt_7155B -= 1 # c dec += left_shift(enc[4], loopcnt_7155B*2) loopcnt_7155B -= 1 # 0 loopcnt_7155B -= 1 dec += "0" # _ loopcnt_7155B -= 1 dec += "_" # b dec += left_shift(enc[5], loopcnt_7155B*2) loopcnt_7155B -= 1 # 4 loopcnt_7155B -= 1 dec += "4" # s dec += left_shift(enc[6], loopcnt_7155B*2) loopcnt_7155B -= 1 # 3 loopcnt_7155B -= 1 dec += "3" # d dec += left_shift(enc[7], loopcnt_7155B*2) loopcnt_7155B -= 1 # _ loopcnt_7155B -= 1 dec += "_" # p dec += left_shift(enc[8], loopcnt_7155B*2) loopcnt_7155B -= 1 # h dec += left_shift(enc[9], loopcnt_7155B*2) loopcnt_7155B -= 1 # 0 loopcnt_7155B -= 1 dec += "0" # t dec += left_shift(enc[10], loopcnt_7155B*2) loopcnt_7155B -= 1 # 0 loopcnt_7155B -= 1 dec += "0" # s dec += left_shift(enc[11], loopcnt_7155B*2) loopcnt_7155B -= 1 # y dec += left_shift(enc[12], loopcnt_7155B*2) loopcnt_7155B -= 1 # n dec += left_shift(enc[13], loopcnt_7155B*2) loopcnt_7155B -= 1 # t dec += left_shift(enc[14], loopcnt_7155B*2) loopcnt_7155B -= 1 # h dec += left_shift(enc[15], loopcnt_7155B*2) loopcnt_7155B -= 1 # 3 loopcnt_7155B -= 1 dec += "3" for i in range(16, len(enc)): dec += left_shift(enc[i], loopcnt_7155B*2) loopcnt_7155B -= 1 dec = dec.ljust(28, "a") print("lactf{" + dec + "}")
seo@seo:~/study/LACTF2024/rbp$ python3 tmp2.py 18 lactf{rub1sc0_b4s3d_ph0t0synth3sqa}
lactf{rub1sc0_b4s3d_ph0t0synth3sqa}
프로그램 결과:
q 대신 1
[hook.so] check4_number: rax = 0x0, rdi = q, dword_70824 = 1 extremely loud incorrect buzzer
def left_shift(_chr, cnt): _chr = ord(_chr) for i in range(cnt): _chr = (_chr - 97) while(_chr <= 0): _chr += 26 _chr += 96 return chr(_chr) enc = "vwbowpcjrhpkobfryu" dec = "" loopcnt_7155B = 33-6 + 1 print(len(enc)) # r dec += left_shift(enc[0], loopcnt_7155B*2) loopcnt_7155B -= 1 # u dec += left_shift(enc[1], loopcnt_7155B*2) loopcnt_7155B -= 1 # b dec += left_shift(enc[2], loopcnt_7155B*2) loopcnt_7155B -= 1 # 1 loopcnt_7155B -= 1 dec += "1" # s dec += left_shift(enc[3], loopcnt_7155B*2) loopcnt_7155B -= 1 # c dec += left_shift(enc[4], loopcnt_7155B*2) loopcnt_7155B -= 1 # 0 loopcnt_7155B -= 1 dec += "0" # _ loopcnt_7155B -= 1 dec += "_" # b dec += left_shift(enc[5], loopcnt_7155B*2) loopcnt_7155B -= 1 # 4 loopcnt_7155B -= 1 dec += "4" # s dec += left_shift(enc[6], loopcnt_7155B*2) loopcnt_7155B -= 1 # 3 loopcnt_7155B -= 1 dec += "3" # d dec += left_shift(enc[7], loopcnt_7155B*2) loopcnt_7155B -= 1 # _ loopcnt_7155B -= 1 dec += "_" # p dec += left_shift(enc[8], loopcnt_7155B*2) loopcnt_7155B -= 1 # h dec += left_shift(enc[9], loopcnt_7155B*2) loopcnt_7155B -= 1 # 0 loopcnt_7155B -= 1 dec += "0" # t dec += left_shift(enc[10], loopcnt_7155B*2) loopcnt_7155B -= 1 # 0 loopcnt_7155B -= 1 dec += "0" # s dec += left_shift(enc[11], loopcnt_7155B*2) loopcnt_7155B -= 1 # y dec += left_shift(enc[12], loopcnt_7155B*2) loopcnt_7155B -= 1 # n dec += left_shift(enc[13], loopcnt_7155B*2) loopcnt_7155B -= 1 # t dec += left_shift(enc[14], loopcnt_7155B*2) loopcnt_7155B -= 1 # h dec += left_shift(enc[15], loopcnt_7155B*2) loopcnt_7155B -= 1 # 3 loopcnt_7155B -= 1 dec += "3" # s dec += left_shift(enc[16], loopcnt_7155B*2) loopcnt_7155B -= 1 # 1 loopcnt_7155B -= 1 dec += "1" for i in range(17, len(enc)): dec += left_shift(enc[i], loopcnt_7155B*2) loopcnt_7155B -= 1 dec = dec.ljust(28, "a") print("lactf{" + dec + "}")
seo@seo:~/study/LACTF2024/rbp$ python3 tmp2.py 18 lactf{rub1sc0_b4s3d_ph0t0synth3s1s}
lactf{rub1sc0_b4s3d_ph0t0synth3s1s}
프로그램 결과:
[hook.so] strcmp p1: vwbowpcjrhpkobfryu, p2: vwbowpcjrhpkobfryu omg how did u guess
끝..
5. 리뷰
다시 정리해보자면
sub_711A1
아래 3가지 함수들 중 실행할 수 있는 하나를 결정
- check3_small_ascii (sub_68000)
- check4_number (sub_69000)
- check5_underbar (sub_70000)
__int64 __fastcall sub_711A1(char a1) { unsigned int v1; // eax unsigned int v2; // eax unsigned int v3; // eax __int64 result; // rax if ( a1 ) v1 = 3; else v1 = 7; if ( (unsigned int)mprotect(check3_small_ascii, 4096, v1) == -1 ) abort(); if ( a1 == 1 ) v2 = 7; else v2 = 3; if ( (unsigned int)mprotect(check4_number, 4096, v2) == -1 ) abort(); if ( a1 == 2 ) v3 = 7; else v3 = 3; result = mprotect(check5_underbar, 4096, v3); if ( (_DWORD)result == -1 ) abort(); return result; }
exception_handler (sub_710F9)
실행할 수 없는 함수일 경우,
모든 문자를 오른쪽으로 쉬프트 연산 1번 수행함.
ucontext_t *__fastcall exception_handler(__int64 a1, siginfo_t *a2, ucontext_t *a3) { ucontext_t *result; // rax int i; // [rsp+1Ch] [rbp-Ch] ucontext_t *__fastcall exception_handler(__int64 a1, siginfo_t *a2, ucontext_t *a3) { ucontext_t *result; // rax int i; // [rsp+1Ch] [rbp-Ch] for ( i = 0; i < dword_70AE4; ++i ) byte_70B00[i] = (byte_70B00[i] - 96) % 26 + 97; a3->uc_mcontext.gregs[13] = 1; // 13 = REG_RAX result = a3; a3->uc_mcontext.gregs[16] = *(_QWORD *)a3->uc_mcontext.gregs[15];// 16 = REG_RIP, 15 = REG_RSP return result; } for ( i = 0; i < dword_70AE4; ++i ) byte_70B00[i] = (byte_70B00[i] - 96) % 26 + 97; a3->uc_mcontext.gregs[13] = 1; // 13 = REG_RAX result = a3; a3->uc_mcontext.gregs[16] = *(_QWORD *)a3->uc_mcontext.gregs[15];// 16 = REG_RIP, 15 = REG_RSP return result; }
check3_small_ascii (sub_68000)
- 소문자 알파벳 범위인지 확인
dword_70AE4
는 암호화된 데이터의 인덱스를 의미, 1씩 증가.byte_70B00
는 암호화된 데이터로 1바이트씩 추가, 맨 마지막에strcmp
에서 최종 비교함.- 입력받는 문자가
‘b’, ‘c’, ‘h’, ‘s’, ‘t’
중 하나일 경우,dword_70AEC
카운트 증가. - 증가된
dword_70AEC
카운트 값이2, 8, 9, 12
일 경우,dword_70AE8 = 1
- 입력받는 문자가 ‘d’일 경우,
dword_70AE8 = 2
dword_70AE8
에 의해 이 다음에 실행시킬 수 있는 함수를sub_711A1
에서 결정해줌.dword_70AE8
이 0일 경우:check3_small_ascii
dword_70AE8
이 1일 경우:check4_number
dword_70AE8
이 2일 경우:check5_underbar
__int64 __fastcall check3_small_ascii(char a1) { int v2; // eax if ( a1 <= 0x60 || a1 > 0x7A ) // 'abcdefghijklmnopqrstuvwxyz' return 0; v2 = dword_70AE4++; byte_70B00[v2] = a1; if ( (a1 == 'b' || a1 == 'c' || a1 == 'h' || a1 == 's' || a1 == 't') && ++dword_70AEC != 2 && dword_70AEC != 8 && dword_70AEC != 9 && dword_70AEC != 12 ) { dword_70AE8 = 1; } if ( a1 == 'd' ) dword_70AE8 = 2; return 1; }
check4_number (sub_69000)
- 0~9 범위인지 확인
- 초기
dword_70824
는13003401
값을 가짐. - 역연산 수행시 a1 = ‘1’ 충족 필요,
dword_70824 = 1300340
- 2번쨰 수행시 a1 = ‘0’,
dword_70824 = 130034
- 3번째 수행시 a1 = ‘4’,
dword_70824 = 13003
check3_small_ascii
에서 증가된dword_70AEC
값이 3일 경우,dword_70AE8 = 2
- 증가된
dword_70AEC
값이 3이 아니면,dword_70AE8 = 0
dword_70AE8
이 0일 경우:check3_small_ascii
dword_70AE8
이 1일 경우:check4_number
dword_70AE8
이 2일 경우:check5_underbar
__int64 __fastcall sub_69000(char a1) { if ( a1 <= 0x2F || a1 > 0x39 ) // 0123456789 return 0; if ( a1 - 48 != dword_70824 % 10 ) return 0; dword_70824 /= 10; if ( dword_70AEC == 3 ) dword_70AE8 = 2; else dword_70AE8 = 0; return 1; }
check5_underbar (sub_70000)
- 입력받은 문자의 제곱을 9024로 나눴을때 나누어 떨어지지만 않으면 됨.
- 사실 수많은 문자가 조건을 만족시킬 수 있으나,
- 9024의 제곱근 = 94.99473669630333
- 유추하면
95 = ‘_’
문자가 들어가야할 것 같음.
__int64 __fastcall check5_underbar(char a1) { if ( !(a1 * a1 % 9024) ) return 0; dword_70AE8 = 0; return 1; }
exception_handler
- 실행할 수 없는 영역에 닿았을때 해당 함수가 호출됨.
- RAX는 항상 1을 반환함.
byte_70B00
는 맨 마지막에strcmp
에서 최종 비교함.byte_70B00
문자들을 오른쪽으로 1만큼 시프트 연산함.
ucontext_t *__fastcall exception_handler(__int64 a1, siginfo_t *a2, ucontext_t *a3) { ucontext_t *result; // rax int i; // [rsp+1Ch] [rbp-Ch] for ( i = 0; i < dword_70AE4; ++i ) byte_70B00[i] = (byte_70B00[i] - 96) % 26 + 97; a3->uc_mcontext.gregs[13] = 1; // 13 = REG_RAX result = a3; a3->uc_mcontext.gregs[16] = *(_QWORD *)a3->uc_mcontext.gregs[15];// 16 = REG_RIP, 15 = REG_RSP return result; }
solve.py
def left_shift(_chr, cnt): _chr = ord(_chr) for i in range(cnt): _chr = (_chr - 97) while(_chr <= 0): _chr += 26 _chr += 96 return chr(_chr) dword_70824 = 13003401 enc = "vwbowpcjrhpkobfryu" dec = "" loopcnt_7155B = 33-6 + 1 print(len(enc)) # r dec += left_shift(enc[0], loopcnt_7155B*2) loopcnt_7155B -= 1 # u dec += left_shift(enc[1], loopcnt_7155B*2) loopcnt_7155B -= 1 # b dec += left_shift(enc[2], loopcnt_7155B*2) loopcnt_7155B -= 1 # 1 dec += chr((dword_70824 % 10) + 48) loopcnt_7155B -= 1 dword_70824 = int(dword_70824 / 10) # s dec += left_shift(enc[3], loopcnt_7155B*2) loopcnt_7155B -= 1 # c dec += left_shift(enc[4], loopcnt_7155B*2) loopcnt_7155B -= 1 # 0 dec += chr((dword_70824 % 10) + 48) loopcnt_7155B -= 1 dword_70824 = int(dword_70824 / 10) # _ loopcnt_7155B -= 1 dec += "_" # b dec += left_shift(enc[5], loopcnt_7155B*2) loopcnt_7155B -= 1 # 4 dec += chr((dword_70824 % 10) + 48) loopcnt_7155B -= 1 dword_70824 = int(dword_70824 / 10) # s dec += left_shift(enc[6], loopcnt_7155B*2) loopcnt_7155B -= 1 # 3 dec += chr((dword_70824 % 10) + 48) loopcnt_7155B -= 1 dword_70824 = int(dword_70824 / 10) # d dec += left_shift(enc[7], loopcnt_7155B*2) loopcnt_7155B -= 1 # _ loopcnt_7155B -= 1 dec += "_" # p dec += left_shift(enc[8], loopcnt_7155B*2) loopcnt_7155B -= 1 # h dec += left_shift(enc[9], loopcnt_7155B*2) loopcnt_7155B -= 1 # 0 dec += chr((dword_70824 % 10) + 48) loopcnt_7155B -= 1 dword_70824 = int(dword_70824 / 10) # t dec += left_shift(enc[10], loopcnt_7155B*2) loopcnt_7155B -= 1 # 0 dec += chr((dword_70824 % 10) + 48) loopcnt_7155B -= 1 dword_70824 = int(dword_70824 / 10) # s dec += left_shift(enc[11], loopcnt_7155B*2) loopcnt_7155B -= 1 # y dec += left_shift(enc[12], loopcnt_7155B*2) loopcnt_7155B -= 1 # n dec += left_shift(enc[13], loopcnt_7155B*2) loopcnt_7155B -= 1 # t dec += left_shift(enc[14], loopcnt_7155B*2) loopcnt_7155B -= 1 # h dec += left_shift(enc[15], loopcnt_7155B*2) loopcnt_7155B -= 1 # 3 dec += chr((dword_70824 % 10) + 48) loopcnt_7155B -= 1 dword_70824 = int(dword_70824 / 10) # s dec += left_shift(enc[16], loopcnt_7155B*2) loopcnt_7155B -= 1 # 1 dec += chr((dword_70824 % 10) + 48) loopcnt_7155B -= 1 dword_70824 = int(dword_70824 / 10) for i in range(17, len(enc)): dec += left_shift(enc[i], loopcnt_7155B*2) loopcnt_7155B -= 1 dec = dec.ljust(28, "a") print("lactf{" + dec + "}")
result
seo@seo:~/study/LACTF2024/rbp$ python3 tmp2.py 18 lactf{rub1sc0_b4s3d_ph0t0synth3s1s}