通过还原Hive来分析木马

原创
2020/02/16 18:41
阅读数 178

    【题外话】:这是一篇旧文,也是一篇经典文;说它旧,是因为它行文于2009年;说它经典,是因为它是当年境外组织渗透我国重要单位时使用的技术,从意想不到的地方进行了突破,巧妙且别具一格,我认为实属里程之碑。


    此文最早发表于2009年《黑客防线》,实在想不到距今已有11个年头了,对它的感情确实有些深,因为当年分析它时吃了不少苦,人类对苦难总是印象深刻,所以一直认为它不应该埋没于茫茫时间长河里,特挑出来放在我的公众号;去年张老师编撰的文集里有过收录,看过的请略;


    【前言】:Windows的注册表和Hive文件是什么关系?

    百度百科:注册表相当于Windows系统中所有32位硬件/驱动和32位应用程序的数据文件,是一个系统信息的数据库。既然是数据文件,那在磁盘上就一定有注册表的影子的存在。注册表文件在系统设置和缺省用户配置数据的情况下,是存放在\系统文件夹\SYSTEM32\CONFIG目录下的6个文件,DEFAULT、SAM、SECURITY、SOFTWARE、USERDIFF和SYSTEM中,而用户的配置信息存放在系统所在磁盘的\Documents and Setting\目录,包括ntuser.dat,ntuser.ini和ntuser.dat.log。其中每个文件的路径都由注册表项HKLM \SYSTEM\CurrentControlSet\Control\Hivelist下的键值指出,如下图示:


我们看到的注册表结构是经过注册表编辑器读取之后呈现给我们的,其磁盘形式并不是一个简单的大文件,而是一组被称为Hive的单独文件形式,Hive中文名曰“储巢”。每个Hive文件可以被理解为一棵单独注册表树,就像Windows的PE格式一样,它也有自己的组织形式。本文的任务就是要分析Hive文件的组织形式并完成一个Hive格式的分析程序。


Windows系统提供了大量的API给用户访问和修改注册表中的数据,regedit就是基于这些API所实现的。注册表API大致分为用户空间的与内核空间的两类,一般用户调用前者,层层调用转移,由内核的注册表API再调用文件系统的驱动等,去访问磁盘上的Hive文件,并最终返回请求的数据结果。这个过程有点冗长,但是为了注册表里存放数据的安全考虑,损失一些性能表现还是值得的。

 

【正文】:关于Windows系统注册表文件的组织格式,即Hive文件格式,并没有对开发者公开,但是针对它们的研究可通过逆向工程或者其他方法进行。通常情况下,所能看到的或者可以获取注册表的信息不是以Hive文件格式的形式存在,要通过Hive文件来进行注册表的检测和分析,首先要获取注册表信息对应的Hive文件。在Windows系统中,可以通过使用API RegSave Key/RegSaveKeyEx函数来将指定键下的注册表信息转储为Hive格式的文件。


一、 Hive的格式

在介绍Hive格式之前,我们先来看看Hive文件的组织形式,如下图-0所示:

注册表中HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\hivelist记录着系统注册表Hive文件的保存路径,而系统许多功能的实现是依赖于里面记录的这些文件提供信息的。正是由于这一性质,决定了系统Hive文件应该是安全的,内容也是最完整的。

1、Hive格式头:HBASE_BLOCK

    Hive格式的文件有个格式头,即开头字母是regf,如下图-1所示:

从图-1中我们可以看到“regf”字符串,这显然是registry files的缩写,标志它是个注册表文件。其实文件的开头是HBASE_BLOCK结构。看下图-2所示:

上图Hive文件的格式头,大小为0x1000,换算一下就是4K大小。这个HBASE_BLOCK 格式里面包含了一些全局信息,包括一个特征签名regf、更新的序列号、时间戳、hive格式版本号、校验和以及该hive的内部文件名,没有什么好解释的,大家可以将图-1和图-2结合起来对照看。

2、HBIN格式

① HBIN头格式

Hive文件是由HBASE_BLOCK和称为BIN的东西组成的,而BIN由称为cell的东西组成。示意图如下:

HBASE_BLOCK

 BIN1

BIN2

BINn

......

    在0x1000开始处是个HBIN结构,如下图-3所示。

HBIN结构中有一个24H字节长的HBIN头,其主要内容是:4字节的“hbin”字符串、4字节的从0x1000开始的偏移、4字节的本BIN的大小,其余字节是时间戳以及一些保留字节。

② CELL格式

如果一个cell要加入一个hive,而该hive必须扩充才能装下它时,系统会创建一个 称为 bin的分配单元。该bin的范围包括了新添cell所占空间再延续到下一个block边界。系统将bin中除了cell以外的部分视为可以分配给其他cell的空闲空间。

所以从0x1000+0x24=0x1024开始处就是CELL的数据。而CELL数据可以是一个键、一个值、一个安全描述符、一列子键或者一列键值。它主要是一个联合体。

