PE재배치
화장실에 갔는데 말이죠!
앞사람이 계속 나오지 않는다면 어떻게 할까요?
다른 방법을 찾아봐야겠져?
실행파일도 마찬가지에요.
내가 메모리에 적재되어야 하는 장소에
다른 실행파일이 적재되어있다면
그 파일이 종료될 때까지 목빠지게 기다리다가
망부석이 될 가능성이 크지요.
망부석이 되면 안되기 때문에
다른 메모리장소(기준주소)를 얻어서 재배치 후
메모리에 적재가 됩니다.
파일이 메모리에 로딩될 때 재배치과정을 살펴보면
1) 하드코딩된 주소를 찾은 후
2) ImageBase만큼 뺍니다.(VA에서 RVA만 남겠죠?)
3) 실제 로딩된 ImageBase를 더해줍니다.(RVA에서 VA로 변경)
4) 그리고 메모리에 적재가 됩니다!
아 그런데 하드코딩된 주소는 누가 어떻게 찾냐구요?
IMAGE_NT_HEADER - IMAGE_OPTIONAL_HEADER - IMAGE_DATADIRECTORY[5]
= BASE RELOCATION Table = IMAGE_BASE_RELOCATION(구조체)
IMAGE_BASE_RELOCATION의 원형
typedef struct _IMAGE_BASE_RELOCATION {
DWORD VirtualAddress; //실제로 RVA입니다.
DWORD SizeOfBlock;
//WORD TypeOffset[1]; //하드코딩된 주소의 Offset!
//WORD TypeOffset[1];
//WORD TypeOffset[1];
//WORD TypeOffset[1];
// n개...(예측불가)
} IMAGE_BASE_RELOCATION;
첫 번째 멤버인 VirtualAddress는 기준주소를 의미합니다.
즉, 0x401000이 코드영역이라면 0x1000가 VirtualAddress가 됩니다.
ImageBase로부터 0x1000만큼 떨어져있다는 말이므로
RVA라는말이겠죠?
두 번째 멤버인 SizeOfBlock은 섹션의 크기를 의미합니다.
해당 섹션에서 하드코딩되어 재배치해야할 주소가 저장된 공간의 크기를
의미합니다.
간단한 예제를 가지고 왔습니다.
노란 박스가 첫 번째 멤버인 VirtualAddress입니다.
파란 박스는 두 번째 멤버인 SizeOfBlock입니다.
0x1000영역의 재배치할 주소가
0x150크기만큼 들어있다는 것을 알 수 있겠죠?
0x150이후에는 어떤 것이 있는지 확인해보니
0x2000영역의 재배치할 주소가
0x158크기만큼 들어있다는 것을 알 수 있겠죠?
이런식으로 알 수 있답니다.
[그림2]의 세 번째 멤버(TypeOffset)를 보면
2바이트(16비트)로 구성되어 있는 것을 알 수 있습니다.
여기서 상위 4비트는 TYPE을 의미합니다.
TYPE은 WinNT.h에 정의되어 있으며
직접 찾으시기 귀찮으실테니 제가 직접 가지고 왔습니다.
짝짝짝!!
이와 같이 상수로 정의되어 있습니다.
32비트파일은 보통 3인 IMAGE_REL_BASED_HIGHLOW로 정의되어 있고,
64비트파일은 보통 0xA(10)인 IMAGE_REL_BASED_DIR64로 정의되어 있습니다.
가끔 정상파일의 코드를 패치한 후
재배치과정을 피하기 위해서 Type을 0(IMAGE_REL_BASED_ABSOLUTE)로
변경하는 악성코드도 있답니다.
세 번째 멤버인 TypeOffset이 0x300D네요.
이 중 상위 4바이트인 3은 type을 의미하며
[그림3]으로 미루어볼 때 IMAGE_REL_BASED_HIGHLOW를 의미합니다.
그리고 Offset은 0xD가 되겠네요.
그렇다면 실제로 저 0xD는 메모리에 적재 시
VirtualAddress[기준주소](0x2000) + Offset(0xD) = 0x200D
새롭게 설정된 ImageBase+0x200D주소에
하드코딩된 주소가 들어있겠군요?
ImageBase(0xE40000) + RVA(0x200D) = VA(0xE4200D)
0x00E4C100이라는 주소로 되어있는 것을 확인할 수 있죠?
전 장에서 다룬
RAW - PointerToRawData = RVA - VirtualAddress
RAW = RVA - VirtualAddress + PointerToRawData
내용을 한 번 더 보겠습니다.
예를 들어
0xE43689가 EP입니다.
파일에서 EP의 위치를 찾고 싶다면?
파일의 주소 = 메모리 로딩 후 오프셋 - 메모리 내 섹션의 상대주소 + 파일 내 섹션 시작주소
메모리 로딩 후 오프셋은 OPTION_HEADER의 ImageBase를 제외한 주소입니다.
0xEB3689 - 0xEB0000 = 0x3689
메모리 내 섹션의 상대주소는 .text섹션헤더의 RVA입니다.
0x1000
파일 내 섹션 시작주소는 .text섹션헤더의 PointerToRawData입니다.
0x400
RAW = 0x3689 - 0x1000 + 0x400
=0x2A89
메모리에 올라간 후와 파일로 존재할 때의 EP를 확인할 수 있습니다.
그러나 조금 자세히보면 전부 같지는 않다는 것을 알 수 있습니다.
이 부분은 이 파일이 원래 ImageBase가 0x01000000이라 재배치되었기 때문입니다.
'Try Attack > Reverse Engineering[basic]' 카테고리의 다른 글
(키보드훔쳐보기) 메세지후킹/키로거제작 (2) | 2020.03.30 |
---|---|
PE파일 섹션 추가 및 삭제하기 (0) | 2020.03.24 |
EasyCrackMe - reversing.kr (0) | 2020.03.12 |
main함수 위치를 찾는방법 (0) | 2020.03.02 |
PE 파일 포맷 (0) | 2020.01.21 |
댓글