强制程序在没有管理员权限的情况下运行

时间:2012-03-19 12:41:01

标签: .net manifest privileges administrator

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

有什么方法可以强迫它不要试图提升和运行常规访问权限?例如。通过修改嵌入式清单或通过一些编程方式?

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

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

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

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

2 个答案:

答案 0 :(得分: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);
        }
    }
}

答案 1 :(得分:0)

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

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

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