콘텐츠로 건너뛰기

[핵테온 2025] barcode

Decompiled-src

main

C++언어로 컴파일되있음. main에서 호출시키는 4가지 함수는 다음과 같았음.

  • sub_12E0
  • sub_18F0
  • sub_2650
  • sub_2850
__int64 __fastcall main(int a1, const char **a2, char **a3)
{
  const char *v3; // rbx
  signed __int64 v4; // rax
  size_t v5; // r14
  char *v6; // r15
  const char *v7; // r15
  size_t v8; // rax
  _BYTE *v9; // r14
  char v10; // al
  std::ostream *v11; // rax
  const char *v12; // rbx
  size_t v13; // rax
  __int64 v14; // rax
  _BYTE *v15; // rbx
  char v16; // al
  std::ostream *v17; // rax
  unsigned int v18; // ebx
  __int64 v19; // rax
  _BYTE *v20; // rbx
  char v21; // al
  void *v22; // rbx
  _BYTE *v23; // r14
  _QWORD *v24; // r15
  _QWORD *v25; // rbp
  unsigned __int64 v26; // rsi
  unsigned int v27; // r8d
  __int64 v28; // rdx
  __int64 v29; // rax
  __int64 v30; // rdi
  __int64 v31; // rax
  __int64 v32; // rdi
  bool v33; // cf
  __m128i *v34; // rbx
  __m128i *v35; // r14
  __m128i *v36; // r13
  __m128i v37; // xmm0
  __m128i v38; // xmm1
  __m128i v39; // xmm2
  __m128i *v40; // r15
  __int64 v41; // r15
  __int64 v42; // rax
  __int64 v43; // r13
  __m128i *v44; // r12
  __int64 v45; // r15
  __m128i v46; // xmm0
  __m128i v47; // xmm1
  __m128i v48; // xmm2
  const __m128i *v49; // rax
  __m128i v50; // xmm0
  __m128i v51; // xmm1
  __m128i v52; // xmm2
  __m128i *v53; // r14
  bool v54; // zf
  std::ostream *v55; // rax
  __int64 v57; // r8
  __int64 v58; // r9
  __int64 v59; // r10
  __int64 v60; // r8
  __int64 v61; // r8
  int v62; // esi
  char *v63; // r10
  __int64 v64; // r11
  __int64 v65; // rbx
  __m128i v66; // xmm3
  _QWORD *v67; // [rsp+0h] [rbp-118h]
  void *v68; // [rsp+8h] [rbp-110h] BYREF
  _QWORD *v69; // [rsp+10h] [rbp-108h]
  __m128i v70; // [rsp+20h] [rbp-F8h] BYREF
  __m128i v71; // [rsp+30h] [rbp-E8h] BYREF
  __m128i v72; // [rsp+40h] [rbp-D8h] BYREF
  __m128i v73; // [rsp+50h] [rbp-C8h] BYREF
  _BYTE v74[64]; // [rsp+60h] [rbp-B8h] BYREF
  void *v75[2]; // [rsp+A0h] [rbp-78h] BYREF
  _QWORD v76[2]; // [rsp+B0h] [rbp-68h] BYREF
  void *v77; // [rsp+C0h] [rbp-58h]
  unsigned __int64 v78; // [rsp+C8h] [rbp-50h]
  _QWORD dest[9]; // [rsp+D0h] [rbp-48h] BYREF

  dest[2] = __readfsqword(0x28u);
  if ( a1 == 2 )
  {
    v3 = a2[1];
    v77 = dest;
    if ( !v3 )
      std::__throw_logic_error("basic_string::_M_construct null not valid");
    v4 = strlen(v3);
    v5 = v4;
    v6 = (char *)dest;
    if ( (unsigned __int64)v4 >= 0x10 )
    {
      if ( v4 < 0 )
        std::__throw_length_error("basic_string::_M_create");
      if ( v4 + 1 < 0 )
        std::__throw_bad_alloc();
      v6 = (char *)operator new(v4 + 1);
      v77 = v6;
      dest[0] = v5;
    }
    if ( v5 )
    {
      if ( v5 == 1 )
        *v6 = *v3;
      else
        memcpy(v6, v3, v5);
    }
    v78 = v5;
    v6[v5] = 0;
    if ( v78 <= 2 )
    {
      std::__ostream_insert<char,std::char_traits<char>>(&std::cerr, "Invalid hex-string", 18);
      v19 = *(_QWORD *)(std::cerr - 24LL);
      v20 = *(_BYTE **)((char *)&std::cerr + v19 + 240);
      if ( !v20 )
        std::__throw_bad_cast();
      if ( v20[56] )
      {
        v21 = v20[67];
      }
      else
      {
        std::ctype<char>::_M_widen_init(*(_QWORD *)((char *)&std::cerr + v19 + 240));
        v21 = (*(__int64 (__fastcall **)(_BYTE *, __int64))(*(_QWORD *)v20 + 48LL))(v20, 10);
      }
      v55 = (std::ostream *)std::ostream::put((std::ostream *)&std::cerr, v21);
      v18 = 1;
      std::ostream::flush(v55);
LABEL_72:
      if ( v77 != dest )
        operator delete(v77);
      return v18;
    }
    v22 = (void *)(v78 - 2);
    v75[0] = v76;
    v23 = (char *)v77 + 2;
    if ( v78 - 2 < 0x10 )
    {
      v24 = v76;
      if ( v78 == 3 )
      {
        LOBYTE(v76[0]) = *v23;
        v24 = v76;
        goto LABEL_37;
      }
    }
    else
    {
      if ( (__int64)v22 < 0 )
        std::__throw_length_error("basic_string::_M_create");
      if ( (__int64)(v78 - 1) < 0 )
        std::__throw_bad_alloc();
      v24 = (_QWORD *)operator new(v78 - 1);
      v75[0] = v24;
      v76[0] = v22;
    }
    memcpy(v24, v23, (size_t)v22);
LABEL_37:
    v75[1] = v22;
    *((_BYTE *)v22 + (_QWORD)v24) = 0;
    sub_12E0(&v68, v75);
    v25 = v68;
    v67 = v69;
    v26 = (unsigned __int64)((char *)v69 - (_BYTE *)v68) >> 3;
    v27 = v26 - 1;
    if ( (int)v26 - 1 > 0 )
    {
      v28 = v27;
      v29 = (unsigned int)v26;
      if ( v27 < 0x22
        || (v57 = (unsigned int)(v26 - 2), v58 = 8 * v28 - 8, (char *)v68 + 8 * v57 - v58 > (char *)v68 + 8 * v57)
        || (char *)v68 + 8 * v28 - v58 > (char *)v68 + 8 * v28
        || (unsigned int)v57 < (int)v28 - 1
        || (unsigned __int64)(v28 - 1) >> 32
        || (v59 = 8 * v28, v60 = ((char *)v69 - (_BYTE *)v68 + 0x7FFFFFFF0LL) & 0x7FFFFFFF8LL, v68 < (char *)v68 + v60)
        && (char *)v68 + v60 - v59 + 8 < (char *)v68 + 8 * v28 + 8 )
      {
        v30 = v28;
      }
      else
      {
        v61 = v28 & 0x7FFFFFFC;
        v29 = (unsigned int)v26 - v61;
        v30 = v28 & 3;
        v62 = v26 - 2;
        v63 = (char *)v68 + v59 - 8;
        v64 = 0;
        do
        {
          v65 = (unsigned int)(v62 + v64);
          v66 = _mm_xor_si128(
                  _mm_xor_si128(_mm_loadu_si128((const __m128i *)&v63[8 * v64 - 16]), (__m128i)-1LL),
                  _mm_loadu_si128((const __m128i *)&v25[v65 - 3]));
          *(__m128i *)&v63[8 * v64] = _mm_xor_si128(
                                        _mm_xor_si128(_mm_loadu_si128((const __m128i *)&v63[8 * v64]), (__m128i)-1LL),
                                        _mm_loadu_si128((const __m128i *)&v25[v65 - 1]));
          *(__m128i *)&v63[8 * v64 - 16] = v66;
          v64 -= 4;
        }
        while ( -(v28 & 0x7FFFFFFC) != v64 );
        if ( v61 == v28 )
          goto LABEL_42;
      }
      v31 = v29 + 4294967294LL;
      v32 = v30 + 1;
      do
      {
        v25[v32 - 1] = ~(v25[v32 - 1] ^ v25[(unsigned int)v31--]);
        v33 = v32-- == 1;
      }
      while ( !v33 && v32 != 1 );
    }
LABEL_42:
    if ( v25 != v67 )
    {
      v34 = 0;
      v35 = 0;
      v36 = 0;
      do
      {
        while ( 1 )
        {
          sub_18F0(*v25, v74);
          sub_2650(&v70, v74);
          if ( v35 == v36 )
            break;
          v37 = _mm_loadu_si128(&v70);
          v38 = _mm_loadu_si128(&v71);
          v39 = _mm_loadu_si128(&v72);
          v35[3] = _mm_loadu_si128(&v73);
          v35[2] = v39;
          v35[1] = v38;
          *v35 = v37;
          v40 = v35;
          v35 += 4;
          if ( ++v25 == v67 )
            goto LABEL_60;
        }
        if ( (char *)v35 - (char *)v34 == 0x7FFFFFFFFFFFFFC0LL )
          std::__throw_length_error("vector::_M_realloc_insert");
        v41 = ((char *)v35 - (char *)v34) >> 6;
        v42 = (v41 == 0) + v41;
        v43 = v42 + v41;
        if ( (unsigned __int64)(v42 + v41) >= 0x1FFFFFFFFFFFFFFLL )
          v43 = 0x1FFFFFFFFFFFFFFLL;
        if ( __CFADD__(v41, v42) )
          v43 = 0x1FFFFFFFFFFFFFFLL;
        if ( v43 )
          v44 = (__m128i *)operator new(v43 << 6);
        else
          v44 = 0;
        v45 = v41 << 6;
        v46 = _mm_loadu_si128(&v70);
        v47 = _mm_loadu_si128(&v71);
        v48 = _mm_loadu_si128(&v72);
        *(__m128i *)((char *)&v44[3] + v45) = _mm_loadu_si128(&v73);
        *(__m128i *)((char *)&v44[2] + v45) = v48;
        *(__m128i *)((char *)&v44[1] + v45) = v47;
        *(__m128i *)((char *)v44 + v45) = v46;
        v40 = v44;
        if ( v34 != v35 )
        {
          v40 = v44;
          v49 = v34;
          do
          {
            v50 = _mm_loadu_si128(v49);
            v51 = _mm_loadu_si128(v49 + 1);
            v52 = _mm_loadu_si128(v49 + 2);
            v40[3] = _mm_loadu_si128(v49 + 3);
            v40[2] = v52;
            v40[1] = v51;
            *v40 = v50;
            v49 += 4;
            v40 += 4;
          }
          while ( v49 != v35 );
        }
        if ( v34 )
          operator delete(v34);
        v36 = &v44[4 * v43];
        v34 = v44;
        v35 = v40 + 4;
        ++v25;
      }
      while ( v25 != v67 );
LABEL_60:
      if ( v34 != v35 )
      {
        v53 = v34;
        do
        {
          sub_2850(v53);
          v54 = v53 == v40;
          v53 += 4;
        }
        while ( !v54 );
      }
      if ( v34 )
        operator delete(v34);
    }
    if ( v68 )
      operator delete(v68);
    if ( v75[0] != v76 )
      operator delete(v75[0]);
    v18 = 0;
    goto LABEL_72;
  }
  std::__ostream_insert<char,std::char_traits<char>>(&std::cout, "Usage: ", 7);
  v7 = *a2;
  if ( *a2 )
  {
    v8 = strlen(*a2);
    std::__ostream_insert<char,std::char_traits<char>>(&std::cout, v7, v8);
  }
  else
  {
    std::ios::clear(
      (char *)&std::cout + *(_QWORD *)(std::cout - 24LL),
      *(_DWORD *)((char *)&std::cout + *(_QWORD *)(std::cout - 24LL) + 32) | 1u);
  }
  std::__ostream_insert<char,std::char_traits<char>>(&std::cout, " {hex-string}", 13);
  v9 = *(_BYTE **)((char *)&std::cout + *(_QWORD *)(std::cout - 24LL) + 240);
  if ( !v9 )
    goto LABEL_88;
  if ( v9[56] )
  {
    v10 = v9[67];
  }
  else
  {
    std::ctype<char>::_M_widen_init(v9);
    v10 = (*(__int64 (__fastcall **)(_BYTE *, __int64))(*(_QWORD *)v9 + 48LL))(v9, 10);
  }
  v11 = (std::ostream *)std::ostream::put((std::ostream *)&std::cout, v10);
  std::ostream::flush(v11);
  std::__ostream_insert<char,std::char_traits<char>>(&std::cout, "Example: ", 9);
  v12 = *a2;
  if ( *a2 )
  {
    v13 = strlen(v12);
    std::__ostream_insert<char,std::char_traits<char>>(&std::cout, v12, v13);
  }
  else
  {
    std::ios::clear(
      (char *)&std::cout + *(_QWORD *)(std::cout - 24LL),
      *(_DWORD *)((char *)&std::cout + *(_QWORD *)(std::cout - 24LL) + 32) | 1u);
  }
  std::__ostream_insert<char,std::char_traits<char>>(&std::cout, " 0x3E08080818381808", 19);
  v14 = *(_QWORD *)(std::cout - 24LL);
  v15 = *(_BYTE **)((char *)&std::cout + v14 + 240);
  if ( !v15 )
LABEL_88:
    std::__throw_bad_cast();
  if ( v15[56] )
  {
    v16 = v15[67];
  }
  else
  {
    std::ctype<char>::_M_widen_init(*(_QWORD *)((char *)&std::cout + v14 + 240));
    v16 = (*(__int64 (__fastcall **)(_BYTE *, __int64))(*(_QWORD *)v15 + 48LL))(v15, 10);
  }
  v17 = (std::ostream *)std::ostream::put((std::ostream *)&std::cout, v16);
  std::ostream::flush(v17);
  return 1;
}

