前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >一种注册表沙箱的思路、实现——注册表的一些基础知识

一种注册表沙箱的思路、实现——注册表的一些基础知识

作者头像
方亮
发布2019-01-16 14:30:27
7810
发布2019-01-16 14:30:27
举报
文章被收录于专栏:方亮方亮

        要做注册表沙箱,就必须要了解部分注册表知识。而注册表的知识很多,本文主要讲述如何在win32系统是上识别注册表映射的。

        在我的xp 32bit系统上,Win+R regedit之后打开注册表管理器。我们可以看到如下主键:HKEY_CLASSES_ROOT、HKEY_CURRENT_USER、HKEY_LOCAL_MACHINE、HKEY_USERS和HKEY_CURRENT_CONFIG。如果关注过注册表的同学可能发现过一个现象:修改HKEY_CURRENT_USER下某键项值为A,搜索A,可以搜索到1~3个结果,不仅值相同,其项的父键名等都一样。这种被“同步”的功能是不是很有意思。其实这个现象是因为HKEY_CURRENT_USER键是HKEY_USERS下某键的映射。同样的HKEY_CLASSES_ROOT和HKEY_CURRENT_CONFIG是HKEY_LOCAL_MACHINE下某键的映射。

        如果Hook过NtOpenKey的同学可能发现过一个现象,我们参数中的注册表路径往往是\Registry\User\……或者\Registry\Machine\……的形式,而没有见过其他形式的路径。\Registry\User对应于HKEY_USERS,\Registry\Machine对应于HKEY_LOCAL_MACHINE。HKEY_CLASSES_ROOT 和HKEY_CURRENT_CONFIG对应的注册表也是很固定的,分别是\Registry\Machine\SOFTWARE\Classes和\Registry\Machine\CurrentControlSet\Hardware Profiles\Current。最捉摸不定的是HKEY_CURRENT_USER的真实路径,我在网上找了一种方法,该方法仅适用于win32系统,我验证过,该方法在win64系统上是不正确的。下面我用程序描述这种思路:

        1 枚举所有ProfileList键下子键

代码语言:javascript
复制
BOOL CConvertRegPath::GetSIDOnWin32( ATL::CString & cstrSid )
{
    BOOL bSuc = FALSE;
    // 通过枚举HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList
    // 下所有子键,确定哪个是SID
    do {
        HKEY hKey = NULL; 

        if ( ERROR_SUCCESS != RegOpenKey( HKEY_LOCAL_MACHINE, ProfileList, &hKey ) ) {
            break;
        }

        WCHAR wszKey[MaxKeyName] = {0}; 
        DWORD nIndex = 0;
        DWORD dwLen = MaxKeyName;

        ATL::CString cstrKeyPath;
        ATL::CString cstrTmpSid;

        while ( ERROR_SUCCESS == RegEnumKey( hKey, nIndex++, wszKey, dwLen ) ) { 
            cstrSid = wszKey; 

            // 拼接完整的注册表DOS路径
              cstrKeyPath = ProfileList;
            cstrKeyPath += L"\\";
            cstrKeyPath += cstrSid;
            cstrKeyPath += L"\\"; 

        2  判断SID是否为当前用户的SID

代码语言:javascript
复制
            if ( IsSidKey( cstrKeyPath ) && cstrSid.GetLength() > CurrentUserSidMinLength ) {
                bSuc = TRUE;
                break;
            }

            cstrSid.Empty();
            dwLen  = MaxKeyName; 
            wmemset( wszKey, 0, MaxKeyName );
        } 

        其中IsSidKey函数的实现如下

代码语言:javascript
复制
BOOL CConvertRegPath::IsSidKey( const ATL::CString & cstrKeyPath )
{
    // 该函数通过判断项RefCount值是否大于0来判断该项名是否是SID值
    BOOL bSidKey = FALSE;

    do {
        DWORD dwRefCount = 0;
        DWORD dwLength = sizeof(DWORD);
        LONG lRes = RegQueryValueEx( HKEY_LOCAL_MACHINE, cstrKeyPath.GetString(), NULL, NULL, (LPBYTE)&dwRefCount, &dwLength );

        // 检查项值是否大于0
        if ( dwRefCount > 0 ){
            bSidKey = TRUE;
        }
   
    } while (0);
        
    return bSidKey;
}

        该函数就是判断诸如HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\S-1-5-21-73586283-2049760794-839522115-1003键下项RefCount的值是否大于0(一般为1)。其实符合这样的键可能不止一个,比如本机上HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\S-1-5-18键的RefCount就是1。于是就又要加个判断,就是键名长度要大于一定的长度(我定义为20)。

2012-6-11 追加

       今天看了别人转载SUDAMI的一篇关于获取SID的方法,个人觉得那个方法比以上经验之谈要靠谱,故贴出他的代码,也没找到他博客的地址,就不列出他博文地址了。

代码语言:javascript
复制
int GetUserName ()
{
    HANDLE hProcess = GetCurrentProcess();
    if(!hProcess) {
        return 0;
    }

    HANDLE hToken;
    if( !OpenProcessToken(hProcess, TOKEN_QUERY, &hToken) || !hToken ){
        CloseHandle(hProcess);
        return 0;
    }

    DWORD dwTemp = 0;
    char tagTokenInfoBuf[256] = {0};
    PTOKEN_USER tagTokenInfo = (PTOKEN_USER)tagTokenInfoBuf;
    if( !GetTokenInformation( hToken, TokenUser, tagTokenInfoBuf, sizeof(tagTokenInfoBuf), &dwTemp ) ) {
            CloseHandle(hToken);
            CloseHandle(hProcess);
            return 0;
    }

    typedef BOOL (WINAPI* PtrConvertSidToStringSid)(
        PSID Sid,
        LPTSTR* StringSid );

    PtrConvertSidToStringSid dwPtr = (PtrConvertSidToStringSid)GetProcAddress( 
        GetModuleHandle(L"Advapi32.dll"), "ConvertSidToStringSidA" );

    LPTSTR MySid = NULL;
    dwPtr( tagTokenInfo->User.Sid, (LPTSTR*)&MySid );

    printf("sudami's PC Name:\n%s\n", MySid);
    getchar ();
    LocalFree( (HLOCAL)MySid );

    CloseHandle(hToken);
    CloseHandle(hProcess);

    return 0;
}

        在内核里有个函数RtlFormatCurrentUserKeyPath也可以获得SID,在Ntdll中也可以导出这个函数。我做了下实验,发现在Ring3不能直接使用该函数获取SID,因为会报错

错误原因应该很明显了,这个函数内部应该要访问系统空间地址(0x7FFFFFFF以上)上的地址,于是就C0000005了。

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

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

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

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

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