最近有一个需求是要查看系统中某些 DCOM 组件的访问权限,索性就写个程序把所有的可被外部拉起的组件都列一下。由于之前并没有接触过这一方面的内容,所以还是有很多问题亟待解决(虽然并不难~)
程序的思路就是遍历 HKEY_CLASSES_ROOT\\CLSID
注册表项下所有的子键和键值,其中拥有子键 LocalServer32
的表明其可以被其他进程拉起,拥有键值 AppId
的表明其是一个 DCOM。转到对应 HKEY_CLASSES_ROOT\\APPID
表项下去查看 AccessPermission
和 LaunchPermission
键值。
AccessPermission
和 LaunchPermission
的键值是编码转换后的二进制,其实际上是一个 SECURITY_INFORMATION
结构,包含了对象的 Owner
、primary group
、discretionary access control list、system access control list 信息。为了方便查看需要将其转化为字符串的形式。
#include
#include
#include
#include
#include
#include
#include
#include
#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 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
部分结果如下所示
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 权限或自身访问