打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
注册表之HIVE
userphoto

2015.10.09

关注
转:http://www.china-cloud.com/yunjishu/yunjisuanhexinjishu/Hadoop/20110409_294.html

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文件.

具体实现的代码如下:

 

#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)也有这种问题

(责任编辑:admin)

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
Linux 开发常用打印
Linux NTP协议
g.711 decoder and encoder
基于ALSA的WAV播放和录音程序
C语言之如何输出uint32_t和uint64_t和16进制
hive文件(注册表格式)
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服