IDA GDB를 이용한 VMware 커널 디버깅

[0x00] Overview

Windows Kernel 디버깅에 있어서 windbg는 정말 가장 강력한 도구입니다. 때문에 해당 포스트가 필요 없을 수 있습니다. 다만 IDA에서는 GDB를 이용한 디버깅이 가능하고 이를 이용하여 Windows Kernel 디버깅이 가능합니다.

windbg의 전통적인 디버깅 방법과는 다르게 동작하기 때문에 꽤 유용하게 사용될 수 있습니다. 예를 들어 PatchGuard 우회 시 사용되는 기법 중 하나인 HalNotifyProcessorFreeze 후킹의 경우에도 windbg는 BSOD를 발생시킵니다.

어쨋든 여러가지 이유로 GDB Stub은 유용합니다.

[0x01] Enable VMware GDB Stub

가상머신 파일이 존재하는 디렉토리에 가서 .vmx 파일을 아래와 같이 수정해야 합니다.

  • x86 Local Debugging : debugStub.listen.guest32 = "TRUE"
  • x64 Local Debugging : debugStub.listen.guest64 = "TRUE"
  • x86 Remote Debugging : debugStub.listen.guest32.remote = "TRUE"
  • x64 Remote Debugging : debugStub.listen.guest64.remote = "TRUE"

다음은 호스트와 통신할 디버깅 포트에 대한 설정을 해줘야 합니다. 기본적으로 x64 guest는 8864 포트, x86 guest는 8832 포트를 사용합니다. 변경하려면 아래와 같이 수정합니다.

  • x86 : debugStub.port.guest32 = "33333"
  • x64 : debugStub.port.guest64 = "33333"

BIOS 로드 시 즉시 디버깅을 사용하는 경우 아래와 같이 추가합니다.

  • x86 : monitor.debugOnStartGuest32 = "TRUE"
  • x64 : monitor.debugOnStartGuest64 = "TRUE"

마지막으로 브레이크 포인트를 하드웨어 브레이크포인트를 이용하려는 경우 아래와 같이 추가합니다.

  • debugStub.hideBreakpoints = "TRUE"

위에서 필요한 내용들을 .vmx 마지막 줄에 추가하고 저장합니다.

[0x02] IDA Setup

이제 IDA에서 설정이 필요합니다. Debugger -> Attach -> Remote GDB debugger 를 선택하고 아래와 같이 설정해야 합니다.

모든 준비가 완료되었습니다. VM을 시작하면 멈춰있게 되며 이 때 IDA gdb를 attach 하게 되면 디버깅이 가능하게 됩니다.

하지만 심볼도 존재하지 않으며 모두 원시코드입니다. 때문에 매우 불편할 수 있으며 현재 메모리 영역이 정리되어 있지 않기 때문에 제대로 보이지 않습니다. 아래와 같이 IDA에서 설정이 필요합니다.

[Debugger]->[Manual memory regions] 탭을 열어 아래와 같이 설정합니다.

이후 다시 시작하고 suspend 시 정상적으로 메모리가 보이게 됩니다. 이제 심볼 로드를 통해 좀 더 정확한 코드를 확인해봅니다.

[0x03] Load symbol

매우 간단합니다. Guest OS 내에 %SystemRoot%\System32\ntoskrnl.exe 파일을 Host로 가져옵니다. 여기서 WKE와 같은 로컬 커널 메모리 에디터 도구가 있다면 더 쉽게 가능합니다. 그 외에도 Process Hacker와 같은 도구를 이용하여 ntoskrnl.exe 모듈의 이미지 베이스를 구해야 합니다.

위와 같이 ntoskrnl.exe 이미지는 0xFFFFF80648A00000 메모리에 로드되어 있습니다. 이를 복사해둡시다.

다음 IDA에서 [File] -> [Load file] -> [PDB file...] 을 이용하여 아래와 같이 심볼을 로드합니다.

다소 시간이 소모됩니다. 이제 제법 디버거 다워지는 모습을 볼 수 있습니다.

그래도 역시 기능적인 면으로만 봤을 때 windbg를 따라올 수는 없습니다. 약간의 편의성과 디버깅 방식의 차이로 인해 몇 가지 이점이 존재합니다.

먼저 KdDebuggerEnabledKdDebuggerNotPresent와 같은 전역변수에서 알아채지 못합니다.

[0x04] Conclusion

어떤 경우에 있어서 해당 디버깅 기법은 참신하며 강력한 기능으로 동작할 수 있습니다. 본인의 경우 Patch Guard 라고 잘 알려져 있는 KPP(Kernel Patch Protection)을 우회하기 위한 다양한 기법 중 예외 기반의 기법을 시연하기 위해 해당 GDB stub을 이용했습니다.