Run

실행시 아래와 같이 매개변수 16진수를 요구함.

seo@seo:~/study/hto2025/barcode$ ./barcode
Usage: ./barcode {hex-string}
Example: ./barcode 0x3E08080818381808

매개변수 8바이트일 경우, 별 아스키 아트가 8줄 출력됨.

./barcode 0x4142434445464748

seo@seo:~/study/hto2025/barcode$ ./barcode 0x4142434445464748
   *  *
***   *
 **   *
* *   *
  *   *
**    *
 *    *
*     *

16바이트인 경우, 별 아스키 아트가 16줄 출력됨.

./barcode 0x4142434445464748abadbabe13371338

seo@seo:~/study/hto2025/barcode$ ./barcode 0x4142434445464748abadbabe13371338
   *  *
***   *
 **   *
* *   *
  *   *
**    *
 *    *
*     *
****   *
** * * *
 ***   *
*  * * *
* *
 **
    *
* * *

그렇다면, flag.barcode는 매개변수가 32바이트여야함.

ex) ./barcode 0x4142434445464748abadbabedeadbeef1337c0de5152535455565758

cat flag.barcode

seo@seo:~/study/hto2025/barcode$ cat flag.barcode

 ******
 *
 ******
 *
 *
 *


 *
 *
 *
 *
 *
 ******


  ****
 *    *
 ******
 *    *
 *    *
 *    *


  ****
 *    *
 *
 *  ***
 *    *
  ****

