레나 튜토리얼 실습파일을 3번을 풀어봅시다.

 

이번시간의 핵심은 PE 구조에 대한 기초적인 이해와 nag 제거 입니다.

 

우선 PE 구조를 분석할때 기본적으로 많이 쓰이는 것은 PEview 라는 툴 입니다.

PEview는 인터넷 검색을 통해 쉽게 찾을 수 있습니다.

 

https://www.aldeid.com/wiki/PEView

 

PEView - aldeid

DRAFT This page is still a draft. Thank you for your understanding. Description INCOMPLETE SECTION OR ARTICLE This section/article is being written and is therefore not complete. Thank you for your comprehension. Installation Download PEView from following

www.aldeid.com

 

여기서 다운받으시면 되구요 설치까지 해줍시다.

 

 

설치하면 이런 돋보기 모양 아이콘의 파일이 나오는데 클릭해서 열어봅시다.

 

파일을 열면 파일 오픈하는 창이 나오는데 일단 이건 닫아주시고

우리가 실습할 3번 폴더의 파일을 드래그해서 열어봅시다.

 

오늘 실습할 파일은 3번 폴더에 있는 RegisterMe.exe 입니다.

 

 

열어보면 이런식으로 구성되어있습니다.

자세히 살펴보면

 

RegisterMe.exe 라는 파일이 무엇으로 구성되어있는지 볼 수 있고 (PE 파일의 구조)

 

 

파일은 Byte들로 이루어져 있는데, 왼쪽에 있는 디렉토리 별로 바이트를 볼 수 있습니다.

 

디렉토리들을 보면

 

보시면 크게 두 가지로 나눌 수 있는데, HEADER 와 SECTION 부분 입니다.

 

헤더들은 파일의 모양이 어떻게 정의되어있는지, 메타데이터 같은 느낌이구요,

주요 내용들은 SECTION들에 들어있습니다.

 

간단하게 헤더부터 살펴보고 갑시다.

 

 

가장 위에는 IMAGE_DOS_HEADER 입니다.

 

DOS는 옛날에 콘솔창만 뜨는 윈도우가 있었는데, 도스 환경에서도 쓸 수 있는 exe 파일이 있었습니다. 

현재는 잘 쓰지 않는데 그때 사용하던 헤더가 DOS 헤더 입니다.

 

 

보시면 시그니처가 5A4D 로 시작하고, 번역하면 MZ라는 단어로 시작한다는 뜻입니다.

 

 

 

실제 바이트를 봐도 MZ로 시작한다는 것을 알 수 있습니다.

+ EXE 파일 앞에는 MZ라는 헤더가 붙습니다.

 

여기서 보시는 정보들도 시그니처를 제외하고는 옛날 파일들에 대한 정보라서 딱히 볼 건 없습니다.

 

그렇다면 옛날에 쓰던걸 왜 아직도 쓰냐는 의문이 들 수 있는데,

이 부분은 옛날부터 쭉 쓰던 부분이라 호환성을 위해서 계속 유지를 하다보니 이 부분이 아직 있는것 입니다.

 

 

MS-DOS Stub Program 은 DOS 모드에서 사용할 수 있는지를 알려주는 부분입니다.

오른쪽 문자열을 보시면 "This program cannot be run in DOS mode" 라고 적혀있는데,

이 파일은 도스 모드에서는 실행되지 않는다 라는 것을 의미합니다.

 

 

다음은 IMAGE_NT_HEADERS 입니다.

이 헤더는 새로 만들어진 헤더이구요,  예전 헤더인 IMAGE_DOS_HEADER의 마지막 오프셋을 보시면

새로운 헤더의 위치를 가르쳐 줍니다. 해당 부분은 0000003C 을 가리키고 있는데

IMAGE_NT_HEADERS의 바이트를 보시면 해당 위치부터 시작하는 것을 알 수 있습니다.

 

오른쪽에 문자열에 PE라고 적혀있는데, 이곳이 바로 PE 라는 헤더를 가지고 있는 부분입니다.

왼쪽에 보시면 PE 헤더가 세 가지 구조체로 이루어져있다는 것을 볼 수 있습니다.

 

시그니처는 위에서 보신것 처럼 PE가 박혀있구요, 

이 PE가 없으면 EXE 파일이 동작하지 않습니다.

 

 

 

다음 밑에는 IMAGE_FILE_HEADER 부분입니다.

 

크게 세 부분으로 볼 수 있는데,

Machine -> 32비트에 돌아가는지 or 64비트에 돌아가는지

Time Date Stamp -> 프로그램이 만들어진 날짜

Characteristics -> 프로그램의 특징

 

등을 알 수 있습니다.

 

 

 

다음은 IMAGE_OPTIONAL_HEADER 입니다.

 

 

기본적으로 컴파일 버전 정보, 코드의 사이즈 (올리디버거로 열었을 때 코드 영역의 크기가 얼마냐를 나타냄)

등을 볼 수 있는데,

 

이번시간에 가장 중요하게 봐야될 부분이 바로 엔트리 포인트와 이미지 베이스 입니다.

 

엔트리 포인트는 1000 번지, 이미지 베이스는 40만 번지를 가리키는데,

 

우선 이해를 위해 이 파일을 올리디버거로 열고 메모리 창을 열어봅시다.

메모리 창은 올리디버거에서 청록색으로 표시된 알파벳 버튼 중에 M 버튼을 클릭하시면 볼 수 있습니다.

 

 

일단 40만번지를 보시면, 오른쪽에 PE header가 올라와 있는 것을 알 수 있습니다.

 

여기서 다시 엔트리 포인트를 보시면 1000번지를 가리키는데 이는 실제로

이미지 베이스로부터 1000바이트 다음 주소에 진입 지점이 있다는 뜻입니다.

따라서 프로그램을 실행하면 401000 번지의 주소부터 시작을 하겠다 라는 말이 되는거죠.

 

실제로 올리디버거에서 보면

 

401000 번지의 주소에서 시작한다는 것을 볼 수 있습니다.

 

정리하자면 Address of Entry Point와 Image Base를 더하면 프로그램 시작 지점을 예측할 수 있습니다.

 

 

 

이 외에 알 수 있는 정보들은 이미지 사이즈 (EXE 파일 자체가 이미지 입니다.), 헤더의 사이즈, 체크섬(데이터의 문제가 있는지 확인하는 용도) 등이 있습니다.

 

다음은 섹션 헤더인데, 섹션 헤더는 밑에 나오는 섹션들에 대한 정보를 가지고 있습니다.

 

안에 내용으로는 섹션의 이름이 있고, Size of Raw Data와 Virtual Size가 있는데,

PE 파일은 기본적으로 메모리에 적재될 때 사이즈가 늘어나게 됩니다.

 

여기서 Size of Raw Data는 원래 데이터의 사이즈이고, Virtual Size가 메모리에 적재될 때 늘어난 사이즈 입니다.

 

밑에 나오는 Characteristcs는 읽기나 쓰기 같은 권한을 가지고 있는 것을 나타냅니다.

 

 

 

 

일단 PE 구조는 이정도로 알아보고, 이제 문제로 넘어가도록 하겠습니다.

 

RegisterMe.exe 파일을 실행했을 때 어떻게 되는지부터 살펴봅시다.

 

클릭하면 레지스터 프로그램에서 nags 를 제거해달라는 메시지가 출력됩니다. OK버튼을 누르면

 

패치를 해서 nag를 삭제해 달라고 합니다.

 

 

여기서 말하는 nag는 쉽게말해서 경고창을 없애달라는 말입니다.

올리디버거로 프로그램을 켜봅시다.

 

 

