Windows 7은 기본적으로 DLL이 랜덤한 주소로 매핑되지만, 컴파일 시 고정된 주소를 설정할 수 있습니다. JAVA 1.6버전의 MSVCR71.dll이 그 대표적인 예 인데, 항상 0x7C340000에 매핑됩니다.

EMET 에는 MandatoryASLR이라는 기능이 있는데, 이 옵션을 키면 NON-ASLR DLL을 랜덤한 주소로 매핑시켜 줍니다.

이렇게 주소가 바뀌게 되면, ROP 시 NON-ASLR DLL을 사용할 수 없게 됩니다.

 

 

EMET 4.1에서는 ROP가 주요 함수들을 호출하여 공격하는 것을 막기 위하여 주요 함수들에 후킹을 걸어 감시합니다.

Deep Hooks 라는 기능이 있는데 이것은 좀 더 많은 API를 커버하는 기능입니다.

예를 들어, VirtualProtect를 호출하면 VirualProtect->VirtualProtectEx->NtProtectVirtualMemory 순으로 호출하는데요, Deep Hooks 기능을 키면 NtProtectVirtualMemory를 후킹합니다. 이걸 옵션으로 뺀 이유가, 다른 시큐리티 회사들이 호환성 문제 때문에 클레임을 걸었다는군요.

아래는 비교 표 입니다. Undocumented API를 커버하여 주네요. 

 

Deep Hooks가 기본 값이 아니기 때문에, 공격자들은 VirtualProtect가 아닌 NtProtectVirtualMemory를 호출하여 우회할 수도 있습니다.

또한 Deep Hooks를 키면 Kernelbase도 추가로 후킹을 합니다.

일반적으로 Ring 3에서는 fs:[0] 과 같은 명령으로 세그먼트 디스크립터가 가리키는 메모리에 접근할 수 있지만, 세그먼트 디스크립터에는 접근할 수 없습니다.

그러나 OllyDbg에서는 아래 그림과 같이 해당 인덱스가 가리키는 세그먼트 디스크립터의 베이스 주소를 표시해주고 있습니다.

Ring 3에서는 일반적인 방법으로는 베이스 주소를 구할 수 없으며, 약간의 트릭이 필요합니다. GetThreadSelectorEntry라는 API를 사용해서 LDT_ENTRY 구조체를 채운 다음, BaseHi + BaseMid + BaseLow 를 통해 베이스 주소를 만들 수 있습니다. LDT_ENTRY는 WinNT.h에 정의되어 있으므로 따로 선언할 필요가 없습니다. (아래 예시는 이해를 돕기위해)

 

위의 방법은 이메일을 통해 올리디버거 제작자인 Oleh Yuschuk에게 문의해서 알아낸 방법이며, 자기가 알기로는 이에 해당하는 64비트 API는 없다고 하네요.

그러나 현재 개발 중인 64비트 올리디버거 스크린샷을 보면 Base Address가 일부 표시되고 있으니 다른 방식으로 구하는 방법이 있는 것 같습니다.

FS 의 경우 비교적 쉽게 구할 수 있는데, FS의 디스크립터가 TEB를 표시하고 있으므로 NtCurrentTeb() 혹은 mov eax, fs:[0x18] 로 베이스 주소를 구할 수 있습니다.

 

+ Recent posts