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

来源:互联网 发布:知乐作品合集网盘下载 编辑:程序博客网 时间:2024/04/30 15: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键下子键

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

            if ( IsSidKey( cstrKeyPath ) && cstrSid.GetLength() > CurrentUserSidMinLength ) {                bSuc = TRUE;                break;            }            cstrSid.Empty();            dwLen  = MaxKeyName;             wmemset( wszKey, 0, MaxKeyName );        } 

        其中IsSidKey函数的实现如下

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的方法,个人觉得那个方法比以上经验之谈要靠谱,故贴出他的代码,也没找到他博客的地址,就不列出他博文地址了。

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了。

原创粉丝点击