[Ghidra] 리버스 엔지니어링 기드라 실전 가이드 스터디 - chapter 5(level2)

2026. 1. 22. 20:46·Security/리버싱

1. level2 crackme(base64)

level 2 크랙미 디스어셈블 결과이다. 

param_2를 입력받아 encode_custom_base64로 인코딩 후에 4PpnRoanRomTze4SKPo+Zwd3IejS와 비교한다.

값이 같으면 correct가 나온다.

undefined8 main(int param_1,undefined8 *param_2)

{
  int iVar1;
  undefined8 uVar2;
  char *__s1;
  size_t __n;
  
  if (param_1 == 2) {
    __s1 = (char *)encode_custom_base64(param_2[1]);
    __n = strlen("4PpnRoanRomTze4SKPo+Zwd3IejS");
    iVar1 = strncmp(__s1,"4PpnRoanRomTze4SKPo+Zwd3IejS",__n);
    if (iVar1 == 0) {
      puts("Correct!!");
      uVar2 = 0;
    }
    else {
      puts("Wrong...");
      uVar2 = 1;
    }
  }
  else {
    printf("%s flag_string_is_here\n",*param_2);
    uVar2 = 0xffffffff;
  }
  return uVar2;
}

 

 


2. Base64 

Base64란?

Base64는 8비트 이진 데이터를 공통 ASCII 문자로 변환하는 인코딩 방식이다. 원리는 8비트 버퍼 3개(24비트)를 모아 6비트씩 4개로 나누어 표현하는 것이다. 이때 3바이트 단위로 떨어지지 않아 남는 공간은 등호(=)를 사용해 패딩한다.

주된 사용 목적은 시스템 간 데이터 전송 시 깨짐을 방지하는 안전성 확보에 있지만 3바이트를 4바이트로 변환하므로 크기가 약 33% 증가한다는 단점이 있다.

표준 규격에서는 +와 /를 사용하지만, URL 등 특수문자 처리가 까다로운 환경에서는 이를 -와 _로 대체하거나 패딩(=)을 생략하는 변형 방식을 사용하기도 한다.

 

