来源于一个注册表保护工具的逆向,主要利用CmpParseKey函数的Object HOOK实现注册表操作重定向来实现注册表还原保护,驱动代码如下:
/*一个简单的注册表还原驱动
来源于某工具逆向,主要解决以下两个问题:
一、理解HIVE文件,这个被system进程独占
二、CmpParseKey函数的挂钩,object HOOK
by:liuke_blue
E-mail:liuke_blue@126.com
*/
#include <ntddk.h>
#include <windef.h>
#include <stdio.h>
extern POBJECT_TYPE *IoFileObjectType;
#define KeyValueFullInformation 1
#define RegHiveFileName L"\\WINDOWS\\system32\\config\\system"
#define RepointRegItem L"\\REGISTRY\\USER\\.DEFAULT\\Volatile\\"
#define ObjectTypeName L"\\ObjectTypes\\Key"
#define itemlen 0x0E
typedef enum _SYSTEM_INFORMATION_CLASS {
SystemBasicInformation, // 0
SystemProcessorInformation, // 1
SystemPerformanceInformation, // 2
SystemTimeOfDayInformation, // 3
SystemNotImplemented1, // 4
SystemProcessesAndThreadsInformation, // 5
SystemCallCounts, // 6
SystemConfigurationInformation, // 7
SystemProcessorTimes, // 8
SystemGlobalFlag, // 9
SystemNotImplemented2, // 10
SystemModuleInformation, // 11
SystemLockInformation, // 12
SystemNotImplemented3, // 13
SystemNotImplemented4, // 14
SystemNotImplemented5, // 15
SystemHandleInformation, // 16
SystemObjectInformation, // 17
SystemPagefileInformation, // 18
SystemInstructionEmulationCounts, // 19
SystemInvalidInfoClass1, // 20
SystemCacheInformation, // 21
SystemPoolTagInformation, // 22
SystemProcessorStatistics, // 23
SystemDpcInformation, // 24
SystemNotImplemented6, // 25
SystemLoadImage, // 26
SystemUnloadImage, // 27
SystemTimeAdjustment, // 28
SystemNotImplemented7, // 29
SystemNotImplemented8, // 30
SystemNotImplemented9, // 31
SystemCrashDumpInformation, // 32
SystemExceptionInformation, // 33
SystemCrashDumpStateInformation, // 34
SystemKernelDebuggerInformation, // 35
SystemContextSwitchInformation, // 36
SystemRegistryQuotaInformation, // 37
SystemLoadAndCallImage, // 38
SystemPrioritySeparation, // 39
SystemNotImplemented10, // 40
SystemNotImplemented11, // 41
SystemInvalidInfoClass2, // 42
SystemInvalidInfoClass3, // 43
SystemTimeZoneInformation, // 44
SystemLookasideInformation, // 45
SystemSetTimeSlipEvent, // 46
SystemCreateSession, // 47
SystemDeleteSession, // 48
SystemInvalidInfoClass4, // 49
SystemRangeStartInformation, // 50
SystemVerifierInformation, // 51
SystemAddVerifier, // 52
SystemSessionProcessesInformation // 53
} SYSTEM_INFORMATION_CLASS;
typedef struct _SYSTEM_HANDLE_INFORMATION
{
ULONG ProcessId;
UCHAR ObjectTypeNumber;
UCHAR Flags;
USHORT Handle;
PVOID Object;
ACCESS_MASK GrantedAccess;
} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;
NTSYSAPI
NTSTATUS
NTAPI
NtQuerySystemInformation(IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
OUT PVOID SystemInformation,
IN ULONG SystemInformationLength,
OUT PULONG ReturnLength OPTIONAL);
NTSYSAPI
NTSTATUS
NTAPI ObOpenObjectByPointer(IN PVOID Object,
IN ULONG HandleAttributes,
IN PACCESS_STATE PassedAccessState,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_TYPE ObjectType,
IN KPROCESSOR_MODE AccessMode,
OUT PHANDLE Handle);
NTSYSAPI
NTSTATUS
NTAPI
ZwRestoreKey(IN HANDLE KeyHandle,
IN HANDLE FileHandle,
IN ULONG Flags);
NTSYSAPI
NTSTATUS
NTAPI
NtClose(IN HANDLE ObjectHandle );
NTSYSAPI
NTSTATUS
NTAPI
ObOpenObjectByName(IN POBJECT_ATTRIBUTES ObjectAttributes,
IN POBJECT_TYPE ObjectType,
IN KPROCESSOR_MODE AccessMode,
IN PACCESS_STATE PassedAccessState,
IN ACCESS_MASK DesiredAccess,
IN OUT PVOID ParseContext,
OUT PHANDLE Handle);
NTSYSAPI
NTSTATUS
NTAPI
ObReferenceObjectByHandle(IN HANDLE Handle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_TYPE ObjectType,
IN KPROCESSOR_MODE AccessMode,
OUT PVOID* Object,
OUT POBJECT_HANDLE_INFORMATION HandleInformation OPTIONAL);
//记得设置为全局变量
ULONG PID;
ULONG Orig_CmpParseKey;
NTSTATUS MyCreateClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp);
ULONG InstallObjectTypeHook(BOOLEAN IsHook);
VOID RestoreReg(PVOID CurrentId);
NTSTATUS Restorssymbol();
//重定向指向打开项或者键值
NTSTATUS fake_CmpParseKey(
IN PVOID ParseObject,
IN PVOID ObjectType,
IN OUT PACCESS_STATE AccessState,
IN KPROCESSOR_MODE AccessMode,
IN ULONG Attributes,
IN OUT PUNICODE_STRING CompleteName,
IN OUT PUNICODE_STRING RemainingName,
IN OUT PVOID Context OPTIONAL,
IN PSECURITY_QUALITY_OF_SERVICE SecurityQos OPTIONAL,
OUT PVOID *Object)
{
wchar_t ItemName[10];
unsigned short fullnamelen;
WORD name1Len;
PVOID repoint_pool;
ULONG name2Len;
unsigned short poollen;
unsigned int childlen;
DWORD tmppos;
ULONG repoint_len;
DWORD CompleteName_;
NTSTATUS status;
CompleteName_=CompleteName;
fullnamelen=CompleteName->Length;
name1Len=(WORD)(itemlen-2);
if (fullnamelen<itemlen)
{
if (fullnamelen==name1Len) //不含"\\"的字符串长度
{
//将L"SOFTWARE"拷贝至ItemName;
memcpy(ItemName,(void*)(CompleteName->Buffer),name1Len);
//最后一位'\0'结尾
ItemName[name1Len>>1]=0;
//字符串转换为大写
_wcsupr(ItemName);
//如果匹配字符串"SOFTWARE"
if (RtlCompareMemory(ItemName,L"SYSTEM\\",name1Len)==name1Len)
{
//分配重定向缓冲区
repoint_pool=ExAllocatePool(PagedPool,0x40u);
memcpy(repoint_pool,L"\\REGISTRY\\USER\\.DEFAULT\\Volatile\\",0x40u);
repoint_len=0x00420040;
goto Over;
}
}
}
else
{
memcpy(ItemName,(void*)(CompleteName->Buffer),itemlen);
ItemName[itemlen>>1]=0;
_wcsupr(ItemName);
name2Len=RtlCompareMemory(ItemName,L"SYSTEM\\",itemlen);
fullnamelen=itemlen;
if (name2Len==itemlen)
{
poollen=(WORD)CompleteName->Length-itemlen+0x42;
repoint_pool=ExAllocatePool(PagedPool,poollen);
memcpy(repoint_pool,L"\\REGISTRY\\USER\\.DEFAULT\\Volatile\\",0x42);
//后面子项的长度,除去前面"SOFTWARE\"的字符串剩下长度
childlen=CompleteName->Length-(WORD)itemlen;
tmppos=*(DWORD*)(CompleteName_+4);
//把"SOFTWARE\\"后面所接的字符子串拷贝到重定向值后面
memcpy((CHAR*)repoint_pool+0x42,(const void *)(tmppos+2*((WORD)(WORD)itemlen>>1)),childlen);
repoint_len=( ((DWORD)(poollen+2)<<16) | ((WORD)poollen) );
Over:
ExFreePoolWithTag(*(PVOID*)(CompleteName_+4),0);
*(DWORD*)CompleteName_=repoint_len;
*(DWORD*)(CompleteName_+4)=(DWORD)repoint_pool;
//重新解析
return STATUS_REPARSE;
}
}
__asm{
push eax
push Object
push SecurityQos
push Context
push RemainingName
push CompleteName_
push Attributes
push AccessMode
push AccessState
push ObjectType
push ParseObject
call Orig_CmpParseKey
mov status,eax
pop eax
}
return status;
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
PDEVICE_OBJECT DeviceObject;
UNICODE_STRING devicename;
UNICODE_STRING linkname;
NTSTATUS status;
HANDLE Threadhandle=NULL;
RtlInitUnicodeString(&devicename,L"\\Device\\RevertHive_2010");
RtlInitUnicodeString(&linkname,L"\\DosDevices\\RevertHive_2010");
status=IoCreateDevice(DriverObject,0,&devicename,FILE_DEVICE_UNKNOWN,0x600,FALSE,&DeviceObject);
if (NT_SUCCESS(status))
{
status=IoCreateSymbolicLink(&linkname, &devicename);
if (NT_SUCCESS(status))
{
DriverObject->MajorFunction[IRP_MJ_CREATE] = MyCreateClose;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = MyCreateClose;
PID=PsGetCurrentProcessId();
if (NT_SUCCESS(PsCreateSystemThread(&Threadhandle,0x1F03FFu, 0, 0, 0, RestoreReg, (PVOID)&PID)))
ZwClose(Threadhandle);
InstallObjectTypeHook(1);
status=STATUS_SUCCESS;
}else
{
IoDeleteDevice(DeviceObject);
}
}
return status;
}
ULONG InstallObjectTypeHook(BOOLEAN IsHook)
{
OBJECT_ATTRIBUTES objAttr;
UNICODE_STRING uObjName;
NTSTATUS status;
HANDLE KeyHandle;
PVOID keyObject;
BYTE* ParseProcedureOfObject;
RtlInitUnicodeString(&uObjName,ObjectTypeName);
InitializeObjectAttributes(&objAttr,&uObjName,OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE ,NULL,NULL);
status=ObOpenObjectByName(&objAttr,NULL,KernelMode,NULL,0,NULL,&KeyHandle);
if (NT_SUCCESS(status))
{
status= ObReferenceObjectByHandle(KeyHandle,0x80000000u,NULL,KernelMode,(PVOID)&keyObject,0);
if (NT_SUCCESS(status))
{
/*
OBJECT_TYPE+0x60-->OBJECT_TYPE_INITIALIZER
OBJECT_TYPE_INITIALIZER+0x3c-->ParseProcedure(nt!CmpParseKey)
而且KeyObject指向OBJECT_TYPE,因此可以进行OBJECT HOOK
*/
ParseProcedureOfObject=(BYTE*)keyObject+0x9C;
if (!MmIsAddressValid((*(DWORD*)ParseProcedureOfObject)))
{
ObfDereferenceObject(keyObject);
ZwClose(KeyHandle);
return status;
}
KdPrint(("CmpParseKey funcaddr=0x%X\n",*(DWORD*)ParseProcedureOfObject));
//开始OBJECT HOOK
if (IsHook)
{
__asm{
push eax
push ecx
mov ecx,ParseProcedureOfObject
mov eax,offset fake_CmpParseKey
xchg eax,[ecx]
mov Orig_CmpParseKey,eax
pop ecx
pop eax
}
}else
{
__asm{
push eax
push ecx
mov eax,Orig_CmpParseKey
mov ecx,ParseProcedureOfObject
xchg eax,[ecx]
pop ecx
pop eax
}
}
ObfDereferenceObject(keyObject);
}
ZwClose(KeyHandle);
}
return status;
}
/*得到system进程里所独占的文件句柄(windows\system32\config\system),
然后重新装载在L"\\REGISTRY\\USER\\.DEFAULT\\Volatile\"下,实现注册表hive文件重定向
*/
VOID RestoreReg(PVOID CurrentId)
{
NTSTATUS status;
PVOID pool;
ULONG dwNeedsize;
ULONG ReturnLength;
unsigned int nCount;
ULONG Object;
ULONG PID;
UNICODE_STRING *filetype;
UNICODE_STRING szfile;
PFILE_OBJECT FileObject=NULL;
ULONG current_handle_info_pos;
UNICODE_STRING Hivename;
HANDLE regedit_software_fileHandle;
UNICODE_STRING volatile_reg;
PUNICODE_STRING filename;
OBJECT_ATTRIBUTES oa;
ULONG numofhandles;
RtlInitUnicodeString(&szfile,L"File");
RtlInitUnicodeString(&Hivename,RegHiveFileName);
dwNeedsize=0x1000;
do
{
pool=ExAllocatePool(PagedPool,dwNeedsize);
if (pool)
{
current_handle_info_pos=(ULONG)pool;
status= NtQuerySystemInformation(SystemHandleInformation, pool, dwNeedsize, &ReturnLength);
}else
return NULL;
if (status==STATUS_INFO_LENGTH_MISMATCH)
{
ExFreePoolWithTag(pool,0);
dwNeedsize*=2;
}
} while(status == STATUS_INFO_LENGTH_MISMATCH);
/*+++
这里注意pool指向的缓冲区的内容,查看文档如下:
The data returned to the SystemInformation buffer is a ULONG count of the number of
handles followed immediately by an array of SYSTEM_HANDLE_INFORMATION.很显然是指句柄的数量,
紧接着就是SYSTEM_HANDLE_INFORMATION的数组,还是的看文档,才清楚.
++*/
if (pool)
{
if (NT_SUCCESS(status))
{
numofhandles=*(ULONG*)current_handle_info_pos;
nCount=0;
Object=((ULONG)pool+0xC);
while (nCount<numofhandles)
{
PID=*(DWORD*)(Object-0x8);
//如果是system进程,并且匹配文件,则打印
if((PID==(*(DWORD*)CurrentId))&&(!RtlCompareUnicodeString(&szfile,(PUNICODE_STRING)(*(DWORD*)(*(DWORD*)Object-0x10)+64),TRUE)))
{
filetype=(PUNICODE_STRING)(*(DWORD*)(*(DWORD*)Object-0x10)+64);
FileObject=*(PULONG)Object;
//KdPrint(("filename=%wZ,vpb=0x%X\n",(PUNICODE_STRING)(&FileObject->FileName),*(DWORD *)(FileObject + 8)));
filename=(PUNICODE_STRING)(&FileObject->FileName);
if (filename)
{
//找到HIVE文件:software
if (!RtlCompareUnicodeString(filename,&Hivename,TRUE))
{
KdPrint(("filetye=%wZ,Filename=%wZ,filelen=%d\n",filetype,filename,filename->Length));
status=ObOpenObjectByPointer(FileObject,512,NULL,0,0,KernelMode,®edit_software_fileHandle);
if (NT_SUCCESS(status))
{
if (regedit_software_fileHandle)
{
RtlInitUnicodeString(&volatile_reg,RepointRegItem);
InitializeObjectAttributes(&oa,&volatile_reg,OBJ_KERNEL_HANDLE|OBJ_CASE_INSENSITIVE,NULL,NULL);
//REG_OPTION_VOLATILE表示创建的项存放在在内存中
status=ZwCreateKey((PHANDLE)(&CurrentId),0xF003Fu,&oa,0,0,5u,¤t_handle_info_pos);
if (NT_SUCCESS(status))
{
//把hive文件临时恢复在设定下的注册表项
status=ZwRestoreKey((HANDLE)CurrentId,regedit_software_fileHandle,8u);
if (NT_SUCCESS(status))
Restorssymbol();
ZwClose((HANDLE)CurrentId);
}
ZwClose(regedit_software_fileHandle);
goto while_break;
}
}
}
}
}
++nCount;
Object+=0x10;
}
}
}
while_break:
ExFreePoolWithTag(pool,0);
return;
}
/*开起一个线程时刻监测是否被HOOK,防止被修复,猥琐的写法
VOID ProtectHook()
{
ULONG Oldaddress;
LARGE_INTEGER Interval;
Interval.QuadPart=100*10000;
while (1)
{
Oldaddress=*(ULONG*)ParseKeyAddress;
if (Oldaddress == Orig_CmpParseKey)
*(ULONG*)ParseKeyAddress=(ULONG)fake_CmpParseKey;
KeDelayExecutionThread(0,0,&Interval);//延缓时间
}
}*/
NTSTATUS MyCreateClose(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Irp->IoStatus.Status;
}
//恢复符号连接
NTSTATUS Restorssymbol()
{
UNICODE_STRING DestinationString;
NTSTATUS status;
OBJECT_ATTRIBUTES oa;
HANDLE handle;
HANDLE KeyHandle;
UNICODE_STRING valuename;
PVOID KeyValueInformation;
ULONG ResultLength;
ULONG Disposition;
UNICODE_STRING setvalue;
CHAR unitevalue[50]={0};
int controlvalue;
ANSI_STRING ansistring;
ANSI_STRING ansistring2;
UNICODE_STRING subkeyname;
HANDLE subkey;
int currentconfigvalue;
CHAR unitevalue2[160]={0};
KeyValueInformation=ExAllocatePool(NonPagedPool,0x100);
RtlInitUnicodeString(&DestinationString, L"\\Registry\\Machine\\System\\Select");
InitializeObjectAttributes(&oa,&DestinationString,OBJ_CASE_INSENSITIVE,NULL,NULL);
status= ZwOpenKey(&handle, 0x20019u, &oa);
if (NT_SUCCESS(status))
{
RtlInitUnicodeString(&valuename, L"Current");
status= ZwQueryValueKey(handle,&valuename,KeyValueFullInformation,KeyValueInformation,0x80,&ResultLength);
NtClose(handle);
if (NT_SUCCESS(status))
{
//得到current的值
controlvalue=*(int *)((char*)KeyValueInformation+0x24);
RtlInitUnicodeString(&valuename,L"\\REGISTRY\\USER\\.DEFAULT\\Volatile\\CurrentControlSet");
InitializeObjectAttributes(&oa,&valuename,OBJ_CASE_INSENSITIVE,NULL,NULL);
status= ZwCreateKey(&KeyHandle,KEY_CREATE_LINK,&oa, 0, 0, REG_OPTION_VOLATILE |REG_OPTION_CREATE_LINK , &Disposition);
if (NT_SUCCESS(status))
{
RtlInitUnicodeString(&setvalue, L"SymbolicLinkValue");
sprintf(&unitevalue,"\\REGISTRY\\USER\\.DEFAULT\\Volatile\\ControlSet%03d",controlvalue);
RtlInitAnsiString(&ansistring,&unitevalue);
valuename.MaximumLength=256;
RtlAnsiStringToUnicodeString(&valuename,&ansistring, FALSE);
status=ZwSetValueKey(KeyHandle, &setvalue, 0, REG_LINK, valuename.Buffer, valuename.Length);
if (NT_SUCCESS(status))
{
RtlInitUnicodeString(&subkeyname, L"Control\\IDConfigDB");
InitializeObjectAttributes(&oa,&subkeyname,OBJ_CASE_INSENSITIVE,KeyHandle,NULL);
status=ZwOpenKey(&subkey,0x20019u,&oa);
NtClose(KeyHandle);
if (NT_SUCCESS(status))
{
RtlInitUnicodeString(&valuename, L"CurrentConfig");
status=ZwQueryValueKey(subkey,&valuename,KeyValueFullInformation,KeyValueInformation,0x80,&ResultLength);
NtClose(subkey);
if (NT_SUCCESS(status))
{
currentconfigvalue= *(int *)((char *)KeyValueInformation + 0x30);
RtlInitUnicodeString(&subkeyname,L"\\REGISTRY\\USER\\.DEFAULT\\Volatile\\CurrentControlSet\\Hardware Profiles\\Current");
InitializeObjectAttributes(&oa,&subkeyname,OBJ_CASE_INSENSITIVE,KeyHandle,NULL);
status= ZwCreateKey(&KeyHandle, KEY_CREATE_LINK, &oa, 0, 0, REG_OPTION_VOLATILE |REG_OPTION_CREATE_LINK, &Disposition);
if (NT_SUCCESS(status))
{
sprintf(&unitevalue2,"\\REGISTRY\\USER\\.DEFAULT\\Volatile\\CurrentControlSet\\Hardware Profiles\\%04d",currentconfigvalue);
RtlInitAnsiString(&ansistring2,&unitevalue2);
valuename.MaximumLength=256;
RtlAnsiStringToUnicodeString(&valuename,&ansistring2, FALSE);
ZwSetValueKey(KeyHandle,&setvalue,0,REG_LINK,valuename.Buffer,valuename.Length);
NtClose(KeyHandle);
}
}
}
status= STATUS_SUCCESS;
}
else
NtClose(KeyHandle);
}
}
}
ExFreePool(KeyValueInformation);
return status;
}
ring3的代码我就不提供了,文章后提供该小工具的bin下载,本文已发表在黑客防线2011年第2期,
在此十分感谢sudami牛,目前对磁盘还原十分有兴趣,希望能够继续学习,谢谢!!
具体效果示意图如下:
[培训]《安卓高级研修班(网课)》月薪三万计划,掌握调试、分析还原ollvm、vmp的方法,定制art虚拟机自动化脱壳的方法