from john lan
[Note] All the stuff of this series are experimented in Windows Server 2003 Standard Edition with SP1[
[Note] All the stuff of this series are about software only DEP feature, not for hardware DEP supported by new chips
Windows Server 2003 SP1 and Windows XP SP2 introduce a new security feature, called DEP,
Data Execution Prevention, what most interesting is some legacy packed or encrypted
binary code may crash when decrypts themselves, sure, if they use Structured Exception
Handing mechanism of Windows operating system, to protect against debuggers, and most
important, if they allocate memory page using VirtualAlloc/Ex without EXECUTE bit set.
Although I ever knew of this feature quite a bit time ago, it was today that I hit this
scenario when analyzing a crash dump from one of our customers. Mr. Customer used a DLL,
which was packed by some unknown packer, the exception record indicated me that the crash
occured exactly in the first instruction of an exception handler, while the context record is all
cleared as 0 by the OS ! Surprisingly, the exception record and context record did not match,
since the crashed exception handler code can be properly disassembled by WINDBG, so the only
possibility is, the code path is forbidden to transfer to the exception handler, which made me
recall of the DEP feature, before invoking an exception handler, OS will check the fact that,
whether the handler code resides in a EXECUTABLE memory page, generally, it should be
allocated using VirtualAlloc/Ex(PAGE_EXECUTE_XXX), unfornately, some packer only
allocated PAGE_READWRITE pages to hide their SEH handler code, hence, once XP SP2
or 2003 SP1 applied, the packed application will crash, what more surprised me is, I never
knew the fact before that a PAGE_READWRITE page can be executed smoothly before DEP age!
I wrote an sample application to simulate the SEH behavior of packers.
#include "stdafx.h"
#include <windows.h>
//
// Probe Data Execution Prevention (DEP) feature
// for Windows XP SP2, Windows Server 2003 SP1
//
ULONG Scratch;
//
// EXCEPTION HANDLER
// for 'mov dword ptr[eax+0B0h], offset Scratch '
// adjustment of offset may be required due to different
// compiler configuration/version
//
UCHAR Instructions[] = {
0x55, // push ebp
0x8B, 0xEC, // mov ebp, esp
0x8B, 0x45, 0x10, // mov eax, dword ptr[ebp + 10h]
0xC7, 0x80, 0xB0, 0x00, 0x00, 0x00, 0x68, 0x7C, 0x42, 0x00, // mov dword ptr[eax+0B0h], offset Scratch
0x33, 0xC0, // xor eax, eax
0x8B, 0xE5, // mov esp, ebp
0x5D, // pop ebp
0xC3, // ret
};
BaseAddress = (PUCHAR)VirtualAlloc(
NULL,
0x1000,
MEM_COMMIT,
PAGE_READWRITE ; to prevent DEP from disturbing u, EXECUTE bit required
);
if(NULL == BaseAddress) {
printf("TRACE: ErrorID %d /n", GetLastError());
return 0;
}
memcpy(BaseAddress, (const PVOID)Instructions, sizeof(Instructions));
__asm {
push BaseAddress
push fs:[0]
mov fs:[0], esp
xor eax, eax
mov dword ptr[eax], 0xDEADBABE
mov eax, [esp]
mov fs:[0], eax
add esp, 8
}
VirtualFree(BaseAddress, 0x1000, MEM_DECOMMIT);
printf("DEP can not detect this execution in data page !/n");
return 0;
}
int __cdecl main(int argc, char* argv[])
{ PUCHAR BaseAddress = NULL;