typedef struct _CELL_DATA{

     union _u    {

         CM_KEY_NODE  KeyNode; 

         CM_KEY_VALUE KeyValue;

         CM_KEY_SECURITY   KeySecurity;

         CM_KEY_INDEX      KeyIndex;

         CM_BIG_DATA       ValueData;       

         HCELL_INDEX       KeyList[1];      

         WCHAR             KeyString[1];    

         }u;

} CELL_DATA, *PCELL_DATA;     

该结构中嵌套了一个联合体,用于代表cell可以存放的不同类型的数据。所以,从0x1024开始就是CM_KEY_NODE的键结构。我们来看下这个键结构,如下图-4所示。

解释如下:

kd> 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//键名

在这个键结构中较重要的是:0x4c处的键名、0x48处的键名长度、0x14处的子键个数值、0x1c处的子键列表偏移值、0x00处的“nk”标志。

接下来,我们看CM_KEY_VALUE的结构。如下图-5所示。

kd> 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              : Uint2B

在这个值结构中较重要的是:0x2处的值名长度、0x4处的数据长度、0x8处的数据偏移或数据、0x14处的值名,另外最重要的就是0x00处的“vk”标志。

接下来,我们再看看CM_KEY_SECURITY结构,如下图-6所示。

这个在具体分析中再看。

来看看下一个结构:CM_KEY_INDEX,如下图-7所示。

    CM_BIG_DATA结构如下图-8所示:

另外 ,在上图-4CM_KEY_NODE结构中提到了一个CM_KEY_REFERENCE,如下图-9所示:

   在上图-6的CM_KEY_SECURITY结构中有个SECURITY_DESCRIPTOR_RELATIVE结构,如下图-10所示:

以上我们已经讲解了重要的一些CELL数据中的结构,其余的结构已不是最重要的了,我们也就不再赘述了。下面我们直接来看文件的分析。


二、文件的分析

现在我们来对照上面说明的数据结构来实战地分析一下那个文件,对掌握Hive格式以及注册表的存储格式有很大的帮助。同时,不要忘了我们的本意是看这个文件具备什么样的功能,说白了就是它想干嘛。


    用WinHex调入待分析的文件,HBIN从0x1000开始,有“hbin”字符串为标志。首先来看看0x1024处的CM_KEY_NODE,如下图-11所示:

从图-11中,我们可以得出:这个键名叫“gogo”(位置在0x1024+0x4c=0x1070),长度为4个字节(位置在0x1024+0x48=0x106c),子键列表的偏移在0x638处(即是0x1000+0x638=0x1638处) (位置在0x1024+0x1c=0x1040),子键数量为2(位置在0x1024+0x14=0x1038)。


所以,我们的子键列表在0x1638,从0x1638+0x4=0x163c开始是一个CM_KEY_INDEX结构。如下图-12所示:

从上图-12中可以看出,CM_KEY_INDEX的标志是“lf”,后面紧跟着就是子键的个数2 个,这和前面是一致的。这里对标志有个说明,如果标志为“CM_KEY_FAST_LEAF”或者“CM_KEY_HASH_LEAF”,那么后面的内容将是“键位置、键Hash”,对照图,可以发现第1个子键的偏移在0x1290处、Hash值为0x61726150,第2个子键的偏移在0x1498处、Hash值为0x75636553。


其次,我们看看0x1290的子键信息。如下图-13所示:

比较一下图-11和图-13,在签名位后面的两个字节是标志位,如果标志位的值是0x2c,则表示这个0x28处的偏移是子键列表的偏移。如果标志位的值是0x20,则表示这个0x28处的偏移是子键下的值的列表。如图-13中反映出这样的信息:这个子键是gogo键下的Parameters,它有2个值,值的列表指向0x1000+0x478=0x1478。


    接着我们来看看0x1478处值列表的内容,如下图-14所示:

我们还是接着看这2个值偏移处的内容,如下图-15:

从图-15中可以反映出:值名长度为0x14,值名为“serviceDll”,值的位置在0x1000+0x1e8=0x11e8处。在第2个值名为“ServiceDllUnloadOnStop”中,DataLength最高位为1,那么它就是数据,且DataLength&0x7fffffff为数据长度。


现在来看下0x1000+0x1e8=0x11e8处的值的内容,如下图-16所示:

看到没有,原来是ServiceDll是“kkkkk.dll”。


看清楚了没有,第1个键就是这样加入的。为了节省片幅,对第2个键我就没有详细描述了,你们可以参照这个来实践一下,这里我就不多展开讲了,方法雷同。


我将最后的结果截了个图,如下图-17所示:

    

    结论:应该说,通过对这个文件的分析,我们大致能知道这个文件主要是通过注册表来添加服务启动程序的,主要是以svchost.exe –k netsvcs来启动DLL文件,如下图-18示:

    

    综观对Hive的学习分析,里面的各种格式、分别计算键、值、安全描述符、子键或者一列键值,着实让人头晕目眩,有种抓狂的感觉,只有不断地坚持、坚持、再坚持,才能走到最后。




本文分享自微信公众号 - MicroPest(gh_696c36c5382b)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部