본문 바로가기

2. Reversing (리버싱)/1) Write UP

[2022.10.08] R4 - crackme#3, crackme#4, crackme#5 문제 풀이

일시: 2022.10.08

스터디원: 정현수, 엄설인, 유예지, 이유빈

 

활동내용: 도서 [리버싱 입문] 3장, abex crackme #3 ~ #5예제 개별 학습 후 피드백 및 질의응답

 

사용 환경: VirtualBox(가상환경), Window 7, Ollydbg(분석 프로그램)

 

# abex crackme 번째 예제

프로그램 처음 실행 화면)

올리디버거에 들어가서 코드 분석을 해보자

 

3가지 부분에서 프로그램에서 출력되는 메시지들이 나온 코드 부분들이라는 것을 있다.

 

주소 ‘0040102A’ ‘CreateFileA’명령어 존재하여 시작지점이라는 것을 있다.

 

주소 ‘00401046’에서는 결과값을 EAX레지스터에 저장하고 파일크기가 12(16진수)인지 확인하는 역할을 한다.

 

구조 분석)

주소 ‘00401025’에서 Filename “abex.l2c” 지정 되어있는 것을 보아 관련이 있을 것이라고 유추해볼 있다. 하지만, 가상 컴퓨터 내에 제목을 가진 파일은 존재하지 않기 때문에 메모장을 이용하여 ‘abex.l2c’파일을 만들어 것이다.

 

10개의 임의의 숫자를 입력하여 저장해보자.

, 모든 파일로 해주어야 인식하므로 점을 유의해야 한다!!!

 

처음에 파일을 찾지 못했다는 문구가 떴기 때문에 파일이름인 “abex.l2c”라는 이름으로 파일크기 10바이트로 하여 같은 위치에 저장한다.

* (파일크기가 10바이트=10 숫자 삽입)

 

파일 유효성 검증하는 부분에 브레이크포인트(F2) 설정한 실행(F9)하여 보자.

후부터 올리디버거가 방금 만든 ‘abex.l2c’파일을 사용하고 있기 때문에 만든 파일을 수정하여 때에는 올리디버거 프로그램의 창을 닫았다가 고친 다시 실행하는 것에 유의해야 한다.

 

브레이크 포인트에서 프로그램 실행이 멈춘다는 것은 바로 이전 주소의 명령어까지 실행이 완료되었다는 의미이다.

 

다시 한번 실행을 눌러 브레이크포인트 이후의 코드들을 실행시켜보면 이러한 결과가 나오게 된다.

 

이제 코드를 분석하여 보자.

JNZ ZF(Zero Flag) 0이거나 앞의 연산 결과가 0 아니면 점프하는 명령어이기 때문에 우리는 ZF 없으므로 앞의 연산 결과가 0 아니게 된다면 주소 00401060 점프하여 실행되게 되는 것이다.

 

Registers( 링크) 부분을 보면 EAX A 되어 있어, 0 아닌 것을 있다.

 

그렇기 때문에 주소가 00401060 속한 “The found file is not a valid keyfile!”이라는 문구가 출력되게 되는 것이다.

 

이를 해결하기 위해 직접 만든 파일의 내용을 바꿔보자.

임의적으로 ‘a’ 바꾸고 다시 한번 브레이크포인트까지 실행해보았다

EAX값이 1 나왔다는 것을 있다.

소스코드와 지금까지 했던 것을 토대로 생각하여 보면, 입력한 글자의 크기와 12 비교한다는 것을 유추해낼 있다. 소스코드들은 16진수로 나타내기 때문에 16진수인 12 우리가 보통 사용하는 10진수로 바꿔낸다면, 18이라는 값이 나오게 된다. A 18 입력하는 것으로 수정해서 다시 한번 실행시켜보자.

 

“Yep, keyfile found!”라는 문구가 나오면 성공이다.

숫자로 하다가 ‘a’라는 문자로 바꿔서 성공했지만, 숫자를 임의적으로 18개를 입력하여 실행해봐도 똑같은 결과값을 얻게 된다.

 

 

# abex crackme 번째 예제

프로그램 처음 실행 화면)

abexcm4.exe를 실행시켜보면 일련번호를 입력하는 창이 나온다. 임의의 숫자를 입력하면 아래에 <Registered>버튼이 비활성화된 상태로 나온다. 프로그램을 분석하여 맞는 일련번호를 찾아 입력하고 <Registered> 버튼이 활성화되며, 누르게 되면 성공 메시지를 보여주는 창이 나오면 성공이다. , 풀고자 하는 문제는 시리얼 번호가 맞을 때 ‘Registered’버튼이 활성화되는 프로그램인 것이다.

 

 

프로그램 분석)

EAX, ECX가 스택으로 PUSH 된다. 함수로 전달되는 인수임을 알 수 있다.