main에서 호출시키는 4가지 함수를 차례대로 살펴보자.

매개변수는 0x000000004142434445464748abadbabedeadbeef1337c0de5152535455565758 으로 우선 넣어주었다.

sub_12E0(__int64 a1, __int64 a2)

  • 호출 전

rdi = 00007FFFFFFFE0E8

MEMORY:00007FFFFFFFE0E8 dq 0

rsi = 00007FFFFFFFE180

MEMORY:00007FFFFFFFE180 dq offset off_55555556BF00
...
MEMORY:000055555556BF00 a41424344454647 db '4142434445464748abadbabedeadbeef1337c0de5152535455565758',0
  • 호출 후

rdi = 7
rsi = 000055555555A010

MEMORY:000055555555A010 dq offset unk_2000000000003

sub_18F0(__int64 a1, _BYTE *a2)

  • 호출 전

rdi = 0000000041424344
rsi = 00007FFFFFFFE140

MEMORY:00007FFFFFFFE140 db 2, 0, 0, 0, 0, 0, 0, 0
MEMORY:00007FFFFFFFE148 db 6, 0, 0, 0, 0, 0, 0, 80h
MEMORY:00007FFFFFFFE150 db 0, 0, 0, 0, 0, 0, 0, 0
MEMORY:00007FFFFFFFE158 db 0, 0, 0, 0, 0, 0, 0, 0
MEMORY:00007FFFFFFFE160 db 0, 0, 0, 0, 0, 0, 0, 0
MEMORY:00007FFFFFFFE168 db 0, 0, 0, 0, 0, 0, 0, 0
MEMORY:00007FFFFFFFE170 db 0, 0, 0, 0, 0, 0, 0, 0
MEMORY:00007FFFFFFFE178 db 0, 0, 0, 0, 0, 0, 0, 0
  • 호출 후

