列出系统中所有 DCOM 及其访问权限

最近有一个需求是要查看系统中某些 DCOM 组件的访问权限,索性就写个程序把所有的可被外部拉起的组件都列一下。由于之前并没有接触过这一方面的内容,所以还是有很多问题亟待解决(虽然并不难~)

程序的思路就是遍历 HKEY_CLASSES_ROOT\\CLSID 注册表项下所有的子键和键值,其中拥有子键 LocalServer32 的表明其可以被其他进程拉起,拥有键值 AppId 的表明其是一个 DCOM。转到对应 HKEY_CLASSES_ROOT\\APPID 表项下去查看 AccessPermissionLaunchPermission 键值。

AccessPermissionLaunchPermission 的键值是编码转换后的二进制,其实际上是一个 SECURITY_INFORMATION 结构,包含了对象的 Ownerprimary groupdiscretionary access control listsystem access control list 信息。为了方便查看需要将其转化为字符串的形式。


#include <time.h> 
#include <windows.h> 
#include <iostream>
#include <stdio.h>  
#include <tchar.h>  
#include <fstream>
#include <queue>
#include <Sddl.h>


#define MAX_KEY_LENGTH 255  
#define MAX_VALUE_NAME 16383  
#define MAX_ACL_LENGTH 255
#define SUCCESS_CHECK(hr) if(hr != ERROR_SUCCESS){printf("RegQuery Error!!\n");return;}

DWORD dwType = REG_BINARY | REG_DWORD | REG_EXPAND_SZ | REG_MULTI_SZ | REG_NONE | REG_SZ;
std::queue<std::wstring> keystack;

//#define COMMAND_OUTPUT

FILE *fp;

