在没有管理员权限的情况下扫描COM dll注册表

时间:2017-06-05 23:49:32

标签: wix registry regsvr32 heat

我试图创建一个扫描COM dll并创建必要注册表项的reg文件的程序,而不必调用regsvr32而不必拥有管理权限。

为此,我使用RegOverridePredefKey重新映射HKEY_CURRENT_USER子项中的Windows注册表配置单元。

https://msdn.microsoft.com/pt-br/library/windows/desktop/ms724901(v=vs.85).aspx

重新映射正在运行。我知道,因为我可以,例如,调用一个Windows api函数在HKEY_LOCAL_MACHINE下创建一个虚假的注册表项,它实际上出现在我的HKEY_CURRENT_USER子项下。无需管理员权限。

这是重新映射的代码:

if (reg::remapRegistry(HKEY_CLASSES_ROOT, HKEY_CURRENT_USER, basekey + "hkcr"))
    {
        if (reg::remapRegistry(HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER, basekey + "hklm"))
        {
            if (reg::remapRegistry(HKEY_USERS, HKEY_CURRENT_USER, basekey + "hku"))
            {
                if (reg::remapRegistry(HKEY_CURRENT_USER, HKEY_CURRENT_USER, basekey + "hkcu"))
                {
                    reg::createKey(HKEY_LOCAL_MACHINE, "Software\\Classes");
                    reg::createKey(HKEY_CURRENT_USER, "Software\\Classes");
                    ret = scan(args);
                    reg::cancelRemapedRegistry(HKEY_CURRENT_USER);
                }
                reg::cancelRemapedRegistry(HKEY_USERS);
            }
            reg::cancelRemapedRegistry(HKEY_LOCAL_MACHINE);
        }
        reg::cancelRemapedRegistry(HKEY_CLASSES_ROOT);
    }

我的扫描功能的args参数只是一个带有我的dll路径的结构。 reg :: 函数只是围绕windows api的包装。

这是我的扫描功能:

int scan(const Args &args)
{
typedef HRESULT (__stdcall *pDllRegisterServer) (void);
try
{
    HMODULE hDLL = LoadLibrary(args.dll.c_str());
    if (hDLL == NULL)
    {
        LOGERROR("Cannot load dll");
        return 1;
    }

    pDllRegisterServer DllRegisterServer = (pDllRegisterServer) GetProcAddress(hDLL, "DllRegisterServer");
    if (DllRegisterServer == NULL)
    {
        LOGERROR("Cannot find function DllRegisterServer in dll");
        FreeLibrary(hDLL);
        return 2;
    }

    HRESULT res = DllRegisterServer();
    DWORD err = GetLastError();

    switch (res)
    {
    case S_OK:
        LOGINFO("successfully called DllRegisterServer");
        return 0;
    case SELFREG_E_TYPELIB:
        LOGERROR("DllRegisterServer error SELFREG_E_TYPELIB");
        return 3;
    case SELFREG_E_CLASS:
        LOGERROR("DllRegisterServer error SELFREG_E_CLASS");
        return 4;
    case E_OUTOFMEMORY:
        LOGERROR("DllRegisterServer error E_OUTOFMEMORY");
        return 5;
    case E_UNEXPECTED:
        LOGERROR("DllRegisterServer error E_UNEXPECTED");
        return 6;
    default:
        LOGERROR("DllRegisterServer really unexpected error");
    }

    return 7;
}
catch (...)
{
    LOGERROR("unknown error loading dll or function");
    return -1;
}
}

DllRegisterServer返回S_OK,但只创建了一半的注册表项。我在HKEY_CURRENT_USER \ tempkey \ hkcr下重新映射的HKEY_CLASSES_ROOT包含所有预期的键。但HKEY_CURRENT_USER \ tempkey \ hklm(重映射HKEY_LOCAL_MACHINE)仅包含空键" Software \ Classes"我自己创造的。它缺少" TypeLib"和"界面" DllRegisterServer应该创建的密钥。

这不是重映射或权限问题,因为我可以创建空的" Software \ Classes"在没有管理员权限的HKEY_LOCAL_MACHINE下。

奇怪的是,使用SELFREG_E_TYPELIB在另一台机器上测试DllRegisterServer失败。

我也尝试调用LoadTypeLib()和RegisterTypeLib(),我得到了错误代码" 0x8002801c访问OLE注册表时出错。"

如果我以管理员身份重新启动visual studio并再次运行该程序,我将获得所有预期的注册表项,包括HKLM下的注册表项。

关于为什么会失败以及如何让这件事发挥作用的任何想法?

我知道可以在不成为管理员的情况下获取所有注册表项,因为wix的收获工具heat.exe成功完成了。我已经检查了他们的源代码,我相信我已经做了他们正在做的所有事情。而且我不希望将wix工具集作为构建环境的一项要求,这也是因为我需要将其文件格式解析为* .reg文件。

1 个答案:

答案 0 :(得分:0)

我找到了解决方案:在进行重映射之前,我们必须调用函数OaEnablePerUserTLibRegistration()。

https://msdn.microsoft.com/en-us/library/windows/desktop/cc713570(v=vs.85).aspx

调用该函数后,来自COM dll的回调DllRegisterServer()将尝试在HKCR而不是HKLM下创建类型库键。