
정적 분석
IDA로 파일 열기
문제 파일을 정적분석하기 위해 앞서 배운 IDA를 사용했다.
IDA를 실행하고, chall0.exe를 끌어넣는다.
파일이 정상적으로 열리면 다음과 같은 창이 나타난다.

위의 창에서는 문제 파일의 간략한 정보를 띄워준다.
바이너리의 아키텍처는 AMD64 (x86-64), 파일 포맷은 PE (Portable Executable) 구조라는 것을 알 수 있다.
이 정보들을 통해 본격적으로 분석하기 전, 분석에 도움이 되는 정보를 획득할 수 있다.

지금까지 과정을 성공적으로 마치면 위와 같은 창이 나타난다.
이는 바이너리에 디버깅 정보를 담고있는 심볼 경로가 존재하는데, 이를 찾아서 로드하겠냐는 질문창이다.
문제 출제자는 별도의 심볼(.pdb)을 제공하지 않았기 때문에 No를 클릭한다.
main 함수 찾기

프로그램이 로드되면 이전 예제와 마찬가지로 main 함수를 찾지 않아도 IDA가 스스로 판단한 main 함수를 보여준다.
IDA가 아무런 정보 없이 main 함수를 찾을 수 있었던 이유는 컴파일러 별 main 함수를 호출하는 패턴이 일정하기 때문이다.
rev-basic-1 문제의 경우 Visual Studio를 사용해 컴파일 되었다.
IDA는 내부적으로 Visual Studio로 프로그램이 컴파일 되었을 때 어떻게 진입점에서 main 함수를 호출하는지 패턴을 알고 있기 때문에 바로 main 함수를 찾을 수 있다.
main 함수 분석

F5를 눌러 디컴파일 된 main 함수를 분석해 보았다.
제일 먼저 v4라는 256바이트의 char 배열을 0으로 초기화한다.
이후에 sub_1400013E0 함수와 sub_140001440 함수를 호출하는데, 이 때 인자에 각각 "Input : ", "%256s" 문자열이 들어간다.
마지막으로 v4 배열을 sub_140001000 함수의 인자로 전달해 반환값이 있다면 “Correct”를, 아니라면 “Wrong” 문자열을 출력한다.
main 함수의 전체적인 구조를 분석했으니, 이제 각 함수 내부로 들어가 내부 동작을 분석했다.
main 내부 함수 분석

sub_1400013E0 함수의 코드는 위와 같다.
이 함수는 이전 실습에서 분석했던 printf 함수와 구조가 굉장히 유사하다.
먼저 _acrt_iob_func 함수를 사용해 1번에 해당하는 stdout 파일 스트림을 가져와 sub_1400012B0 함수로 전달한다.

sub_1400012B0 함수 내부에서는 _stdio_common_vfprintf 함수를 호출한다.
vfprintf 함수의 파일 스트림이 stdout이기 때문에 sub_1400013E0 함수는 printf임을 추측할 수 있다.
sub_1400013E0 함수가 printf 함수임을 알았으니 IDA에서 심볼의 이름을 변경하는 ‘n’ 단축키를 이용해 이름을 printf 로 변경했다.

분석한 함수가 어떤 함수인지 알아냈다면, 이처럼 분석한 내용을 토대로 이름을 설정하는 것이 코드를 분석하는데 더 간편하다.
지금은 연습을 위한 실습 문제를 분석하고 있지만, 추후 용량이 큰 프로그램을 분석할 때에는 같은 함수가 여러 번 호출될 때가 있다.
그렇기 때문에 미리 함수의 이름을 설정해 둔다면 더욱 깔끔한 형태의 코드로 분석할 수 있다.
main 내부 함수 분석

sub_140001440 함수 또한 printf 함수와 비슷한 형태의 코드 패턴을 가지고 있다.
하지만 _acrt_iob_func 함수를 통해 가져오는 파일 스트림이 0번으로, stdin 파일 스트림을 가져온다.
즉, 표준 입력을 사용하는 함수라는 의미이다.

위는 sub_140001300 함수 내부의 모습이다.
코드를 살펴보면, _stdio_common_vfscanf 함수를 호출하므로 sub_140001440 함수는 scanf 함수로 볼 수 있다.
프로그램을 분석하다 보면 공통된 형태의 코드 패턴을 볼 수 있다.
개발자가 모든 코드를 직접 작성하는 것이 아니기 때문에 이처럼 자주 사용되는 함수들의 패턴을 익혀둔다면 좀 더 빠른 속도로 프로그램을 분석할 수 있다.
main 흐름 파악

printf 함수와 마찬가지로 앞서 분석한 함수 이름을 scanf로 변경한 후 main 함수를 다시 보면 위와 같습니다.
rev-basic-1 프로그램은 “Input : “이라는 문자열을 화면에 출력하고 256바이트의 문자열을 v4 변수에 입력 받는다는 것을 알 수 있다.
그리고 sub_140001000 함수의 반환값을 통해 “Correct”와 “Wrong” 중 출력할 문자열을 결정한다.
따라서 sub_140001000 함수가 입력값을 검사하는 함수임을 알 수 있다.
입력값 검사 함수 분석

“Correct”를 출력하기 위해서는 sub_140001000 함수가 1을 리턴해야 함을 먼저 기억하고, sub_140001000 함수를 분석한다.
위의 창을 살펴보면, a1 인자는 우리가 입력한 값이며, 1바이트 단위로 값을 비교한다.
다수의 조건문이 존재하는데 문자열의 각 인덱스 별로 정해진 숫자와 다르다면 0을 리턴하고, 마지막 조건인 입력값의 21번째 인덱스가 0이라면 1을 리턴한다. 즉, 입력해야 하는 문자열의 각 인덱스 값이 정해져 있고 정해진 값과 모두 일치한다면 “Correct”를 출력하는 함수임을 알 수 있다.
입력값 검사 함수 분석

조건문에서 비교하는 각 숫자는 문자와 1대 1로 대응되는 아스키 코드로 변환할 수 있다.
IDA에서 숫자를 문자로 변환하는 단축키는 ‘r’ 이다.
각 숫자에 커서를 올리고 ‘r’을 누르면 숫자에서 문자로 변환하는 것이 가능하다.
위는 문자로 변환한 모습이다.
모두 아스키 코드로 변환하고 이를 이어붙이면 우리가 입력해야 하는 입력값이 될 것이다.
문자열의 끝은 NULL 문자로 0을 의미하기 때문에 마지막에 비교하는 0은 직접 입력하지 않아도 자동으로 들어가 함수의 조건을 모두 만족하게 된다.
플래그 인증
입력값이 맞는지 확인하기 위해 직접 프로그램을 실행해 입력해 보았다.

위의 창을 확인해보면, 분석한 결과대로 Correct를 출력한다.