본문 바로가기

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

[2022.10.01] R4 - crackme#1, crackme#2 문제 풀이

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

활동 내용: 어셈블러 명령어 암기 시험, 도서 [리버싱 입문] 2장, abex crackme #1, #2 예제 개별 학습 후 피드백

# 어셈블러 명령어 종류
1) 데이터 이동
- MOV : 데이터 복사
- MOVZX : 0을 확장하여 데이터 복사
- MOVSX : 부호 확장하여 데이터 복사
- LEA : 주소 복사
2) 산술 연산자
- ADD : 덧셈
- SUB : 뺄셈
- MUL : 부호 없는 곱셈
- IMUL : 부호 있는 곱셈
- DIV : 부호 없는 나눗셈
- IDIV : 부호 있는 나눗셈
- INC : 1 증가
- DEC : 1 감소
- NEG : 부호 반전
3) 부울 연산자
- AND : 둘 다 참이어야 참이다.
- OR : 둘 중에 하나만 참이어도 참이다.
- XOR : 배타적 OR 연산 (다르면 1, 같으면 0)
4) 분기 명령어
- CMP : 비교
- JMP: 점프
- JE : 같을 경우 점프 (Jump Equal)
- JNE : 다를 경우 점프 (Jump Not Equal)
- JZ : 0일 경우 점프 (Jump Zero)
- JNZ : 0이 아닐 경우 점프 (Jump Not Zero)
- JA : 앞의 값이 크면 점프 (Jump Above)
- JB : 뒤의 값이 크면 점프 (Jump Below)
5) 시프트 연산자
- SHL : 왼쪽으로 비트를 이동하고 오른쪽 공간은 0으로 채운다. 곱셈과 관련. =SAL
- SHR : 오른쪽으로 비트를 이동한다. 나눗셈과 관련. =SAR
6) 스택 연산자
- PUSH : 데이터를 스택에 저장
- POP : 스택에서 데이터 꺼냄
- PUSHAD : 레지스터 백업 용도 -> PUSH ALL
- POPAD : 레지스터 복구
7) 기타 연산자
- CALL : 서브루틴(함수) 호출
- RETN : 복귀
- TEST : 테스트

# abex' crackme 첫 번째 예제

본 문제를 풀기 전, crackme 문제 같은 경우에는 악성코드인 것도 있기 때문에 가상환경에서 실행을 시켜주어야 한다.
이때 가상머신은 VirtualBox 내 Window 7 버전을 사용하였다. Ollydbg로 분석을 하였다.

abex crackme #1을 실행하게 되면 Make me think your HD is a CD-Rom. -> Nah... This is not a CD-ROM Drive!
순으로 두 개의 팝업창을 볼 수 있다.
우리가 하려는 크랙은 프로그램에서 '확인' 을 클릭하면 'Ok, I really think that your HD'가 메세지 박스로 출력되게 하는 것이다. 즉, 프로그램을 실행했을 때 하드디스크가 CD롬으로 인식되도록 변경하는 것이다.

먼저, 소스 분석을 해보면 CMP 명령어는 주어진 두 값을 비교하고, JE 는 조건 분기로 ZF가 1이면 점프한다.
<MessageBoxA>호출과 <GetDriveType> 호출이 있는데 <MessageBoxA>를 호출할 시, 팝업창이 뜨게 된다.
주소 00401024에는 CMP EAX, ESI 00401026에는 JE SHORT abex' _cr. 0040103D로 나타나 있는데,
이를 해석해보면 EAX와 ESI를 비교하여 두 값이 같다면 0040103D로 점프하라는 뜻이다.
하지만, 주소 0040101D ~ 00401024를 보면 절대 EAX, ESI가 같아질 수가 없다. 따라서 프로그램을 있는 그대로 실행 시킬 경우 0040103D로 점프를 하지못하게 되고 'Nah... This is not a CD-ROM Drive!' 메세지 창만 계속 뜨게 된다.

문제를 해결하기 위한 방법은 두 가지가 있다.
첫 번째는, JE를 JMP로 바꾸는 것이다.
JE는 같으면 점프라는 조건을 가진 점프이지만, JMP는 조건 없이 그냥 점프를 하는 어셈블리 명령어이다.
따라서, 이를 바꿔주면 우리가 원하는 메세지 박스를 출력할 수 있을 것이다.
F9 단축키로 프로그램을 실행시킨 후,
마우스 오른쪽을 클릭하여 Assemble 메뉴를 통해 00401016 위치에 있는 JE를 JMP로 바꿔주자.

변경후 Assemble 버튼을 누르면 적용되고 빨간색 글씨로 바뀐다.
이제 단축키 F8 혹은 push 키를 이용해 한줄 한줄씩 실행 시켜보자.

