Be myself :: Be myself

달력

42024  이전 다음

  • 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

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
|