【问题标题】:Force a program to run without admin privileges?强制程序在没有管理员权限的情况下运行?
【发布时间】:2012-03-19 12:41:01
【问题描述】:

我有一个 .net 程序,在我尝试运行它时默认请求管理员权限。我不知道它在我的特定情况下需要这些特权的任何原因,所以我只是怀疑它背后的惰性编程(强制管理员访问以防万一它最终可能需要它)。

有什么办法可以强制它不尝试提升并使用常规访问权限运行?例如。通过修改嵌入式清单或通过一些编程方式?

以管理员身份运行常规应用程序非常简单,但反过来可能吗?

更新: 我只能访问已编译的 .exe,而不能访问源代码或原始清单文件。我通过 Kenny Kerr 的 ManifestView 查看了 .exe 的嵌入式清单,它肯定需要管理员权限,因为它包括以下内容:

<requestedPrivileges>
    <requestedExecutionLevel level="requireAdministrator" />
</requestedPrivileges>

有什么方法可以更改已编译的 .exe 程序集的清单吗?例如。有什么工具可以做到这一点或有关如何以编程方式做到这一点的信息?

【问题讨论】:

  • @Jason:这似乎与这里要求的相反。
  • @cHao:但它可以深入了解可能需要对清单进行的更改,以扭转它。
  • 问题是我无法访问应用程序的源代码或清单,只能访问已编译的 .exe 程序集。那么如何修改已编译的 .exe 的清单呢?
  • 作为第一步,使用 Regmon 和 Filemon 来确定程序想要访问哪些注册表项和文件/文件夹

标签: .net manifest privileges administrator


【解决方案1】:

我尝试创建一个小型 C# 应用程序来修改嵌入式清单,这样它就不会请求管理员权限。这是我最终想出的解决方案,进行了一系列 Win32 调用以提取清单并替换现有清单。已经够长了,所以我省略了我实际修改清单的部分(只是一些基本的 XML 操作)。

这里有两个静态方法:LoadManifestResource,它加载一个可执行文件的嵌入式清单的字符串表示和SaveManifestResource,它保存一个清单资源的字符串表示在指定的可执行文件中,覆盖旧的。

这是一个快速而肮脏的解决方案,对我来说效果很好,但很可能并非在所有情况下都有效。

public static class Library
{
    [DllImport("kernel32.dll")]
    static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hReservedNull, LoadLibraryFlags dwFlags);

    [DllImport("kernel32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool FreeLibrary(IntPtr hModule);

    [DllImport("kernel32.dll")]
    static extern IntPtr FindResource(IntPtr hModule, int lpName, int lpType);

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern IntPtr LoadResource(IntPtr hModule, IntPtr hResInfo);

    [DllImport("kernel32.dll")]
    static extern IntPtr LockResource(IntPtr hResData);

    [DllImport("Kernel32.dll", EntryPoint = "SizeofResource", SetLastError = true)]
    private static extern uint SizeofResource(IntPtr hModule, IntPtr hResource);

    [System.Flags]
    enum LoadLibraryFlags : uint
    {
        DONT_RESOLVE_DLL_REFERENCES = 0x00000001,
        LOAD_IGNORE_CODE_AUTHZ_LEVEL = 0x00000010,
        LOAD_LIBRARY_AS_DATAFILE = 0x00000002,
        LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE = 0x00000040,
        LOAD_LIBRARY_AS_IMAGE_RESOURCE = 0x00000020,
        LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008
    }

    public static unsafe string LoadManifestResource(string fileName)
    {
        // load library to retrieve manifest from
        var libraryHandle = LoadLibraryEx(fileName, IntPtr.Zero, LoadLibraryFlags.LOAD_LIBRARY_AS_DATAFILE);
        if (libraryHandle.ToInt32() == 0)
        {
            throw new Win32Exception(Marshal.GetLastWin32Error(), "couldn't load library");
        }
        try
        {
            // find manifest
            var resource = FindResource(libraryHandle, 1, 24);
            if (resource.ToInt32() == 0)
            {
                throw new Win32Exception(Marshal.GetLastWin32Error(), "couldn't find manifest resource");
            }

            // load manifest
            var loadedManifest = LoadResource(libraryHandle, resource);
            if (loadedManifest.ToInt32() == 0)
            {
                throw new Win32Exception(Marshal.GetLastWin32Error(), "couldn't load manifest resource");
            }

            // lock manifest
            var lockedManifest = LockResource(loadedManifest);
            if (lockedManifest.ToInt32() == 0)
            {
                throw new Win32Exception(Marshal.GetLastWin32Error(), "couldn't lock manifest resource");
            }

            // calculate size of manifest, copy to byte array and convert to string
            int manifestSize = (int)SizeofResource(libraryHandle, resource);

            byte[] data = new byte[manifestSize];
            Marshal.Copy(lockedManifest, data, 0, manifestSize);
            var manifest = Encoding.UTF8.GetString(data);

            return manifest;
        }
        finally
        {
            FreeLibrary(libraryHandle);
        }
    }

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern IntPtr BeginUpdateResource(string pFileName,
       [MarshalAs(UnmanagedType.Bool)]bool bDeleteExistingResources);

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool UpdateResource(IntPtr hUpdate, string lpType, string lpName, ushort wLanguage, IntPtr lpData, uint cbData);

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool UpdateResource(IntPtr hUpdate, int lpType, int lpName, ushort wLanguage, IntPtr lpData, uint cbData);

    [DllImport("kernel32.dll", SetLastError = true)]
    static extern bool EndUpdateResource(IntPtr hUpdate, bool fDiscard);

    public static unsafe void SaveManifestResource(string file, string manifest)
    {
        var hUpdate = BeginUpdateResource(file, false);

        byte[] bytes = Encoding.UTF8.GetBytes(manifest);
        IntPtr ptr = Marshal.AllocHGlobal(bytes.Length);
        try
        {
            Marshal.Copy(bytes, 0, ptr, bytes.Length);

            if (!UpdateResource(hUpdate, 24, 1, 0, ptr, (uint)bytes.Length))
            {
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }

            if (!EndUpdateResource(hUpdate, false))
            {
                throw new Win32Exception(Marshal.GetLastWin32Error());
            }
        }
        finally
        {
            Marshal.FreeHGlobal(ptr);
        }
    }
}

【讨论】:

    【解决方案2】:

    如果您的应用程序中有任何需要管理员权限的代码,我相信您将无法运行该应用程序。

    某些代码/api 被标记为需要某些权限。所以我不相信你能通过那个:/

    我会看到的唯一解决方案是将有罪的代码分离到一个您可能加载或不加载的模块中。这样一来,您就必须运行这两个版本,同时保持“相同”的产品。

    【讨论】:

    • 对不起,应该在问题的前面澄清:我无权访问源代码,因此根本无法真正将该代码移动到单独的模块中。好吧,也许通过反编译和重新编译,但如果可以避免的话,我宁愿不去那里。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-03-28
    • 1970-01-01
    • 2012-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-21
    • 2014-03-19
    相关资源
    最近更新 更多