rdi 값에 의해 64바이트 크기의 배열이 생성됨.

rdi = 0
rsi = 00007FFFFFFFE140

MEMORY:00007FFFFFFFE140 db 0, 0, 1, 0, 0, 0, 1, 0
MEMORY:00007FFFFFFFE148 db 1, 1, 0, 0, 0, 0, 1, 0
MEMORY:00007FFFFFFFE150 db 0, 1, 0, 0, 0, 0, 1, 0
MEMORY:00007FFFFFFFE158 db 1, 0, 0, 0, 0, 0, 1, 0
MEMORY:00007FFFFFFFE160 db 0, 0, 0, 0, 0, 0, 0, 0
MEMORY:00007FFFFFFFE168 db 0, 0, 0, 0, 0, 0, 0, 0
MEMORY:00007FFFFFFFE170 db 0, 0, 0, 0, 0, 0, 0, 0
MEMORY:00007FFFFFFFE178 db 0, 0, 0, 0, 0, 0, 0, 0

sub_2650(_BYTE *a1, _BYTE *a2)

  • 호출 전

rdi = 00007FFFFFFFE100

MEMORY:00007FFFFFFFE100 dq offset off_7FFFF7E2A000
...
MEMORY:00007FFFF7E2A000 off_7FFFF7E2A000 dq offset off_7FFFF7E24318
...
MEMORY:00007FFFF7E24318 off_7FFFF7E24318 dq offset off_7FFFF7D4FA30
...
MEMORY:00007FFFF7D4FA30 off_7FFFF7D4FA30 dq offset unk_89485355FA1E0FF3