2번째 라인에 보시면 핸들을 가져오는 함수를 실행을 하는데, 하게 되면 결과값으로 400000이 나오게 되고 EAX에 저장하게 됩니다. (40만은 엔트리 포인트가 있는 곳으로, MZ 헤더가 있는 곳입니다.) 

 

근데 밑에 보시면 CMP 명령으로 EAX와 0이 같은지 비교를 하고, 같다면 점프를 하게 되는데, 만약 점프를 하지 않게 되면 nag를 제거하라는 메세지가 출력됩니다. 

 

사실상 점프를 할 수 없는 구간인데, 임의로 점프를 하게 만들어야 하는 구간이죠.

 

저번시간에 배운 내용으로 직접 JMP 명령어로 수정해서 갈 수도 있겠지만, 

이번에는 엔트리 포인트를 변경해서 진행해보도록 하겠습니다.

 

보시면 우리가 점프해서 도착해야 할 지점은 401024 지점입니다.

 

따라서 엔트리 포인트를 401024로 바꿔서 프로그램 시작을 401000 부터 시작하지 않고 401024 부터 시작하도록 바꾸는 것 입니다.

 

우선 그 전에 밑에 또 잔소리를 하는 구간이 있는데, 이 부분은 강제로 JMP 할 수 있는 부분이 없으니 NOP으로 채워줍시다.

 

이 부분을 드래그 해서 우클릭 후 Binary -> Fill with NOPs 를 클릭해줍시다.

 

잔소리 부분을 NOP으로 채웠습니다.

 

이제 다시 엔트리 포인트를 바꿔보도록 합시다.

아까 봤던 'M' 버튼을 클릭 해 메모리 창으로 가봅시다.

 

원래 엔트리 포인트였던 40만 번지가 있는 곳에 더블 클릭을 해서 들어갑니다.

 

더블 클릭 후 나오는 창을 확대해 보면

이런 창이 나옵니다.

여기서 쭈우우욱 내려 보면..

 

 

4000C0 구간에 PE 시그니처가 있는 것을 볼 수 있습니다. 위에서 PEview에서 보던 것을 올리디버거로 보는 셈이죠.

 

좀더 내려 보면

 

 

 

4000E8 자리에 엔트리 포인트가 보입니다!

 

 

여기서 잠깐 PEview를 보시면

도구 창에서 표시된 부분 (VA) 을 클릭 하고

 

엔트리 포인트 위치를 보면 가상 메모리에 올라와 있는 곳의 주소를 알 수 있습니다.

여기에 나와있는 엔트리 포인트의 위치 4000E8 을 보니 올리디버거와 매칭이 될 수 있다는 것을 알 수 있습니다.

 

이제 다시 올리디버거의 덤프 창으로 가서 확인해보도록 하겠습니다. 'C' 버튼을 클릭하시면 됩니다.

 

 

덤프창에서 컨트롤 + G 누르고 4000E8번지를 검색합니다.

 

 

리틀 엔티안 방식이라 실제는 00 00 10 00 바이트 인데, 젤 마지막 00 바이트 부분을 클릭하고 스페이스를 누른 다음

 

 

24로 바꿔주시면 됩니다.

 

그 이유는 바로

 

위에서 JE 명령을 통해 원래 점프 후 도착해야하는 구간이 401024 였고, 

원래 프로그래 시작점은 401000 이었습니다. (400000 + 1000)

 

때문에 E8 구간에 저장되어있던 00 10 00 00 (실제 읽을 때는 00 00 10 00) 이 바로 1000 이 들어가 있었고,

24 10 00 00 으로 바꿔줌으로써 00 00 10 24 즉 1024가 들어가서 프로그램 시작 지점이 401024로 바뀌는 것 입니다.

 

 

일단 이때까지 수정했던 부분만 해서 저장을 해봅시다.

덤프 창에 마우스 우클릭 -> Copy to executable file -> 새로 뜨는 창에 다시 마우스 우클릭 ->save file -> save

 

저장하고 실행하면 전에 나왔던 경고 창이 안뜨고 바로 흰색 화면이 나온 것을 볼 수 있습니다.

 

하지만 X 버튼을 누르니 경고창이 하나 남아있네요. 

 

아마 바뀐 부분 동시에 저장하는 과정에서 문제가 생겼나 봅니다.

 

crack 파일을 다시 올리디버거로 불러온 다음 경고창을 띄우는 곳을 다시 NOP 로 바꿔준 다음 crack_2로 새로 저장해봅시다.

 

실행하면 시작했을 때와 X를 눌렀을 때 둘 다 사라졌는 것을 볼 수 있습니다.

 

 

RegisterMe.exe 파일은 이것으로 해결이 되었고, 3번 실습파일 보시면 RegisterMe.Oops.exe 파일이 또 있습니다.

 

이 파일은 어떤 건지 올리로 한번 올려보면

 

에러 창이 떠버리고

 

아까와는 전혀 다른 주소 공간이 보입니다. 

 

디버깅을 하기 어려운 곳으로 온 것 같습니다.

이럴때는 두 가지 분석 방법이 있습니다.

 

첫 번째는 PE 구조를 보고 엔트리 포인트를 직접 보는 것이고,

두 번째는 현재 에러는 PE 구조가 이상해서 에러가 났기 때문에, PE 구조를 수정해서 에러를 잡는 방법이 있습니다.

 

 

가장 쉬운 방법은 401000 번지 주소를 찾는 것인데, 우선 컨트롤 + G 로 찾아가봅시다.

일단 프로그램 시작 지점이 401000이 아니기 때문에 저 위치에 브레이크 포인트를 걸어주고 F9를 눌러 401000 까지 오게 만들어 줍시다.

 

이제 여기까지 왔기 때문에 위에서 했던 분석 과정을 똑같이 해주시면 됩니다.

 

 

두 번째는 PE 구조 수정인데,

우선 두 개의 파일을 비교하기 위해 PEview를 두개 열고 RegisterMe와 RegisterMe.Oops를 각각 열어봅시다.

 

왼쪽이 RegisterMe, 오른쪽이 RegisterMe.Oops 입니다. 

한눈에 보기에도 Oops는 없는 부분이 많은 것으로 보이는데, 이 파일은 올바른 PE 구조가 아닙니다.

 

그렇다고 해서 윈도우에서 PE 파일을 실행할 때 모든 구조를 검사하고 실행하는 것이 아니기 때문에 실제로 파일을 클릭해서 실행해 보면 RegisterMe와 똑같이 실행되게 됩니다.

 

하지만 올리디버거를 통해 실행해보면 제대로 실행되지 않죠.

 

한번 수정을 해보도록 합시다.

 

일단 위에서 엔트리 포인트와 이미지 베이스 등 중요한 정보를 가지고 있는 IMAGE_OPTIONAL_HEADER가 Oops 파일에는 보이지 않습니다. 그래서 이것으로는 PEview를 통해 분석할 수 없습니다.

 

 

대신에 HxD 를 사용해서 보도록 하겠습니다.

 

https://mh-nexus.de/en/downloads.php?product=HxD20

 

Downloads | mh-nexus

