Reversing Basic Challenge #6

Static analysis in IDA of a routine that checks user input character by character.

2026.08.18 Reversing original post

문제 개요

이번 문제는 실행 파일을 IDA로 분석하여 올바른 입력값을 찾아내는 Reverse Engineering 문제이다. 프로그램은 사용자로부터 문자열을 입력받은 뒤, 내부 검증 함수를 통해 입력값이 올바른지 확인한다. 입력값이 맞으면 Correct 를 출력하고, 틀리면 Wrong 을 출력한다.

main 함수 분석

IDA에서 main 함수를 확인하면 다음과 같은 코드 구조를 볼 수 있다.

int __fastcall main(int argc, const char **argv, const char **envp)
{
    char v4[256];  // [rsp+20h] [rbp-118h] BYREF

    memset(v4, 0, sizeof(v4));
    sub_1400011B0("Input : ", argv, envp);
    sub_140001210("%256s", v4);

    if ( (unsigned int)sub_140001000(v4) )
        puts("Correct");
    else
        puts("Wrong");
    return 0;
}

위 코드를 보면 프로그램은 먼저 v4 라는 256바이트 크기의 버퍼를 생성하고, memset 을 이용해 전체를 0으로 초기화한다. 그 후 “Input : ” 이라는 문자열을 출력하고, sub_140001210("%256s", v4); 를 통해 사용자 입력을 v4 에 저장한다.

가장 중요한 부분은 다음 코드이다.

if ( (unsigned int)sub_140001000(v4) )
    puts("Correct");
else
    puts("Wrong");

즉, 입력값 v4 가 sub_140001000 함수로 전달되고, 이 함수가 1을 반환하면 Correct, 0을 반환하면 Wrong 이 출력된다. 따라서 핵심은 sub_140001000 함수가 입력값을 어떻게 검증하는지 분석하는 것이다.

검증 함수 분석

IDA에서 sub_140001000 함수를 확인하면 다음과 같은 코드가 보인다.

__int64 __fastcall sub_140001000(__int64 a1)
{
    int i;  // [rsp+0h] [rbp-18h]

    for ( i = 0; (unsigned __int64)i < 0x12; ++i )
    {
        if ( byte_140003020[*(unsigned __int8 *)(a1 + i)] != byte_140003000[i] )
            return 0LL;
    }
    return 1LL;
}

이 함수는 입력값의 앞부분 18바이트를 검사한다. 여기서 0x12 는 10진수로 18이다. 즉, 반복문은 18번 실행된다. 검증 조건을 해석하면 다음과 같다.

byte_140003020[input[i]] == byte_140003000[i]

만약 하나라도 다르면 즉시 0을 반환하고, 모든 18바이트가 조건을 만족하면 1을 반환한다. 따라서 입력값을 찾기 위해서는 byte_140003000 의 각 값이 byte_140003020 배열의 몇 번째 인덱스에 위치하는지 찾아야 한다. 그 인덱스 값을 문자로 변환하면 정답 문자열이 된다.

풀이 아이디어

검증 함수의 조건을 반대로 생각하면 다음과 같다.

input[i] = index of byte_140003000[i] in byte_140003020

즉, byte_140003000[i] 값이 byte_140003020 배열 안에서 몇 번째 위치에 있는지 찾으면 된다. 예를 들어, 만약 byte_140003000[0] 값이 0x00이고 byte_140003020 배열에서 0x00이 0x52번째 위치에 있다면, 첫 번째 입력 문자는 ASCII 0x52, 즉 ‘R’ 이 된다. 이 과정을 18번 반복하면 전체 정답 문자열을 얻을 수 있다.

IDA의 Script command 창에서 Scripting language 가 IDC 로 되어 있었기 때문에, 다음과 같은 IDC 코드를 작성했다. 사실 IDC 코드 못 짜서 지피티한테 로직 설명하고 시켰다.

auto target, table, answer, i, b, j;

answer = "";
for (i = 0; i < 0x12; i++) {
    b = Byte(0x140003000 + i);
    for (j = 0; j < 0x100; j++) {
        if (Byte(0x140003020 + j) == b) {
            answer = answer + sprintf("%c", j);
            break;
        }
    }
}
Message("%s\n", answer);