rsi = 00007FFFFFFFE140

MEMORY:00007FFFFFFFE140 db 0, 0, 1, 0, 0, 0, 1, 0
MEMORY:00007FFFFFFFE148 db 1, 1, 0, 0, 0, 0, 1, 0
MEMORY:00007FFFFFFFE150 db 0, 1, 0, 0, 0, 0, 1, 0
MEMORY:00007FFFFFFFE158 db 1, 0, 0, 0, 0, 0, 1, 0
MEMORY:00007FFFFFFFE160 db 0, 0, 0, 0, 0, 0, 0, 0
MEMORY:00007FFFFFFFE168 db 0, 0, 0, 0, 0, 0, 0, 0
MEMORY:00007FFFFFFFE170 db 0, 0, 0, 0, 0, 0, 0, 0
MEMORY:00007FFFFFFFE178 db 0, 0, 0, 0, 0, 0, 0, 0
  • 호출 후

rdi = 00007FFFFFFFE100

MEMORY:00007FFFFFFFE100 db 0, 0, 1, 0, 0, 0, 1, 0
MEMORY:00007FFFFFFFE108 db 1, 1, 0, 0, 0, 0, 1, 0
MEMORY:00007FFFFFFFE110 db 0, 1, 0, 0, 0, 0, 1, 0
MEMORY:00007FFFFFFFE118 db 1, 0, 0, 0, 0, 0, 1, 0
MEMORY:00007FFFFFFFE120 db 0, 0, 0, 0, 0, 0, 0, 0
MEMORY:00007FFFFFFFE128 db 0, 0, 0, 0, 0, 0, 0, 0
MEMORY:00007FFFFFFFE130 db 0, 0, 0, 0, 0, 0, 0, 0
MEMORY:00007FFFFFFFE138 db 0, 0, 0, 0, 0, 0, 0, 0

