前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >一种注册表沙箱的思路、实现——研究Reactos中注册表函数的实现2

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

作者头像
方亮
发布2019-01-16 15:59:11
5140
发布2019-01-16 15:59:11
举报
文章被收录于专栏:方亮方亮

上一篇博文中主要介绍了Reactos中大部分函数的思路和HKEY和HANDLE之间的关系,本文将介绍一些Reactos中有意思的函数和存在bug的函数。(转载请指明出处

        CreateNestedKey是一个辅助创建键的函数,比如我们要创建\Regsitry\User\3\2\1,而我们只是存在\Regsitry\User\,我们最终将调用此函数将在User下创建键3,然后在3键下创建键2,最后在2键下创建键1。假如你是这个函数的实现者,你要思考这个函数的实现思路。最容易的办法是将\Regsitry\User\3\2\1路径拆成一系列键名(\Regsitry\User、3、2、1),然后从根键一步一步的调用NtCreateKey,这样就可以保证路径上的所有键都被创建。这个方法的优点是简单。但是Reactos实现的思路却不是这样的。我列一下我改写的该函数。

NTSTATUS OriCreateNestedKey(
    PHANDLE pKeyHandle,
    POBJECT_ATTRIBUTES ObjectAttributes,
    PUNICODE_STRING ClassString,
    DWORD dwOptions,
    REGSAM samDesired,
    DWORD *lpdwDisposition )
{
    UNICODE_STRING LocalKeyName;
    NTSTATUS lRes = STATUS_INVALID_PARAMETER;
  
    do {
        if ( NULL == ObjectAttributes || NULL == ObjectAttributes->ObjectName ) {
            break;
        }

        lRes = RtlCreateUnicodeString_( &LocalKeyName, ObjectAttributes->ObjectName->Buffer );
        CHECKRESULT(lRes);

        lRes = GETORIFUNC(CreateKey)( pKeyHandle, samDesired,
            ObjectAttributes, 0, ClassString, dwOptions, (PULONG)lpdwDisposition );

        if ( STATUS_OBJECT_NAME_NOT_FOUND != lRes ) {
            return lRes;
        }

        OBJECT_ATTRIBUTES LocalObjectAttributes;
        RtlCopyMemory( &LocalObjectAttributes, ObjectAttributes, sizeof(OBJECT_ATTRIBUTES));

        LocalObjectAttributes.ObjectName = &LocalKeyName;
        ULONG FullNameLength = LocalKeyName.Length / sizeof(WCHAR);

        HANDLE LocalKeyHandle = NULL;

        PWCHAR Ptr = NULL;
        ULONG Disposition = 0;

        // 通过将\\改成结尾符,逐个去掉最后一个键名,查看什么路径的注册表键存在
        while ( STATUS_OBJECT_NAME_NOT_FOUND == lRes ) {
            Ptr = wcsrchr(LocalKeyName.Buffer, '\\');
            if ( NULL == Ptr || Ptr == LocalKeyName.Buffer ) {
                lRes = STATUS_UNSUCCESSFUL;
                break;
            }

            // 通过将\\改成结尾符,通过长度去掉键名
            *Ptr = (WCHAR)0;
            LocalKeyName.Length = wcslen(LocalKeyName.Buffer) * sizeof(WCHAR);

            lRes = GETORIFUNC(CreateKey)( &LocalKeyHandle, KEY_CREATE_SUB_KEY,
                &LocalObjectAttributes, 0, NULL, 0, &Disposition );
        }

        CHECKRESULT(lRes);

        // 通过将结尾符改成\\,重新拼接上键名,逐个创建键
        ULONG Length = wcslen(LocalKeyName.Buffer);
        while ( TRUE ) {
            if ( NULL != LocalKeyHandle ) {
                GETORIFUNC(Close) (LocalKeyHandle);
            }

            // 通过将结尾符改成\\,重新拼接上键名
            LocalKeyName.Buffer[Length] = L'\\';
            Length = wcslen (LocalKeyName.Buffer);
            LocalKeyName.Length = Length * sizeof(WCHAR);

            if ( Length == FullNameLength ) {
                // 如果已经拼接回以前的键名了,则执行完后就退出
                lRes = GETORIFUNC(CreateKey)( pKeyHandle, samDesired,
                    ObjectAttributes, 0, ClassString, dwOptions, (PULONG)lpdwDisposition);
                break;
            }

            // 创建祖宗键
            lRes = GETORIFUNC(CreateKey)( &LocalKeyHandle, KEY_CREATE_SUB_KEY,
                &LocalObjectAttributes, 0, NULL, 0, &Disposition);

            if ( NT_FAILED(lRes) ) {
                break;
            }
        }
    } while (0);
    RtlFreeUnicodeString_(&LocalKeyName);
    return lRes;
}

        大致说下这个函数的流程:

  1. 使用NtCreateKey函数调用传入的参数。如果不是返回STATUS_OBJECT_NAME_NOT_FOUND,则说明要创建的路径上的键的父键是存在的,直接返回创建的结果;否则说明父键就不存在,得依赖之后的步骤将父键创建起来。
  2. 声明个变量OBJECT_ATTRIBUTES LocalObjectAttributes;将作为参数传入的ObjectAttributes全部拷贝到LocalObjectAttributes,同时记录下路径的长度FullNameLength。
  3. 将LocalObjectAttributes.LocalKeyName中的记录路径的Buffer字段,从后向前寻找“\”符号,找到一个,就将其改为空,同时再计算LocalObjectAttributes中LocalKeyName的长度。得到修改后的LocalObjectAttributes后,再调用NtCreateKey。以上面的例子为例,就是用NtCreateKey创建\Regsitry\User\3\2。查看返回结果,如果结果还是STATUS_OBJECT_NAME_NOT_FOUND,说明父键还是不存在的,于是要重复3的步骤,一直到NtCreateKey执行成功。如例子中,一直到用NtCreateKey创建\Regsitry\User\3就停止这个循环,因为3键可以创建成功。
  4. 比较LocalObjectAttributes.LocalKeyName的长度和FullNameLength,如果相等,则说明我们应该创建的键都创建完了。如果不等,则我们将LocalObjectAttributes.LocalKeyName的最前一个空改成“\”,得到修改后的LocalObjectAttributes,再调用NtCreateKey。在我们的例子中,就是创建\Regsitry\User\3\2。一直重复4,一直到LocalObjectAttributes.LocalKeyName的长度和FullNameLength相等。

       我很欣赏这样的思路,通过改改内存达到目的,效率方面会好很多。     

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2012年06月12日,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档