[note]注册表之HIVE

1.HIVE结构

  首先,要明白的是注册表是由多个hive文件组成.

  而一个hive是由许多bin组成,一个bin是由很多cell组成.

  而cell可以有好几种类型.比如 key cell(cm_key_node) value cell(CM_KEY_VALUE) subbkey-list cell,value-list cell等

  当新的数据要扩张一个hive时,总是按照block的粒度(4kb)来增加,一个hive的第一个块是base block.包含了有关该hive的全局信息.参考结构 _hbase_block

  bin也有头部,其中包含了一个特征签名hbin,一个记录该bin在hive中的offset(偏移),以及该bin的大小. bin头的大小一般为0x20.

 

  所以一个hive的磁盘映像看起来如下图;

  +===============+

  +  _hbase_block (4kb)   +

  +===============+

  +       _bin0      +

  +===============+

  +         _bin1              +

  +===============+

  +         _bin2              +

  +===============+

  +        .........              +

  +===============+

  +        _bin N              +

  +===============+

 

  bin头的结构_hbin如下:

  typedef struct _HBIN

{

           +0x000       ULONG Signature;                //”hbin”字符串

           +0x004       ULONG FileOffset;              //本BIN相差0x1000的偏移

           +0x008       ULONG Size;                        //本BIN的大小

           +0x00c       ULONG Reserved1[2];

           +0x014       LARGE_INTEGER  TimeStamp;

           +0x01c       ULONG Spare;

           +0x020       ULONG Reserved2;

           +0x024

           //

          //这里开始是cell数据

          //

}

所以定位到第一个cell的步骤如下:

1,将磁盘上的hive文件*.dat通过CreateFile()和CreateFileMapping()映射到内存,得到hFileMap.

2,hFileMap加上一个_base_block大小(0x1000),定位到bin头,即RootBin=hFileMap+0x1000.

3,RootBin加上一个_hbin的大小,即可定位到第一个cell,即pKeyNode=RootBin+0x24;(假设该hive的第一个cell为_CM_KEY_NODE结构)

 

2.关于cell的几个结构.

一个cell可以容纳一个键,一个值,一个安全描述,一列子键,或者一列键值.

typedef struct _CELL_DATA

{

     union _u              //注意它是一个联合体

    {

         CM_KEY_NODE       KeyNode; //键结构

         CM_KEY_VALUE      KeyValue;//值的结构, 包含一个键的值的信息.

         CM_KEY_SECURITY   KeySecurity;//安全描述

         CM_KEY_INDEX      KeyIndex;//一列子键,又一系列的键cell的cellindex所构成的cell,这些cell是一个公共parent key的所有subkey.

         CM_BIG_DATA       ValueData;

         HCELL_INDEX       KeyList[1];//一列键值,

         WCHAR             KeyString[1];

     } u;

} CELL_DATA, *PCELL_DATA;

 

lkd> DT _CM_KEY_NODE

nt!_CM_KEY_NODE

    +0x000 Signature         : Uint2B          //”nk”字符串

    +0x002 Flags             : Uint2B

    +0x004 LastWriteTime     : _LARGE_INTEGER

    +0x00c Spare             : Uint4B

    +0x010 Parent            : Uint4B

    +0x014 SubKeyCounts      : [2] Uint4B            //SubKeyCounts[0]子键的个数

    +0x01c SubKeyLists       : [2] Uint4B              //SubKeyLists[0]子键列表相差本BIN的偏移

    +0x024 ValueList         : _CHILD_LIST           //ValueList.Count值的个数

                        //ValueList.List值列表相差本BIN的偏移 

    +0x01c ChildHiveReference : _CM_KEY_REFERENCE

    +0x02c Security          : Uint4B

    +0x030 Class             : Uint4B

    +0x034 MaxNameLen        : Pos 0, 16 Bits

    +0x034 UserFlags         : Pos 16, 4 Bits

    +0x034 VirtControlFlags : Pos 20, 4 Bits

    +0x034 Debug             : Pos 24, 8 Bits

    +0x038 MaxClassLen       : Uint4B

    +0x03c MaxValueNameLen   : Uint4B

    +0x040 MaxValueDataLen   : Uint4B

    +0x044 WorkVar           : Uint4B

    +0x048 NameLength        : Uint2B                 //键名的长度

    +0x04a ClassLength       : Uint2B

    +0x04c Name            : [1] Uint2B      //键名

 

