Be myself :: 'Reversing' 카테고리의 글 목록 (2 Page)

달력

32024  이전 다음

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

'Reversing'에 해당되는 글 16건

  1. 2014.05.11 인라인 패치
  2. 2014.05.10 Upack 분석중 정리
  3. 2014.05.09 UPX압축 디버깅
  4. 2014.05.08 IAT와 EAT
  5. 2014.05.08 PE구조
  6. 2014.05.04 기본 레지스터

인라인 패치

Reversing 2014. 5. 11. 13:45

1 개요

인라인 패치를 통해 지금까지 배운 내용들을 총 정리하는 시간을 가지자. 패치를 통해 파일의 내용이 어떻게 가상메모리상에 올라가는지, 가상메모리에 올라간 프로그램이 어떻게 실행 되는지 등의 그림을 그릴 수 있을 것이다. 이 기법은 후킹을 할때도 이용된다. 

2 분석

일단 파일의 내용이 어떻게 가상메모리 상에 올라가고, 연산되는지 전체적인 그림을 그리자
먼저 unpackme#1.aC.exe파일을 실행시켜 보자. 파일은 http://ap0x.jezgra.net/download/patchme_no1.rar 에서 받을 수 있다.

NAG(잔소리)라고 쓴 글자를 바꾸라는 것 같다.

Status의 메시지도 바꾸는 것이 우리의 목표이다.

일단 올리디버거로 디버깅하기 전에 우선, PE구조를 분석하여 이 파일이 가상메모리상에서 어떻게 존재하게 되는지 파악한다. 다음과 같은 그림이 그려진다. (각자 그려보자)

자, 이제 대략적인 메모리 구조가 파악이 됐으니 ollyDbg로 뜯어보면서 확인 이 메모리상에서 어떤 일이 벌어지는지 확인해 보자. 우선 분석을 하다보면 첫 번째, 반복 루틴을 만나게 된다.

EBX에 0x4010F5~0x401249까지의 값에 44의 XOR값으로 연산되고 있다. 여기서 XOR 은 기본적인 암호화, 복호화 연산에 잘 사용된다. 예를들어 a XOR 11로 암호화하고 a XOR 11로 복호화 하는식이다. 그렇다면 위의 값은 44로 위의 주소 값에 존재하는 값을 복호화 하고 있다. 계속 트레이싱 해보자. 두 번재 반복 루틴을 만난다.

EBX의 0x401007~0x401086까지의 값을 7로 복호화 하고있다. 계속 살펴 보자.

세 번째 루틴이다. EBX의 0x4010F5~0x401249 의 값을 11로 다시 복호화 하고 있다. 즉, 0x4010F5~0x401249영역은 첫 번째와 세 번째 루틴에서 두 번 복호화 하고 있다. 두 번 암호화 된 것이다.

자 계속 트레이싱 해보자.

0x401062의 명령어를 보면 0x4010F5~0x401249 영역의 값을 더한 값을 31EB8DB0의 값과 비교하고 있다. 이 것은 이 데이터가 손실되진 않았는지, 변형되진 않았는지 확인하는 CheckSum값이다. 계속 트레이싱 해보자. CALL 0040108A부분을 들어가면 다음과 같은 루틴이 확인된다.

EBX에 0x40124A~0x401280 까지의 값을 17로 복호화 하고 있다.

자, 지금까지의 과정을 정리해 보면 다음과 같다.

1.0x4010F5~0x401249까지의 값에 44의 XOR값으로 연산
2.0x401007~0x401086까지의 값을 7로 복호화
3.0x4010F5~0x401249 의 값을 11로 다시 복호화
4.0x4010F5~0x401249 영역의 값을 더한 값을 31EB8DB0의 값과 비교
5.0x40124A~0x401280 까지의 값을 17로 복호화
6.JMP 0040121E명령어로 OEP로 점프

이를 제일 처음에서 살펴 보았던 가상메모리상의 구조와 함께 이해하자. 그럼 다음과 같은 그림이 그려진다.