Downloads Note: Starting with HxD 2.3, the portable edition is available as separate setup program, and can be run with minimal privileges (no admin rights required). For the portable edition, the setup program writes only into the selected folder (e.g., U

mh-nexus.de

여기서 다운로드 하시면 되구요 현재 우리가 실습하고 있는 윈도우 XP는 영문판이라서 한국어 버전보다 영문버전을 다운받는 것이 좋을 것 같습니다.

 

 

일단 RegisterMe 하나를 열어 보시고 위에 도구 창에

Analysis -> Data comparison -> Compare 를 클릭해봅시다.

 

밑에 비교 대상 파일을 Oops 파일로 설정한 다음 OK를 누릅니다.

 

그러면 이런식으로 한 화면에 두 파일이 비교되어 나타나고, 다른 부분을 자동으로 Search 해줍니다.

 

위에 사진 보시면 이미 다른 부분이 하나 나와있고, 단축키로 F6을 누르시면 다음 다른 부분을 자동으로 찾아줍니다.

 

 

우선 처음 다른 곳을 살펴보면

 

000000DF 의 위치에 있는 데이터가 정상파일에서는 00이지만 Oops 파일에서는 40 입니다.

이 부분에 대해서 좀 더 보기위해 PEview를 살펴보면

 

Size of Code 의 부분입니다. 

 

정상 파일은 Size of Code가 00 04 00 00 (00 00 04 00) 인데, Oops 파일은 00 04 00 40 (40 00 04 00) 이 되어버린 것이죠. 

 

이제 정상파일 처럼 고쳐 봅시다.

 

오른쪽 Oops 파일에서 다른 부분에 00을 입력해서 수정해줍니다.

수정한 부분은 붉은색으로 표시가 되었습니다. 위와 같은 방식으로 F6을 눌러 다른 부분을 찾고, 정상 파일과 같은 값으로 모두 바꿔주면 RegisterMe.exe와 똑같은 파일이 되고, PEview나 올리디버거에 올려봐도 정상적으로 나오는 것을 볼 수 있습니다. 

 

 

3번 문제도 해결!

 

 

 

출처 :

https://cha4ser.tistory.com/entry/%EB%A0%88%EB%82%98-%ED%8A%9C%ED%86%A0%EB%A6%AC%EC%96%BC-3-nag-%EC%A0%9C%EA%B1%B0%ED%95%98%EA%B8%B0-with-PE-%EB%B6%84%EC%84%9D?category=892885

레나 튜토리얼 실습파일을 2번을 풀어봅시다.

 

2번 폴더에 들어가면 reverseMe.exe 파일이 있는데 파일 자체는 1번이랑 똑같습니다.

그리고 클릭해보면

 

 

You really did it Contratz 라는 메세지가 뜹니다.

 

일단 폴더에 있는 Keyfile이 이미 있는데 이 파일을 만드는게 2번의 목적이니 실습을 위해 지워줍시다.

 

 

지우고 다시 파일을 열어보니 1번문제와 유사한 메세지가 떴습니다.

 

일단 올리디버거로 한번 열어봅시당

 

역시 같은 파일이라 익숙한 화면이 나오네요.

복습을 위해 F8을 눌러서 진행을 한번 해봅시다.

 

 

CreateFileA까지 왔습니다. 이 함수는 Keyfile.dat 파일을 불러오는데 파일이 없기 때문에 오류가 났었죠. 

이제 파일을 만들러 가봅시다.

 

우선 실습파일이 있는 폴더에 빈 텍스트 파일을 하나 만들어 줍니다.

그리고 파일 이름을 Keyfile.dat 라고 바꿔줍시다.

(경고창이 나와도 무시하시고 확인 누르시면 됩니다.)

 

 

그 다음 메모장을 켜서 Keyfile.dat 파일을 열어봅니다.

 

우선 아무런 문자 abcd를 넣고나서 올리디버거로 돌아가봅시다.

 

 

이번엔 Keyfile.dat 파일이 있으니 CreateFileA 함수가 실패하지 않겠죠?

1번에서는 함수가 실패하여 EAX에 "FFFFFFFF" 가 들어갔는데, 지금은 성공해서 44가 들어갔습니다.

 

그럼 밑에 CMP 명령을 통한 JNZ가 정상적으로 실행되면서 점프가 됩니다!

 

 

쭉쭉 진행한 다음 ReadFile이 있는 곳까지 왔습니다.

hFile을 보시면 44가 들어가있는데 아까 CreateFileA를 실행한 결과로 EAX에 들어가 있는 값과 동일한 값인 것을 알 수 있습니다.

 

우선 F8로 ReadFile 함수도 정상적으로 진행되는지 확인해봅시다.

 

왼쪽 밑에있는 덤프창을 클릭 후 Ctrl + G를 누르고 ReadFile의 버퍼가 있는 곳인 0040211A 를 입력해 이동해봅시다.

 

 

 

확인해 보시면 우리가 임의로 입력했던 abcd가 잘 들어간 것을 볼 수 있습니다.

 

또한 ReadFile 함수에 pBytesRead라는 변수가 있는데 이는 몇 바이트를 읽었는지를 저장하는 변수입니다. 

위치는 위에 나온것 처럼 00402173 이니 이것도 Ctrl + G로 찾아서 확인해봅시다.

 

 

입력한 대로 4Byte가 저장이 되었습니다.

 

다음 F8로 진행하면 JNZ 명령어가 나오는데 ReadFile 또한 정상적으로 되었기 때문에 임의로 플래그를 수정하지 않아도 정상적으로 점프하게 됩니다.

 

 

다음으로 XOR 연산이 두번 나옵니다.

여기 나오는 XOR 연산의 목적은 레지스터를 초기화 하기 위함입니다.

XOR 연산은 비트연산으로 같으면 0, 다르면 1인데, 

"XOR EBX EBX" 처럼 같은 값을 XOR 연산을 하니까 당연히 0이 되겠죠?

 

여기서도 마찬가지로 콤마를 기준으로 오른쪽에 있는 데이터를 왼쪽에 넣는 것이니 XOR 연산을 한 결과를

EBX에 넣는다 라는 의미가 됩니다.

 

실제로 실행해 보면 EBX와 ESI가 0으로 바뀐 것을 볼 수 있습니다.

 

쉽게 C언어로 설명드리자면 

int EBX = 0;

int ESI  = 0;

 

과 같은 개념입니다.

 

다음은 CMP 명령어인데, 402173 자리에 있는 수와 10과 비교를 하는 명령어입니다.

 

402173은 위에서 본 것 처럼 pBytesRead가 들어가 있는 곳으로, 읽어들인 바이트 수 입니다.

현재 402173에 저장된 것은 4바이트 인데, 10과 비교를 하면 4가 더 작습니다. 

이 상황에서 CMP 명령을 했을 때의 결과를 한 번 봅시다.

 

 

 

1번 문제를 풀 때와 같이 10보다 4가 더 작기 때문에 S 플래그가 1로 셋팅되었습니다.

때문에 JL 명령이 활성화 되었고, 점프하게되면 키 파일이 올바르지 않다는 메세지박스를 띄우는 곳으로 가게 됩니다.

 

*여기서 주의할 점은 저기 나와있는 10은 16진수를 의미하기 때문에 10바이트가 아닌 16바이트로 해석해야 합니다.

(CMP 명령을 할 때도 사실은 10과 4를 비교하는 것이 아니라 16과 4를 비교하는 셈이죠)

 

 

그럼 여기서 할 수 있는 일은 키 파일을 수정하는 것입니다.

 

키 파일은 우리가 좀전에 "abcd"의 4바이트를 넣어놨었는데, CMP와 JL을위해 16바이트를 넘겨서 저장 후 다시 돌려봅시다!

 

키 파일을 적당히 16바이트 이상으로 저장을 하고 새로 올리디버거로 돌려봅시다.

 

 

 

다시 돌려본 후 402173 자리에 가보면 16진수로 11 즉, 17바이트가 저장되었다 라고 볼 수 있고, S플래그도 0으로 되어 JL 명령어가 활성화되지 않았습니다.

 

다음으로 넘어가봅시다.

 

다음은 MOV AL, BYTE PTR DS: [EBX + 40211A] 입니다.

MOV는 오른쪽에 있는 값을 왼쪽에 넣는 명령어 입니다.

이 명령어는 40211A와  EBX를 더한 위치에 있는 값을 AL에 넣는 것 입니다.

 

우선 EBX는 위에서 XOR을 통해 0으로 초기화를 해주었으니 40211A에 있는 값을 다시 확인해봅시다.

 

 

보시면 아까 임의로 넣었던 키 파일의 내용이 들어가있습니다.

 

즉, 40211A + 0 이 위치한 자리의 값 => '0'을 AL에 저장하는 명령입니다.

제대로 들어갔는지 확인해봅시다.

 

EAX의 AL 부분을 보면 30이 들어갔습니다.

0이 아닌 30이 들어간 이유는 위의 HEX dump 창에서도 알 수 있듯이 숫자 0은 아스키 코드로 '30'이고, 이 30이 40211A의 위치에 저장된 것입니다. 따라서 AL에는 숫자 0이 아닌 문자'0'을 뜻하는 Hex값 30이 들어간거죠. 

 

때문에 다음 명령어인 CMP AL, 0 을 실행하게 되면 서로 다르다라는 결과가 나오고, JE 명령어도 활성화되지 않습니다. 

(JE 명령어가 활성화 되려면 문자 '0'이 아닌 Hex값으로 0이 AL에 저장되어야 합니다.)

 

실행해봅시당.

 

실제로 값이 다르기 때문에 Zero 플래그가 0으로 남아있고, JE 명령어도 활성화되지 않았습니다.

 

그 다음 명령은 CMP AL, 47로, AL과 47을 비교하는 명령어 입니다.

여기 나오는 47은 위에 0과 마찬가지로 Hex값의 47을 의미하고, 이는 아스키코드 표를 참고하면 알파벳 'G' 입니다. 

즉, 키 파일에서 읽어들인 문자가 'G'인지 아닌지를 비교하는 명령어 입니다.

 

만약 'G'라면  제로 플래그가 1이 될것이고, 바로 아래에 있는 JNZ 명령어가 활성화 되지 않고, INC ESI와 INC EBX를 모두 실행할 것이고, 'G'가 아니라면 INC EBX만 실행하게 될 것입니다.

 

(JNZ는 제로 플래그가 0일때 점프를 하며, 제로 플래그는 CMP 명령을 통해 값이 같으면 1, 다르면 0입니다.

즉, 값이 다르면 점프를 하게 됩니다.)

 

INC 명령어는 해당 레지스터에 1을 더해주는 명령입니다.

EBX와 ESI는 0으로 초기화 했으니 

만약 읽어들인 문자가 'G'이면 점프를 안하기 때문에 ESI와 EBX 모두 1이 되고,

아니라면 점프를 하기 때문에 EBX만 1이고 ESI는 그대로 0이 되겠죠?

우리의 첫번째 문자는 '0'으로 'G'와 다르기 때문에 제로 플래그가 0이고, JNZ 명령이 활성화되면서 INC ESI는 건너뛰고 INC EBX만 실행됩니다.

 

다음은 4010C1의 위치에 있는 명령어로 점프하는 명령어 입니다.

이동한 위치의 명령어는 40211A 에 EBX를 더한 위치의 값을 AL에 넣는 곳 입니다.

처음에는 EBX가 0이었지만, 이제는 INC EBX를 통해 1이 되었습니다.

그럼 AL에는 40211A + 1의 위치에 있는 데이터를 넣게 됩니다. 

 

40211A + 1을 하게되면 40211B가 될 것이고, 해당 위치를 보면

 

키 파일에 입력한 내용 중 두번째 문자 입니다. 

 

 

따라서 AL은 문자 '1'의 아스키 값 31이 들어가게 되고 위에 했던 과정을 반복하게 됩니다.

 

현재 키 파일은 0123456789abcdefg 총 17개의 문자가 저장되어 있고,

 

40211A에서부터 저장된 문자를 모두 읽은 후에는 Hex 값 0이 저장되어 있습니다.

 

따라서 총 17번의 반복을 진행하면서 키 파일의 문자를 모두 읽은 다음,

CMP AL, 0의 명령을 통해 반복이 종료된 다는 것을 알 수 있습니다.

 

우선 모든 반복문을 진행한 후에 다음 명령어들을 살펴봅시다.

 

 

 

모든 반복이 끝나면 AL에 0이 들어가게 되면서 점프를 하게되는데, 점프를 하면

ESI와 8을 비교한 후에 ESI가 8보다 작으면 아래 JL 명령을 수행하게 되고,

8 이상일 경우 JL 명령은 활성화되지 않고 우리의 목표인 JMP 00401205 를 수행할 수 있습니다.

 

ESI는 위에서 키 파일의 내용 중 'G'라는 문자가 있을 경우에 1씩 증가했습니다.

즉, 키 파일의 내용에 'G' 문자가 총 8개 이상일 경우에 성공한다고 볼 수 있습니다.

 

 

위의 반복문을 보기 쉽게 C++ 언어로 표현하자면

이런식으로 나타낼 수 있을것 같습니다.

 

 

이제 키 파일을 다시 수정해봅시다.

 

G를 8번 이상 넣으면서, 키 파일의 첫 번째 조건이었던 16바이트 이상을 만족시켜준 후에 저장하고 새로 실행해봅시다.

 

첫 번째 문자가 'G'였으니 AL에 47이 들어갔고, INC ESI 명령이 정상적으로 수행된 후에 ESI가 1 증가하였음을 볼 수 있습니다. 이제 반복문을 끝내고 나와봅시다.

 

반복이 끝나면 ESI가 8을 넘었기 때문에 JL은 활성화되지 않고 바로 JMP 명령을 수행할 수 있게됩니다.

 

점프를 하게 되면

성공 메세지를 띄워주는 곳까지 오게됩니다.

 

다시 폴더로 돌아와서 reverseMe.exe. 파일을 실행해도 성공 메세지가 뜹니다.

 

이로써 2번 문제도 해결!

 

 

 

출처 :

https://cha4ser.tistory.com/entry/%EB%A0%88%EB%82%98-%ED%8A%9C%ED%86%A0%EB%A6%AC%EC%96%BC-2-%EB%9D%BC%EC%9D%B4%EC%84%BC%EC%8A%A4-%ED%82%A4-%EC%95%8C%EA%B3%A0%EB%A6%AC%EC%A6%98-%EB%B6%84%EC%84%9D%ED%95%98%EA%B8%B0?category=892885

Tutorial 1 - 라이센스 루틴 지나가기

 

 

실습준비가 끝났으면 1번부터 문제를 풀어봅시다.

 

우선 1번문제 files 폴더에 reverseME.exe 파일을 올리디버거로 끌어서 실행시킵니다.

 

(Options - Add to Explorer 에서 Add Ollydbg to menu~~ 를 클릭해두시면 reverseMe 파일을 우클릭 하여 Open with Ollydbg 클릭해서 바로 올리디버거로 띄울 수 있습니다. )

 

그럼 이제 올리디버거 첫 화면부터 알아봅시다.

 

[그림 1] 가상메모리

 

먼저 가장 왼쪽에 나와있는 부분이 가상메모리 주소를 나타내는 부분입니다.

 

프로그램은 실행이 되는순간 프로세스가 되는데, 이는 가상메모리에 프로그램 파일이 올라간다라고 할 수 있습니다.

 

여기서 가상메모리란 운영체제가 물리메모리를 효율적으로 사용하기 위한 시스템입니다.

우리가 흔히 말하는 메모리 8GB, 16GB는 물리메모리를 뜻하며, 가상메모리가 없으면 이 물리 메모리를 효율적으로 사용하지 못할 것입니다.

 

[그림 2] 기계어 코드와 어셈블리어

 

그 오른쪽에는 기계어 코드와 어셈블리어가 있습니다.

기계어 코드는 CPU가 읽어들여 실행시키는 코드를 뜻하는데 사람이 잘 알아볼 수 없는 숫자들로 이루어져있습니다. 

이를 사람이 알아볼 수 있게 1대1 매칭한 것이 바로 옆에있는 어셈블리어 입니다. 

 

기계어 코드는 일반적으로 잘 안보고 필요할때만 가끔 보기때문에 자리가 부족하다면 살짝 가려놔도 무방합니다.

 

[그림 3] 주석

 

그 다음엔 주석이 나옵니다. 프로그램 실행에 직접적인 영향이 있는 부분은 아니며, 코드를 이해하기 쉽게 메모하는 부분이라고 생각하시면 될 것 같습니다. 주로 함수에 실행에 필요한 매개변수에 대한 정보를 나타내고 있는 것으로 보입니다.

 

[그림 4] 레지스터

 

다음은 레지스터 입니다. 레지스터는 CPU가 사용하려고 가지고 있는 데이터인데 일종의 변수라고 생각하시면 편할거같습니다. 일반적으로 각각 레지스터는 쓰이는 용도가 다르기 때문에 어느정도는 알고가시면 좋습니다.

 

EAX : 계산에 대한 저장을 하는 데이터

EBX : (base register) 다목적으로 사용

ECX : (counter register) 숫자를 세거나 for문 등

EDX : (data register) 다목적으로 사용

 

ESI : (source index) 출발지

EDI : (destination index) 목적지

=> 복사, 붙여넣기 (컨c 컨v)같은 개념

 

EBP : (base pointer) 스택의 아랫부분

ESP : (stack pointer) 스택의 윗부분

 

EIP : CPU가 다음에 실행할 명령어 주소

=> 위의 그림에서 검은색으로 표시된 00401000번지가 다음에 실행항 명령어의 위치이며, 실제 명령은 PUSH 0이다.

 

 

각 레지스터 앞에 공통적으로 E가 붙어있는데 이는 32비트 환경을 뜻합니다. 

숫자 두개를 묶어서 한 바이트로 보는데 8개가 있어서 4바이트 -> 32비트 입니다. 

 

만약 E가 없고 AX만 있으면 16비트를 의미하고, 

AH와 AL은 8비트를 의미합니다.

 

레지스터 부분 더블클릭을 하면 직접 데이터를 컨트롤 할 수도 있습니다. 

 

64비트에서는 RAX라고 표현을 하며, 그림으로 설명하면 아래 그림과 같습니다.

 

 

[그림 4-1] 레지스터 구조

 

 

 

[그림 5] 덤프

 

다음 왼쪽 아래에는 덤프값을 볼 수 있습니다. 위에는 명령어 형식으로 되어있고, 아래는 그냥 데이터로 쫙 표현해놓은 값입니다. 찾고싶은 위치가 있다면 컨트롤 + G를 누르고 401000 같은 주소를 입력하면 됩니다.

 

[그림 6] 스택

 

마지막으로 오른쪽 밑에는 스택을 나타내는 창 입니다. 위에 레지스터에 ESP와 EBP와 비교해보면 스택이 0012FFC4 주변을 가리키고 있다는 것을 알 수 있고, 왼쪽에 나타나있는 가상메모리와는 많이 다른 부분에 위치하고 있음을 알 수 있습니다.

 

이쪽 영역에 마우스 우클릭 후 Address - Relative ESP or EBP를 클릭하면 ESP나 EBP로부터 얼마나 떨어져있는지도 확인할 수 있습니다.

 

 

F8을 누르면 한단계 실행이 됩니다. 한번 눌러봅시다.

 

[그림 7] 한단계 실행 화면

 

F8을 누르고 나면 가장 왼쪽에 검은색으로 칠해진 것이 한단계 내려갔고, PUSH 0 이라는 명령어가 실행되었습니다.

오른쪽에 레지스터도 바뀐 것을 볼 수 있습니다. PUSH는 스택에 값을 넣는 것을 의미하며, 스택에 값을 넣었기 때문에 ESP가 한 바이트 이동하게 되었습니다. (12FFC4 -> 12FFC0) 

 

컨트롤 F2를 누르면 처음으로 돌아가는데, 처음 공부할 때 F8을 하나하나 눌러가면서 레지스터나 스택이 어떤식으로 바뀌고 돌아가는지 계속 확인해 보면 유익할것 같습니다.

 

 

어느정도 사용법을 익혔으면 이제 본격적으로 문제를 풀어봅시다!

 

우선 실습 파일인 ReverseMe.exe를 실행시켜 봅시다.

 

 

 

일단 클릭을 해보면 라이센스가 없고 새로 구입하라는 메시지가 뜹니다. 1번 문제의 목적은 이 오류를 우회를 해서 라이센스가 있는 척을 하는게 문제입니다.

 

다시 올리디버거로 돌아가봅시다. 

 

==================

 

올리디버거 단축키

 

한스텝 진행 (함수 진입 x) : F8

한스텝 진행 (함수 진입 x) : F7

재시작 : Ctrl + F2

브레이크 포인트 : F2

주소 이동 : Ctrl + G

브레이크 포인트까지 계속 진행 : F9

 

==================

 

좀전에 가장 처음 명령어를 실행해두었으니 그 다음부터 봅시다.

 

 

다음 나온 명령어는 CALL 이라는 명령어 입니다. 

CALL은 함수를 호출하는 명령어로 예를들어 C언어로 짜여진 프로그램의 함수를 실행하는 명령어 입니다.

[그림 7] 한단계 실행 화면

 

다음 나온 명령어는 CALL 이라는 명령어 입니다.

CALL은 함수를 호출하는 명령어로 예를들어 C언어로 짜여진 프로그램의 함수를 실행하는 명령어 입니다.

호출하는 함수는 KERNEL32.DLL에 있는 GetModuleHandleA라는 함수 입니다.

 

마이크로소프트에서 제작한 DLL인데, 본 문제에서는 크게 중요한 부분이 아니기 때문에 넘어가도록 하겠습니다.

(자세한 설명이 궁금하면 MSDN 사이트에서 검색하시면 됩니다.)

 

다음 명령어로 가봅시다. (F8)

 

 

다음은 MOV 명령어들이 많이 나옵니다. 

 

처음 나와있는 명령어를 보면 

 

MOV DWORD PTR DS:[402177], EAX

 

라고 적혀있는데, EAX의 값을 402177 주소의 값에 넣는다는 의미입니다.

DWORD PTR DS는 크게 신경쓸건 아니고 뒤에 괄호안에있는 주소로 넣는다 정도만 생각해도 될 것 같습니다.

 

 

명령어를 실행한 후에  Ctrl + G를 눌러서 실제 저 자리에 EAX 값이 들어갔는지 한번 확인해봅시다.

 

 

현재 EAX값은 400000인데,  해당 주소로 들어가보면 00 00 40 00 이 들어가있습니다.

 

이는 리틀엔디안 방식 때문에 그렇습니다.

 

그런데, 리틀엔디안과 빅엔디안에 대해서는 잘 설명해놓은 글이 많기때문에 자세히 알고싶으면 구글링해보시기 바랍니다. 

 

간단하게 설명드리자면

 

12345678 이 있으면 리틀엔디안 방식이면

78 56 34 12 이런식으로 들어가게 됩니다.

 

따라서 400000도 

00 00 40 이 됩니다.

 

다음 MOV 명령어들도 마찬가지로 들어가게 되며, 하나하나 보시면서 이해해보시기 바랍니다.

 

다만

이 명령어는 402177의 주소에 있는 값을 EAX로 넣는 명령어 입니다.

항상 콤마를 기준으로, 뒤에 있는 값을 앞에 있는 값에 붙여넣는다는 개념으로 이해하시면 됩니다.

 

 

다음 PUSH 명령으로 스택에 4와 EAX에 있는 값인 400000을 넣었습니다.

 

다음은 LoadIconA라는 함수를 호출하는데 별다른 내용이 없기 때문에 이런게 실행되고 있구나 라는 정도만 아시면 됩니다.

 

(함수에 대한 리턴값은 EAX에 저장이 되니 참고해주시면 되겠습니다.)

 

 

그 밑에도 딱히 문제될 것 같은 명령어는 안보이니 계속 실행해 주시면 되는데, 밑에 보시면 CreateFileA라는 함수가 보입니다. 다른건 몰라도 파일을 만들고 하는 함수는 살짝 의심스러우니 자세히 봅시다.

 

위에도 보신것 처럼 별다른 문제가 없는 명령어가 많고 하나하나 F8을 눌러가면 불편하기 때문에, 의심스러운 곳을 BreakPoint로 걸어놓고 (F2) 해당 지점까지 자동으로 실행하는 F9를 누릅시다.

 

보시는것 처럼 00401073 위치에 F2로 BreakPoint를 설정해 놓으면 빨간색으로 변하고, F9를 누르면 해당 위치까지 한번에 이동하게 됩니다. 

 

CreateFileA 함수는 유명한 함수이기 때문에 msdn에서 구조를 살펴볼 필요가 있습니다.

 

검색은 구글에 CreateFileA msdn 이라고 치면 MS에서 만든 사이트가 나오는데 함수 구조를 잘 설명해두었습니다.

 

 

msdn에서 보시면 이처럼 CreateFileA 함수 호출에 필요한 여러가지 인자들을 소개해 주었는데, 

이 그림에서 함수호출 직전 PUSH 명령어들이 많습니다. 이 과정이 인자를 채워주는 과정이라고 보시면 됩니다.

오른족에 주석을 보시면 어떤 변수에 어떤 값을 넣었는지 쉽게 볼 수 있습니다.

 

 

일단 한번 함수를 호출해 봅시다 (F8)

 

 

함수를 실행하면 EAX가 FFFFFFFF로 채워진 것을 볼 수 있다.

 

위에 함수에 대한 결과를 EAX에 저장한다고 했는데 CreateFileA 함수를 호출하고 난 결과가 FFFFFFFF이란 뜻입니다.

 

함수 리턴값은 msdn에서 Return Value를 보시면 됩니다.

 

해당 함수에서는 실패하면 INVALID_HANDLE_VALUE가 반환된다고 하였는데 그 결과가 -1 (FFFFFFFF) 입니다.

 

 

 

 

실패한 이유는 함수 msdn에 나와있는것 처럼 CreateFileA 함수는 파일을 만드는것 뿐만 아니라 파일을 Open하기도 합니다.

 

하지만 우리의 실습파일을 보면

함수의 옵션에 OPEN_EXISTING으로 설정되어 있고 해당 파일을 Keyfile.dat라고 설정해 두었습니다. 

하지만 실습폴더에는 Keyfile.dat 파일이 없죠. 그래서 오류가 나게 된 것입니다.

 

OPEN_EXISTING 역시 msdn에서 검색하시면 어떤 옵션인지 알 수 있습니다.

(해당 함수 페이지에서 컨트롤+f로 OPEN_EXISTING 검색하시면 편리합니다.)

 

 

함수 호출에는 실패했지만 일단 다음으로 넘어가봅시다.

 

 

 

다음은 EAX와 -1을 비교하는 부분입니다. 현재 FFFFFFFF이 들어와있는데 이건 -1과 같은 값을 의미합니다.

00000000 에서 1을 빼면 FFFFFFFF이 되겠죠.

 

따라서 해당 명령어는 위의 함수가 실패했는지 성공했는지를 따지는 부분이 되겠습니다. 

 

그리고 해당 명령어를 실행하면 

 

 

우측 레지스터 부분에 Z라는 부분이 0에서 1로 바뀌었습니다.

C,P,Z ... 나와있는 부분은 Flag인데, 각 연산의 결과에 따라 바뀌는 값들입니다.

 

CMP 명령을 했을때 두 값이 같다면 0, 다르면 1이 결과값으로 나오는데,

Z는 Zero Flag로, CMP의 결과값이 0이면 1로 바뀌게 됩니다.

즉, CMP 명령 이후 값이 같다면 Z가 1로 된다는 뜻입니다.

 

위의 경우에도 EAX가 -1과 같은 값이기 때문에 Z가 1로 바뀌게 된 것입니다.

 

 

 

다음은 JNZ 명령어가 나옵니다.

기본적으로 앞에 J가 붙으면 JUMP 명령으로, 지정한 위치로 이동을 하는것이고, 뒤에 NZ는 옵션입니다.

NZ 같은 경우는 Not Zero 이고, Zero의 값이 0일때 JMP 명령을 실행하게 됩니다.

만약 JZ였으면 Zero가 1이기 때문에 점프를 하게 되는것이고

 

 

위치는 보기 쉽게 화살표로 나타내져 있고, 중간 명령어들을 건너뛰고 바로 화살표가 가리키는곳으로 이동하게 됩니다.

 

만약 점프를 안해버리면 저 위치로 넘어가지 않고, 바로 다음 명령어인 PUSH 0을 하게 되고, 결국은 MessageBoxA라는 함수를 호출하게 되버리는 것이죠. 저 메세지 박스가 처음 ReverseMe.exe를 실행했을때 라이센스를 구입하라는 메시지를 의미합니다. 그리고 그 다음은 ExitProcess를 호출하여 프로세스를 종료하는 루틴을 밟게 됩니다.

 

 

그렇다면 우리가 할 수 있는 일은 CMP 이후 JNZ 명령을 실행하기 전에 Zero Flag를 바꾼 다음 JNZ에서 정상적으로 JUMP할 수 있게 해줘야 합니다. Zero Flag는 더블클릭으로 쉽게 바꿔줄 수 있으니 한번 바꿔봅시다.

 

표시된 부분을 더블클릭해서 Zero Flag를 0으로 바꿨습니다. 

 

이제 F8을 눌러 명령을 실행하면 정상적으로 JUMP가 됩니다.

 

 

다음으로 쭉 진행하다 보면 ReadFile 함수가 실행되고, 그 다음 

TEST EAX, EAX 가 나옵니다.

이건 EAX의 값이 0인지 아닌지를 확인하는 명령어라고 생각하시면 됩니다.

 

그런 다음 JUMP 명령어가 두개가 나옵니다. 위에는 좀전에 했던 Zero Flag가 0일때 JUMP를 하고,

밑에는 아무런 조건없이 바로 JUMP를 하는 명령어 입니다. 

 

JNZ로 점프를 하게되면 바로밑에 있는 점프 명령어는 실행되지 않을 것이고,

제로 플래그가 1이라서 JNZ명령을 건너뛰면 밑에있는 JMP 명령을 수행하게 되겠죠.

 

그럼 여기서의 상황을 봅시다.

 

Zero Flag는 TEST 명령을 통한 결과도 마찬가지로 반영을 합니다.

결과가 0이면 플래그가 1이되고, 결과가 1이면 플래그가 0이 됩니다.

 

지금은 EAX의 값이 0이기 때문에 TEST의 결과가 0이 되고, 오른쪽에 제로 플래그도 1이 되어버렸습니다.

이렇게 되면 JNZ 명령이 아닌 JMP 명령이 있는 곳을 수행하게 되죠. 그럼 JMP 명령을 실행했을때 어디로 가는지 한번 확인해봅시다. 

 

아까처럼 명령어 위치에 클릭했을 때, 빨간색 화살표가 가리키는 위치를 보시면 됩니다.

 

 

그쪽을 찾아가 보면 4010F7의 위치를 볼 수 있는데, 이 위치에 가게 되면, 아까와 유사한 메세지 박스 함수와 프로세스를 종료하는 함수가 있습니다. 

 

결론적으로 말하자면, CreateFileA함수에 대한 결과를 임의로 바꿨기 때문에, ReadFile의 결과도 00000000이 되어 EAX에 들어가게 되었고, 이때 TEST 명령을 통해 JNZ 명령을 수행하지 않고 JMP 명령을 통해 다시 KeyFile이 올바르지 않다는 메세지박스를 보게되는 것입니다.

 

(CreateFileA 함수에서 정상적인 파일이 있었으면, ReadFile의 결과도 정상적으로 나왔을것입니다. ReadFile의 결과인 0도 CreateFileA 함수에서의 -1처럼 비정상적인 값이라는 뜻입니다.)

 

 

 

그럼 위에서 했던것 처럼 JNZ명령을 수행하기 전에 제로 플래그를 바꾸고 JNZ 명령을 수행해 봅시다.

 

 

정상적으로 점프가 되었고, XOR이 있는 곳까지 왔습니다.

 

 

그 밑에 명령어들을 보시면, 어려워보이는 많은 점프문들이 있습니다. 일단 F8을 눌러 진행해봅시다.

 

 진행을 하다보면, 왠지모르게 결국은 키파일이 이상하다는 메시지 박스를 호출하는곳으로 이동합니다.

 

위의 방법처럼 진행을 하려면 점프문을 지나는곳마다 플래그값을 찾고 하나하나 비교해야하는데 너무 번거로울것 같습니다. 다른방법을 찾아봅시다. 

 

 

 

명령어가 나와있는곳에 마우스 우클릭을 한 후에 Search for -> All referenced text strings를 클릭해 봅시다.

 

 

여기는 프로그램을 실행하면서 참조되는 메세지나 스트링을 볼 수 있는데

보시면 우리가 아까 봐왔던 메세지들을 볼 수 있습니다.

 

근데 맨 아래를 보면 

You really did it! Congratz!!! 라는 메세지가 보입니다. 뭔가 모든것이 정상적으로 되었고, 문제를 풀었을때 띄워주는 메세지처럼 생겼습니다.

 

원하는 메세지를 더블클릭하면 해당 메세지가 있는 곳으로 바로 넘어가게 되니 축하해주는 메세지를 더블클릭해서 위치로 가봅시다.

 

 

이동 후 자세히 보면 빨간색 화살표가 있고 어디선가 점프를 해왔다 라는 것을 알 수 있습니다. 어디서 점프가 이루어졌는지 한번 따라가봅시다. 

 

출발지를 찾았습니다. 근데 보시면 ReadFile 함수도 보이고 아까 우리가 했던 위치에서 조금 더 가야 되는것을 알 수 있습니다.  얼마 안남았으니 조금만 더 힘내서 찾아봅시다!

 

 

우선 아까 점프를 다른곳으로 했기 때문에 처음으로 돌아가봅시다. (Ctrl + F2)

 

CreateFileA 부분에서는 브레이크포인트를 이미 걸어놨으니 놔두고, ReadFile 이후 JNZ 하는 위치에서도 플래그를 바꿔줘야하기때문에 브레이크포인트를 걸어 둡시다.

 

 

그리고 위에서 했던것 처럼 제로 플레그를 바꿔가며 ReadFile 다음까지 실행해 봅시다.

 

먼저 F9를 눌러 처음 브레이크포인트까지 진행을 하시고, 제로플래그를 바꾼 후에 다시 F9를 눌러 4010B0까지 가서 제로플래그를 바꿔주시면 됩니다.

 

이제 아까 했던곳으로 다시 왔습니다. 다음 명령어를 살펴봅시다.

 

JL이 나옵니다. JL은 제로플래그로 결정되는것이 아니고, Less than 의 약자로 비교를 했을때 더 더 작냐를 판단합니다.

(JE는 같을때, JG는 클때 점프합니다.)

 

비교대상은 위의 CMP 명령을 통한 S플래그 입니다.

 

위의 CMP 명령에서는 402173에 있는 값과 10을 비교합니다. 

CMP 명령은 기본적으로 뺄셈을 통해 이루어지고, 

S 플래그는 CMP를 통한 결과가 양수이면 0, 음수이면 1이 됩니다. 

 

이 경우는 402173에 있는 값이 0인데 10과 비교하면서 뺄셈을 하게 되면 -10이 되어 음수가 되었고, 이때문에 S플래그가 1이 되었습니다. 때문에 JL 명령이 실행하게 되는것이죠. 

 

이번에는 S 플래그를 더블클릭해서 0으로 바꿔서 점프하지않도록 해줍시다.

 

내려간 다음 JE 명령어가 보이지만 최종 목적지인 JMP reverseM.00401285가 실행되는 위치까지는 지장이 없으니 계속 진행해줍시다.

 

 

다음 JL 명령어를 보니 또 딴길로 빠지려고 합니다. S플래그도 1로 되었구요. 

JL은 S플래그가 1일때 점프를 하니 바로 0으로 바꿔주고 F8로 넘어갑시다.

 

정상적으로 넘어갔고 해당 점프문을 실행하면

 

아까봤던 축하 메세지를 띄우는 곳까지 왔습니다!

계속 F8로 넘어가봅시다.

 

드디어 성공했습니다! 여기서 OK를 누른다음 F8을 더 누르면 프로그램이 종료됩니다.

 

하지만 여기서 저장을 하지 않으면 항상 이 파일을 열때마다 플래그를 바꿔주는 작업을 반복해야하기 때문에 변경한 크랙 파일을 저장해주는것까지 해줍시다. 

 

명령어가 있는곳에서 스페이스바를 누르면 편집할 수 있습니다.

우선 처음 플래그를 바꾼 곳인 40107B를 찾아가서 스페이스를 눌러봅시다.

 

 

원래는 이런식으로 JNZ로 나와있는데, 우리는 원래 점프해야되는 부분을 강제로 점프하게 해주었으니 

JNZ에서 JMP로 바꿔줍시다.

 

정상적으로 JMP로 바뀐것을 볼 수 있습니다.

 

 

그다음 바꿔줄 부분은 4010B0 입니다. 이부분도 JNZ였으니 JMP로 바꿔줍시다.

 

다음 수정할 부분은 JL이 나오는 4010BF입니다.

이 부분에서는 점프를 하면 "key is not valid" 메시지 박스가 발생되는 지점으로 가게 되므로, JMP로 바꿔주면 안되고, 아무런 명령을 실행하지 않도록 바꿔줘야 합니다.

 

이렇게 nop으로 바꿔줍시다.

요로케

 

다음 JL이 또 등장하는 4010D6 부분도 nop로 바꿔줍시당

 

 

다 바꿨으면 저장해줍시다.

 

 

수정은 우선 우리가 바꿔준 부분(ex. 401073 ~ 4010D8) 을 드래그해서 마우스 우클릭을 한 후에

Copy to executable -> Selection을 클릭합시다.

 

그럼 선택한 부분이 창으로 뜨는데 거기서 다시 마우스 우클릭 후 Save file을 누르시고 새로 파일을 만들면 됩니다.

이런식으로 크랙파일을 만들어봅시다.

저장한다음 크랙 파일을 클릭해보면 바로 실행이 된 것을 확인할 수 있습니다.

 

 

참고

https://cha4ser.tistory.com/entry/%EB%A0%88%EB%82%98-%ED%8A%9C%ED%86%A0%EB%A6%AC%EC%96%BC-1-%EB%9D%BC%EC%9D%B4%EC%84%BC%EC%8A%A4-%EB%A3%A8%ED%8B%B4-%EC%A7%80%EB%82%98%EA%B0%80%EA%B8%B0?category=892885

리버싱 입문을 위한 Lena Tutorial 입니다.

 

유튜브에 보안프로젝트 재즐보프님이 강의를 올려주신 것을 활용하여 함께 공부할 겸 정리해보려고 합니다!

 

총 40번까지의 문제와 강의가 있지만, 11번부터는 유료로 진행되기 때문에 1~10번 까지만 올릴 예정입니다.

10번까지는 디버거 사용법 및 적응기간이라 할 수 있고 이후에는 안티디버깅과 패커 프로텍터와 우회기법 등 심화적인 내용을 다룹니다.

 

10번까지만 해도 리버싱을 처음 접하는 입장에서 굉장히 유익하다고 생각하고, 더 깊게 공부하실 분은 인프런에서 결제 후 영상 보시는 것을 추천드립니다!

 

 

============================================================================

 

실습은 버츄얼박스로 MS윈도우 XP 체험판에서 진행합니다.

 

사용하는 툴은 올리디버거를 사용하고, 실습파일과 윈도우XP체험판, 올리디버거는 댓글에 다운로드 링크 달아드리겠습니다.

 

 

버추얼박스 설치하시고 다운받은 윈도우 붙여주시면 됩니다. 

네트워크 및 공유폴더 설정은 댓글에 재즐보프님께서 올려주신 영상 링크를 함게 올리겠습니다. 

(기본적인 설정방법을 다 알고계신다면 넘어가셔도 됩니다. 공유폴더만 설정하시면 문제없이 하실거에요)

 

설정을 다 하시면 실습파일과 올리디버거를 받아주시면 되는데, 실습파일 다운하면 아래와 같은 40개의 폴더가 나옵니다.

 

 

왼쪽 위에서부터 1번이구요 안에 들어가보시면

 

이런식으로 구성되어있는데 실제로 사용할 파일은 files폴더 안에 있는

 

 

 

reverseMe 파일입니다!

 

 

파일 다운로드가 끝나면 올리디버거 설정을 간단하게 해줘야 합니다.

 

위에 사진에 있는 ollydbg 설정 파일을 잘라내서 

올리디버거가 설치된 폴더에 붙여주시면 됩니다.

 

그런다음 올리디버거를 켜주시면..!

짜잔 오류가 나게됩니다! 

 

그럼 이제 해결을 해봅시다.

 

일단 OK를 누르면 올리디버거 빈 화면이 나오는데 위에 Option-Appearance - Directories에 들어갑니다.

오류가 난 이유가 저기 나와있는 UDD와 Pluging 폴더 경로가 없는 경로라서 오류가 나게 됩니다. 그럼 간단하게 저 경로를 만들어주면 해결이 됩니다.

 

이런식으로 올리디버거 설치폴더에 UDD와 Plugins라는 폴더를 만들어 줍시다.

 

 

그 다음 각각 폴더의 경로를 복사하고

 

여기에 새로 붙여넣기를 하면 됩니다. Plugin도 마찬가지로 복사해서 붙여넣어주세용

 

OK를 누르고 올리디버거를 끄고 다시 시작하면 오류없이 실행이 됩니다.

 

다음 잘 돌아가는지 확인을 위해 예시로 메모장 파일을 열어봅시다.

 

File - Open 한 후에

경로를 c:\windows\notepad.exe 하고 Open 해봅시다.

 

 

 

요런식으로 뜨면 성공입니다. 혹시나 글씨체를 키우고싶다 하시면

 

Option - Appearance - Fonts - Change 에서 키우시면 됩니다.

 

그럼 다음 글 부터 1번문제 들어가도록 하겠습니다!

 

 

출처 :

https://cha4ser.tistory.com/entry/%EB%A0%88%EB%82%98-%ED%8A%9C%ED%86%A0%EB%A6%AC%EC%96%BC-0-%EC%8B%A4%EC%8A%B5-%EC%A4%80%EB%B9%84?category=892885

 

 

01. 올리 디버거 + 어셈블리어를 이해하여 기본적인 "reverseme" 바이너리 패치
02. 어셈블리어를 이해하여 "reversme" 바이너리에서 요구하는 키 파일 생성
03. 기본적인 Nag 창 제거 및 PE 헤더 문제
04. 기본 및 외관(실행에는 중요하지 않지만 그냥 깔끔하게 하기 위함) 패치
05. "JMP" 등과 같은 조건문(분기문)에서의 조건 비교, BP 및 Animate Over/IN
06. "The Plain Stupid" 패치 방법 및 문자열 검색 기능
07. "Intermediate" 레벨 패치 방법
08. W32Dasm 툴을 이용한 디버깅, "VA / Offset" 설명 및 "LordPE" 헥스 에디터처럼 사용하기
09. "Visual Basic" 개념 및 "SmartChecK" 툴 설정 및 사용법
10. "Visual Basic" 리버싱, 디컴파일러 사용법 및 기본적인 안티 안티 디버깅 기법
11. 올리 디버거의 "Pane Window"를 이용한 "Intermediate" 레벨 패치 방법
12. 여러 패치를 이용하여 프로그램 흐름 바꾸기
13. 소프트웨어 내에서 API 사용법 및 더블체킹(이중 체크) 트릭 우회 방법
14. 인라인 패치
16. 코드 흐름 분석하는 방법 및 포인터를 사용한 인라인 패치
17. 기본적인 (셀프) 키젠의 개념
18. "분석 방해 코드(잉여/쓰레기 코드)", 암/복호화, 자기 변조 코드 및 다형성 코드
19. 디버거 탐지 및 안티 안티 디버깅 기법 설명
20. 패커와 프로텍터 - 입문
20. 임포트 리빌딩
22. API 리다이렉트
23. "Stolen Bytes"
24. 로더를 이용하여 프로그램 실행 시 패치하는 기법
25. 로더를 이용하여 프로그램 실행 시 패치하는 기법 및 "Armadillo" 프로텍터 언패킹
26. 특정 환경에서 동작하는 로더 및 "Armadillo" 언패킹/디버깅
27. "tElock" 프로텍터 및 "Advanced" 패치
28. 서버 체크 우회 및 종료하는 기법
29. 서버 체크 우회 및 종료하는 고급 기법
30. SFX, Run Trace 및 고급 문자열 검색 기능
31. 올리 디버거와 "DeDe"에서 델파이 바이너리 분석하기
32. 바이너리 제작자 트릭, HIEW 툴 사용 및 인라인 패치
33. FPU, 무결성 체크 & 로더 vs 패쳐
34. 패킹 된 바이너리 리버싱 및 ASProtect 패커를 대상으로 하는 Search and Replace 로더 생성
35. 다형성 코드 (바이너리) 인라인 패치
36. 키젠       
37. 심도 있는 언패킹 & 패커 / 프로텍터 혼합 안티 안티 디버깅
38. 언패킹 & DLL / TLS 를 이용한 디버거 탐지 
39. 패커 + CRC 체크 적용된 DLL 내부에서 "blowfish" 인라인 + "ASProtect SKE2.2" 언패킹     
40. 난독화, 그리고 알고리즘 하이딩/숨기기

 

 

 

출처

: https://bob3rdnewbie.tistory.com/155?category=680106

+ Recent posts