360注冊表操作原理分析 (前段閑的蛋疼才分析的,錯誤的,大牛們請指出)
360為了有效的對注冊表進行操作,繞過了RegXXXX函數的使用,自己封裝了一套API:BAPI.DLL 以及BAPIDRY.SYS來實現可靠的,有效的注冊表和文件操作;
調用流程如下:
(以BRegDeleteKey為例)
對BRegDeleteKey的封裝在Ring 3模仿了微軟的做法,BRegDeleteKey-->BRegDeleteKeyW之類的,
對于BRegDeleteKeyW則不再調用NtDeleteKey,而是利用了ZwDeviceIoControl向BAPIDRY.SYS發控制碼,自己驅動去做NtDeleteKey做的操作;
關鍵在于360 Reg操作所用的方式:通過CmRegXXXX實現,360是如何可靠的獲取CmRegXXXX的地址的呢?如下:
1、通過打開注冊表的鍵值,獲取注冊表類型的objectType
2、打開兩個注冊表項,獲取對象以待后面用
3、對其中一個注冊表對象
nt!_CM_KEY_BODY
+0x000 Type : Uint4B
+0x004 KeyControlBlock : Ptr32 _CM_KEY_CONTROL_BLOCK
+0x008 NotifyBlock : Ptr32 _CM_NOTIFY_BLOCK
+0x00c ProcessID : Ptr32 Void
+0x010 Callers : Uint4B
+0x014 CallerAddress : [10] Ptr32 Void
+0x03c KeyBodyList : _LIST_ENTRY
.
里面的CM_KEY_CONTROL_BLOCK.
nt!_CM_KEY_CONTROL_BLOCK
+0x000 RefCount : Uint4B
+0x004 ExtFlags : Pos 0, 8 Bits
+0x004 PrivateAlloc : Pos 8, 1 Bit
+0x004 Delete : Pos 9, 1 Bit
+0x004 DelayedCloseIndex : Pos 10, 12 Bits
+0x004 TotalLevels : Pos 22, 10 Bits
+0x008 KeyHash : _CM_KEY_HASH
+0x008 ConvKey : Uint4B
+0x00c NextHash : Ptr32 _CM_KEY_HASH
+0x010 KeyHive : Ptr32 _HHIVE
+0x014 KeyCell : Uint4B
+0x018 ParentKcb : Ptr32 _CM_KEY_CONTROL_BLOCK
+0x01c NameBlock : Ptr32 _CM_NAME_CONTROL_BLOCK
+0x020 CachedSecurity : Ptr32 _CM_KEY_SECURITY_CACHE
+0x024 ValueCache : _CACHED_CHILD_LIST
+0x02c IndexHint : Ptr32 _CM_INDEX_HINT_BLOCK
+0x02c HashKey : Uint4B
+0x02c SubKeyCount : Uint4B
+0x030 KeyBodyListHead : _LIST_ENTRY
+0x030 FreeListEntry : _LIST_ENTRY
+0x038 KcbLastWriteTime : _LARGE_INTEGER
+0x040 KcbMaxNameLen : Uint2B
+0x042 KcbMaxValueNameLen : Uint2B
+0x044 KcbMaxValueDataLen : Uint4B
+0x048 KcbUserFlags : Pos 0, 4 Bits
+0x048 KcbVirtControlFlags : Pos 4, 4 Bits
+0x048 KcbDebug : Pos 8, 8 Bits
+0x048 Flags : Pos 16, 16 Bits
里面的HHIVE
nt!_HHIVE
+0x000 Signature : Uint4B
+0x004 GetCellRoutine : Ptr32 _CELL_DATA*
+0x008 ReleaseCellRoutine : Ptr32 void
+0x00c Allocate : Ptr32 void*
+0x010 Free : Ptr32 void
+0x014 FileSetSize : Ptr32 unsigned char
+0x018 FileWrite : Ptr32 unsigned char
+0x01c FileRead : Ptr32 unsigned char
+0x020 FileFlush : Ptr32 unsigned char
+0x024 BaseBlock : Ptr32 _HBASE_BLOCK
+0x028 DirtyVector : _RTL_BITMAP
+0x030 DirtyCount : Uint4B
+0x034 DirtyAlloc : Uint4B
+0x038 RealWrites : UChar
+0x03c Cluster : Uint4B
+0x040 Flat : UChar
+0x041 ReadOnly : UChar
+0x042 Log : UChar
+0x044 HiveFlags : Uint4B
+0x048 LogSize : Uint4B
+0x04c RefreshCount : Uint4B
+0x050 StorageTypeCount : Uint4B
+0x054 Version : Uint4B
+0x058 Storage : [2] _DUAL
里面的函數HvpGetCellMapped進行hook,在而后分別對哪兩個打開的注冊表項進行若干的注冊表操作(調用前面獲取的NtRegxxx來完成),那么360為什么要hook那個函數膩,原因是,NtRegxxxx的若干操作會調用相應的CmRegxxxx來完成,而CmRegxxx又會調用HvpGetCellMapped這個函數,Fake_HvpGetCellMapped的作用很簡單:
假設對那個自己的測試鍵值調用了NtSetValueKey,在找個函數里可以找到如下代碼:
if (NT_SUCCESS(status))
{
status = CmSetValueKey(........)
}
這里就是和諧的CmSetValueKey,當這個東西運行,在這個函數里可以找到調用了HvpGetCellMapped這個函數,然而現在卻調用了Fake_HvpGetCellMapped這個函數,找個函數里面通過?;厮輽C制,定位到上面那個圖的代碼對應的
CALL CmpSetValueKey,(?;厮菔峭ㄟ^找個函數的第一個參數
作為回溯查找對象的,前面打開自己的注冊表時保存了找個值,這樣就確定了CmRegxxxx的地址。