E1L을 RTFM으로 인코딩(https://namu.wiki/w/BASE64)

 


3. encode_custom_base64 분석

void * encode_custom_base64(char *input_str)

{
  lVar6 = *(long *)(in_FS_OFFSET + 0x28);
  i = 0;
  //할당할 힙 메모리 계산 인코딩하면 33%증가한 것까지 
  sVar9 = strlen(input_str);
  iVar7 = (int)((sVar9 * 8 + 5) / 6);
  iVar8 = iVar7 + 3;
  if (iVar8 < 0) {
    iVar8 = iVar7 + 6;
  }
  base64_len = (iVar8 >> 2) * 4;
  //힙 할당
  __s = malloc((long)(base64_len + 1));
  memset(__s,0,(long)(base64_len + 1));
  
  while (0 < base64_len) {
    if (base64_len < 3) {//base 64 패딩 ==
      if (base64_len == 2) { //== 2 개 
        bVar1 = input_str[i * 3];
        bVar2 = input_str[(long)(i * 3) + 1];
        bVar3 = input_str[(long)(i * 3) + 1];
        *(char *)((long)(i << 2) + (long)__s) =
             "b9V12dPGtk7BKZUD/NJeX4vxjIcERzH+pQgT5iwYAlMyCWOFfnr3Soq06L8hamsu"
             [(int)(char)((byte)input_str[i * 3] >> 2)];
        *(char *)((long)(i << 2) + 1 + (long)__s) =
             "b9V12dPGtk7BKZUD/NJeX4vxjIcERzH+pQgT5iwYAlMyCWOFfnr3Soq06L8hamsu"
             [(int)(char)(bVar2 >> 4 | (bVar1 & 3) << 4)];
        *(char *)((long)(i << 2) + 2 + (long)__s) =
             "b9V12dPGtk7BKZUD/NJeX4vxjIcERzH+pQgT5iwYAlMyCWOFfnr3Soq06L8hamsu"
             [(int)(char)((bVar3 & 0xf) << 2)];
        *(undefined1 *)((long)__s + (long)(i << 2) + 3) = 0x3d;
        base64_len = 0;
      }
      else {//=1개 
        bVar1 = input_str[i * 3];
        *(char *)((long)(i << 2) + (long)__s) =
             "b9V12dPGtk7BKZUD/NJeX4vxjIcERzH+pQgT5iwYAlMyCWOFfnr3Soq06L8hamsu"
             [(int)(char)((byte)input_str[i * 3] >> 2)];
        *(char *)((long)(i << 2) + 1 + (long)__s) =
             "b9V12dPGtk7BKZUD/NJeX4vxjIcERzH+pQgT5iwYAlMyCWOFfnr3Soq06L8hamsu"
             [(int)(char)((bVar1 & 3) << 4)];
        *(undefined1 *)((long)__s + (long)(i << 2) + 2) = 0x3d;
        *(undefined1 *)((long)__s + (long)(i << 2) + 3) = 0x3d;
        base64_len = base64_len + -1;
      }
    }
    else {
      bVar1 = input_str[i * 3];
      bVar2 = input_str[(long)(i * 3) + 1];
      bVar3 = input_str[(long)(i * 3) + 1];
      bVar4 = input_str[(long)(i * 3) + 2];
      bVar5 = input_str[(long)(i * 3) + 2];
      *(char *)((long)(i << 2) + (long)__s) =
           "b9V12dPGtk7BKZUD/NJeX4vxjIcERzH+pQgT5iwYAlMyCWOFfnr3Soq06L8hamsu"
           [(int)(char)((byte)input_str[i * 3] >> 2)];
      *(char *)((long)(i << 2) + 1 + (long)__s) =
           "b9V12dPGtk7BKZUD/NJeX4vxjIcERzH+pQgT5iwYAlMyCWOFfnr3Soq06L8hamsu"
           [(int)(char)(bVar2 >> 4 | (bVar1 & 3) << 4)];
      *(char *)((long)(i << 2) + 2 + (long)__s) =
           "b9V12dPGtk7BKZUD/NJeX4vxjIcERzH+pQgT5iwYAlMyCWOFfnr3Soq06L8hamsu"
           [(int)(char)(bVar4 >> 6 | (bVar3 & 0xf) << 2)];
      *(char *)((long)(i << 2) + 3 + (long)__s) =
           "b9V12dPGtk7BKZUD/NJeX4vxjIcERzH+pQgT5iwYAlMyCWOFfnr3Soq06L8hamsu"
           [(int)(char)(bVar5 & 0x3f)];
      base64_len = base64_len + -3;
    }
    i = i + 1;
  }
  if (lVar6 != *(long *)(in_FS_OFFSET + 0x28)) {
                    /* WARNING: Subroutine does not return */
    __stack_chk_fail();
  }
  return __s;
}

 

  • 함수는 입력된 문자열(input_str)의 길이를 기반으로 인코딩 후의 길이를 계산하고, 힙(Heap) 메모리를 할당한다.
  • 가장 중요한 특징은 표준 Base64 테이블(A-Z...)이 아닌, 커스텀 테이블을 사용한다는 점이다.
  • "b9V12dPGtk7BKZUD/NJeX4vxjIcERzH+pQgT5iwYAlMyCWOFfnr3Soq06L8hamsu"

4. PyGhidra를 사용한 풀이

파이썬 스크립트로 아래와 같이 짜면 

# -*- coding: utf-8 -*-
#@author
#@category _NEW_
#@keybinding
#@menupath
#@toolbar
#@runtime PyGhidra


#TODO Add User Code Here
import string
import base64

#기존 base64테이블
default_base64_table="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"

#커스텀 테이블에서 base64로 변경 후 디코드 
def custom_base64_decode(s, custom_table):
    s = s.translate(str.maketrans(custom_table, default_base64_table))
    return base64.b64decode(s)
    
#custom_table 가져오기
base64_custom_table_addr = toAddr(0x100e00) 
base64_custom_table_array = getBytes(base64_custom_table_addr, 64)
b64_table = ''.join([chr(b) for b in base64_custom_table_array])

#비교할 문자열 
enc = "4PpnRoanRomTze4SKPo+Zwd3IejS"

code = custom_base64_decode(enc, b64_table)

print(''.join([chr(b) for b in code]))

 

기드라 스크립트로 돌리면 아래 문자열이 나온다.

 

CyberChef로 교차 검증해보면 Th1s_1s_cu5t0m_6ase64가 나와 맞는 걸 볼 수 있다.


5. 3줄 요약

  • 이 문제는 입력값을 커스텀 Base64로 인코딩하여 특정 문자열과 비교하는 로직을 가진다.
  • 분석 결과, 표준 테이블이 아닌 하드코딩된 b9V1... 형태의 커스텀 테이블을 사용하는 것이 식별되었다.
  • 기드라 스크립트를 사용해 문제를 풀었다.

 

 

'Security > 리버싱' 카테고리의 다른 글

[Ghidra] 리버스 엔지니어링 기드라 실전 가이드 스터디 - chapter 5(level4-GO바이너리)  (0) 2026.01.24
[Ghidra] 리버스 엔지니어링 기드라 실전 가이드 스터디 - chapter 5(level3)  (0) 2026.01.24
[Ghidra] 리버스 엔지니어링 기드라 실전 가이드 스터디 - 기드라 취약점 3  (0) 2026.01.23
[Ghidra] 리버스 엔지니어링 기드라 실전 가이드 스터디 - chapter 5(level1)  (0) 2026.01.22
[Ghidra] 리버스 엔지니어링 기드라 실전 가이드 스터디 - 00  (0) 2026.01.04
'Security/리버싱' 카테고리의 다른 글
  • [Ghidra] 리버스 엔지니어링 기드라 실전 가이드 스터디 - chapter 5(level3)
  • [Ghidra] 리버스 엔지니어링 기드라 실전 가이드 스터디 - 기드라 취약점 3
  • [Ghidra] 리버스 엔지니어링 기드라 실전 가이드 스터디 - chapter 5(level1)
  • [Ghidra] 리버스 엔지니어링 기드라 실전 가이드 스터디 - 00
yt_5246
yt_5246
yt5246 님의 블로그 입니다.
  • yt_5246
    yt의 공부 블로그
    yt_5246
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
    • 분류 전체보기 (61)
      • IT (1)
      • Security (11)
        • 시스템해킹 (3)
        • 리버싱 (6)
        • 암호학 (0)
        • tools (2)
      • Book (0)
      • 자격증 (3)
      • 워게임 (46)
        • DVWA (7)
        • WebGoat (4)
        • webhacking.kr (35)
      • 버그바운티 (0)
  • 인기 글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
yt_5246
[Ghidra] 리버스 엔지니어링 기드라 실전 가이드 스터디 - chapter 5(level2)
상단으로

티스토리툴바