在 Windows 7 上创建高程 COM 对象失败
Posted
技术标签:
【中文标题】在 Windows 7 上创建高程 COM 对象失败【英文标题】:Failure to create elevation COM object on Windows Seven 【发布时间】:2011-05-07 21:29:00 【问题描述】:我正在用 C 语言开发一个 COM 代理 对象,我的应用程序将使用它来为某些需要管理权限的操作调用 UAC 提升对话框。
计划是让它导出一个函数,该函数接受一个指向具有可变数量参数的函数的指针,并在不同的上下文中执行它。这样,应用程序可以使用该对象执行一些具有管理员权限的操作,他们需要做的就是使用该对象并将指针传递给必须以所述权限执行的函数。
这部分工作,调用 CoCreateInstance 没问题,传递函数指针并执行我的函数。
但是,当我使用COM Elevation Moniker archive 和 Microsoft 的 CoCreateInstanceAsAdmin 示例代码创建此对象的实例时,会出现问题。
代码如下:
HRESULT CoCreateInstanceAsAdmin(HWND hwnd, REFCLSID rclsid, REFIID riid, __out void ** ppv)
// Manual implementation of CreateInstanceAsAdmin
CComPtr<IBindCtx> BindCtx;
HRESULT hr = CreateBindCtx(0,&BindCtx);
BIND_OPTS3 bo;
memset(&bo, 0, sizeof(bo));
bo.cbStruct = sizeof(bo);
bo.grfMode = STGM_READWRITE;
bo.hwnd = hwnd;
bo.dwClassContext = CLSCTX_LOCAL_SERVER;
hr = BindCtx->SetBindOptions(&bo);
if (SUCCEEDED(hr))
// Use the passed in CLSID to help create the COM elevation moniker string
CComPtr<IMoniker> Moniker;
WCHAR wszCLSID[50];
WCHAR wszMonikerName[300];
StringFromGUID2(rclsid,wszCLSID,sizeof(wszCLSID) / sizeof(wszCLSID[0]));
//Elevation:Administrator!new
hr = StringCchPrintfW(wszMonikerName, sizeof(wszMonikerName)/sizeof(wszMonikerName[0]), L"Elevation:Administrator!new:%s", wszCLSID);
if (SUCCEEDED(hr))
// Create the COM elevation moniker
ULONG ulEaten = 0;
ULONG ulLen = (ULONG)wcslen(wszMonikerName);
LPBC pBindCtx = BindCtx.p;
hr = MkParseDisplayName(pBindCtx,wszMonikerName,&ulEaten,&Moniker);
if (SUCCEEDED(hr) && ulEaten == ulLen)
// Use passed in reference to IID to bind to the object
IDispatch * pv = NULL;
hr = Moniker->BindToObject(pBindCtx,NULL,riid,ppv);
return hr;
调用 CoCreateInstanceAsAdmin 失败并显示“类未注册”。
通过创建以下注册表项来注册对象(这里是 REG 文件的主体)
[HKEY_CLASSES_ROOT\COMsurrogate]
@="COMsurrogate Class"
[HKEY_CLASSES_ROOT\COMsurrogate\CurVer]
@="COMsurrogate.1"
[HKEY_CLASSES_ROOT\COMsurrogate\CLSID]
@="686B6F70-06AE-4dfd-8C26-4564684D9F9F"
[HKEY_CLASSES_ROOT\CLSID\686B6F70-06AE-4dfd-8C26-4564684D9F9F]
@="COMsurrogate Class"
"LocalizedString"="@C:\\Windows\\system32\\COMsurrogate.dll,-101"
"DllSurrogate"=""
[HKEY_CLASSES_ROOT\CLSID\686B6F70-06AE-4dfd-8C26-4564684D9F9F\ProgID]
@="COMsurrogate.1"
[HKEY_CLASSES_ROOT\CLSID\686B6F70-06AE-4dfd-8C26-4564684D9F9F\VersionIndependentProgID]
@="COMsurrogate"
[HKEY_CLASSES_ROOT\CLSID\686B6F70-06AE-4dfd-8C26-4564684D9F9F\InprocServer32]
@="@C:\\windows\system32\COMsurrogate.dll"
"ThreadingModel"="Apartment"
[HKEY_CLASSES_ROOT\CLSID\686B6F70-06AE-4dfd-8C26-4564684D9F9F\NotInsertable]
[HKEY_CLASSES_ROOT\CLSID\686B6F70-06AE-4dfd-8C26-4564684D9F9F\Programmable]
我想某些注册表项丢失了——这是我在阅读错误消息时得出的结论。但是,此注册表项列表是在浏览 MSDN 和其他网站上的文档后编译的 - 所以我很确定没有遗漏任何内容。
我尝试解决的问题之一是通过 ATL 实现它(这样注册是自动化的)。这行得通,但问题是我无法将函数指针传递给 MIDL 生成的函数原型。
我尝试使用 VARIANT 类型传递它:
v.vt = VT_PTR;
void (*myptr)(void);
myptr = &DoTheStuff;
v.byref = myptr;
hr = theElevated->CoTaskExecuter(0, v);
结果我得到“无效的参数类型”。
有人能解释一下这个主题吗?也许我想要实现的目标无法通过设计实现?
【问题讨论】:
呸。这应该作为一个单独的进程运行吗?这是在 64 位版本的 Windows 上吗?空白 DllSurrogate 在 x64 Win7 上是一个问题。也没有 AppID 或代理/存根的迹象。参考:msdn.microsoft.com/en-us/library/ms686606%28VS.85%29.aspx 呸!这东西是一个巨大的安全漏洞。如果你需要一些东西来执行具有提升权限的代码,那么给它固定的功能来执行。让它执行任意函数指针意味着你也可以提升原始程序! 您不能将有意义的指针传递给进程外 COM 对象,“进程外”位应该提示您进入该对象。在这种情况下,您可以做的最好的事情是拥有一个预先注册的对象来完成这项工作,然后您将其编组跨越边界,但是您不妨首先提升该 COM 对象。至于错误,请仔细检查它是在 HKEY_LOCAL_MACHINE(导航到 Software\Classes\CLSID\...)而不是 HKEY_CURRENT_USER 中注册的。如果它在当前用户中,那么提升的用户由于他们在 vista+ 中实现 COM 的方式而看不到它。 【参考方案1】:我相信您遇到的问题是设计使然,并且 Windows 安全改进的目的是帮助避免潜在的安全风险。
【讨论】:
【参考方案2】:如果 Microsoft 可以阻止您提升权限,那么它并不真正希望您提升权限。如果 Windows 甚至是一个相当安全的系统,那么以特权用户身份执行任意功能绝不应该是一件容易的事。您可以尝试使用令牌模拟不同的用户并以这种方式获得更好的访问权限,但即便如此,这也将是一个延伸。如果我没记错的话,用户模拟甚至不能保证您将获得完全访问权限。在这种情况下,最好的解决方案就是使用超级用户帐户并正确请求正确的权限。
【讨论】:
以上是关于在 Windows 7 上创建高程 COM 对象失败的主要内容,如果未能解决你的问题,请参考以下文章
无法在 Windows 7 x64 上使用 VB 脚本中的 CreateObject