rsi = 00007FFFFFFFE140

MEMORY:00007FFFFFFFE140 db 0, 0, 1, 0, 0, 0, 1, 0
MEMORY:00007FFFFFFFE148 db 1, 1, 0, 0, 0, 0, 1, 0
MEMORY:00007FFFFFFFE150 db 0, 1, 0, 0, 0, 0, 1, 0
MEMORY:00007FFFFFFFE158 db 1, 0, 0, 0, 0, 0, 1, 0
MEMORY:00007FFFFFFFE160 db 0, 0, 0, 0, 0, 0, 0, 0
MEMORY:00007FFFFFFFE168 db 0, 0, 0, 0, 0, 0, 0, 0
MEMORY:00007FFFFFFFE170 db 0, 0, 0, 0, 0, 0, 0, 0
MEMORY:00007FFFFFFFE178 db 0, 0, 0, 0, 0, 0, 0, 0

64바이트 크기의 배열 값이 a1에 복사됨.

이후 while(1) 루프문에 의해 계속 sub_18F0, sub_2650 함수가 호출됨.

sub_18F0(__int64 a1, _BYTE *a2) (2트)

마찬가지로 BAB9B8B715100605 값에 의해 64바이트 크기의 배열이 생성됨.

  • 호출 전

RDI = BAB9B8B715100605
RSI = 00007FFFFFFFE140

MEMORY:00007FFFFFFFE140 db 0, 0, 1, 0, 0, 0, 1, 0
MEMORY:00007FFFFFFFE148 db 1, 1, 0, 0, 0, 0, 1, 0
MEMORY:00007FFFFFFFE150 db 0, 1, 0, 0, 0, 0, 1, 0
MEMORY:00007FFFFFFFE158 db 1, 0, 0, 0, 0, 0, 1, 0
MEMORY:00007FFFFFFFE160 db 0, 0, 0, 0, 0, 0, 0, 0
MEMORY:00007FFFFFFFE168 db 0, 0, 0, 0, 0, 0, 0, 0
MEMORY:00007FFFFFFFE170 db 0, 0, 0, 0, 0, 0, 0, 0
MEMORY:00007FFFFFFFE178 db 0, 0, 0, 0, 0, 0, 0, 0

그럼, BAB9B8B715100605저 값은 그럼 어떻게 나온걸까?

main 함수 중 아래 코드, XOR과 NOR 연산시키는 반복문에 브포 걸어봄.

do
{
  v25[v32 - 1] = ~(v25[v32 - 1] ^ v25[(unsigned int)v31--]);
  v33 = v32-- == 1;
}
while ( !v33 && v32 != 1 );

1트:

어셈 코드:

.text:0000000000001F27                 xor     rcx, [rbp+rdi*8-8]

실행 전

  • rcx = DEADBEEF1337C0DE
  • [rbp+rdi*8-8] = 000055555556C068
MEMORY:000055555556C068 dq offset unk_5152535455565758

실행 후

  • rcx = 8FFFEDBB46619786

어셈 코드:

.text:0000000000001F2C                 not     rcx

실행 후

  • rcx = 70001244B99E6879

2트:

어셈 코드:

.text:0000000000001F27                 xor     rcx, [rbp+rdi*8-8]

실행 전

  • rcx = 0x45464748ABADBABE
  • [rbp+rdi*8-8] = 000055555556C060
MEMORY:000055555556C060 dq offset unk_DEADBEEF1337C0DE

실행 후

  • rcx = 9BEBF9A7B89A7A60

