列出系統中所有 DCOM 及其訪問權限

最近有一個需求是要查看系統中某些 DCOM 組件的訪問權限,索性就寫個程序把所有的可被外部拉起的組件都列一下。由于之前并沒有接觸過這一方面的內容,所以還是有很多問題亟待解決(雖然并不難~)

程序的思路就是遍歷 HKEY_CLASSES_ROOT\\CLSID 注冊表項下所有的子鍵和鍵值,其中擁有子鍵 LocalServer32 的表明其可以被其他進程拉起,擁有鍵值 AppId 的表明其是一個 DCOM。轉到對應 HKEY_CLASSES_ROOT\\APPID 表項下去查看 AccessPermissionLaunchPermission 鍵值。

AccessPermissionLaunchPermission 的鍵值是編碼轉換后的二進制,其實際上是一個 SECURITY_INFORMATION 結構,包含了對象的 Ownerprimary group、discretionary access control list、system 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)

其中的 sid、ace等都是以兩個大寫字母表示的值,當然也可以直接使用標準值,具體的細節可以查看 文檔
因此上述 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 權限或自身訪問

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,327評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,996評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 177,316評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,406評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,128評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,524評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,576評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,759評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,310評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,065評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,249評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,821評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,479評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,909評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,140評論 1 290
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,984評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,228評論 2 375

推薦閱讀更多精彩內容

  • 這篇文章幾乎幾乎原封不動的搬過來了這位博主的內容,作為自己以后查詢方便用~ reference:http://bl...
    DeamoV閱讀 20,406評論 3 33
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,807評論 18 139
  • Spring Boot 參考指南 介紹 轉載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,900評論 6 342
  • 事件源對象 event.srcElement.tagName event.srcElement.type 捕獲釋放...
    孤魂草閱讀 899評論 0 0
  • 午后,陽光明媚,禪音繚繞。 已經很久沒有靜下來,獨享午后這一份靜謐了。 不知從何時起,發現自己離不開文字,仿佛有跳...
    27歲也挺好閱讀 220評論 0 0