IsDebuggerPresent 그리고 패치
2011/07/04 09:48
Anti-Reversing 기법 중에서 가장 기초적인 방법은 IsDebuggerPresent1 함수를 사용하는 것입니다. IsDebuggerPresent 함수는 호출된 프로세스가 유저 모드 디버거에 의해 호출되었는지를 확인하는 Windows API입니다. windows.h 헤더파일을 인클루드하면 바로 호출할 수 있고, Windows 2000부터 지원된다고 MSDN에 설명되어 있습니다. 함수 원형은 아래와 같습니다.
BOOL IsDebuggerPresent (void);파라미터는 필요 없고, 현재 프로세스가 유저 모드 디버거에 의해 호출된 것이면 0이 아닌 값을 반환합니다.
그런데 아무래도 Windows에서 제공하는 API이기 때문에 함수 호출 지점을 검색해서 nop 처리해버리면 쉽게 우회되는 단점이 있습니다. 그래서 동일한 기능을 하는 아래와 같은 코드를 사용합니다.
BOOL CheckIsDebuggerPresent ()
{
__asm {
mov eax, fs:18h // TEB
mov eax, [eax+30h] // PEB
movzx eax, byte ptr [eax+2] // BeingDebugged
}
}이 코드는 IsDebuggerPresent 함수와 실제로 같은 코드입니다. IsDebuggerPresent 함수는 PEB 구조체의 세 번째 값인 BeingDebugged를 반환합니다. 유저 모드 디버거에 의해 프로세스가 호출되면 BeingDebugged 값이 1이고, 그렇지 않으면 0이기 때문이죠.

그렇다면 반대로 BeingDebugged 값을 애초에 0으로 바꿔놓으면 이 값을 확인해서 디버거를 탐지하는 방법은 무용지물이 되겠죠. 그래서 아래와 같이 패치 코드를 작성할 수 있습니다.
void PatchBeingDebugged ()
{
__asm {
mov eax, fs:18h
mov eax, [eax+30h]
lea eax, byte ptr [eax+2]
mov [eax], 0b
}
}PEB 구조체의 BeingDebugged의 메모리 주소를 구해서 메모리에 0을 바로 집어넣는 것이죠. 그러면 패치 이후로는 PEB의 BeingDebugged를 검사하여도 디버거를 탐지하지를 못합니다.

위 코드는 인라인 어셈으로 작성된 코드입니다. 제가 사용하는 Immunity Debugger에서 조금 더 유연하게 패치하려면 PyCommand로 작성해두면 더 좋죠. 아래는 Python 코드로 작성된 코드입니다.
imm = immlib.Debugger ()
imm.writeMemory (imm.getPEBaddress () + 0x2, '\x00')막강한 immlib 모듈이죠. 사실, 이미 immunityDebugger에는 hidedebugger.py에 저런 코드가 적용되어 있지만요.
덧붙임) MSDN에서는 IsDebuggerPresent 함수가 Windows 2000부터 지원된다고 했지만, 이 함수가 적용되는 _WIN32_WINNT 매크로 값이 0x400 이상이라고 합니다. _WIN32_WINNT 0x400은 Windows 95인데, 어떤 게 맞는 걸까요?
"0x02 Windows RCE" 분류의 다른 글
| 게임 매크로 Inventory A+ 분석 | 2012/02/15 |
| DumpFromOEP.py for Immunity Debugger | 2011/10/22 |
| From AppInit_DLLs To Injection | 2011/09/28 |
| Windows Debugging Intrenals: A to Z | 2011/08/28 |
| API Redirect on Themida | 2011/02/27 |
Trackback Address:http://hisjournal.net/blog/trackback/362