当前位置: 首页 > 编程日记 > 正文

一种注册表沙箱的思路、实现——研究Reactos中注册表函数的实现3

这篇我们看一个”容错“”节省“的实例。一下是一个Win32API的声明(转载请指明出处)

LONG WINAPI RegEnumKeyEx(__in         HKEY hKey,__in         DWORD dwIndex,__out        LPTSTR lpName,__inout      LPDWORD lpcName,__reserved   LPDWORD lpReserved,__inout      LPTSTR lpClass,__inout_opt  LPDWORD lpcClass,__out_opt    PFILETIME lpftLastWriteTime
);

节省

这个函数底层是使用ZwEnumerateKey,使用过该函数的同学应该知道,该函数根据传入的KEY_INFORMATION_CLASS不同而查询该项不同结构体的数据。我们来看两个不同结构体

typedef struct _KEY_BASIC_INFORMATION {LARGE_INTEGER LastWriteTime;ULONG         TitleIndex;ULONG         NameLength;WCHAR         Name[1];
} KEY_BASIC_INFORMATION, *PKEY_BASIC_INFORMATION;
typedef struct _KEY_NODE_INFORMATION {LARGE_INTEGER LastWriteTime;ULONG         TitleIndex;ULONG         ClassOffset;ULONG         ClassLength;ULONG         NameLength;WCHAR         Name[1];
} KEY_NODE_INFORMATION, *PKEY_NODE_INFORMATION;

可见到NODE比BASIC多出ClassOffset和ClassLength和藏在Name中的Class信息。RegEnumKeyEx要获取的信息中是可以通过是否为NULL来定的,如果你不想获取Class的信息,可以将lpClass和lpcClass指定为NULL。那么Reactos中如何实现的呢?我们先思考下,如果我们在NtEnumerateKey中一股脑儿使用KEY_NODE_INFORMATION去查询,是很简单,但是是不是有点浪费呢(也许用户不用查询Class信息)?如果使用KEY_BASIC_INFORMATION,则如果用户要查询Class信息,则我们将查询不到。或许你想到了——特殊情况特殊处理,是的Reactos就是如此做的。下面看一段我修改后的代码