补充下_CHILD_LIST结构:

nt!_CHILD_LIST
   +0x000 Count            : Uint4B  //ValueList.Count值的个数

   +0x004 List             : Uint4B  //ValueList.List值列表相差本BIN的偏移

 通过观察_CM_KEY_NODE结构,

 我们发现pKeyNode+0x4c获得键名,即RootKeyName=pKeyNode->Name;

 

 通过ValueList域,可得到值列表相差本bin的偏移,可以定位该键的值结构.即_CM_KEY_VALUE.

 ValueIndex=(ULONG *)(Bin+ValueLists+0x4);

 value=(PCM_KEY_VALUE)(Bin+ValueIndex[i]+0x4);

 

 而通过SubKeyLists域,可得到子键列表相差本bin的偏移.

 DWORD SubKeyLists=KeyNode->SubKeyLists[0];
 KeyIndex=(PCM_KEY_INDEX)(RootBin+SubKeyLists+0x4);

 

lkd> DT _CM_KEY_VALUE

nt!_CM_KEY_VALUE

    +0x000 Signature         : Uint2B //”vk”字符串

    +0x002 NameLength        : Uint2B

    +0x004 DataLength        : Uint4B //数据长度,以字节计,包括结束符

    +0x008 Data              : Uint4B //注意:数据偏移或数据判断:如果DataLenth最高位为1,那么它就是数据,且DataLenth&0x7FFFFFFF为数据长度

    +0x00c Type              : Uint4B

    +0x010 Flags             : Uint2B

    +0x012 Spare             : Uint2B

    +0x014 Name              : [1] Uint2B

通过_CM_KEY_VALUE结构,可以获得该键值的类型(type),名字(Name),以及数据(Data)

 

lkd> dt _CM_KEY_INDEX

nt!_CM_KEY_INDEX

   +0x000 Signature        : Uint2B

   +0x002 Count            : Uint2B //这里也是表示子键的数量,与前面的相同

   +0x004 List             : [1] Uint4B //这里要注意了

如果Signature==CM_KEY_FAST_LEAF或CM_KEY_HASH_LEAF,那么从0x004偏移开始的数组元素结构如下:

struct

{

         ULONG offset;

         ULONG HashKey;

}

否则:

ULONG offset;

对于_CM_KEY_INDEX结构,通过List域可以定位所有子键的_CM_KEY_NODE结构,具体实现如下:

 DWORD KeyNodeOffset=KeyIndex->List[i*2];                   //(其中的i是,USHORT i=0,i<count,i++)
   KeyNode=(PCM_KEY_NODE)(Bin+KeyNodeOffset+0x4);

这样定位到每个子键的_CM_KEY_NODE结构,就能获得该子键的键值,以及该子键下面的子子键,

这样重复上述的步骤就能实现对整个hive的解析.

ps下:通过是ring3的RegSaveKey(),可以生成一个Hive文件.

具体实现的代码如下:

 

 

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
#include < windows.h >
#include
< stdio.h >
#include
< stdlib.h >

#define REGF 0x66676572 // fger
#define HBIN 0x6e696268 // nibh
#define CM_KEY_FAST_LEAF 0x666c // fl
#define CM_KEY_HASH_LEAF 0x686c // hl


// 数据结构定义
typedef struct _CHILD_LIST
{
ULONG Count;
ULONG List;
}CHILD_LIST;

typedef
struct _CM_KEY_NODE
{
USHORT Signature;
CHAR Reserve_1[
18 ];
ULONG SubKeyCounts[
2 ];
ULONG SubKeyLists[
2 ];
CHILD_LIST ValueList;
CHAR Reserve_2[
28 ];
USHORT NameLength;
SHORT ClassName;
CHAR Name;
} CM_KEY_NODE,
* PCM_KEY_NODE;

typedef
struct _CM_KEY_INDEX
{
USHORT Signature;
USHORT Count;
ULONG List[
1 ];
} CM_KEY_INDEX,
* PCM_KEY_INDEX;