조건 없이 점프를 하게 되어 우리가 원하는 Ok, I really think that your HD를 볼 수 있다.

두 번째 방법은, CMP EAX, ESI를 CMP EAX, EAX로 바꾸는 것이다.
CMP 비교 이후에 JE라는 조건 점프절이 있기 때문에 CMP로 값을 무조건 같게 만들어 버리는 것이다.
첫 번째 방법과 마찬가지로 마우스 오른쪽을 클릭해 Assemble 메뉴로 변경해준다.

그러면 우리가 원하는 창을 볼 수 있고, 문제 해결에 성공한다.

# abex' crackme 두 번째 예제

두번째 예제는 프로그램을 분석해서 사용자가 입력한 이름과 관련 있는 일련번호를 검증하는 프로그램으로 구성되어 있다. 첫번째 예제는 단순히 메세지창만 출력됐다면 이번에는 프로그램이 실행되면 사용자가 입력을 하는 창이 뜬다.  이름과 일련번호를 입력하고 check 버튼을 누르면 처리 결과를 보여주고 다시 사용자의 입력을 기다린다. 이 프로그램의 name 은 최소 4글자 이상부터 가능하기 때문에 4글자 미만으로 입력하면 에러창이 뜬다.

리버싱 입문에서 나온대로 단축키 F9로 실행을 시킨 다음 창이 뜨면 이름에는 abcd, 일련번호에는 1234를 입력한다.

check 버튼을 누르니 Nope, this serial is wrong! 이란 Wrong serial 창이 뜬다. 일단 ok를 누르고 분석을 시작해보자.


이 창을 분석하려면 일단 Wrong serial 유니코드가 포함되어 있는 위치를 찾아야한다. 마우스 오른쪽을 누르고 Search for - All referenced text strings 메뉴를 클릭하면 빠르게 텍스트의 위치를 찾을 수 있다.

Wrong serial의 위치를 찾고 소스코드를 분석해보겠다. 마우스 오른쪽을 눌러 Search for text로 Wrong을 검색해서 Wrong Serial 유니코드가 있는 위치를 찾아보자. 찾고 난 후 enter를 누르면 바로 그 위치로 이동한다.

Wrong serial 주변 함수나 내용을 한번 분석해보자. 이번 문제는 추측을 통해 문제를 풀어야한다. 

위로 더 올려보면 우리가 원하는 유니코드도 있고, TEST AX,AX 구문도 보인다.  TEST AX, AX 는 정답인지 오답인지 판단하는 역할을 한다. 따라서 결과에 영향을 미티는 EAX 레지스터 하위 비트 값을 아는 것이 중요하다.

따라서 , 일단 먼저 004032EF 주소에 F2로 breakpoint를 설정해주고 F9를 통해 실행시켜준다. 메세지 박스에 처음과 똑같이 입력 후 check를 누르면, break point 까지 실행이 될 것이다. 단축키 F8으로 004032FD까지 실행 시킨 후, 커서는 00403307에 오게한다. 00403307에서 사용된 명형어는 EAX 레지스터가 가리키는 주소에 있는 데이터를 4바이트 읽어서 'EBP-94'에 복사한다는 내용이다.

명령어 실행 전에 'EBP-94'가 가리키는 위치에 어떤 데이터가 있는지 메모리에서 확인 가능하다.

메모리에서 마우스 오른쪽을 클릭한 후 Long-Address with ASCII dump 메뉴를 선택한다.

그럼 메모리 구조가 이렇게 변한다. 다시 코드 부분에서 마우스 오른쪽을 클릭해 Follow in dump > Memory address 메뉴를 선택하면 메모리에 저장된 위치로 바로 갈 수 있다.

해당 메모리에 저장된 것은 'C5C6C7C8'인 것을 확인할 수 있다. 

또한 레지스터를 보면 EAX에 005B9C44 UNICODE "1234" 라고 되어 있는데, 이는 주소 값에 005B9C44가 저장되어 있고 일련번호 '1234'을 가리키고 있다는 것을 뜻한다.

실제로 스택을 보면 1234가 저장되어 있는 것을 볼 수 있다. (EBP주소로 변경 : 마우스 오른쪽-> Address -> Relative to EBP) 이는 우리가 입력한 일련번호 '1234'와 비슷한 위치에 나타나는 문자열 'C5C6C7C8'이 이름 'abcd'와 일치하는 일련번호라는 것을 추측할 수 있다. 따라서 사용자 입력창에 이름 abcd와 일련번호 C5C6C7C8을 입력하면 문제가 해결된다.