심플스 Challenge에 있는 문제들을 하나씩 풀어보기로 했습니다.

물론 리버스 엔지니어링을 공부해본적이 전혀 없습니다..

친구가 하는 걸 한 두번 구경한 것 뿐이에요

풀이도 보고 검색도 하면서 차근차근 기초부터 배워나가야겠내요

이 글은 혼자서 검색도 하고 풀이도 보고 혼자 이해하기 위해서 쓰는 글입니다.

내용이 다소 먼 산으로 갔다가 돌아오기도 할 듯 하내요

 

제가 알기론 심플스가 예전엔 리버싱 관련 커뮤니티로 꽤 왕성하게 활동이 있었던걸로 알고 있는대요

아쉽게도 지금은 예전만큼의 활동은 안보이는듯 하더라구요

그래도 자료는 쉽게 구할 수 있으니 둘러보시면 좋을 듯 합니다.

http://simples.kr/Report

 

우선 심플스에 올라와있는 CrackMe L01 문제는 다음과 같습니다.

 

Down 표시는 기존 게시글에 Down 문자 바로 밑에 크랙미 파일 다운 링크가 있어서 있는겁니다.

어쨌든 문제를 보면 크랙미01의 주 핵심 API의 이름을 물어보고 있습니다.

예로 MessageBox를 적어줬내요. 저런식의 답을 원한다 이런거 아닐까 싶습니다.

그럼 CrackMe L01을 다운 받아봅니다.

 

CrackMe_L01.exe

 

이 파일이 의심스러우신분은 심플스에서 다운 받으시면 되겠습니다.

http://simples.kr/index.php?_filter=search&mid=Report&search_keyword=Crack&search_target=title&category=10705&document_srl=10828

 

다운 받아서 실행시켜보시면 정말 간단한 프로그램이라는 걸 알 수 있을껍니다.

 

            

 

대충 보면 하드를 시디롬으로 인식시켜달라는 말 같내요..

그냥 확인을 눌러버리면 '이건 시디롬이 아니야'라고 오류를 뱉고는 사라져버립니다.

 

그러면 사용법은 잘 모르지만 올리디버거를 이용해서 한 번 까(?)보겠습니다.

 

 

올리디버거로 크랙미 01을 열어보면 위 화면과 같은 내용들이 화면에 출력될 것입니다.

보면 3번 째 줄에 처음 실행시켰을 때 나왔던 메시지박스의 텍스트가 있내요

뭐가 뭔지 모르겠지만 그냥 눈으로 읽을 수 있는 것들을 쭉 내려가면서 읽어볼게요

6번 째 줄을 보면 RootPathName = "C:\" 라고 써져있습니다.

처음 봤던 메시지박스의 내용을 보고 대충 어림짐작해보면 아마 C드라이브를 시디롬으로 인식시켜야 되지 않나 싶내요.

바로 그 밑에는 빨간색으로 GetDriveTypeA 라고 쓰여져있습니다.

아직 뭔지 모르지만 일단 넘어가봅니다.

 

내려오다보면 두 번째 메시지박스의 텍스트가 있는 것을 알 수 있내요

근데 첫 번째 메시지박스의 출력내용과는 다르게 왼 쪽에 흰 줄로 묶여있는 걸 볼 수 있습니다.

묶여있는 제일 마지막 줄에는 빨간 글씨로 MessageBoxA라고 쓰여져있내요

아무래도 묶여져있는게 MessageBoxA라는 함수(표현이 맞나..)와 관련이 있어보입니다.

뭔지 궁금하니까 구글에 검색을 해봤습니다.

MessageBoxA는 Windows API 중 하나라고 하내요.

그렇다면 메시지창 하나를 띄우기 위해서 MessageBoxA라는 API를 사용한 걸 알 수 있습니다.

 

그 아래에 방금 전과 같이 MessageBoxA로 묶여있는 부분이 있는데 이 건 처음 실행했을 때 나오지 않았던 내용이내요

아마 C드라이브를 시디롬으로 인식시키는걸 성공 시키면 저 메시지가 출력되지 않을까 싶습니다.

그러고는 ExitProcess로 묶여있는 듯 보이내요.

바로 그 아래 흰 글씨로 GetDriveTypeA와 ExitProcess는 아직 어떤 역할을 하는지 모르니 일단 무시하도록 하죠.

 