typedef
struct _CM_KEY_VALUE
{
USHORT Signature;
SHORT NameLength;
ULONG DataLength;
ULONG Data;
ULONG Type;
CHAR Reserve_1[
4 ];
CHAR Name;
}CM_KEY_VALUE,
* PCM_KEY_VALUE;


VOID TpyeKeyAndValue(PVOID FileMemAddr);
VOID TypeSubKey(PCHAR Bin,PCM_KEY_INDEX KeyIndex);
VOID TypeSubKeyName(PCHAR Bin,PCM_KEY_NODE KeyNode);
VOID TypeValue(PCHAR Bin,PCM_KEY_VALUE value);

int main( int argc, char * argv[])
{
HANDLE hFile;
HANDLE hFileMap;
DWORD FileSize;
PVOID FileMem;

#ifndef _DEBUG
if (argc != 2 )
{
printf(
" *************************\n " );
printf(
" Useage:\nHivePase FileName\n " );
printf(
" *************************\n " );
system(
" pause " );
return 1 ;
}
hFile
= CreateFile(argv[ 1 ],GENERIC_READ, 0 ,NULL,
OPEN_EXISTING,FILE_FLAG_OVERLAPPED,NULL);
#else
hFile
= CreateFile( " c:\\test_root.dat " ,GENERIC_READ, 0 ,NULL,
OPEN_EXISTING,FILE_FLAG_OVERLAPPED,NULL);
#endif

if (hFile == INVALID_HANDLE_VALUE)
{
printf(
" Error:File doesn's Exist!\n " );
system(
" pause " );
return 1 ;
}
FileSize
= GetFileSize(hFile,NULL);
hFileMap
= CreateFileMapping(hFile,NULL,PAGE_READONLY | SEC_COMMIT, 0 ,FileSize,NULL);
if (hFileMap == NULL)
{
printf(
" CreateFileMapping Error!\n " );
CloseHandle(hFile);
system(
" pause " );
return 1 ;
}
CloseHandle(hFile);
FileMem
= MapViewOfFile(hFileMap,FILE_MAP_READ, 0 , 0 , 0 );
if (FileMem == NULL)
{
printf(
" MapViewOfFile Error!\n " );
CloseHandle(hFileMap);
system(
" pause " );
return 1 ;
}
CloseHandle(hFileMap);
TpyeKeyAndValue(FileMem);
printf(
" \nSuccess!\n " );
system(
" pause " );
return 0 ;
}

VOID TpyeKeyAndValue(PVOID FileMemAddr)
{
char RootKeyName[ 256 ];
PCHAR RootBin;
PCM_KEY_NODE KeyNode;
PCM_KEY_INDEX KeyIndex;
if ( * (ULONG * )FileMemAddr != REGF)
{
printf(
" Not a Hive File!\n " );
system(
" pause " );
}
RootBin
= ( char * )FileMemAddr + 0x1000 ;
KeyNode
= (PCM_KEY_NODE)(RootBin + 0x24 );
if ( * (ULONG * )RootBin != HBIN)
{
printf(
" Hive File Error!\n " );
system(
" pause " );
}
ZeroMemory(RootKeyName,
256 );
memcpy(RootKeyName,
& KeyNode -> Name,KeyNode -> NameLength);
printf(
" Root Key: %s\n " ,RootKeyName);
DWORD SubKeyLists
= KeyNode -> SubKeyLists[ 0 ];
KeyIndex
= (PCM_KEY_INDEX)(RootBin + SubKeyLists + 0x4 );
TypeSubKey(RootBin,KeyIndex);

}

VOID TypeSubKey(PCHAR Bin,PCM_KEY_INDEX KeyIndex)
{
USHORT KeyCount;
PCM_KEY_NODE KeyNode;
KeyCount
= KeyIndex -> Count;
for (USHORT i = 0 ;i < KeyCount;i ++ )
{
if (KeyIndex -> Signature == CM_KEY_FAST_LEAF || KeyIndex -> Signature == CM_KEY_HASH_LEAF)
{
DWORD KeyNodeOffset
= KeyIndex -> List[i * 2 ];
KeyNode
= (PCM_KEY_NODE)(Bin + KeyNodeOffset + 0x4 );
TypeSubKeyName(Bin,KeyNode);
}
else
{
DWORD KeyNodeOffset
= KeyIndex -> List[i * 2 ];
KeyNode
= (PCM_KEY_NODE)(Bin + KeyNodeOffset + 0x4 );
TypeSubKeyName(Bin,KeyNode);
}
}

}