어셈 코드:

.text:0000000000001F2C                 not     rcx

실행 후

  • rcx = 641406584765859F

3트:

어셈 코드:

.text:0000000000001F27                 xor     rcx, [rbp+rdi*8-8]

실행 전

  • rcx = 0x0000000041424344
  • [rbp+rdi*8-8] = 000055555556C058
MEMORY:000055555556C058 dq offset unk_45464748ABADBABE

실행 후

  • rcx = 0x45464748EAEFF9FA

어셈 코드:

.text:0000000000001F2C                 not     rcx

실행 후

  • rcx = 0xBAB9B8B715100605

여기서 BAB9B8B715100605 값이 나왔다.

즉, 0x0000000041424344와 45464748ABADBABE이 XOR하고 NOT연산되어 나온것.

>>> hex(~(0x0000000041424344 ^ 0x45464748ABADBABE) & 0xffffffffffffffff)
'0xbab9b8b715100605'

XOR과 NOT 연산 반복문이 끝나면, 아래 값들이 sub_18F0 호출전 RDI로 지정됨.

MEMORY:000055555556C050 dq offset unk_41424344
MEMORY:000055555556C058 dq offset unk_BAB9B8B715100605
MEMORY:000055555556C060 dq offset unk_641406584765859F
MEMORY:000055555556C068 dq offset unk_70001244B99E6879
MEMORY:000055555556C070 dq 0

0x000000004142434445464748abadbabedeadbeef1337c0de5152535455565758

8바이트씩 나누면 다음과 같은데, 각각 a, b, c, d로 명명하겠음.

  • 0x0000000041424344 → a
  • 0x45464748abadbabe → b
  • 0xdeadbeef1337c0de → c
  • 0x5152535455565758 → d

아래와 같이 계산되었다고 볼 수 있음.

0x0000000041424344 → 0x0000000041424344

0xBAB9B8B715100605hex(~(a ^ b) & 0xffffffffffffffff)

0x641406584765859Fhex(~(b ^ c) & 0xffffffffffffffff)

0x70001244B99E6879

hex(~(c ^ d) & 0xffffffffffffffff)

재구현

32바이트 크기의 매개변수값이 XOR/NOT 연산되어, 64바이트 배열들이 4번 나오는 코드를 재구현시키면 아래와 같음.

sub_18F0 함수는 64개 비트 저장할 리스트 생성하고, n번째 비트를 추출하여 저장시킴.

  • barcode_reimpl.py
value = 0x000000004142434445464748abadbabedeadbeef1337c0de5152535455565758

hex_str = f"{value:064x}"
a = int(hex_str[0:16], 16)
b = int(hex_str[16:32], 16)
c = int(hex_str[32:48], 16)
d = int(hex_str[48:64], 16)

print(f"a = 0x{a:016x}")
print(f"b = 0x{b:016x}")
print(f"c = 0x{c:016x}")
print(f"d = 0x{d:016x}")

_a = a
_b = ~(a ^ b) & 0xffffffffffffffff
_c = ~(b ^ c) & 0xffffffffffffffff
_d = ~(c ^ d) & 0xffffffffffffffff

a=_a
b=_b
c=_c
d=_d

print("XOR/NOT loop calculated")
print(f"a = 0x{a:016x}")
print(f"b = 0x{b:016x}")
print(f"c = 0x{c:016x}")
print(f"d = 0x{d:016x}")

def sub_18F0(a1: int):
    a2 = [0] * 64 
    for i in range(64):
        a2[i] = ((a1 >> i) & 1)  # i번째 비트를 추출하여 저장

    return a2

def pretty_print(bits: list[int]):
    output = ""
    for i in range(64):
        if i % 8 == 0 and i != 0:
            output += "\n"  # 8비트마다 줄바꿈
        output += "*" if bits[i] else " "
    print(output)

for val in (a, b, c, d):
    r = sub_18F0(val)
    pretty_print(r)
  • Result