__vbaStrCmp() 함수의 실행 결과는 EAX 레지스터에 담기고 다양한 연산을 통해 결과가 분석된다.

(__vbaStrCmp(): 문자열 비교하는 함수)

 

분석 결과는 DI 레지스터에 담기고, 이 값을 비교하여 같을 경우에 점프한다.

 

이 프로그램은 오류 메시지를 먼저 확인할 수 없으므로 문자열 검색을 통해서는 분석의 실마리를 찾기 어렵다. 그래서 API검색을 이용하여 일련번호는 문자열 비교 함수를 많이 사용하기 때문에 모듈에서 호출하는 API 중에서 비교함수를 찾아볼 것이다.

 

앞서 분석할 때 본 __vbaStrCmp()함수를 찾아 엔터를 누르게 되면 코드 영역에 해당 함수가 있는 위치로 이동하게 된다.

 

이 주위에 비교 구문 등 다양한 코드를 확인할 수가 있는데, 화면 기준으로 아래에서 2번째에 있는 ‘0040232E’ 주소를 보면 ‘TEST DI, DI’가 존재한다. 이것은 DI 레지스터 값을 확인하여 ZF(Zero Flag)를 설정하는 명령어이다. 밑에 있는 ‘00402331’주소에 있는 ‘JE SHORT crackme4.00402371’은 앞의 ZF 값에 따라 주소 ‘00402371’에 점프하는 명령어이다.

* (JE명령어: 비교하는 값이 같을 경우 점프, ZF=1)

 

점프문이 어떤 역할을 하는지 알아보기 위해 브레이크포인트를 사용하고 프로그램을 다시 시작하여 실행해보자

 

처음처럼 일련번호 입력창이 나오는데, 임의의 숫자인 ‘9’를 입력하자마자 브레이크포인트가 설정된 주소에서 멈추게 된다.

 

Registers (퀵 링크)창에서 Z1로 되어있는 것을 0으로 바꿔주어 점프를 하지 않고 계속 시행되게 만들어준 다음, 다시 시행버튼(F9)을 눌러본다.

* (Z=ZF(Zero Flag))

 

<Registered>버튼이 활성화가 되며, 클릭하게 되면 성공 문구가 뜨게 된다.

 

다른 방법)

주소 ‘0040230D’를 보게 되면 ‘__vbastrCmp’가 있는 것으로 보아 ECX값을 비교하는 것을 알 수 있다. 이를 브레이크포인트(F2)를 설정해서 실행을 하여 임의의 시리얼 값을 입력해보자.

입력하는 순간 브레이크 포인트에서 멈추게 되면서 시리얼 값을 입력하는 창이 닫히게 된다. 이 때 화면이 바뀌는데 Registers부분을 확인해보자.

 

ECX 값에 유니코드 “2244420”이 생겨난 것을 알 수 있다. 프로그램을 다시 실행해서 저 값을 입력해보자.

원하는 창을 볼 수 있으며 이 방법으로도 문제 해결을 성공하게 된다.

 

 

# abex crackme 다섯 번째 예제

프로그램 처음 실행 화면)

시리얼 번호를 입력하여 문제를 해결하는 문제이다.

 

 

구조 분석)

파일 시스템 정보와 볼륨 정보를 가져와서 일련번호를 만들기 위한 입력 값으로 사용하는 것을 알 수 있다.

또한, ‘004010A3’주소에 보면, 주소 ‘0040225C’에 있는 데이터가 일련번호를 만드는 데 사용이 되는 것을 알 수 있다.

 

파일 시스템 정보와 프로그램 내부에 들어 있는 문자열을 결합하여 만든 새로운 문자열을 반복문을 통해 다른 문자열로 변형한다.

 

파일 시스템 정보와 프로그램 내부에 들어있는 문자열들을 결합하여 일련번호를 생성한다.

 

생성한 일련번호와 사용자가 입력한 값이 맞는지 비교하여 확인하고, 성공유무에 대한 메시지를 출력한다.

 

 

문제 해결)

일단 프로그램을 그냥 실행시켜보고, 아무 값이나 입력하여 값을 집어넣어봤는데, 역시나 실패 메시지가 출력되었다

 

코드 부분을 보다가 에러 출력에 관련된 코드가 있어서 브레이크를 걸고 한번 다시 프로그램을 실행시켜보았다.

 

똑같은 방법으로 값을 입력하였더니, 아까와는 다른 화면이 출력되는 것을 확인할 수 있다.

여기서 ‘String2’는 방금 입력한 기본 시리얼 값이 들어가 있는 것을 확인할 수 있다.

주소 ‘004010FC’를 보면, CMP명령어를 이용하여 String2String1을 비교하는 것을 알 수 있다. 그렇기 때문에 String1은 프로그램의 진짜 시리얼 값이라는 것으로 유추할 수가 있다.

 

문제 5에서 성공하는 메시지를 출력되는 것을 볼 수 있다.