VOID TypeSubKeyName(PCHAR Bin,PCM_KEY_NODE KeyNode)
{
char SubKeyName[ 256 ];
ULONG ValueLists;
ULONG ValueCount;
ULONG
* ValueIndex;
PCM_KEY_VALUE value;
PCM_KEY_INDEX KeyIndex;
ZeroMemory(SubKeyName,
256 );
strncpy(SubKeyName,
& KeyNode -> Name,KeyNode -> NameLength);
printf(
" Sub Key: %s\n " ,SubKeyName);
ValueLists
= KeyNode -> ValueList.List;
ValueCount
= KeyNode -> ValueList.Count;
if (ValueLists !=- 1 )
{
ValueIndex
= (ULONG * )(Bin + ValueLists + 0x4 );
for (ULONG i = 0 ;i < ValueCount;i ++ )
{
value
= (PCM_KEY_VALUE)(Bin + ValueIndex[i] + 0x4 );
TypeValue(Bin,value);
}
}
if (KeyNode -> SubKeyLists[ 0 ] !=- 1 )
{
KeyIndex
= (PCM_KEY_INDEX)(Bin + KeyNode -> SubKeyLists[ 0 ] + 0x4 );
TypeSubKey(Bin,KeyIndex);
}
}


VOID TypeValue(PCHAR Bin,PCM_KEY_VALUE value)
{
char ValueName[ 256 ];
ULONG DataLenth;
PCHAR Data;
ZeroMemory(ValueName,
256 );
strncpy(ValueName,
& value -> Name,value -> NameLength);
printf(
" Value Name: %s\n " ,ValueName);
switch (value -> Type)
{
case REG_SZ:
printf(
" REG_SZ " );
break ;
case REG_BINARY:
printf(
" REG_BINARY " );
break ;
case REG_DWORD:
printf(
" REG_DWORD " );
break ;
case REG_MULTI_SZ:
printf(
" REG_MULIT_SZ " );
break ;
case REG_EXPAND_SZ:
printf(
" REG_EXPAND_SZ " );
break ;
default :
break ;
}
if (value -> Type == REG_DWORD)
{
Data
= (PCHAR) & value -> Data;
printf(
" %08x " , * (ULONG * )Data);
}
else
{
if (value -> DataLength & 0x80000000 )
{
DataLenth
= value -> DataLength & 0x7FFFFFFF ;
Data
= (PCHAR) & value -> Data;
for (ULONG i = 0 ;i < DataLenth;i ++ )
{
if (value -> Type == REG_BINARY)
{
printf(
" %1x " ,Data[i]);
}
else
{
printf(
" %c " ,Data[i]);
}
}
}
else
{
DataLenth
= value -> DataLength;
DWORD DataOffset
= value -> Data;
Data
= Bin + DataOffset + 0x4 ;
for (ULONG i = 0 ;i < DataLenth;i ++ )
{
if (value -> Type == REG_BINARY)
{
printf(
" %1x " ,Data[i]);
}
else
{
printf(
" %c " ,Data[i]);
}
}
}
}
printf(
" \n " );
}

关于上面code的一些补充说明:(by linxer)

1.对nk节点下二级索引子键的情况没有处理(有ri节点情况,当子键过多的时候系统会使用ri节点的)
2.TypeValue里对值名称的处理有问题,问题出在这下面两行代码
     strncpy(ValueName,&value->Name,value->NameLength);
     printf("Value Name:  %s\n",ValueName);
vk节点的值名称未必就是ascii字符串,因此用str系列函数是不可以的,正确用法应该是
     memcpy(ValueName,&value->Name,value->NameLength);因此显示语句也不能用printf来显示,目前我看到的很多代码都有这样的问题(chntpw),还有一些使用的hive解析的工具(SnipeSword0225)也有这种问题

 

相关参考:<<windows注册表文件格式的简单分析>>

     <<简单认识下注册表的HIVE文件格式>>

 

 

 

 

转载于:https://www.cnblogs.com/Tbit/archive/2010/08/08/1794973.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值