lpKeyInfo = HeapAlloc( GetProcessHeap(), 0, BufferSize );if ( NULL == lpKeyInfo ) {// 分配失败lRes = STATUS_MEMORY_NOT_ALLOCATED;break;}ULONG ResultSize = 0;// 查询不同类型的结构体取决于lpClass是否需要查询lRes = GETORIFUNC(EnumerateKey)(hKeyHandle,dwIndex,lpClass ? KeyNodeInformation : KeyBasicInformation,lpKeyInfo,BufferSize,&ResultSize );CHECKRESULT(lRes);// 定义一个联合体typedef union {KEY_NODE_INFORMATION Node;KEY_BASIC_INFORMATION Basic;} un;un* KeyInfo = (un*)lpKeyInfo;if ( NT_FAILED(lRes) ) {break;}else {if ( NULL == lpClass ) {// 如果lpClass不需要查询,则使用KEY_BASIC_INFORMATION结构体中数据if ( KeyInfo->Basic.NameLength > NameLength ) {// 承载的空间不够lRes = STATUS_BUFFER_OVERFLOW;}else {RtlCopyMemory( lpName, KeyInfo->Basic.Name, KeyInfo->Basic.NameLength );// 返回的长度不包含结尾符*lpcName = (DWORD)( KeyInfo->Basic.NameLength / sizeof(WCHAR) );// 设置结尾符lpName[*lpcName] = (WCHAR)0;}}else {// 如果lpClass需要查询,则使用KEY_NODE_INFORMATION结构体中数据if ( KeyInfo->Node.NameLength > NameLength || KeyInfo->Node.ClassLength > ClassLength ) {// 承载的空间不够lRes = STATUS_BUFFER_OVERFLOW;}else {// 拷贝数据到内存中RtlCopyMemory( lpName, KeyInfo->Node.Name, KeyInfo->Node.NameLength );// 设置返回的大小,不包含结尾符*lpcName = KeyInfo->Node.NameLength / sizeof(WCHAR);// 设置结尾符lpName[*lpcName] = (WCHAR)0;// 拷贝数据到内存中RtlCopyMemory( lpClass,(PVOID)((ULONG_PTR)KeyInfo->Node.Name + KeyInfo->Node.ClassOffset),KeyInfo->Node.ClassLength );// 设置返回的大小,不包含结尾符*lpcClass = (DWORD)(KeyInfo->Node.ClassLength / sizeof(WCHAR));// 设置结尾符lpClass[*lpcClass] = (WCHAR)0;}}if ( lRes == STATUS_SUCCESS && NULL != lpftLastWriteTime ) {if ( lpClass == NULL ) {// 如果lpClass需要查询,则使用KEY_NODE_INFORMATION结构体中数据lpftLastWriteTime->dwLowDateTime = KeyInfo->Basic.LastWriteTime.u.LowPart;lpftLastWriteTime->dwHighDateTime = KeyInfo->Basic.LastWriteTime.u.HighPart;}else {// 如果lpClass需要查询,则使用KEY_NODE_INFORMATION结构体中数据lpftLastWriteTime->dwLowDateTime = KeyInfo->Node.LastWriteTime.u.LowPart;lpftLastWriteTime->dwHighDateTime = KeyInfo->Node.LastWriteTime.u.HighPart;}}}

Reactos使用了联合体解决了这个问题。

容错。

        我们写的API,往往会接受调用方传入的一些数据。如果这个数据是个很大的且没有固定结构的数据时,那么就要非常注意这个空间的大小了。如RegEnumKeyEx函数就接受了两个用户传入的空间及其大小。

        在我们重写的RegEnumKey中对用户传入的数据进行填充前,我们要先准确无误地获取数据,而用户传入的空间和大小我们不能用,因为我们不知道他对不对,于是我们要先分配一个适合大小的空间,调用NtEnumerateKey得到数据后再对用户传入空间大小进行判断,对空间进行填充。但是这个空间大小如何定义呢?有一种办法就是不断试错,通过ResultLength参数得到适合的空间大小。

        但是是不是很费呢?是的,Reactos对RegEnumKey的实现则是利用用户传入的空间大小,而没有用其传入的空间,这样一旦空间过小,会快速发现,而不用等数据都查完了才发现用户传入的空间太小。但是现在存在一个问题,如果用户传入的空间大小特别大,实际用不到这么大的数据,那怎么办?难道我们也要听从用户分配一个巨大的内存空间么?不是,我们看看Reactos的做法(我修改后的代码)

LPVOID lpKeyInfo = NULL;do { ULONG NameLength = 0;if ( *lpcName > 0 ) {NameLength = min( *lpcName - 1, MAX_PATH ) * sizeof(WCHAR);}else {NameLength = 0;}ULONG BufferSize = 0;ULONG ClassLength = 0;if ( lpClass ) {if ( *lpcClass > 0 ) {ClassLength = min( *lpcClass - 1, MAX_PATH ) * sizeof(WCHAR);}else {ClassLength = 0;}// +3 再& ~3是为了让大小按4字节对齐且取其上限// 如果存在lpClass,则要将ClassLength的长度算进去// 如果存在lpClass,则要使用KEY_NODE_INFORMATION结构体BufferSize = ( ( sizeof(KEY_NODE_INFORMATION) + NameLength + 3 ) & ~3 ) + ClassLength;}else {// 如果不存在lpClass,则使用KEY_BASIC_INFORMATION结构体BufferSize = sizeof(KEY_BASIC_INFORMATION) + NameLength;}// 在堆上分配一段适合大小的空间lpKeyInfo = HeapAlloc( GetProcessHeap(), 0, BufferSize );

它在别人传入的空间-1和260之间选了一个最小值。如果调用方传了一个巨大的空间大小,我们也就分配260个WCHAR的大小。可能有人问:那么如果Class和KeyNamed的长度就是长于260呢?好问题!Reactos系统中Class和KeyName的最大长度就是260,何来长于260的名字呢?我在我电脑上刚做了实验,将某键名改成250个1,Regedit就会报错,说名字太长。

      这种容错还用在RegQueryValueEx的实现中,以下列出我修改后的部分代码

NTSTATUS WINAPI OriRegQueryValueEx(HANDLE KeyHandle,LPCWSTR lpValueName,LPDWORD lpReserved,LPDWORD lpType,LPBYTE lpData,LPDWORD lpcbData )
{NTSTATUS lRes = STATUS_INVALID_PARAMETER;char buffer[256] = {0};char *buf_ptr = buffer;do {KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;// KEY_VALUE_PARTIAL_INFORMATION结构的必要结构体长度static const int info_size = offsetof( KEY_VALUE_PARTIAL_INFORMATION, Data );// 参数判断if ( ( NULL != lpData && NULL == lpcbData ) || lpReserved ) {return STATUS_INVALID_PARAMETER;}UNICODE_STRING name_str;RtlInitUnicodeString_( &name_str, lpValueName );// 取一段比较合理的空间大小,这样避免用户传入过大的空间大小DWORD total_size = 0;if ( NULL != lpData ) {total_size = min( sizeof(buffer), *lpcbData + info_size );}else {total_size = info_size;if ( NULL != lpcbData ) {*lpcbData = 0;}}/* this matches Win9x behaviour - NT sets *type to a random value */if ( lpType ) {*lpType = REG_NONE;}
……

因为Value的长度理论上是可以超过260的,于是有以下处理

lRes = GETORIFUNC(QueryValueKey)(KeyHandle,&name_str, KeyValuePartialInformation,buffer, total_size, &total_size );if ( NT_FAILED(lRes) && lRes != STATUS_BUFFER_OVERFLOW ) {break;}if ( NULL == lpData ) {lRes = STATUS_SUCCESS;}else {while ( lRes == STATUS_BUFFER_OVERFLOW && total_size - info_size <= *lpcbData ) {// 空间不足,且需要的空间大小比用户传入的小// 释放之前分配的内存if ( buf_ptr != buffer ) {HeapFree( GetProcessHeap(), 0, buf_ptr );buf_ptr = NULL;}// 重新分配内存buf_ptr = (char*)HeapAlloc( GetProcessHeap(), 0, total_size );if ( NULL == buf_ptr ) {return STATUS_NO_MEMORY;}info = (KEY_VALUE_PARTIAL_INFORMATION *)buf_ptr;lRes = GETORIFUNC(QueryValueKey)( KeyHandle, &name_str, KeyValuePartialInformation,buf_ptr, total_size, &total_size );}if ( NT_SUCCESS(lRes) ) {memcpy( lpData, buf_ptr + info_size, total_size - info_size );/* if the type is REG_SZ and data is not 0-terminated* and there is enough space in the buffer NT appends a \0 */if ( is_string(info->Type) && total_size - info_size <= *lpcbData - sizeof(WCHAR) ) {WCHAR *ptr = (WCHAR *)( lpData + total_size - info_size );if (ptr > (WCHAR *)lpData && ptr[-1]) {*ptr = 0;}}}else if ( lRes != STATUS_BUFFER_OVERFLOW ) {break;}}if ( NULL != lpType) {*lpType = info->Type;}if ( NULL != lpcbData) {*lpcbData = total_size - info_size;}} while (0);

在空间不够的情况下,会在堆上分配更多的空间。

相关文章:

腾讯Angel升级:加入图算法,支持十亿节点、千亿边规模!中国首个毕业于Linux AI基金会的开源项目...

出品 | AI科技大本营&#xff08;ID&#xff1a;rgznai100&#xff09;【导语】Angel 是腾讯的首个AI开源项目&#xff0c;于 2016 年底推出、2017年开源。近日&#xff0c;快速发展的 Angel 完成了从 2.0 版本到 3.0 版本的跨越&#xff0c;从一个单纯的模型训练系统进化成包…

如何在JSP页面中获取当前系统时间转

出自&#xff1a;http://hi.baidu.com/itfuck_/item/803662469cdf7baa61d7b945 1: import java.util.*; int y,m,d,h,mm; Calendar c Calendar.getInstance(); y c.get(Calendar.YEAR); //年 m c.get(Calendar.MONTH) 1; //月 d c.get(Calendar.DAY_OF_MONTH); //日 …

如何用Python实现超级玛丽的界面和状态机?

作者 | marble_xu编辑 | 郭芮来源 | CSDN博客小时候的经典游戏&#xff0c;代码参考了github上的项目Mario-Level-1&#xff08;https://github.com/justinmeister/Mario-Level-1&#xff09;&#xff0c;使用pygame来实现&#xff0c;从中学习到了横版过关游戏实现中的一些处理…

一种注册表沙箱的思路、实现——研究Reactos中注册表函数的实现4

今天为了KPI&#xff0c;搞了一天的PPT&#xff0c;搞得恶心想吐。最后还是回到这儿&#xff0c;这儿才是我的净土&#xff0c;可以写写我的研究。 这儿讲一些Reactos中一些明显的错误。&#xff08;转载请指明出处&#xff09; 在Reactos的RegQueryInfoKeyW中有段这样的实现 i…

Netscaler 认证,访问报http 5000 内部错误

在VDI项目中&#xff0c;Netscaler经常与AD不在同一网络&#xff0c;有时在icaprofile中写的SF或WI的FQDN&#xff0c;访问VDI&#xff0c;会报http 5000 内部错误&#xff1b;解决办法如下&#xff1a;1.NS无法解析Storefont或WI的主机名&#xff0c;需要修改icaprofile 中SF或…

解读 | 2019年10篇计算机视觉精选论文(中)

导读&#xff1a;2019 年转眼已经接近尾声&#xff0c;我们看到&#xff0c;这一年计算机视觉&#xff08;CV&#xff09;领域又诞生了大量出色的论文&#xff0c;提出了许多新颖的架构和方法&#xff0c;进一步提高了视觉系统的感知和生成能力。因此&#xff0c;我们精选了 20…

PE文件和COFF文件格式分析--概述

刚工作的时候&#xff0c;我听说某某大牛在做病毒分析时&#xff0c;只是用notepad打开病毒文件&#xff0c;就能大致猜到病毒的工作原理。当时我是佩服的很啊&#xff0c;同时我也在心中埋下了一个种子&#xff1a;我也得有这天。随着后来的工作进行&#xff0c;一些任务的和这…

2015第22周六Java反射、泛型、容器简介

Java的反射非常强大&#xff0c;传递class&#xff0c; 可以动态的生成该类、取得这个类的所有信息&#xff0c;包括里面的属性、方法以及构造函数等&#xff0c;甚至可以取得其父类或父接口里面的内容。 obj.getClass().getDeclaredMethods();//取得obj类中自己定义的方法&…

中服公司企业信息化的ERP系统选择

中服公司企业信息化的ERP系统选择一、 中服公司概况 1. 组织概况 中服公司创建于1950年9月&#xff0c;是国家120家企业集团试点单位之一&#xff0c;主要经营各类纺织原料、半成品、服装、针棉毛织品以及其他商品的进出口业务&#xff0c;同时通过合资、联营等方…

PE文件和COFF文件格式分析--MS-DOS 2.0兼容Exe文件段

MS 2.0节是PE文件格式中第一个“节”。其大致结构如下&#xff1a;&#xff08;转载请指明来源于breaksoftware的csdn博客&#xff09; 在VC\PlatformSDK\Include\WinNT.h文件中有对MS-DOS 2.0兼容EXE文件头的完整定义 typedef struct _IMAGE_DOS_HEADER { // DOS .EXE h…

时间可以是二维的?基于二维时间图的视频内容片段检测 | AAAI 2020

作者 | 彭厚文、傅建龙来源 | 微软研究院AI头条&#xff08;ID: MSRAsia&#xff09;编者按&#xff1a;当时间从一维走向二维&#xff0c;时序信息处理问题中一种全新的建模思路由此产生。根据这种新思路及其产生的二维时间图概念&#xff0c;微软亚洲研究院提出一种新的解决时…

《燃烧的岁月》

温含着优美的文句中&#xff0c;字里行间&#xff0c;透过一层薄薄的纸&#xff0c;牵挂起往事如烟&#xff0c;曾经的努力和成长&#xff0c;透过那以视频同时走过的路&#xff0c;默默无闻&#xff0c;牵挂着的是一句句唯美的文笔&#xff0c;留下情感的诗句文笔&#xff0c;…

PE文件和COFF文件格式分析——签名、COFF文件头和可选文件头1

本文将讨论PE文件中非常重要的一部分信息。&#xff08;转载请指明来源于breakSoftware的CSDN博客&#xff09; 首先说一下VC中对应的数据结构。“签名、COFF文件头和可选文件头”这三部分信息组合在一起是一个叫IMAGE_NT_HEADERS的结构体。 typedef struct _IMAGE_NT_HEADERS6…

遇到bug心寒了?用Enter键即可解决!

本文图片来自网络做程序员难不难&#xff1f;很难&#xff01;做个程序员压力大不大&#xff1f;超级大&#xff01;&#xff01;测试bug时&#xff08;图片来自网络&#xff09;当找到Bug&#xff0c;开始修改的你……&#xff08;图片来自网络&#xff09;那怎么办&#xff1…

8月第1周安全回顾 0Day漏洞成企业最大威胁 应重视网络监听

文章同时发表在&#xff1a;[url]http://netsecurity.51cto.com/art/200708/52822.htm[/url]本周&#xff08;0730至0805&#xff09;安全方面值得关注的新闻集中在安全管理、安全威胁和安全产品方面。安全管理&#xff1a;0Day漏洞***成为企业信息安全的最大威胁新闻&#xff…

最大匹配、最小顶点覆盖、最大独立集、最小路径覆盖(转)

在讲述这两个算法之前&#xff0c;首先有几个概念需要明白&#xff1a; 二分图: 二分图又称二部图&#xff0c;是图论中的一种特殊模型。设G(V,E)是一个无向图&#xff0c;如果顶点V可以分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个…

一种在注入进程中使用WTL创建无焦点不在任务栏出现“吸附”窗口的方法和思路

最近一直在做沙箱项目&#xff0c;在项目快接近结尾的时候&#xff0c;我想给在我们沙箱中运行的程序界面打上一个标记——标识其在我们沙箱中运行的。我大致想法是&#xff1a;在被注入程序的顶层窗口上方显示一个“标题性”窗口&#xff0c;顶层窗口外框外显示一个“异形”的…

转:ASP.NET状态保存方法

ASP.NET状态保存分为客户端保存和服务器端保存两种&#xff1a;使用客户端选项存储页信息而不使用服务器资源的这些选项往往具有最低的安全性但具有最快 的服务器性能&#xff0c;因为对服务器资源的要求是适度的。但是&#xff0c;由于必须将信息发送到客户端来进行存储&#…

时至今日,NLP怎么还这么难!

作者 | 刘知远在微博和知乎上关注自然语言处理&#xff08;NLP&#xff09;技术的朋友&#xff0c;应该都对#NLP太难了#、#自然语言理解太难了#两个话题标签不陌生&#xff0c;其下汇集了各种不仅难煞计算机、甚至让人也发懵的费解句子或歧义引起的笑话。然而&#xff0c;这些例…

Quartz定时任务学习(四)调度器

org.quartz.Scheduler 类层次 作为一个 Quartz 用户&#xff0c;你要与实现了 org.quartz.Scheduler 接口的类交互。在你调用它的任何 API 之前&#xff0c;你需要知道如何创建一个 Scheduler 的实例。取而代之的是用了某个工厂方法来确保了构造出 Sheduler 实例并正确的得到初…

反汇编算法介绍和应用——线性扫描算法分析

做过逆向的朋友应该会很熟悉IDA和Windbg这类的软件。IDA的强项在于静态反汇编&#xff0c;Windbg的强项在于动态调试。往往将这两款软件结合使用会达到事半功倍的效果。可能经常玩这个的朋友会发现IDA反汇编的代码准确度要高于Windbg&#xff0c;深究其原因&#xff0c;是因为I…

项目计划书的内容

1.引言 1.1计划的目的 1.2项目的范围和目标 1.2.1范围描述 1.2.2主要功能 1.2.3性能 1.2.4管理和技术约束 2.项目估算 2.1使用的历史数据 2.2使用的评估技术 2.3工作量、成本、时间估算 3.风险管理战略 3.1风险识别 3.2有关风险的讨论 3.3风险管理计划 3.3.1风险计划 3.3.2风险…

不用写代码就能学用Pandas,适合新老程序员的神器Bamboolib

作者 | Rahul Agarwal译者 | 陆离编辑 | Jane出品 | AI科技大本营&#xff08;ID&#xff1a;rgznai100&#xff09;曾经&#xff0c;你有没有因为学习与使用 Pandas 进行数据检索等操作而感到厌烦过&#xff1f;实现同样的功能&#xff0c;Pandas 给用户提供了很多种方法&…

后海日记(8)

来深圳已经这么长时间了&#xff0c;深圳给我的感觉总体很好&#xff0c;天那么蓝&#xff0c;空气也很清新&#xff0c;总的来说很不错。 努力学习&#xff0c;早日成才。 加油&#xff01;版权声明&#xff1a;本文为博主原创文章&#xff0c;未经博主允许不得转载。 转载于:…

反汇编算法介绍和应用——递归下降算法分析

上一篇博文我介绍了Windbg使用的线性扫描&#xff08;linear sweep&#xff09;反汇编算法。本文我将介绍IDA使用的递归下降&#xff08;recursive descent&#xff09;反汇编算法。&#xff08;转载请指明来源于breaksoftware的csdn博客&#xff09; 递归&#xff08;recursiv…

如何快速get到AI工程师面试重点,这12道题必备!

作者 | JP Tech译者 | 刘畅编辑 | Jane出品 | AI科技大本营&#xff08;ID&#xff1a;rgznai100&#xff09;【导读】2020 年的三月春招要来了&#xff0c;现在想要 Get 一个算法工程师的实习或全职机会&#xff0c;已经不是一件易事了。如果现在着手复习&#xff0c;茫茫题海…

金邦黑金刚4G内存 VS Vista系统

我的机器配置是 Intel Core 2 4320CPU 金邦黑金刚2G DDR2 800*2 P965P-DS3主板 N 8600GTS 为什么在Vista中 只识别了3.5G 我升级了主版BIOS 主版最高支持8G,哎结果网上一看&#xff0c;才明白。。。现在的系统不是很好的支持4G的内存。…

程序员的量化交易之路(25)--Cointrader之MarketData市场数据实体(12)

转载需注明出处&#xff1a;http://blog.csdn.net/minimicall&#xff0c;http://cloudtrade.top/ 前面一节我们说到了远端事件。其中&#xff0c;市场数据就属于远端事件。市场数据有什么&#xff1f;我们通过代码来回答这个问题&#xff1a; package org.cryptocoinpartners.…

滴滴开源在2019:十大重点项目盘点,DoKit客户端研发助手首破1万Star

整理 | Jane出品 | AI科技大本营&#xff08;ID&#xff1b;rgznai100&#xff09;2018 年&#xff0c;科技企业纷纷布局开源战略后迎来的第一个“丰收年”。但对滴滴来说&#xff0c;2019 年才迎来其第一波开源小高潮。自2017年滴滴零星开源数个项目后&#xff0c;滴滴开源项目…

PE文件和COFF文件格式分析——签名、COFF文件头和可选文件头2

之前的博文中介绍了IMAGE_FILE_HEADER结构&#xff0c;现在来讨论比较复杂的“可选文件头”结构体。(转载请指明来自breaksoftware的csdn博客)先看下其声明 typedef struct _IMAGE_OPTIONAL_HEADER {//// Standard fields.//WORD Magic;...DWORD BaseOfData; // not e…