最近有一個(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)下去查看 AccessPermission
和 LaunchPermission
鍵值。
AccessPermission
和 LaunchPermission
的鍵值是編碼轉(zhuǎn)換后的二進(jìn)制穆端,其實(shí)際上是一個(gè) SECURITY_INFORMATION
結(jié)構(gòu)盐茎,包含了對(duì)象的 Owner
、primary 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)