[分享]调戏:自建ASLR机制
理论上这玩意没有想象中那么高深莫测 

无非就是NtMapViewOfSection的时候,让文件映射的基址发生变化。


对于32位的系统可以直接上驱动级hook去处理。
但是因为最近我不太喜欢使用驱动,所以呢,写个ring3的处理吧(其实老外早做过这事儿了)。
好了不管那些事儿了,直接代码走起。
这里有个事情就是如何实现在Kernel32后快速加载么?
我实现的方法其实就是LPK劫持。这劫持效率你懂得。
typedef LONG (__stdcall *T_NtMapViewOfSection)(
__in HANDLE SectionHandle,
__in HANDLE ProcessHandle,
__inout PVOID *BaseAddress,
__in ULONG_PTR ZeroBits,
__in SIZE_T CommitSize,
__inout_opt PLARGE_INTEGER SectionOffset,
__inout PSIZE_T ViewSize,
__in int InheritDisposition,
__in ULONG AllocationType,
__in int Win32Protect
);
typedef LONG (__stdcall *T_NtUnmapViewOfSection)(
__in HANDLE ProcessHandle,
__in PVOID BaseAddress
);
T_NtUnmapViewOfSection funcNtUnmapViewOfSection =NULL;
T_NtMapViewOfSection OldNtMapViewOfSection = NULL;
LONG __stdcall
OnNtMapViewOfSection(
__in HANDLE SectionHandle,
__in HANDLE ProcessHandle,
__inout PVOID *BaseAddress,
__in ULONG_PTR ZeroBits,
__in SIZE_T CommitSize,
__inout_opt PLARGE_INTEGER SectionOffset,
__inout PSIZE_T ViewSize,
__in int InheritDisposition,
__in ULONG AllocationType,
__in int Win32Protect
)
{
MEMORY_BASIC_INFORMATION mbi;
LONG ns;
ns = OldNtMapViewOfSection(SectionHandle,
ProcessHandle,
BaseAddress,
ZeroBits,
CommitSize,
SectionOffset,
ViewSize,
InheritDisposition,
Win32Protect);
if (ns==0 || ns == 0x40000003)
{
VirtualQuery(*BaseAddress,&mbi,sizeof(mbi));
if (mbi.Type == MEM_IMAGE)
{
PIMAGE_DOS_HEADER DosHeader;
PIMAGE_NT_HEADERS NtHeader;
DosHeader = (PIMAGE_DOS_HEADER)*BaseAddress;
NtHeader = (PIMAGE_NT_HEADERS)((char *)DosHeader+DosHeader->e_lfanew);
if (NtHeader->OptionalHeader.ImageBase == (ULONG)*BaseAddress)
{
if(!(NtHeader->OptionalHeader.DllCharacteristics & 0x40))
{
if (NtHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress)
{
funcNtUnmapViewOfSection(ProcessHandle,*BaseAddress);//释放原始
VirtualAlloc(*BaseAddress,*ViewSize,MEM_RESERVE,PAGE_NOACCESS);//占坑
ns = OldNtMapViewOfSection(SectionHandle,
ProcessHandle,
BaseAddress,
ZeroBits,
CommitSize,
SectionOffset,
ViewSize,
InheritDisposition,
Win32Protect);
}
}
}
}
}
return ns;
}
VOID InitASLR()
{
//除了ntdll.dll之外的dll理论上都可以的,但是为了方便我还是从kernel32之后的dll做这个处理,其实fs:[x]的存在,即使怎么随机化,都是没用的
funcNtUnmapViewOfSection = (T_NtUnmapViewOfSection)GetProcAddress(GetModuleHandleA("ntdll.dll"),"NtUnmapViewOfSection");
InlineHook((void *)GetProcAddress(GetModuleHandleA("ntdll.dll"),"NtMapViewOfSection"),(void *)OnNtMapViewOfSection,(void **)&OldNtMapViewOfSection);
}


至于驱动级的实现,可以把kernel32也处理了,但是ntdll因为KiXXX系列函数被系统绑定了加载地址,所以ntdll理论上只能在系统启动时,随机一次地址(正统的ASLR也是这样的)。具体驱动怎么实现释放和占坑,这就看写驱动的人了,反正我没搞驱动的。