일단 눈으로 볼 수 있고 읽을 수 있는 단어들만 둘러보면서 알 수 있었던 거는

API를 사용했다면 그 API가 사용하는 것들은 하나로 묶어서 보인다는 점.

그리고 C드라이브를 CD-ROM으로 인식시켜야될 것 같다는 점.

인식이 된다면 최초 실행시 못 봤던 메시지박스가 뜬다는 점.

GetDriveTypeA라는 API가 C드라이브를 가르키고 있다는 점.

대략적으로 이렇게 알 수 있겠내요.

이 4가지 단서들 중에 제가 느끼기에 중요해보이는 건 아무래도 GetDriveTypeA라는 API와 그에 관련해서

C드라이브를 시디롬으로 인식시켜야된다는게 중요하다고 느껴지내요.

여기서 유추를 해보면 C드라이브를 시디롬으로 인식시키려면 아무래도 무엇인가 비교를 해야하지 않을까 싶습니다.

아마 GetDriveTypeA라는 API를 사용하면 비교할 수 있는 어떠한 값이 나오지 않을까 싶습니다.

그럼 일단 GetDriveTypeA라는 API가 C드라이브를 가르키고 있다는게 무슨 의미인지 알아봐야겠내요.

구글링을 해보겠습니다...

...

꽤 검색을 해봤는데 한글로 글을 써놓으신 분이 거의 없더라구요..

한글로 된 책에서 찾아보지 않는 이상 정확하게 번역된 걸 찾기가 어렵지 않을까 하는 생각입니다..

그래서 그냥 MS공홈에서 제공하는 설명을 중요해보이는 리턴값에 대한 것만 캡쳐해왔습니다.

 

GetDriveTypeA라는 API를 사용했을 때 반환되는 값에 대한 내용인대요

예를 들어 API를 사용할 때 지정해준 드라이브가 뭔지 모를 때는 0의 값을 반환하내요.

영어끈이 짧아서 반환값 1에 대한건 무엇인지 해석이 안되내요..ㅠㅠ

나머지는 끈이 짧아도 충분히 알겠는데 말이죠 ..

어쨌든 이번 문제를 풀기 위해서 필요한건 C드라이브를 지정했을 때 반환값과

CD-ROM을 지정했을 때 반환값이 필요할 것 같습니다.

CD-ROM일 때는 반환값이 5라는 건 쉽게 알 수 있습니다.

그리고 C드라이브 같은 경우는 아무래도 이동식 디스크 같이 유동적인 드라이브가 아니라

고정적으로 물려있는 드라이브기 때문에 DRIVE_FIXED라는 반환값을 가지지 않을까 싶습니다.

물론 FIXED말고 다른 값을 가질만한게 없어보이긴 합니다.

그럼 이제 GetDriveTypeA라는 API를 사용했을 때 C:\나 D:\같은 고정적인 드라이브에 대한 반환값이 3이라는 것과

CD-ROM의 반환값이 5라는 것을 알았습니다.

아무래도 이 값들이 제일 중요한듯 한데 아마 문제의 답은 이 API가 아닐까 싶습니다.

 

이제 다시 OllyDbg로 돌아와봅니다.

반환값을 알았으니 이 반환값을 비교하는 걸 찾아야되겠내요

어찌 찾아야하나 .. 이리저리 찾다보니 이젠 .. 어셈블리어를 봐야되나보더군요..

아는게 하나도 없지만 눈치코치로 한 번 봐보겠습니다.

올리디버거 화면을 보면 왼쪽에 화면을 제일 크게 차지하고 있는 곳에 3번 째칸..음 사진으로 볼게요..

아까 썼던 이미지지만 보겠습니다.    ↑↑↑↑↑↑여기↑↑↑↑↑↑

이 화면에서 어셈블리어가 보이는 곳은 초록색 글자들이 있는 칸입니다.

영어 단어들과 요상한 숫자 조합들로 구성이 되어있는대요

잘 보면 익숙한 영 단어들도 있습니다.. 딱 봐서 제일 많이 보이는 PUSH도 보이구요

그 아래로 CALL이라는 단어도 보이내요

그 외 한 단어는 아니지만 축약어로 추청되는 INC, DEC, JE, JMP도 보이내요

아무래도 이 영 단어들이 어셈블리어일듯 합니다.

