#include <ntddk.h>
#include <KerStr.h>
#include <RtlHelp.c>
#define MEM_HOT_PATCH 'HotP'
PVOID _MmSystemLoadLock ;
#define HotPatchSectionName '.hotp1'
LIST_ENTRY _MiHotPatchList ;
ERESOURCE _PsLoadedModuleResource ;
LIST_ENTRY _PsLoadedModuleList ;
ULONG_PTR _MiSessionImageStart ;
ULONG_PTR _MiSessionImageEnd ;
extern ULONG RtlGetHotPatchHeader(ULONG ImageBase) ;
extern ULONG
RtlFindRtlPatchHeader(LIST_ENTRY HotPatchList,
PLDR_DATA_TABLE_ENTRY LdrData );
extern BOOL RtlpIsSameImage(PRTL_PATCH_HEADER PatchHeader,
PLDR_DATA_TABLE_ENTRY LdrData);
extern NTSTATUS RtlCreateHotPatch(PRTL_PATCH_HEADER *ImageBase ,
PHOTPATCH_HEADER HPSectionData ,
PLDR_DATA_TABLE_ENTRY LdrData,
NTSTATUS Flags);
extern NTSTATUS
ExLockUserBuffer (
__inout_bcount(Length) PVOID Buffer,
__in ULONG Length,
__in KPROCESSOR_MODE ProbeMode,
__in LOCK_OPERATION LockMode,
__deref_out PVOID *LockedBuffer,
__deref_out PVOID *LockVariable
);
extern VOID
ExUnlockUserBuffer (
__inout PVOID LockVariable
);
//two function form Windows Research Kernel source code
extern void RtlFreeHotPatchData(PRTL_PATCH_HEADER PatchData) ;
NTSTATUS
MiPerformHotPatch(PLDR_DATA_TABLE_ENTRY LdrData ,
ULONG ImageBase ,
NTSTATUS Flags)
{
ULONG TempLdr = 0;
PHOTPATCH_HEADER HPSectionData ;
NTSTATUS stat ;
PLDR_DATA_TABLE_ENTRY Link1 ;
PRTL_PATCH_HEADER PatchHeader ;
PVOID LockedBuffer ;
PVOID LockVariable ;
HPSectionData = RtlGetHotPatchHeader(ImageBase) ;
//获得HotPacth文件中的HotPacth数据
if (!HPSectionData)
{
return STATUS_INVALID_IMAGE_FORMAT ;
}
ImageBase = RtlFindRtlPatchHeader(_MiHotPatchList ,LdrData) ;
//查找HotPatch是否已安装
if (!ImageBase )
{
if (!Flags && 1)
{
return STATUS_NOT_SUPPORTED;
//如果RtlPatchHeader不存在而HOTP_PATCH_APPLY=0
//则出错
}
stat = RtlCreateHotPatch(&ImageBase, HPSectionData, LdrData ,Flags);
PatchHeader = (PRTL_PATCH_HEADER)ImageBase ;
//创建HotPacth头
if (!NT_SUCCESS(stat))
{
return stat ;
}
ExAcquireResourceExclusiveLite(_PsLoadedModuleResource ,TRUE) ;
//开始遍历PsLoadedModuleList
//寻找符合的模块
Link1 = _PsLoadedModuleList.Blink ;
while (Link1 != _PsLoadedModuleList)
{
TempLdr = Link1 ;
if (Link1->DllBase < _MiSessionImageStart ||
Link1->DllBase >= _MiSessionImageEnd)
{
if (RtlpIsSameImage(PatchHeader ,Link1))
{
break ;
}
}
Link1 = _PsLoadedModuleList.Blink ;
}
//验证模块
ExReleaseResourceLite(_PsLoadedModuleResource) ;
if (!PatchHeader->TargetDllBase)
{
return STATUS_DLL_NOT_FOUND ;
}
stat = ExLockUserBuffer(LdrData->DllBase,
LdrData->SizeOfImage ,
KernelMode,
&LockedBuffer,
&LockVariable
) ;
//锁定用户内存
if (!NT_SUCCESS(stat))
{
RtlFreeHotPatchData(PatchHeader );
return stat ;
}
stat = RtlInitializeHotPatch(PatchHeader ,(ULONG)LockedBuffer - LdrData->DllBase) ;
ExUnlockUserBuffer(LockVariable);
if (!NT_SUCCESS(stat))
{
RtlFreeHotPatchData(PatchHeader );
return stat ;
}
}
}
NTSTATUS RtlpApplyRelocationFixups(PRTL_PATCH_HEADER PatchHeader , PVOID DllBase)
{
}
NTSTATUS RtlInitializeHotPatch(PRTL_PATCH_HEADER PatchHeader , PVOID DllBase)
{
NTSTATUS stat ;
stat = RtlpApplyRelocationFixups()
if (!NT_SUCCESS(stat))
{
return stat ;
}
stat = RtlpValidateTargetRanges(PatchHeader ,TRUE) ;
if (!NT_SUCCESS(stat))
{
return stat ;
}
stat = RtlReadHookInformation(PatchHeader) ;
return stat ;
}
NTSTATUS MmHotPatchRoutine(PSYSTEM_HOTPATCH_CODE_INFORMATION RemoteInfo)
{
UNICODE_STRING HotPatchName ;
ULONG ImageBase ;
HANDLE ImageHandle;
NTSTATUS stat ;
NTSTATUS stat2 ;
stat2 = RemoteInfo->Flags ;
HotPatchName.Length = RemoteInfo->KernelInfo.NameLength ;
HotPatchName.MaximumLength = RemoteInfo->KernelInfo.NameLength ;
HotPatchName.Buffer = (ULONG)RemoteInfo + RemoteInfo->KernelInfo.NameOffset ;
__asm
{
push eax
mov eax, fs : 0x124
dec dword ptr [eax + 0xd4]
pop eax
}
//enable the KTHREAD->KernelApcDisable
KeWaitForSingleObject(_MmSystemLoadLock ,
WrSuspended,
NULL,
NULL,
NULL) ;
//wait for mmsystemLoadLock
stat = MmLoadSystemImage(&HotPatchName ,
NULL,
NULL,
NULL,
&ImageHandle,
&ImageBase
) ;
//加载hotpatch驱动程序
if (!NT_SUCCESS(stat))
{
if (stat == STATUS_IMAGE_ALREADY_LOADED )
{
goto OK1;
}
goto Failed;
}
//如果驱动加载失败,返回
//如果加载成功或镜象已经加载,则返回Image Base Address
OK1:
stat = MiPerformHotPatch((PLDR_DATA_TABLE_ENTRY)ImageHandle , ImageBase , stat2) ;
//执行补丁
if (!NT_SUCCESS(stat))
{
if (stat == STATUS_IMAGE_ALREADY_LOADED)
{
goto OK2;
}
MmUnloadSystemImage(ImageHandle);
}
//如果执行失败,卸载镜象
OK2:
stat = stat2 ;
Failed:
KeReleaseMutant(_MmSystemLoadLock , 1 , NULL,NULL) ;
__asm
{
push eax
push esi
mov eax, fs : 0x124
inc dword ptr [esi + 0xd4]
jnz end1
lea eax, [esi + 0x34]
;ApcState
cmp [ eax ], eax
jz end1
mov cl , 1
mov byte ptr [esi + 0x49] ,1
call HalRequestSoftwareInterrupt
pop esi
pop eax
}
//disable the KTHREAD->KernelApcDisable
return stat ;
}
Hotpatch逆向代码(2) KerStr.h和RtlHelp.c~
{
APPLICATION_MANIFEST,
ASSEMBLY_MANIFEST
};
struct entity
{
DWORD kind;
union
{
struct
{
WCHAR *tlbid;
WCHAR *version;
WCHAR *helpdir;
} typelib;
struct
{
WCHAR *clsid;
} comclass;
struct {
WCHAR *iid;
WCHAR *name;
} proxy;
struct
{
WCHAR *name;
} class;
struct
{
WCHAR *name;
WCHAR *clsid;
} clrclass;
struct
{
WCHAR *name;
WCHAR *clsid;
} clrsurrogate;
} u;
};
struct assembly_identity
{
WCHAR *name;
WCHAR *arch;
WCHAR *public_key;
WCHAR *language;
WCHAR *type;
struct version version;
BOOL optional;
};
struct dll_redirect
{
WCHAR *name;
WCHAR *hash;
struct entity_array entities;
};
struct entity_array
{
struct entity *base;
unsigned int num;
unsigned int allocated;
};
struct assembly
{
enum assembly_type type;
struct assembly_identity id;
struct file_info manifest;
WCHAR *directory;
BOOL no_inherit;
struct dll_redirect *dlls;
unsigned int num_dlls;
unsigned int allocated_dlls;
struct entity_array entities;
};
struct file_info
{
ULONG type;
WCHAR *info;
};
typedef struct _ACTIVATION_CONTEXT
{
ULONG magic;
int ref_count;
struct file_info config;
struct file_info appdir;
struct assembly *assemblies;
unsigned int num_assemblies;
unsigned int allocated_assemblies;
} ACTIVATION_CONTEXT;
typedef struct _LDR_DATA_TABLE_ENTRY {
LIST_ENTRY InLoadOrderLinks; //0x00
LIST_ENTRY InMemoryOrderLinks; //00x08
LIST_ENTRY InInitializationOrderLinks; //0x10
PVOID DllBase; //0x18
PVOID EntryPoint; //0x01c
ULONG SizeOfImage; // 0x20
UNICODE_STRING FullDllName; //0x24
UNICODE_STRING BaseDllName; //0x2c
ULONG Flags; //0x3
USHORT LoadCount;
USHORT TlsIndex;
union {
LIST_ENTRY HashLinks;
struct {
PVOID SectionPointer;
ULONG CheckSum;
};
};
union {
struct {
ULONG TimeDateStamp;
};
struct {
PVOID LoadedImports;
};
};
struct _ACTIVATION_CONTEXT * EntryPointActivationContext;
PVOID PatchInformation;
} LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
typedef struct _RTL_PATCH_HEADER {
LIST_ENTRY PatchList;
HMODULE PatchImageBase;
struct _RTL_PATCH_HEADER * NextPatch;
ULONG PatchFlags;
LONG PatchRefCount;
PHOTPATCH_HEADER HotpatchHeader;
UNICODE_STRING TargetDllName;
HMODULE TargetDllBase;
PLDR_DATA_TABLE_ENTRY TargetLdrDataTableEntry;
PLDR_DATA_TABLE_ENTRY PatchLdrDataTableEntry;
PSYSTEM_HOTPATCH_CODE_INFORMATION CodeInfo;
} RTL_PATCH_HEADER, *PRTL_PATCH_HEADER;
//_RTL_PATCH_HEADER & _HOTPATCH_HEADER
//this two struct is form OpenRCE
typedef struct _HOTPATCH_HEADER {
DWORD Signature; //0x00
DWORD Version; //0x04
DWORD FixupRgnCount; //0x08
DWORD FixupRgnRva; //0x0c
DWORD ValidationCount; //0x10
DWORD ValidationArrayRva; //0x14
DWORD HookCount; //0x18
DWORD HookArrayRva; //0x1c
ULONGLONG OrigHotpBaseAddress; //0x20
ULONGLONG OrigTargetBaseAddress; //0x28
DWORD TargetNameRva; //0x30
DWORD ModuleIdMethod; //0x34
union {
ULONGLONG Quad;
GUID Guid;
struct {
GUID Guid;
DWORD Age;
} PdbSig;
BYTE Hash128[16];
BYTE Hash160[20];
} TargetModuleIdValue;
} HOTPATCH_HEADER, *PHOTPATCH_HEADER;
typedef struct _FILE_RENAME_INFORMATION {
BOOLEAN ReplaceIfExists;
HANDLE RootDirectory;
ULONG FileNameLength;
WCHAR FileName[1];
} FILE_RENAME_INFORMATION, *PFILE_RENAME_INFORMATION;
typedef struct _HOTPATCH_HOOK_DESCRIPTOR{
ULONG_PTR TargetAddress; //0x0c
PVOID MappedAddress; //00x10
ULONG CodeOffset; //0x14
ULONG CodeSize; //0x18
ULONG OrigCodeOffset; //0x1c
ULONG ValidationOffset; //0x20
ULONG ValidationSize; //0x24
} HOTPATCH_HOOK_DESCRIPTOR, *PHOTPATCH_HOOK_DESCRIPTOR;
typedef struct _SYSTEM_HOTPATCH_CODE_INFORMATION {
ULONG Flags; //0x00
ULONG InfoSize; //00x04
union {
struct {
ULONG DescriptorsCount; //00x08
HOTPATCH_HOOK_DESCRIPTOR CodeDescriptors[1]; // variable size structure
} CodeInfo;
struct {
USHORT NameOffset; //0x08
USHORT NameLength; //0x0a
} KernelInfo;
struct {
USHORT NameOffset; //0x8
USHORT NameLength; //0x0a
USHORT TargetNameOffset; //0x0c
USHORT TargetNameLength; //0x0e
} UserModeInfo;
struct {
HANDLE FileHandle1;
PIO_STATUS_BLOCK IoStatusBlock1;
PFILE_RENAME_INFORMATION RenameInformation1;
ULONG RenameInformationLength1;
HANDLE FileHandle2;
PIO_STATUS_BLOCK IoStatusBlock2;
PFILE_RENAME_INFORMATION RenameInformation2;
ULONG RenameInformationLength2;
} RenameInfo;
struct {
HANDLE ParentDirectory;
HANDLE ObjectHandle1;
HANDLE ObjectHandle2;
} AtomicSwap;
};
//
// NOTE Do not add anything after CodeDescriptors array as
// it is assumed to have a variable size
//
} SYSTEM_HOTPATCH_CODE_INFORMATION, *PSYSTEM_HOTPATCH_CODE_INFORMATION;
NTSTATUS MmLoadSystemImage(
IN PUNICODE_STRING ImageFileName,
IN PUNICODE_STRING NamePrefix OPTIONAL,
IN PUNICODE_STRING LoadedBaseName OPTIONAL,
IN ULONG LoadFlags,
OUT PVOID *ImageHandle,
OUT PVOID *ImageBaseAddress
);
//the routine to load the image into system kernel
NTSYSAPI
LONG
KeReleaseMutant (
__inout PRKMUTANT Mutant,
__in KPRIORITY Increment,
__in BOOLEAN Abandoned,
__in BOOLEAN Wait
);
NTHALAPI
VOID
FASTCALL
HalRequestSoftwareInterrupt (
KIRQL RequestIrql
);
NTSTATUS
MmUnloadSystemImage (
IN PVOID ImageHandle
) ;
PIMAGE_NT_HEADERS
NTAPI
RtlImageNtHeader(
PVOID Base
);
PIMAGE_SECTION_HEADER
RtlpFindSectionHeader(PIMAGE_NT_HEADERS ImageNtHeader ,
LPCSTR SectionName)
{
ULONG OHeaderSize ;
ULONG NumberOfSection ;
ULONG SectionHeaderStart ;
ULONG i ;
OHeaderSize = ImageNtHeader->FileHeader.SizeOfOptionalHeader ;
NumberOfSection = ImageNtHeader->FileHeader.NumberOfSections ;
SectionHeaderStart = (ULONG)ImageNtHeader->OptionalHeader + OHeaderSize ;
if (NumberOfSection <= 0)
{
return 0;
}
for (i= 0 ; i < NumberOfSection ; i++)
{
if (RtlCompareMemory(SectionHeaderStart ,
SectionName ,
IMAGE_SIZEOF_SHORT_NAME) == IMAGE_SIZEOF_SHORT_NAME)
{
return SectionHeaderStart ;
}
SectionHeaderStart += sizeof(IMAGE_SECTION_HEADER) ;
}
return 0;
}
//该函数的作用是从PE镜象中找到指定Section名的Section Header并返回
ULONG RtlGetHotPatchHeader(ULONG ImageBase)
{
PIMAGE_NT_HEADERS ImageNtHeader ;
PIMAGE_SECTION_HEADER SectionStart ;
PHOTPATCH_HEADER HPSectionData ;
ImageNtHeader = RtlImageNtHeader(ImageBase) ;
if (!ImageBase)
{
return 0 ;
}
SectionStart = RtlpFindSectionHeader(ImageNtHeader , HotPatchSectionName );
if (!SectionStart)
{
return 0 ;
}
if (SectionStart->Misc.VirtualSize < sizeof(HOTPATCH_HEADER))
{
return 0;
}
HPSectionData = SectionStart->VirtualAddress ;
if (HPSectionData->Signature != 0x31544F48 )
{
//Char 'HOT1'
return 0 ;
}
if (HPSectionData->Version = 0x10000)
{
return HPSectionData;
}
return 0;
}
// 该函数的作用从PE镜象中找到HOTPATCH节的地址,并进行一些基本验证
ULONG
RtlFindRtlPatchHeader(LIST_ENTRY HotPatchList,
PLDR_DATA_TABLE_ENTRY LdrData )
{
LIST_ENTRY HotPatchList1 ;
HotPatchList1 = HotPatchList1.Blink ;
while (HotPatchList1 != HotPatchList)
{
if (*(ULONG*)HotPatchList1 + 0x2c == (ULONG)LdrData)
{
return HotPatchList1 ;
}
HotPatchList1 = HotPatchList1.Blink ;
}
return 0 ;
}
// 从目前已安装的补丁列表中寻找当前的补丁是否是已经安装的
//即是从MiHotPatchList这个双向链表中寻找是否有符合的RTL_PATCH_HEADER
BOOLEAN RtlpValidatePeHeaderHash2(PRTL_PATCH_HEADER PatchHeader,
PVOID DllBase)
{
//not implement
return FALSE ;
}
BOOLEAN RtlpValidatePeChecksum(PRTL_PATCH_HEADER PatchHeader,
PLDR_DATA_TABLE_ENTRY LdrData)
{
//not implement
return FALSE
}
BOOLEAN RtlpValidateTargetModule(PRTL_PATCH_HEADER PatchHeader,
PVOID DllBase)
{
ULONG Method ;
Method = PatchHeader->HotpatchHeader->ModuleIdMethod ;
switch (Method)
{
case 0x0 :
DbgPrintEx(0x57 ,0x2 ,"HOTP_ID_None/n" ) ;
return TRUE ;
case 0x1 :
DbgPrintEx(0x57, 0x2 , "HOTP_ID_PeHeaderHash1") ;
return FALSE ;
case 0x2 :
DbgPrintEx(0x57, 0x2 , "HOTP_ID_PeHeaderHash2") ;
return RtlpValidatePeHeaderHash2(PatchHeader , LdrData->DllBase ) ;
case 0x3 :
return RtlpValidatePeChecksum(PatchHeader , LdrData->DllBase ) ;
case 0x10 :
DbgPrintEx(0x57, 0x2 ,"HOTP_ID_PeDebugSignature") ;
return FALSE ;
default :
DbgPrintEx(0x57 ,0x2 ,"Unrecognized" ) ;
return FALSE ;
}
return FALSE ;
}
BOOL RtlpIsSameImage(PRTL_PATCH_HEADER PatchHeader,
PLDR_DATA_TABLE_ENTRY LdrData)
{
ULONG ImageNtHeader ;
ImageNtHeader = RtlImageNtHeader(LdrData->DllBase) ;
if (!ImageNtHeader)
{
return FALSE ;
}
if (!RtlEqualUnicodeString(PatchHeader->TargetDllName, LdrData->BaseDllName , TRUE) )
{
return FALSE ;
}
if (!RtlpValidateTargetModule(PatchHeader , LdrData ))
{
return FALSE ;
}
PatchHeader->TargetLdrDataTableEntry = LdrData ;
PatchHeader->TargetDllBase = LdrData->DllBase ;
return TRUE ;
}
void RtlpFreeHotPatchMemory(PVOID Pool)
{
ExFreePoolWithTag(Pool,
MEM_HOT_PATCH);
return ;
}
void RtlFreeHotPatchData(PRTL_PATCH_HEADER PatchData)
{
if (PatchData->CodeInfo)
{
RtlpFreeHotPatchMemory(PatchData->CodeInfo) ;
}
RtlFreeAnsiString(&PatchData->TargetDllName) ;
RtlpFreeHotPatchMemory(PatchData);
return ;
}
NTSTATUS RtlCreateHotPatch(PRTL_PATCH_HEADER *ImageBase ,
PHOTPATCH_HEADER HPSectionData ,
PLDR_DATA_TABLE_ENTRY LdrData,
NTSTATUS Flags)
{
PRTL_PATCH_HEADER PatchHeader ;
ANSI_STRING AnsiDllName ;
UNICODE_STRING UniDllName ;
NTSTATUS stat ;
PatchHeader = ExAllocatePoolWithTag(PagedPool , 0x34 ,MEM_HOT_PATCH) ;
if (!PatchHeader)
{
return STATUS_NO_MEMORY ;
}
RtlZeroMemory(PatchHeader , 0x0d);
PatchHeader->PatchFlags = Flags & 0xfffffffe ;
PatchHeader->HotpatchHeader = HPSectionData ;
PatchHeader->PatchLdrDataTableEntry = LdrData ;
PatchHeader->PatchImageBase = LdrData->DllBase ;
PatchHeader->PatchList.Blink = PatchHeader ;
PatchHeader->PatchList.Flink = PatchHeader ;
RtlInitAnsiString(&AnsiDllName ,
(LPCSTR)(HPSectionData->TargetNameRva + LdrData->DllBase));
stat = RtlAnsiStringToUnicodeString(&UniDllName , &AnsiDllName , TRUE) ;
if (!NT_SUCCESS(stat))
{
RtlFreeHotPatchData(PatchHeader);
return stat ;
}
ImageBase = PatchHeader ;
return stat ;
}
#define POOL_QUOTA_FAIL_INSTEAD_OF_RAISE 8
VOID
ExUnlockUserBuffer (
__inout PVOID LockVariable
)
{
MmUnlockPages ((PMDL)LockVariable);
ExFreePool ((PMDL)LockVariable);
return;
}
NTSTATUS
ExLockUserBuffer (
__inout_bcount(Length) PVOID Buffer,
__in ULONG Length,
__in KPROCESSOR_MODE ProbeMode,
// __in LOCK_OPERATION LockMode,
__deref_out PVOID *LockedBuffer,
__deref_out PVOID *LockVariable
)
//modify to Windows xp module
/*++
Routine Description:
Wrapper for MmProbeAndLockPages. Creates an MDL and locks the
specified buffer with that MDL.
Arguments:
Buffer - pointer to the buffer to be locked.
Length - size of the buffer to be locked.
ProbeMode - processor mode for doing the probe in MmProbeAndLockPages.
LockMode - the mode the pages should be locked for.
LockedBuffer - returns a pointer to the locked buffer for use by the
caller.
LockVariable - returns a context pointer. This must be passed into
ExUnlockUserBuffer when complete so the MDL can be freed.
Return Value:
Returns one of the following status codes:
STATUS_SUCCESS - Normal, successful completion.
STATUS_ACCESS_VIOLATION - The buffer is not accessible with the
specified LockMode.
STATUS_INSUFFICIENT_RESOURCES - not enough memory to allocate the MDL.
--*/
{
PMDL Mdl;
SIZE_T MdlSize;
//
// It is the caller's responsibility to ensure zero cannot be passed in.
//
ASSERT (Length != 0);
*LockedBuffer = NULL;
*LockVariable = NULL;
//
// Allocate an MDL to map the request.
//
MdlSize = MmSizeOfMdl( Buffer, Length );
Mdl = ExAllocatePoolWithQuotaTag (NonPagedPool | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE,
MdlSize,
'ofnI');
if (Mdl == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Initialize MDL for request.
//
MmInitializeMdl(Mdl, Buffer, Length);
try {
MmProbeAndLockPages (Mdl, ProbeMode, 1);
} _except (EXCEPTION_EXECUTE_HANDLER) {
ExFreePool (Mdl);
return GetExceptionCode();
}
Mdl->MdlFlags |= MDL_MAPPING_CAN_FAIL;
*LockedBuffer = MmGetSystemAddressForMdl (Mdl);
if (*LockedBuffer == NULL) {
ExUnlockUserBuffer (Mdl);
return STATUS_INSUFFICIENT_RESOURCES;
}
*LockVariable = Mdl;
return STATUS_SUCCESS;
}