2008년 01월 07일
SSDT에 대한 고찰
며칠전 부터 SSDT에 대해서 유심히 살펴보았고, 변경된 SSDT를 Restore해주는
녀석의 코드를 살펴본 결과를 정리해보고자 한다.
sunwangme라는 사람이 만든 sdtreset 이라는 녀석은 메모리에 있는 SSDT를
디스크내에 ntoskrnl.exe 안의 export된 SSDT와 비교해서 바뀐 부분을 복구시키는
간단한 POC이다.
그런데 한가지 문제는 내가 사용하는 PC에는 현재 KAV(카스퍼스키 백신)이 깔려
있기에 이녀석이 SSDT를 Relocation 한다는 사실이다.
일반적으로 KeServiceDescriptorTable의 Base 주소가 바뀌지 않았을 경우에는
ntoskrnl.exe에서 적절한 값을 찾아내어 복구 할 수 있었다. 하지만 KAV는 이 Base
주소를 ntoskrnl.exe의 바이너리 외부로 빠져버렸기 때문에 아무리 디스크 이미지
내에서 찾으려 해도 불가능하다는 것이다. 대략 난감. ㅠㅠ;
하지만 솟아날 구멍은 항상 존재하는 것~ ROOTKIT에 올라온 기사 가운데
A more stable way to locate real KiServiceTable 이라는 것에서 힌트를 얻게 되었다.
KAV와 같이 KeServiceDescriptorTable을 Relocation하는 녀석들의 경우는 더 Stable
한 방법으로 KiServiceTable의 주소를 알아내는 방법이다.
아래는 KeServiceDescriptorTable이 KiInitSystem()에서 초기화 되는 것을 코드로 표현한
것이다.
KeServiceDescriptorTable[0].Base = &KiServiceTable[0];
KeServiceDescriptorTable[0].Count = NULL;
KeServiceDescriptorTable[0].Limit = KiServiceLimit;
KeServiceDescriptorTable[0].Number = &KiArgumentTable[0];
for (Index = 1; Index < NUMBER_SERVICE_TABLES; Index += 1) {
KeServiceDescriptorTable[Index].Limit = 0;
}
위와 같은 코드라면 분명 리버싱해보면 다음과 같은 assembly code를 찾을 수 있을 것이다.
C7 05 ..8 bytes.. mov ds:_KeServiceDescriptorTable.Base, offset _KiServiceTable위와 같은 인스트럭션은 DLL이라면 재배치가 필요하다. 기준 재배치를 위해서 reloc 섹션을
참고해야만 할 것이다. 그럼 우선 ntoskrnl을 dll로 매핑한 다음에 export 되어 있는
KeServiceDescriptorTable의 주소를 GetProcAddress()로 알아낸다. 그리고 reloc 섹션을
탐색하여 위의 인스트럭션이 존재하는 RVA값을 알아낸다. 인스트럭션이 시작하는 오프셋에서
6을 더하면 그곳이 KiServiceTable의 주소가 될 것이다. 그러면 실제 복구를 할 때 디스크에서
이 주소를 기본으로 하여 각각의 서비스 인덱스에 대한 주소값을 가져온 후에 KAV가 바꿔버린
서비스 디스패처 루틴의 주소를 복구해줄 수 있다는 결론이다.
# by | 2008/01/07 10:38 | └Windows Internals | 트랙백 | 덧글(0)






