来源于一个注册表保护工具的逆向,主要利用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; }
在此十分感谢sudami牛,目前对磁盘还原十分有兴趣,希望能够继续学习,谢谢!!
具体效果示意图如下:
