列出系統(tǒng)中所有 DCOM 及其訪問(wèn)權(quán)限

最近有一個(gè)需求是要查看系統(tǒng)中某些 DCOM 組件的訪問(wèn)權(quán)限,索性就寫(xiě)個(gè)程序把所有的可被外部拉起的組件都列一下惰匙。由于之前并沒(méi)有接觸過(guò)這一方面的內(nèi)容豺总,所以還是有很多問(wèn)題亟待解決(雖然并不難~)

程序的思路就是遍歷 HKEY_CLASSES_ROOT\\CLSID 注冊(cè)表項(xiàng)下所有的子鍵和鍵值羡榴,其中擁有子鍵 LocalServer32 的表明其可以被其他進(jìn)程拉起匀归,擁有鍵值 AppId 的表明其是一個(gè) DCOM坑资。轉(zhuǎn)到對(duì)應(yīng) HKEY_CLASSES_ROOT\\APPID 表項(xiàng)下去查看 AccessPermissionLaunchPermission 鍵值。

AccessPermissionLaunchPermission 的鍵值是編碼轉(zhuǎn)換后的二進(jìn)制穆端,其實(shí)際上是一個(gè) SECURITY_INFORMATION 結(jié)構(gòu)盐茎,包含了對(duì)象的 Ownerprimary group徙赢、discretionary access control list字柠、system access control list 信息。為了方便查看需要將其轉(zhuǎn)化為字符串的形式狡赐。


#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;
}

部分結(jié)果如下所示

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 其結(jié)構(gòu)如下

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等都是以兩個(gè)大寫(xiě)字母表示的值,當(dāng)然也可以直接使用標(biāo)準(zhǔn)值枕屉,具體的細(xì)節(jié)可以查看 文檔
因此上述 CLSID 的 AccessPermission 解釋出來(lái)為

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 權(quán)限或自身訪問(wèn)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末常柄,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子搀擂,更是在濱河造成了極大的恐慌西潘,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件哨颂,死亡現(xiàn)場(chǎng)離奇詭異喷市,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)威恼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén)品姓,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人箫措,你說(shuō)我怎么就攤上這事腹备。” “怎么了斤蔓?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵植酥,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我弦牡,道長(zhǎng)友驮,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任喇伯,我火速辦了婚禮喊儡,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘稻据。我一直安慰自己艾猜,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布捻悯。 她就那樣靜靜地躺著匆赃,像睡著了一般。 火紅的嫁衣襯著肌膚如雪今缚。 梳的紋絲不亂的頭發(fā)上算柳,一...
    開(kāi)封第一講書(shū)人閱讀 49,144評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音姓言,去河邊找鬼瞬项。 笑死蔗蹋,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的囱淋。 我是一名探鬼主播猪杭,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼妥衣!你這毒婦竟也來(lái)了皂吮?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤税手,失蹤者是張志新(化名)和其女友劉穎蜂筹,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體芦倒,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡艺挪,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了熙暴。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片闺属。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖周霉,靈堂內(nèi)的尸體忽然破棺而出掂器,到底是詐尸還是另有隱情,我是刑警寧澤俱箱,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布国瓮,位于F島的核電站,受9級(jí)特大地震影響狞谱,放射性物質(zhì)發(fā)生泄漏乃摹。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一跟衅、第九天 我趴在偏房一處隱蔽的房頂上張望孵睬。 院中可真熱鬧,春花似錦伶跷、人聲如沸掰读。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)蹈集。三九已至,卻和暖如春雇初,著一層夾襖步出監(jiān)牢的瞬間拢肆,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留郭怪,地道東北人支示。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像移盆,于是被迫代替她去往敵國(guó)和親悼院。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 這篇文章幾乎幾乎原封不動(dòng)的搬過(guò)來(lái)了這位博主的內(nèi)容咒循,作為自己以后查詢方便用~ reference:http://bl...
    DeamoV閱讀 20,221評(píng)論 3 33
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)绞愚,斷路器叙甸,智...
    卡卡羅2017閱讀 134,601評(píng)論 18 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,748評(píng)論 6 342
  • 事件源對(duì)象 event.srcElement.tagName event.srcElement.type 捕獲釋放...
    孤魂草閱讀 867評(píng)論 0 0
  • 午后,陽(yáng)光明媚位衩,禪音繚繞裆蒸。 已經(jīng)很久沒(méi)有靜下來(lái),獨(dú)享午后這一份靜謐了糖驴。 不知從何時(shí)起僚祷,發(fā)現(xiàn)自己離不開(kāi)文字,仿佛有跳...
    27歲也挺好閱讀 215評(píng)論 0 0