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 검사를 통해
v151바이트씩 검사. 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 = 1dword_70AE8 = -1dword_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_asciidword_70AE8이 1일 경우:check4_numberdword_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_asciidword_70AE8이 1일 경우:check4_numberdword_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}