lhywk 님의 블로그

[Dreamhack] Simple Crack Me 2 본문

Reversing/Dreamhack

[Dreamhack] Simple Crack Me 2

lhywk 2025. 12. 23. 16:52

문제

이 문제는 사용자에게 문자열을 받아 정해진 방법으로 입력값을 검증하여 correct 또는 wrong을 출력하는 프로그램이 주어집니다.

해당 바이너리를 분석하여 correct를 출력하는 입력값을 찾으세요!

문제 풀이

해당 문제의 바이너리는 elf입니다.

실행시켜 보겠습니다.

바이너리 실행

123이라는 임의값을 입력했더니 your input length is wrong x(라는 문자열이 출력됐습니다.

입력 값이 맞으면 올바른 출력 문자열이 나오겠네요.

IDA를 통해 분석 해보겠습니다.

문자열 확인

your input length is wrong x(이라는 문자열을 봤으니 그 문자열을 참조하는 곳으로 가보겠습니다.

xref

x 단축키로 해당 문자열을 참조하고 있는 주소로 갑니다.

디컴파일

디컴파일한 코드입니다.

코드를 분석해보겠습니다.

먼저 scanf로 우리의 입력값을 s1으로 받습니다.

if 문 안에 sub_4011B6 함수가 있는데 문자열의 길이를 검증하는 거 같습니다.

그 다음 조건 문 내에

sub_4011EF, sub_401263, sub_4012B0 3개의 함수가 있습니다.

그리고 최종적으로 이 함수를 거친 s1의 값을 s2의 값과 32바이트만큼 비교해 맞다면 Correct 출력입니다.

32글자를 입력했더니 이번엔 your input is wrong x( 라는 문자열이 출력되어 입력값은 32자임을 알아냈습니다.

 

큰 틀의 코드 분석은 끝났습니다.

sub_4011B6 함수부터 분석해보겠습니다.

 

sub_4011B6

sub_4011B6 디컴파일

해당 함수를 디컴파일 하면 입력값의 문자열의 길이를 리턴하고 있습니다.

 

 

sub_4011EF

sub_4011EF 디컴파일

매개변수로 받은 a2의 문자열 길이를 result 변수에 대입합니다.

그리고 64비트 정수로 v4에 대입합니다.

반복문을 32번 돌고

내부 코드는

이런식으로 구성되어 있습니다.

이 코드를 쉽게 변경 해보면

이렇게 구성해볼수 있습니다.

 

sub_401263

sub_401263 디컴파일

해당 함수는 매개변수로 입력값, a2를 받습니다.

result 변수에 a2의 값을 대입하고 반복문을 32번 돕니다.

내부 코드를 보면

이런식으로 구성되어 있습니다.

이 코드도 쉽게 변경 해보면

이런식으로 구성할 수 있습니다.

sub_4012B0

sub_4012B0 디컴파일

해당 함수도 매개변수로 a1 입력값과 a2를 받습니다.

반복문을 32번 반복하고 내부코드를 보겠습니다.

해당 코드를 쉽게 변경 해보겠습니다.

이렇게 구성할수 있습니다.

 

모든 함수의 분석이 끝났고 문제 풀이 과정을 생각해보겠습니다.

프로그램 흐름도

순서는 위 그림과 같습니다.

이를 풀어내기 위해선 이 흐름도의 연산을 역으로 수행하면 됩니다.

이때 xor 연산을 하는 sub_4011EF는 그대로 처리하면 되지만

sub_401263함수와 sub_4012B0 함수는 각각 더하는 함수, 빼는 함수기 때문에 이 연산은 역으로 처리해야 합니다.

 

s2의 값을 확인해보겠습니다.

s2 변수 값 확인

402008에 실제 값의 주소가 시작합니다.

이를 따라가 보겠습니다.

402008 배열 값 확인

402008부터 402028까지 총 32바이트의 배열 값이 존재합니다.

export data

 

매개변수 값 확인

매개변수로 들어가는 배열의 값들을 확인합니다.

 

해당 값들을 export로 가져오고 이제 파이썬으로 역연산 코드를 작성해보겠습니다.

data = bytearray([0xF8, 0xE0, 0xE6, 0x9E, 0x7F, 0x32, 0x68, 0x31, 0x05, 0xDC, 
  0xA1, 0xAA, 0xAA, 0x09, 0xB3, 0xD8, 0x41, 0xF0, 0x36, 0x8C, 
  0xCE, 0xC7, 0xAC, 0x66, 0x91, 0x4C, 0x32, 0xFF, 0x05, 0xE0, 
  0xD9, 0x91, 0x00])

param1 = bytearray([0x11, 0x33, 0x55, 0x77, 0x99, 0xBB, 0xDD])
param2 = bytearray([0xEF, 0xBE, 0xAD, 0xDE])
param3 = bytearray([0xDE, 0xAD, 0xBE, 0xEF])

def len_check(string):
    return len(string)

def xor_op(data, param1):
    result = len_check(param1)
    for i in range(32):
        data[i] = data[i] ^ param1[i % result]

def inc_op(data, param):
    result = param
    for i in range(32):
        data[i] = (data[i] + param) & 0xFF
        
def dec_op(data, param):
    result = param
    for i in range(32):
        data[i] = (data[i] - param) & 0xFF
    
xor_op(data, param1)
dec_op(data, 243)
inc_op(data, 77)
xor_op(data, param2)
inc_op(data, 90)
dec_op(data, 31)
xor_op(data, param3)

for i in data:
    print(chr(i), end='')

아까 분석했던 코드를 4가지 함수로 전부 구현해줍니다.

inc_op 함수와 dec_op 함수는 & 0xFF 연산을 하여 1바이트 만을 남깁니다.

아까 말한것처럼 역연산을 할때 xor 연산은 그대로 가지만 dec와 inc는 반대로 써서 역으로 올라갑니다.

플래그를 획득합니다.

'Reversing > Dreamhack' 카테고리의 다른 글

[Dreamhack] Check Function Argument  (0) 2025.12.26
[Dreamhack] Simple Patch Me  (0) 2025.12.24
[Dreamhack] Simple Crack Me  (0) 2025.12.23
[Dreamhack] rev-basic-8  (0) 2025.12.23
[Dreamhack] rev-basic-6  (0) 2025.12.17