BOOL GetRegData(HKEY rootKey, const wchar_t* path, wchar_t* value, unsigned char* lpData)
{
    HKEY hKey;
    BOOL rlt = FALSE;
    if (RegOpenKeyEx(rootKey, path, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
    {
        RegCloseKey(hKey);
        return NULL;
    }
    
    DWORD ret;
    DWORD dwType;
    DWORD dwNameLen = 255;
    ret = RegQueryValueEx(hKey, value, 0, &dwType, lpData, &dwNameLen);
    if (ret == ERROR_SUCCESS)
    {
        rlt = TRUE;
        
    }
    return rlt;
}

void QueryAppIdPermission(HKEY rootKey, const wchar_t* path)
{
    BYTE cbAPermission[255] = { 0 };
    LPWSTR lpAPermission[1] = {0};
    if (GetRegData(rootKey, path, L"AccessPermission", cbAPermission))
    {
        ConvertSecurityDescriptorToStringSecurityDescriptor((PSECURITY_DESCRIPTOR)cbAPermission, SDDL_REVISION_1, DACL_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION, lpAPermission, NULL);
        fwprintf(fp, L" AccessPermission: %s\n", lpAPermission[0]);
    }

    BYTE cbLPermission[255] = { 0 };
    LPWSTR lpLPermission[1] = { 0 };
    if (GetRegData(rootKey, path, L"LaunchPermission", cbLPermission))
    {
        ConvertSecurityDescriptorToStringSecurityDescriptor((PSECURITY_DESCRIPTOR)cbLPermission, SDDL_REVISION_1, DACL_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION, lpLPermission, NULL);
        fwprintf(fp, L" LaunchPermission: %s\n", lpLPermission[0]);
    }
}

BOOL IsLocalServer(HKEY rootKey, const wchar_t* path)
{
    BOOL rlt = FALSE;
    HKEY hKey;
    

    TCHAR    achKey[MAX_KEY_LENGTH];   // buffer for subkey name   
    DWORD    cSubKeys = 0;               // number of subkeys      
    DWORD    cName;                   // size of name string   
    DWORD    i, retCode;

    std::wstring newPath = L"";
    newPath.append(path);
    newPath.append(L"\\LocalServer32");

    if (RegOpenKeyEx(rootKey, newPath.c_str(), 0, KEY_READ, &hKey) == ERROR_SUCCESS)
    {
        
        rlt = TRUE;
    }
    RegCloseKey(hKey);
    return rlt;
}

BOOL IsDComponent(HKEY rootKey, const wchar_t* path)
{
    BOOL   rlt = FALSE;

    BYTE szBuffer[255] = { 0 };

    if (GetRegData(rootKey, path, L"AppID", szBuffer))
    {
        rlt = TRUE;
    }
    return rlt;
}

void regQuery(HKEY rootKey, const wchar_t* path)
{
#ifdef COMMAND_OUTPUT
    _tprintf(TEXT("\nProcess: %s :\n"), path);
#endif
    HKEY hKey;
    if (RegOpenKeyEx(rootKey, path, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
    {
        RegCloseKey(hKey);
        return;
    }

    TCHAR    achKey[MAX_KEY_LENGTH];   // buffer for subkey name  
    DWORD    cbName;                   // size of name string   
    TCHAR    achClass[MAX_PATH] = TEXT("");  // buffer for class name   
    DWORD    cchClassName = MAX_PATH;  // size of class string   
    DWORD    cSubKeys = 0;               // number of subkeys   
    DWORD    cbMaxSubKey;              // longest subkey size   
    DWORD    cchMaxClass;              // longest class string   
    DWORD    cValues;              // number of values for key   
    DWORD    cchMaxValue;          // longest value name   
    DWORD    cbMaxValueData;       // longest value data   
    DWORD    cbSecurityDescriptor; // size of security descriptor   
    FILETIME ftLastWriteTime;      // last write time   

    DWORD i, retCode;

    // Get the class name and the value count.   
    retCode = RegQueryInfoKey(
        hKey,                    // key handle   
        achClass,                // buffer for class name   
        &cchClassName,           // size of class string   
        NULL,                    // reserved   
        &cSubKeys,               // number of subkeys   
        &cbMaxSubKey,            // longest subkey size   
        &cchMaxClass,            // longest class string   
        &cValues,                // number of values for this key   
        &cchMaxValue,            // longest value name   
        &cbMaxValueData,         // longest value data   
        &cbSecurityDescriptor,   // security descriptor   
        &ftLastWriteTime);       // last write time   

                                 // Enumerate the subkeys, until RegEnumKeyEx fails.  
    if (cSubKeys)
    {
#ifdef COMMAND_OUTPUT
        printf("Number of subkeys: %d\n", cSubKeys);
#endif
        for (i = 0; i<cSubKeys; i++)
        {
            cbName = MAX_KEY_LENGTH;
            retCode = RegEnumKeyEx(hKey, i,
                achKey,
                &cbName,
                NULL,
                NULL,
                NULL,
                &ftLastWriteTime);
            if (retCode == ERROR_SUCCESS)
            {
                //use achKey to build new path and input it into stack.
                std::wstring newPath = L"";
                newPath.append(path);
                newPath.append(L"\\");
                newPath.append(achKey);

                if (IsLocalServer(rootKey, newPath.c_str()))
                {
                    fwprintf(fp, L"CLSID : %s\n", achKey);
                    std::wstring progPath = L"";
                    progPath.append(newPath);
                    progPath.append(L"\\ProgID");

                    BYTE szBuffer[255];
                    if (GetRegData(rootKey, progPath.c_str(), L"", szBuffer))
                    {
                        fwprintf(fp, L" ProgId: %s\n", szBuffer);
                    }

                    ZeroMemory(szBuffer,255);
                    if (GetRegData(rootKey, newPath.c_str(), L"AppId", szBuffer))
                    {
                        fwprintf(fp, L" AppId: %s\n", szBuffer);
                        std::wstring newPath = L"AppID";
                        newPath.append(L"\\");
                        newPath.append((wchar_t *)szBuffer);
                        QueryAppIdPermission(rootKey, newPath.c_str());
                    }
                }
            }
        }
    }
    RegCloseKey(hKey);
}


int _tmain(int argc, _TCHAR* argv[])
{
    fp = fopen("reg.txt","w");
    regQuery(HKEY_CLASSES_ROOT, L"CLSID");
    fclose(fp);
    return 0;
}

部分结果如下所示

CLSID : {F87B28F1-DA9A-4F35-8EC0-800EFCF26B83}
    ProgId: SPPUI.SPPUIObjectInteractive.1
    AppId: {0868DC9B-D9A2-4f64-9362-133CEA201299}
    AccessPermission: O:BAG:BAD:(A;;CCDCLC;;;PS)(A;;CCDCLC;;;SY)
    LaunchPermission: O:BAG:BAD:(A;;CCDCLCSWRP;;;WD)

其中 AccessPermission 就是格式化为字符串之后的 Security Descriptor 其结构如下

O:owner_sid
G:group_sid
D:dacl_flags(string_ace1)(string_ace2)... (string_acen)
S:sacl_flags(string_ace1)(string_ace2)... (string_acen)

其中的 sidace等都是以两个大写字母表示的值,当然也可以直接使用标准值,具体的细节可以查看 文档
因此上述 CLSID 的 AccessPermission 解释出来为

AccessPermission: O:BAG:BAD:(A;;CCDCLC;;;PS)(A;;CCDCLC;;;SY)

Owner: SDDL_BUILTIN_ADMINISTRATORS    S-1-5-32-544
Group: SDDL_BUILTIN_ADMINISTRATORS    S-1-5-32-544
DACL: 
    ACE[00]:
        ace_type : ACCESS_ALLOWED_ACE_TYPE
        ace_flags : 
        rights : 
                ADS_RIGHT_DS_CREATE_CHILD
                ADS_RIGHT_DS_DELETE_CHILD
                ADS_RIGHT_ACTRL_DS_LIST
        object_guid : 
        inherit_object_guid : 
        account_sid : SDDL_PERSONAL_SELF   S-1-5-10
    ACE[01]:
        ace_type : ACCESS_ALLOWED_ACE_TYPE
        ace_flags : 
        rights : 
                ADS_RIGHT_DS_CREATE_CHILD
                ADS_RIGHT_DS_DELETE_CHILD
                ADS_RIGHT_ACTRL_DS_LIST
        object_guid : 
        inherit_object_guid : 
        account_sid : SDDL_LOCAL_SYSTEM S-1-5-18

表示该组件可以被 Sytem 权限或自身访问

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 这篇文章几乎几乎原封不动的搬过来了这位博主的内容,作为自己以后查询方便用~ reference:http://bl...
    DeamoV阅读 20,538评论 3 33
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 135,269评论 19 139
  • Spring Boot 参考指南 介绍 转载自:https://www.gitbook.com/book/qbgb...
    毛宇鹏阅读 47,005评论 6 342
  • 事件源对象 event.srcElement.tagName event.srcElement.type 捕获释放...
    孤魂草阅读 942评论 0 0
  • 午后,阳光明媚,禅音缭绕。 已经很久没有静下来,独享午后这一份静谧了。 不知从何时起,发现自己离不开文字,仿佛有跳...
    27岁也挺好阅读 225评论 0 0