이 단어들이 정확히 무슨 기능을 하는지 모르니 검색을 해봤습니다.

 

우선 가장 많이 보이는 PUSH.

PUSH 인자1

push는 스택에 값을 저장하는 구문이라고 합니다.

여기서 또 스택이 뭔지 모르니 찾아봤는데요.

PUSH와 같이 정리가 되어있는 블로그가 있어서 참고 했습니다.

스택은 아주 간단하게 '데이터를 임시적으로 저장했다가 필요할 때 꺼내서 쓰는 임시기억장치'라고 하내요.

(참고 : http://csdit.tistory.com/16 )

대충은 이해되나 아직 정확하게 이해는 안되니 일단 넘어가겠습니다..

그리고 CALL.

CALL은 아무래도 단어 뜻 처럼 '부르다, 호출하다 등'의 의미와 똑같지 않나 싶지만 이 역시 검색해봤습니다.

검색을 하다보니 간단하게 기본적인 어셈블리어 구문에 대해 정리해놓은 블로그를 발견했내요

이 곳에 INC, DEC, JMP에 대한 글이 있으니 참고하시면 될 것 같습니다.

이 외에도 검색하면 많은 블로그들이 있으니 찾아보시면 좋을 듯 합니다.

(참고 : http://zerohz.tistory.com/61 )

아주아주 간단하게

CALL은 무엇인가를 호출할 때

INC는 값을 1씩 증가시키고자 할 때

DEC는 값을 1씩 감소시키고자 할 때

JMP는 특정 위치로 이동할 때

사용한다고 생각하시면 되겠습니다.

 

대략적으로 이 크랙미에서 사용하는 어셈블리어를 알아봤으니 다시 올리디버거를 찬찬히 보겠습니다.

어셈블리어가 나열되어있는 곳을 보면 PUSH로 시작합니다.

PUSH는 스택에 값을 저장하는 거니 뒤에 오는 값을 스택에 저장을 하겠구나.. 하고 넘어가겠습니다..

그러다 CALL을 만나는걸 보실 수 있습니다.

CALL 뒤를 보면 <JMP.&USER32.MessageBoxA>라고 써져있습니다.

자세히는 모르지만 아무래도 MessageBoxA라는 API를 호출하고 있는 것 같내요

F7을 이용해서 쭉 둘러봤지만 도통 아는게 없으니 뭔가 엄청난게 작동을 하는 것 처럼 보입니다.

하지만 단순히 MessageBoxA가 생성되고 실행되는 과정이겠죠

이렇게까지는 모르니 그냥 CALL로 MessageBoxA API를 불러온다는 것만 알고 넘어가겠습니다.

그 후 또 다시 한번 CALL이 있내요

그 뒤에는 <JMP.&KERNEL32.GetDriveTypeA>라고 써져있습니다.

이 문제의 핵심인 GetDriveTypeA라는 API를 호출하고 있는 듯 하내요.

GetDriveTypeA가 호출이 됬다면 반환값이 생길텐데 어디로 저장되는지는 아직 모르니 일단 쭉 내려가보겠습니다.

GetDriveTypeA를 호출하고 바로 다음 줄을 보면 INC ESI 라고 써져있습니다.

INC는 아까 적었듯이 값을 1씩 증가시켜주는 어셈블리어였습니다.

그렇다는건 ESI의 값을 1 증가 시키겠다는 거겠내요.

바로 그 밑에를 보면 DEC EAX라고 써있습니다.

DEC은 INC와 반대로 1씩 감소시키는 어셈블리어였죠

그렇다는건 EAX의 값을 1 감소 시키겠다는 의미일테구요.

그 아래로 ESI 와 EAX라는 단어가 계속해서 나오는데 이것에 대해서 또 검색을 해봤습니다.

 

찾아보니 EAX와 ESI는 범용레지스터에 속하는 녀석들이내요

잘 정리해놓은 블로그를 또 찾았습니다.

(참고 : http://blog.eairship.kr/186 )

여기서 필요한 EAX와 ESI에 대해 아주 간단하게 적어보자면

EAX - 산술, 논리 연산을 수행하고 함수의 반환값이 저장되는 레지스터

ESI - 데이터를 조작하거나 복사 할 때 Source 데이터의 주소가 저장되는 레지스터

참고한 블로그의 내용을 보고 이렇게 쓸 수 있겠내요.

여기서 EAX의 설명글 중에 '함수의 반환값을 저장'이라는 문장을 보면 왠지 GetDriveTypeA API의 반환값도

이 레지스터에 저장이 되지 않을까 생각이 듭니다.

일단 계속해서 어셈블리어로 되어있는 부분을 봐보겠습니다.

(새로 캡쳐한 이미지)

한 줄 한 줄 내려오다가 처음 INC와 DEC를 만난 이후에도 INC와 DEC가 한 두번 정도 더 사용되는 걸 볼 수 있내요

뭔가 계속 증가시키고 빼고 있내요

그러다가 CMP를 만나게 됩니다.

CMP는 아마 compare의 축약어인 것 같내요. 단어 의미 그대로 두 인자를 비교할 때 사용하는 어셈블리어라고 합니다.

이미지를 보면 CMP EAX, ESI 써있는게 보이는데요 EAX의 값과 ESI의 값을 비교하는 부분입니다.

위에서 예상했듯이 무엇인가를 비교하는 부분이 나왔내요

비교를 하고 서로 값이 다르거나 같다면 어떠한 행동을 취하겠구나 생각하고 다음 줄을 보겠습니다.

다음 줄을 보면 JE 라는 어셈블리어가 있내요

뭔지 찾아봤더니 JMP와 사촌격이랄까요

JMP는 지정된 곳으로 이동을 할 때 사용하지만 JE는 조건에 따라 이동을 하거나 안하거나 하는 어셈블리어라고 합니다.

보통적으로 CMP 같이 비교하는 명령어와 같이 사용하게 된다고 하내요.

그렇다는건 위에서 CMP로 비교한 결과에 따라 JE로 이동을 하게 되거나 그냥 지나치게 되겠내요

JE는 비교명령어를 사용했을 때 두 인자가 '같으면' 점프를 하는 명령어입니다.

JE 외에도 여러가지가 있는대요 그건 위에 어셈블리어를 검색하다가 찾은 블로그에 잘 정리가 되어있습니다.

어쩄든 JE 쪽에 써있는 걸 보면 'JE SHORT Crack_.0040103D'라고 쓰여져 있내요

조건이 맞으면 0040103D 주소로 이동하라는 것 같습니다. 앞에 크랙이라고 쓰여져있는건 파일명이내요.

0040103D가 어딘지 위 이미지로는 잘 안보이니 큰 이미지로 볼게요 

요 부분        ↑ 을 보면 가느다란 화살표가 JE가 이동하는 곳을 가르키고 있내요

가르키고 있는 곳을 보니 아무래도 CMP가 비교하는 값, 즉 EAX와 ESI의 값이 같으면

Error 메시지가 아닌 YEAH! 메시지를 볼 수 있겠내요.

어쨌든 JE 명령어 이후 아래부분은 맨 처음 봤던 MessageBoxA API부분과 동일하내요

마지막에 ExitProcess API만 빼고 말이죠. 이 API는 이름만 봐도 알 수 있다싶이 프로세스를 종료할 때 호출이 되는 API인 듯합니다.

 

이제 어셈블리어 부분도 다 봤습니다. 이 부분을 보면서 알 수 있었던 것은

CALL이라는 명령어가 GetDriveTypeA를 호출한다는 것.

산술이나 논리 연산, 혹은 함수의 반환값이 EAX 레지스터에 저장된다는 것.

INC와 DEC를 이용해서 값에 변화를 주고 있다는 것.

CMP로 비교한 EAX와 ESI의 값이 같으면 이 프로그램은 Error메시지가 아닌 다른 것을 출력 한다는 것.

 

그렇다면 이제 올리디버거에서 프로그램을 천천히 돌려보면서 EAX와 ESI의 값을 찾아보겠습니다.

올리디버거에서 레지스터 값이 표시되는 부분은                              ↓↓↓↓↓여기↓↓↓↓↓ 입니다. 

화살표로 표시해둔 부분을 보면 EAX와 ESI를 찾을 수 있습니다.

그 외에 ECX, EDX, EBX 등등 여러 레지스터들의 값들도 보이내요.

일단 프로그램을 처음 올리디버거로 불러왔을 때 레지스터 값을 보겠습니다.

EAX에는 770E494F 라는 .. 값이 들어가있고

ESI에는 00000000 이라는 아무것도 들어있지 않내요

이제 Alt + F9를 이용해서 천천히 한 줄 한 줄 실행시켜 보겠습니다.

MessageBoxA API까지 실행시켰습니다.

희안하게도 EAX에 값이 1이 들어갔습니다.(레지스터 부분에 빨간색 글씨들은 값이 이전과 다르면 빨간색으로 표시되내요)

ESI는 여전히 0이내요

이번에는 이번 문제의 핵심 API인  GetDriveTypeA를 실행시켜보겠습니다.

EAX의 값이 00000003으로 변했내요

EAX는 연산 결과값이나 함수의 반환값이 저장되는 거니 00000003 이라는건 GetDriveTypeA의 반환값이겠내요

API의 반환값이 3이면 DRIVE_FIXED의 반환값이내요.

유동적이지 않고 고정적으로 장착되어있는 드라이브의 반환값. API가 실행될 때 가르키고 있던게 C드라이브기 때문에

반환값 3을 EAX에 저장하게 된 것 같습니다.

ESI는 여전히 00000000이내요

다음 INC와 DEC들을 실행시켜보겠습니다.

우선 INC ESI가 위에 말했듯이 ESI의 값을 1 증가시키는지 확인해보겠습니다.

INC ESI를 지나니 정말 ESI의 값이 00000001로 변한 것을 확인 할 수 있내요

EAX는 00000003으로 유지되고 있구요

나머지 INC와 DEC들을 모두 실행시켜보겠습니다.

총 INC ESI가 3번, DEC EAX가 2번 실행됬으니

ESI의 값은 00000003이 되고 EAX의 값은 00000001이 된 것을 확인할 수 있습니다.

그리고 EAX와 ESI를 비교할 CMP와 JE를 실행시켜보겠습니다. 

비교 결과 EAX != ESI 이기 때문에 JE가 실행되지 않고 그냥 다음 줄로 넘어가버립니다.

이대로 계속 실행을 한다면 Error 메시지박스가 실행되게 되고 그 후 JMP를 만나면서 ExitProcces API가 실행됩니다.

Error메시지를 더이상 보고 싶지 않으니 JE가 실행되도록 값을 수정을 해야겠내요.

위에 CMP 명령어를 실행하기 직전에 EAX의 값과 ESI의 값을 같게 바꿔줘보겠습니다.

       

저는 그냥 GetDriveTypeA API의 CD-ROM 반환값인 5로 수정해줬습니다.

(아무래도 단순한 구조다보니 그냥 값만 같으면 상관없는 것 같더라구요)

다 바꾸고 Alt +F9로 한 줄 한 줄 볼 필요가 없으니 F9로 그냥 실행시켜 보겠습니다.

드디어 Error 메시지창이 아닌 YEAH! 메시지창이 출력이 됬내요.

이러면 이 크랙미는 끝입니다.

물론 EAX와 ESI의 값을 이렇게 직접적으로 수정하지 않고도 JE를 실행되게 할 수도 있습니다.

JE를 그냥 JMP로 바꾼다던지 INC나 DEC를 손 본다던지 하는 식으로 여러방법이 있습니다.

그 여러 방법을 다 적을 수도 없거니와 제가 다 알지도 못해서 여기까지 써야겠내요.

 

 

 

레벨 1 문제임에도 포스팅하려고 캡쳐하고 하다보니 시간이 몇 배는 더 걸리내요 ..

거기다 아무것도 모르는 바닥부터 천천히 검색하고 정리하면서 하려니 시간이 훅훅 지나가내요..

초반이니 기초적인 걸 찾아가면서, 적어가면서 한거라 내용도 꽤 길어져버렸내요

고작 레벨 1인데..

틀렸거나 추가되야할 내용이 있다면 댓글 달아주세요

아 그리고 .. 참고 URL 링크 ... 블로거분들 링크 걸어놓은게 싫으시거나 하시면 바로 말씀해주세요

 

 

참고 URL

http://simples.kr/Report - 심플스
http://csdit.tistory.com/16 - PUSH와 스택
http://zerohz.tistory.com/61 - 어셈블리어
http://blog.eairship.kr/186 - 범용레지스터

 

 

' 2016년 이전 > CrackMe' 카테고리의 다른 글

abex CrackMe 03  (0) 2014.05.16
abex CrackMe L02  (0) 2014.05.15

+ Recent posts