(출처: http://www.partner114.com/bbs/board.php?bo_table=B33&wr_id=91)
자 이제 분석이 끝났으니, 어떻게 패치 할까 고민해 보자. 우리는 인라인 패치 방법을 진행하려 한다. 이 방법은 파일의 빈영역에 명령어를 집어 넣고 OEP로 점프하는 부분을 우리가 입력한 패치 코드부분으로 JMP하도록 한다음, 패치를 수행한 후 원래의 OEP로 되돌려 주면 된다. 그럼 일단 빈영역을 확보해야 하는데, 우리는 text section을 이용하도록 하자. 앞에서 살펴 보았듯이 text section은 0x401280 부분에 끝이 나게된다. 그렇다면, 이 부분에 파일이 비었는지 확인을 해야하는데 이는 RVA->RWA변환을 하면 된다. 0x401280(RVA) – 0x1000(Virtual Address) + 400(PointerToRawData) = 680이다. 이부분을 헥스 에디터로 살펴 보자.

공간이 충분한 것 같다. 그럼 이 부분을 올리디버거를 이용해 어셈블리로 명령어를 입력해 파일을 저장한 후, JMP OEP부분을 이 부분으로 바꾸면 패치가 완료 된다.

다음과 같이 명령어를 입력하자.

자 이제 이 파일을 저장하자. 그 다음 OEP로 가는 부분을 찾아보자

명령어가 E9 96 01로 되어있는데 이 부분을 우리가 원하는 주소로 입력하면 된다.

이렇게 변경하면 명령어가 E9 F8 01 이렇게 된다. 이 값을 XOR 7으로 다시 암호화 해서 파일에 값을 적어 넣으면 완성이다. 401083(RVA)->483(RAW)값 이므로 이 위치의 값을 밑의 그림처럼 바꾸면 된다.

저장한 다음, 파일을 실행 시키면 다음과 같이 뜬다.

성공이다.!

'Reversing' 카테고리의 다른 글

SEH를 이용한 안티디버깅  (1) 2014.05.15
TLS 콜백 안티디버깅  (0) 2014.05.15
Upack 분석중 정리  (0) 2014.05.10
UPX압축 디버깅  (0) 2014.05.09
IAT와 EAT  (0) 2014.05.08
Posted by flack3r
|

Upack 분석중 정리

Reversing 2014. 5. 10. 00:24

1. Dos Header에서 file header위치를 dos header에서 바꿀수 있다

2. File Header에서  Optional Header의 크기를 결정 할 수 있다

*여기서 주의할 점은 section헤더의 시작은 

Optional Header의 시작주소 + File Header->sizeofOptioanlHeader값.

4. OptionalHeader에서 NumberOfRvaAndsSizes 값이 바뀔 수 있다. 건드리면

안되는 부분만 제외하면 조작가능

5. Section Header에서도 주요한 것 제외하곤 없어도 됨


'Reversing' 카테고리의 다른 글

TLS 콜백 안티디버깅  (0) 2014.05.15
인라인 패치  (0) 2014.05.11
UPX압축 디버깅  (0) 2014.05.09
IAT와 EAT  (0) 2014.05.08
PE구조  (0) 2014.05.08
Posted by flack3r
|

UPX압축 디버깅

Reversing 2014. 5. 9. 13:41

1 개념

UPX실행 압축된 파일을 뜯어보면서 OEP까지 가는게 목표이다. 한번 읽어보고 직접 실습하면서 연습하자.

2 분석

어떤식으로 압축 알고리즘이 되어 있는지 살피기 위해 일단, PE구조를 살펴 보았다.

IMAGE_SECTION_HEADER UPX0의 구조이다. 여기서 주목할 점은 파일에서의 사이즈가 0이라는 점이다. 하지만 Virtual Size를 보면 10000값을 가진다. 이것이 의미하는 것은 다른 섹션에서 압축해제 알고리즘을 가지고 있어 그 섹션에서 먼저 EP가 실행이 되고 압축해제가 완료되면 원래의 UPX0섹션에서 OEP를 가진다는 것을 유추할 수 있다. 자, 그럼 이제 올리디버거로 이 파일을 까보자.

빠르게 훑어보면 코드섹션에 많은 데이터가 압축되거나 암호화되어 있고, 그 결과로 분석된 코드가 정상적이지 않을 수 있다는 말을 뱉어낸다. 그냥 '예'를 눌러준다.

처음 명령어를 살펴 보면, 먼저, EAX~EDI 레지스터 들을 스택에 push한 다음, ESI와 EDI값을 설정한다. 그 중 ESI와 EDI에 어떤 값이 들어가는지 살펴 보면 1011000값과 1001000값이 들어 있다. 이 값은 각각 아까 PEview에서 보았듯이 UPX1섹션과 UPX0섹션의 시작 값 이였다. 그렇다면 아까 우리가 예상 했듯이 UPX1에서 압축해제 알고리즘이 끝나면 UPX0에 압축해제된 내용이 존재하고, 원래의 OEP로 찾아 갈 수 있을 것 같다.

계속 트레이싱 하다 보면, 다음과 같은 루프를 만날 수 있다.

ECX의 수만큼, EDX의 하위 1바이트 값을 AL에 넣고, AL값을 EDI값(UPX0위치)에 넣는 루틴이다. 값은 NULL을 넣으니, UPX0의 공간을 확보하는 루틴이라 보아도 좋을 것 같다.

그 이후 EDI에 값을 넣는 루틴을 3가지 정도 발견 할 수 있다.

  (첫째)

(둘째)

(셋째)

EAX에 압축해제된 데이터가 존재하고 이 값을 EDI(UPX0)에 넣는 과정이다.

그 다음 만나는 루프는 다음과 같다.

UPX0에서 E8과 E9(CALL, JMP명령어)부분을 찾아 어떤 연산을 수행하는데, 잘은 모르겠지만 점프할 주소를 원래대로 복원시키는 작업인 것 같다. 계속 트레이싱 해보자.

뭔가 많이 본 함수가 보이지 않나? LoadLibraryA-> GetProcAddress가 반복된다. 앞에서 살 펴 본 IAT에 함수 시작값을 입력하는 순서에 나왔었다. 즉 이 반복루틴은 INT에 함수의 시작점을 입력하는 루틴이다. 여기까지 보면 의문스러운 점이 한두가지가 아닐 것이다. 일단 INT에 함수의 시작점을 쓴다는데, 그럼 LoadLibraryA의 시작주소는 어떻게 메모리에 올라가 있는 것인가? GetProcAddress는 또 어떠한가. 그래서 PE Viewer로 찾아보았다.

IMPORT Directory Table이 .rsrc섹션에 존재하고 있었다! 그렇다면 중요한 라이브러리의 함수들은 rsrc섹션에 이미 다 로드 되어 있고, 나머지 함수들이 UPX0섹션의 INT영역에 API주소가 입력되어 진다는 것이다.

자 이제 끝났다. 조금 더 트레이싱 하다보면, 다음과 같은 화면을 볼 수 있다.

JMP로 OEP에 가는 것을 볼 수 있다. 100739D는 UPX0의 영역이다.

'Reversing' 카테고리의 다른 글

인라인 패치  (0) 2014.05.11
Upack 분석중 정리  (0) 2014.05.10
IAT와 EAT  (0) 2014.05.08
PE구조  (0) 2014.05.08
기본 레지스터  (0) 2014.05.04
Posted by flack3r
|

IAT와 EAT

Reversing 2014. 5. 8. 20:17

1 개요

자 이제 IAT와 EAT에 관해서 알아 볼 것이다. 앞 장에서 자세히 설명하지 않고 넘어간 NT Header -> Optional Header -> DataDirectory 멤버의 구조체에서 EXPORT Directory와 IMPORT Directory와 관련된 부분이다. API후킹 방법 중 하나로 활용되므로 꼭 숙지하길 바란다.

IAT(Import Address Table)로 쉽게 말해서 프로그램이 어떤 라이브러리에서, 어떠한 함수를 사용하는지 적은 메모장이라 생각하면 된다.

IAT의 원리를 알기 위해선 DLL에 대한 개념이 필수적이다. DLL이란, 여러 프로세스에서 공유하면서 쓰는 라이브러리인데 멀티태스킹 환경에서는 각 프로세스마다 라이브러리를 가지고 그 용량을 차지하는 것 보다, 메모리에 한번 로딩시켜 프로세스마다 공유시키면 메모리를 더 효율적으로 사용 할 수 있기 때문에 DLL이 탄생하였다.

<출처 http://www.hanbit.co.kr/network/view.html?bi_id=1326>

예를 들어, 위의 프로세스 A의 Page 1이 Frame 5를 가리키고, 프로세스 B의 Page 7도 마찬가지로 Frame 5를 가리킨다. 이것은, DLL을 한번 메모리에 로드 시키고, 그 영역을 프로세스 별로 공유한다는 것을 뜻한다. 여기서 주의할 점은, DLL이 메모리에 어느 곳에 로딩되어 있는지 프로그래밍 할 당시에 확인할 방법이 없다는 것이다. 그래서, IAT라는 공간을 만들어 두고, PE Loader가 이 공간에 DLL이 메모리상 어디에 위치 되어 있는지 쓰는 과정을 거치게 된다.

여기서 또 알 수 있는 점은 DLL이 올라 갈 때, 메모리상에 바로 올라 가는 것이 아니라 프로세스 가상메모리에 먼저 올라 가고, 페이지 테이블에서 물리 메모리에 지정된다는 것이다. IAT와 EAT를 배우면 이 과정이 좀더 자세하게 그림이 그려질 것이다.

2 IAT

자, IMAGE_IMPORT_DESCRIPTOR구조체의 FirstThunk라는 멤버가 IAT를 가리킨다. 그럼, IMAGE_IMPORT_DESCRIPTOR는 어디에서 확인할까? 바로 NT Header-> Optioinal Header-> DataDirectory 에서의 2번째 변수 값이 가리키는 위치에 존재한다. 그럼, IMAGE_IMPORT_DESCRIPTOR 구조체가 어떤 멤버로 구성되어 있는지 확인해 보자.

보통 하나의 프로그램에서 여러 개의 라이브러리를 갖기 때문에, IID는 배열의 형식으로 나타나게 된다. 이 멤버들 중 우리에게 중요한 부분은 주석으로 달린 부분들 이다. OriginalFirstThunk같은 경우는 라이브러리의 함수들의 주소를 가리키고 있는 부분들이다. Name멤버는, 라이브러리의 이름을 뜻한다. FirstThunk멤버는 IAT의 주소값을 가리킨다.

자 이제 어떠한 방식으로 IAT에 함수 주소들이 로딩되는지 알아 볼 텐데 꾀나 복잡하다. 하지만 상식적으로 생각하면 쉽게 와 닿는다. 프로그램에서 라이브러리를 사용 할 경우, 먼저 라이브러리를 로딩시켜야 하지 않겠나? 그럼 필요한 것이 라이브러리의 이름이다.(Name 멤버) 그 다음 필요한 것이 무엇 이겠는가? 우린 지금 라이브러리에 존재하는 함수들의 위치를 IAT에 적으려 하고 있다. 그렇다면 필요한 것은 바로 라이브러리에 존재하는 함수들의 이름이다(INT멤버) 그럼 필요한 것은 모두 구했다. 이제 이 값을 이용해 FirstThunk 를 이용하여 IAT에 함수 주소를 입력하면 끝이다. 이 순서를 좀 더 자세히 표현한 것은 다음과 같다.

1. IDD의 Name멤버를 이용해 라이브러리의 이름을 얻는다.
2. 라이브러리를 로딩시킨다(Loadlibrary).
3. INT의 값을 읽어 IMAGE_IMPORT_BY_NAME구조체들의 주소(RVA)를 얻는다.
4. IMAGE_IMPORT_BY_NAME 의 멤버를 이용하여 함수의 시작주소를 얻는다.
5. FirstThunk멤버를 이용해 IAT에 함수의 시작 주소값을 입력한다.
6. OriginalFirstThunk가 끝날 때 까지 3~5의 과정을 반복한다.

여기서 다루지 않은 부분이 IMAGE_IMPORT_BY_NAME구조체 부분이다.

참고로 INT와 IAT는 NULL로 끝나고 둘의 크기는 반드시 같아야 한다.

3 EAT

EAT(Export Address Table)란 라이브러리 파일에서 제공하는 함수를 다른 프로그램에서 가져다 사용할 수 있도록 해주는 과정에서 중요한 역할을 한다. IAT를 공부 할 때, LoadLibrary 함수를 이용해 라이브러리를 로딩시키는 과정에서 일어나는 과정을 설명할 것이다. 우선 IMAGE_EXPORT_DIRECTORY의 구조체를 살펴 보자. 이 구조체 위치는 OptionalHeader->DataDirectory[0]이 가리킨다.

중요한 멤버들은 주석으로 표시를 하였다.
그렇다면 이제 어떤 과정으로 라이브러리의 함수들이 로딩 되는지 살펴 보겠다.

1. AddressOfNames 멤버(RVA값)를 이용해 '함수 이름 배열' 로 간다. 즉, 함수들의 이름을 적어놓은 공간이라 생각하면 된다.
2. '함수 이름 배열'은 문자열 주소가 저장되어 있다. 문자열 비교를 통해 원하는 함수의 이름을 찾는다. 그리고 이 때의 인덱스 값을 구한다.
3. AddressOfNameOrdinals 멤버(RVA)값 을 이용해 'ordinal'배열로 간다.
4. 'ordinal'배열에서 2번에서 구한 인덱스 값을 이용해 ordinal값을 찾는다.
5. AddressOfFunctions을 이용해 EAT로 간다.
6. EAT에서 4번에서 구한 ordinal을 배열 인덱스로 하여 원하는 함수의 시작 주소를 얻는다.

4 정리

EAT와 IAT의 과정을 묶어서 이해 할 필요가 있습니다. 어떤 순서로 되는지 짚어 보겠습니다.

-------------------------<IAT 과정>-------------------------

1. IDD의 Name멤버를 이용해 라이브러리의 이름을 얻는다.
2. 라이브러리를 로딩시킨다(Loadlibrary).
3. INT의 값을 읽어 IMAGE_IMPORT_BY_NAME구조체들의 주소(RVA)를 얻는다.
4. IMAGE_IMPORT_BY_NAME 의 멤버를 이용하여 함수의 시작주소를 얻는다.

-------------------------<EAT 과정>-------------------------

4-1. AddressOfNames 멤버(RVA값)를 이용해 '함수 이름 배열' 로 간다. 즉, 함수들의 이름을 적어놓은 공간이라 생각하면 된다.
4-2. '함수 이름 배열'은 문자열 주소가 저장되어 있다. 문자열 비교를 통해 원하는 함수의 이름을 찾는다. 그리고 이 때의 인덱스 값을 구한다.
4-3. AddressOfNameOrdinals 멤버(RVA)값 을 이용해 'ordinal'배열로 간다.
4-4. 'ordinal'배열에서 2번에서 구한 인덱스 값을 이용해 ordinal값을 찾는다.
4-5. AddressOfFunctions을 이용해 EAT로 간다.
4-6. EAT에서 4번에서 구한 ordinal을 배열 인덱스로 하여 원하는 함수의 시작 주소를 얻는다.
-----------------------------------------------------------------
5. FirstThunk멤버를 이용해 IAT에 함수의 시작 주소값을 입력한다.
6. OriginalFirstThunk가 끝날 때 까지 3~5의 과정을 반복한다.



'Reversing' 카테고리의 다른 글

인라인 패치  (0) 2014.05.11
Upack 분석중 정리  (0) 2014.05.10
UPX압축 디버깅  (0) 2014.05.09
PE구조  (0) 2014.05.08
기본 레지스터  (0) 2014.05.04
Posted by flack3r
|

PE구조

Reversing 2014. 5. 8. 15:50

1 개요

이번엔 PE구조에 대해 살펴보도록 하자. PE구조를 처음 공부할 때는 어디에 쓰이는지 몰라 이걸 왜 공부해야 하는지 잘 모를 것이다. 필자 역시 그러했다. 하지만 공부를 하면 할수록 윈도우 리버싱에서 꼭 알고 가야 할 것이 PE관련 지식들이었다. 간단한 예를 들면 간단한 압축파일의 패치를 할 경우에, 여러가지 방법이 있겠지만, 그 중 쓰지 않는 섹션의 공간에 패치명령어를 입력하는 방법을 쓸 때, PE관련 지식이 없다면 사용 할 수도 없을 것이다. 또한 IAT를 후킹 할 시에도 PE관련 지식이 필수적이다. 또 PE에 관한 지식이 있다면, IDT를 조작하여 DLL인젝션도 가능 하다. 이처럼 여러 가지 기법을 사용함에 있어 PE구조에 관한 지식은 필수라 할 수 있다.

 

2 PE란?

PE란 Portable Executable의 약자로, 윈도우 운영체제에서 사용되는 실행파일 형식이다. 애초에 Portable의 의미대로 여러 운영체제간의 이식성을 좋게 하려는 의도였으나 현실은 윈도우 계열의 운영체제에서만 사용된다. PE를 보고 알 수 있는 점은 참 많다. 프로세스의 각 섹션들이 어떻게 메모리에 적재되는지, 어떤 DLL들이 사용되는지, 필요한 stack과 heap의 크기가 어떤지 등이 모두 적혀져 있다. 참고로 64비트에서의 실행파일은 PE+ 혹은 PE32+라 부른다.

 

3. PE 파일 포맷

위의 그림은 메모장을 Hex에디터로 열어본 것이다. 이 Hex값들을 토대로 PE구조를 살펴 볼 것이다.

3-1 기본 개념

본격적으로 PE구조에 대해 살펴보기 전에, PE구조에 의해 어떻게 파일이 메모리에 적재되는지 살펴 보자.

<출처 reversecore>

그림을 살펴 보면, DOS header에서 Section header까지 PE header라 부르고 그 아랫 부분을 PE body라 부른다. 여기서 주의깊게 봐야 할 점은 header부분은 메모리와 파일의 위치가 같은데, body부분은 위치가 다르다는 것이다. 하지만 그 오프셋(어떤 값의 어떤 위치에서부터의 메모리상에서 위치) 값은 같게된다. VA(Virtual Address)는 프로세스 가상 메모리의 절대주소를 말하며, RVA(Relative Virtual Address)는 오프셋 값을 나타낸다. 따라서 RVA + ImageBase = VA값이 된다. 여기서 또 주목할 점은, 어던 값의 파일에서의 오프셋과 메모리에서의 오프셋은 같으므로 이러한 공식이 성립된다. RAW(파일에서 어떤 메모리의 위치) – PointerToRawData = RVA – VirtualAddress가 성립된다. PointerToRawData란, 데이터에서의 섹션의 시작지점을 나타내고, VirtualAddress란 메모리에서 섹션의 시작주소를 나타낸다. 예를 들어 RVA값이 6000이라면 .text section에 존재하므로 VirtualAddress값은 1000이고, PointerToRawData의 값은 400이 된다. 따라서, RAW(파일에서의 이 값의 위치)는 = 6000 – 1000 + 400 이다. 이 때의 값은 16진수임에 유의해서 계산한다. 이 계산을 자유자재로 할 수 있을 만큼 연습해야 할 것이다.

혹자는 여기까지 읽으면 궁금한 점이 하나 있을 것이다. (필자는 궁금하다.) 과연 PE Format은 누가 어떻게 사용하는 것인가? 이에 대한 답은 윈도우 커널에서 PE loader가 로드 시키는 것이다. 필자의 추측으론, 어떠한 실행파일을 실행 시키면, 시스템 콜을 OS에 전달하고, 이에 대한 처리로써, PE loader를 실행시켜 메모리에 PE구조에 맞게 각 섹션들과 데이터들을 로드시키지 않나 생각한다.

3-2 dos헤더

이제 본격적으로 PE구조에 관한 사항들을 살펴 보자. 먼저 DOS Header이다. 마이크로 소프트는 DOS파일에 대한 호환성을 고려해 PE구조를 디자인하였다. DOS Header의 모습은 어떠한지 살펴 보자.

위의 부분이 DOS Header 부분이다. 이 중 눈 여겨 볼 것은 딱 2가지 부분이다. e_magic 부분과 e_lfanew 부분이다. E_magic은 젤 앞에 4D 5A부분으로 ASCII 값으로 'MZ'이다. 이는 DOS signature 값으로 항상 이 값이 존재 해야 한다. E_lfanew부분은 제일 마지막 E0 00 00 00 부분으로 이 값은 NT Header 구조체를 가리킨다. 그리고 그 다음 ASCII값으로 PE가 나오기 전까지의 부분은 DOS Stub코드 이다. 이 부분은 도스의 호환성을 위해 마련된 자리이므로 없어도 상관없다. 따라서 컴파일러 설정만 조정하면 이 부분을 없앨 수 있다.

3-3 Nt 헤더

NT헤더 구조체가 어떻게 생겼는지 구경해 보자.


<출처:http://blog.naver.com/PostView.nhn?blogId=cor2quard&logNo=150169612062&beginTime=0&jumpingVid=&from=search&redirect=Log&widgetTypeCall=true>

위의 사진에서 보다시피 NT Header는 ASCII값으로 PE라고 적힌 Signature부분과 FileHeader, OptionalHeader부분으로 구성되어 있다. 이제 각각의 경우를 살펴보자. 부분을 살 펴 보자.

3-3-1 Signature

Signature부분은 ASCII코드 값으로 PE를 나타내며, NT Header의 시작을 표현한다.

3-3-2 file header

파일의 개략적인 속성을 나타내는 구조체이다.

<출처 MSDN>

여기서 우리가 주목해야 할 점은 Machine부분과 NumberOfSections, SizeofOptionalHeader, Characteristics 부분이다.

<Machine>
CPU별로 고유한 값을 가진다. Intel x86호환칩은 14C값을 가진다.

<NumberOfSections>
글자 그대로 섹션들의 개수를 나타낸다.

<SizeofOptionalHeader>
글자 그대로 OptionalHeaer의 크기를 나타낸다. OptionalHeader가 무엇인지는 뒤에서 살펴 볼 것이다.

<Characteristics>
파일의 속성을 나타내는 값이다. 실행파일인지 dll파일인지 등의 정보들이 or연산으로 저장되어 있다.

그림에 표시된 부분이 PE signature 와 PE FileHeader 부분이다.

3-3-3 file optional header

어떤 구조체인지 모습을 살펴 보자

제일 밑에 보면 IMAGE_DATA_DIRECTORY가 있는데 이것 또한 어떻게 생겼는지 훑어 보자.

Optional Header에서 중요한 멤버들을 찍어 보겠다.

Magic, AddressOfEntryPoint, ImageBase, SectionAlignment, FileAlignment, SizeOfImage, SizeOfHeaders, Subsystem, NumberOfRvaAndSizes, DataDirectory 부분이다. 하나하나 살펴 보도록 하겠다.

<Magic>
32비트환경인 경우 10B, 64비트인 경우 20B의 값을 가진다.

<AddressOfEntryPoint>
EP(Entry Point)의 RVA값을 가지고 있다.

<ImageBase>
메모리 상에서 PE파일이 로딩되는 시작 값을 가진다. 즉, PE로더는 메모리에 PE파일을 실행 시킬 때, AddressOfEntryPoint + ImageBase의 값을 EIP값으로 지정한다.

<SectionAlignment, FileAlignment>
파일에서 섹션의 최소단위가 FileAlignment이고 메모리에서 섹션의 최소단위가 SectionAlignmnet이다.

<SizeOfImage>
가상메모리 상에서 PE Image가 차지하는 크기이다.

<SizeOfHeader>
PE헤더의 전체 크기를 나타낸다. (파일상에서) 따라서 파일 시작위치에서 SizeOfHeader만큼 떨어진 위치에서 섹션이 시작된다.

<SubSystem>
시스템 드라이버파일인지, 일반 실행 파일인지 구분한다.

<NumberOfRvaAndSizes>
DataDirectory 배열의 개수를 나타낸다.

<DataDirectory>
데이터 디렉토리 배열에 어떤 값들이 정의되어 있는지 살펴보자.

<출처 : http://keybreak.tistory.com/98>

위에 밑줄 그어져 있는 것들을 유심히 잘 보시기 바란다. 이러한 내용들 까지 다 설명 하려면 날이 다 샐 것 같으니 다음 글에서 설명하도록 하겠다. 간단히 설명하자면, 외부에서 사용할 수 있도록 한 함수들이 정의된 부분이 EXPORT부분이고 외부에서 가져와 쓰는 함수들이 정의된 부분이 IMPORT이고 TLS같은 경우 쓰레드의 생성 시 EP시작 전에 시작되는 부분인데, 보통 이 부분에 바이러스 프로그램을 넣거나, 혹은 디버깅이 불가능하게 만들도록 Anti Debugging기법에서도 많이 쓰인다.

지금까지의 값들을 Hex로 확인하면 다음과 같다.

3-4 section header

이제 거의 다왔다. 조금만 더 참고 인내하자.

섹션은, 안정적인 구조를 위해 구현 되었다. 읽고 쓰기 등의 권한을 주어서 관리하는 것이다. 그래서 이러한 값들을 저장할 공간이 필요하게 되었고 섹션헤더 라는 공간을 만들게 되었다.

<출처: MSDN>

여기서 우리가 주목해야 할 멤버는 VirtualSize, VirtualAddress, SizeOfRawData, PointerToRawData, Characteristics정도 이다.

항목

의미

VirtualSize

메모리 상에서 섹션의 크기

VirtualAddress

메모리 상에서 섹션의 시작주소(RVA)값

SizeOfRawData

파일 상에서 섹션의 크기

PointerToRawData

파일 상에서 섹션의 위치

Characteristics

읽기, 쓰기, 실행 등의 설정 값

여기서 VirtualSize값과 SizeOfRawData값이 따로 존재하는지 궁금해 하시는 분이 있을 수 있습니다. 그 이유는 메모리 상에서의 사이즈 값과, 실제 파일에서의 크기가 다를 수 있기 때문입니다. 이는 아까 NT Header -> Optional Header -> FileAlignment, SectionAlignment 에서도 다루었습니다. 이 부분은 RVA -> RAW변환에서 상당히 중요한 개념입니다. 잘 기억하시기 바랍니다.

'Reversing' 카테고리의 다른 글

인라인 패치  (0) 2014.05.11
Upack 분석중 정리  (0) 2014.05.10
UPX압축 디버깅  (0) 2014.05.09
IAT와 EAT  (0) 2014.05.08
기본 레지스터  (0) 2014.05.04
Posted by flack3r
|

기본 레지스터

Reversing 2014. 5. 4. 01:48

 

개요

8086내부에서 사용하는 대표적인 레지스터들을 알아볼 것이다.

 

상세 분석

지금부터 대표적으로 사용되는 레지스터들을 알아 볼 텐데, 사실 여기에 정리한 내용은 대략적으로 익히고 디버그나 리버싱, 취약점분석 등 필요할때 마다 검색이나 서적을 통해 참조하다 보면 자연스럽게 익혀질 것이므로 억지로 외우려거나 할 필요는 없다고 생각한다. 32bit 시스템 기준이다. 

 

 

 

EAX- accumulator register라고 해서 산술,논리 연산의 중심이 되는 레지스터이다. 또 하나 중요한 역할을 하는데, 셸코드 작성시 시스템콜 번호를 넘기는 역할을 하기도 한다. 

EBX- 간접 번지 지정시 사용되는 레지스터이다. 베이스 레지스터로 주로 사용된다. 쉽게 말하자면 이 값을 참조해서 원하고자 하는 값을 참조하는 방식이다. 

ECX- counter register로 for문이나 while문 같은 루프문에서 반복수행하고자 하는 횟수를 지정할때 주로 사용된다. 

EDX - 곱셈이나 나눗셈 등의 보조 어큐뮬레이터로 사용되기도 한다. 

 

위의 4가지 레지스터에 대한 설명은 일반적인 쓰임이 그렇다는 것이지, 반드시 위의 용도로만 쓰이는 것은 아니다. 레지스터는 단지 값을 저장하는 메모리일 뿐이라는 사실을 기억하기 바란다. 

 

ESP(스택포인터)와 EBP(베이스 포인터)같은 경우는 스택프레임이 만들어 지는 과정을 다음에 살펴보면서 더 자세히 알아 보겠다. 간단히 설명하자면, EBP같은 경우, 지역변수의 참조를 위해 사용되고, ESP같은 경우 스택프레임의 제일 위의 주소값을 나타낸다. 

 

ESI, EDI - 연산이나 간접 번지 지정에 사용된다. 그밖에 주로 문자열 전송이나 비교 등을 하는 문자열관련 명령에서 SI는 source(대상)가 되는 문자열을, DI는 destination(목표)가 되는 문자열의 번지를 표시한다. 

 

이 외에는

EIP- 다음에 실행할 명령어 번지를 가리키는데, CS세그먼트 레지스터와 한 쌍이 되어 실행 번지가 만들어진다. 예를들어 0x0001[0x0003] 이라는 간접주소가 있으면 0x00010은 CS세그먼트에, 0x0003은 EIP에 저장되어 두 값을 더하여 실제 물리주소값을 나타 낸다. 

 

 

참고 URL 및 도서

-그림 seednote.tistory.com

 

'Reversing' 카테고리의 다른 글

인라인 패치  (0) 2014.05.11
Upack 분석중 정리  (0) 2014.05.10
UPX압축 디버깅  (0) 2014.05.09
IAT와 EAT  (0) 2014.05.08
PE구조  (0) 2014.05.08
Posted by flack3r
|