PS C:\Users\seo\Desktop\핵테온\핵테온_2025\barcode> python3 .\barcode_reimpl.py
a = 0x0000000041424344
b = 0x45464748abadbabe
c = 0xdeadbeef1337c0de
d = 0x5152535455565758
XOR/NOT loop calculated
a = 0x0000000041424344
b = 0xbab9b8b715100605
c = 0x641406584765859f
d = 0x70001244b99e6879
  *   * 
**    * 
 *    *
*     *




* *
 **
    *
* * *
*** ** *
   *** *
*  *** *
 * *** *
*****  *
* *    *
* *  **
***   *
   ** *
 **
  * *
  *  **
*  ****
   * **
 ****  *
*  *** *
  *   *
 *  *

    ***

solve.py

  1. 먼저 flag.barcode 파일을 파싱하여 8바이트 align 시켜 각 배열로 저장. (barcode_array 2차원 리스트 생성됨)
  2. calculated_val 변수를 통해 인덱스 별로 0x0~0xFF 범위의 한 바이트씩 바꿨을때, get_star_result 결과의 한 배열과 같을 경우, 다음 인덱스 진행.
def parse_barcode_file(filename):
    result = []
    with open(filename, 'r', encoding='utf-8') as f:
        lines = f.readlines()

    for line in lines:
        line = line.rstrip('\n')
        # 빈 줄이면 8개의 0으로 채운 행 추가
        if not line.strip():
            result.append([0] * 8)
            continue

        row = []
        for ch in line:
            if ch == '*':
                row.append(1)
            elif ch == ' ':
                row.append(0)
        result.append(row)

    return result

barcode_array = parse_barcode_file('flag.barcode')
# print(barcode_array)

def edit_byte(v: int, idx: int, b: int, size: int = 32) -> int:
    """
    v      : 수정할 정수
    idx    : 0부터 시작하는 바이트 인덱스 (0 = 최상위 바이트)
    b      : 대체할 새 바이트 값 (0–255)
    size   : 전체 바이트 길이 (기본 32바이트)
    """
    ba = bytearray(v.to_bytes(size, 'big'))
    ba[idx] = b & 0xFF
    return int.from_bytes(ba, 'big')

def get_star_result(value):    
    hex_str = f"{value:064x}"
    a = int(hex_str[0:16], 16)
    b = int(hex_str[16:32], 16)
    c = int(hex_str[32:48], 16)
    d = int(hex_str[48:64], 16)

    _a = a
    _b = ~(a ^ b) & 0xffffffffffffffff
    _c = ~(b ^ c) & 0xffffffffffffffff
    _d = ~(c ^ d) & 0xffffffffffffffff

    a=_a
    b=_b
    c=_c
    d=_d

    def sub_18F0(a1: int):
        a2 = [0] * 64 
        for i in range(64):
            a2[i] = ((a1 >> i) & 1)

        return a2

    all_data = []
    for val in (a, b, c, d):
        r = sub_18F0(val)
        all_data += r

    grouped = [all_data[i:i+8] for i in range(0, len(all_data), 8)]
    return grouped

def get_a_b_c_d(value):
    value = f"{calculated_val:064x}"
    while len(value) < 64:
        value = '0' + value
    a = int(value[0:16], 16)
    b = int(value[16:32], 16)
    c = int(value[32:48], 16)
    d = int(value[48:64], 16)
    return a, b, c, d

value, a, b, c, d = 0, 0, 0, 0, 0
calculated_val = value

def decrypt_hex(start_idx, end_idx):
    global calculated_val

    for i in range(8):
        for j in range(0x0, 0x100):
            calculated_val = edit_byte(calculated_val, end_idx - i, j)
            star_group = get_star_result(calculated_val)
            if(star_group[i + start_idx] == barcode_array[i + start_idx]):
                break

decrypt_hex(0, 7)
decrypt_hex(8, 15)
decrypt_hex(16, 23)
decrypt_hex(24, 31)

a, b, c, d = get_a_b_c_d(calculated_val)
print(f"0x{calculated_val:064x}")

Result

PS C:\Users\seo\Desktop\핵테온\핵테온_2025\barcode> python3 .\solve.py
0x000202027e027e00ff83ffff83ff83ff003e424202424000fffdffcfffff83ff
태그: