Replace

Patching the compare instruction so any input is accepted, which reveals the stored password.

2026.08.18 Reversing original post

프로그램을 켜고 확인해보면, 입력을 받고 Check 버튼을 누르면 맞는지 아닌지를 확인하는 프로그램인 걸 알 수 있습니다. 이러한 방식의 문제는 그 패스워드가 플래그일 것이라는 걸 암시합니다. 일단 메인 함수와 문자열 찾기 방법을 통해 메인 코드에 진입합니다.

Figure 1

처음에는 00401071 의 점프문을 무조건적으로 참으로 만들어서 correct 문구를 띄워봅니다. 하지만 그 방식으로는 플래그를 알아낼 수 없다는 걸 깨달을 수 있습니다.

프로그램을 일단 실행시켜보고 12345 를 넣습니다. 실행을 시켜보면 다음과 같이 eax 값을 004084d0 에 저장하는데, 이 값은 16진수로 3039 입니다.

eax = 0x004084d0 = 0x3039

Figure 2

그 후 해당 함수로 이동하고 (40466F), 그곳에서 4084D0 의 값을 두 번 증가시킵니다.

eax = 0x3039 (12345)
0x004084d0 = 0x3039 + 2 = 0x303B

계속 실행시켜보면 해당 부분에서 또 연산이 있습니다 (ret 때문에). eax 는 1 증가시키고 004084d0 의 값은 601605c7 만큼 증가시킵니다.

eax = 0x3039 + 1 = 0x303a
0x004084d0 = 0x3039 + 2 + 0x601605c7

또 순서대로 해당 부분을 다시 거치면서 다시 한번 4084D0 의 값을 증가시킵니다.

eax = 0x303a
0x004084d0 = 0x3039 + 2 + 0x601605c7 + 1

Figure 3

이후 eax 값을 초기화하고 404690 으로 분기가 된다.

Figure 4

404690 주소에서는 4084D0 의 값을 DWORD 크기만큼 eax 에 저장한다 (60163604 임). 이후 404689 를 호출하여 INC 를 통해 2를 더해서 60165CA 로 만들어 4084D0 에 저장한다. 호출된 주소는 처음의 오류가 발생했던 지점이다.

40466F 에서 발생하는 오류는 결국 eax 에 정상적인 주소가 들어가지 못하였기에 생긴 오류이다. 따라서 정상적으로 작동을 한다면, eax 에 NOP 이 들어갈 것이다.

Figure 5

오류가 발생한 이후 스택 상태를 확인하였다. 스택 상태를 보니, 404672 에서 return 이 될 때 리턴할 주소는 4046AE 주소였다. 4046AE 주소로 정상적으로 복귀했을 경우, 해당 위치 이후의 코드가 실행되면서 eax 값이 1만큼 증가하게 된다.

이후 다시 40466F 주소를 호출하게 되는데, 이 부분은 eax 에 들어 있는 값을 주소처럼 사용하여 특정 값을 메모리에 저장하는 루틴으로 보인다. 앞서 발생했던 오류의 원인은 eax 에 정상적인 주소가 들어가지 못한 상태에서 해당 루틴이 실행되었기 때문이며, 정상적으로 동작하는 경우 eax 에는 유효한 주소가 들어가게 된다. 이때 해당 주소에 NOP(0x90) 이 저장되도록 설계된 것으로 보이며, 이러한 NOP 저장이 정상적으로 수행되면 함수는 ret 을 통해 다시 호출 지점으로 복귀하게 된다.

이후 실행 흐름을 따라가다 보면 4046BE 주소에서 pop eax 명령이 실행되는 것을 확인할 수 있는데, 이 명령은 eax 값을 사용하기 위한 목적이라기보다는 스택에 남아 있는 값을 정리하기 위한 용도로 사용된 것으로 보인다. 실제로 스택을 확인해보면 이전 단계에서 남아 있던 40469F 주소가 스택에 존재하고 있었고, 이 값이 pop eax 를 통해 제거되면서 스택 상태가 정상화된다.

스택 정리가 완료된 이후에는 4046C4 주소에 위치한 점프문을 통해 실행 흐름이 401071 주소로 분기된다. 이 401071 주소는 처음에 강제로 분기시켜 Correct 문구를 출력했던 위치로, 정상적인 조건을 만족했을 경우에만 도달할 수 있는 루틴이다. 즉, 앞선 연산과 스택 정리 과정이 모두 정상적으로 수행되었을 때에만 최종적으로 Correct 가 출력되는 구조임을 알 수 있다.

내부 연산 과정을 추적해보면 입력값에 2를 더하고, 0x601605C7 을 더한 뒤 다시 1과 1을 더하는 과정을 거치며, 이 최종 결과가 0x00401071 이 되어야만 분기 조건을 만족하게 된다. 이걸 식으로 표현하면:

x + 2 + 0x601605C7 + 1 + 1 = 0x00401071
x = 0xA02A0AA6
  = 2687109798   (10진수)

실제로 해당 값을 입력하면 Correct 문구가 출력되는 것을 확인할 수 있었고, 결과적으로 이 값이 플래그다.

Figure 6