콘텐츠로 건너뛰기

[LACTF2024] rbp

Analysis

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

심볼 찾기

main에서 처음 호출되는 sub_71840 함수

_dl_runtime_resolvejmp r11sigemptyset

심볼 복구 결과 (희미한 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_7082413003401 값을 가짐.
  • 역연산 수행시 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}
태그: