[P#调用C / C ++ DLL调用出口(-1)时C#主机应用程序关闭;

问题描述 投票:2回答:1

我有一个C#应用程序,它在VisualC中PInvokes一个已编译的DLL,当执行exit(-1)方法时,它将关闭整个过程;在DLL中。

我没有本机DLL的源代码,并且我知道DLL是该进程的一部分,并且exit(n);关闭宿主进程。

我有类似的建议:

  • 修改本机DLL。
  • 使用AppDomain(太多依赖项,并且应用程序过于广泛)。
  • 重新实现本机DLL(过于广泛)。

问题是:

  • 是否有可能在C#托管应用程序中捕获exit(n);并防止关闭整个应用程序?
  • 或在调用本机DLL的方法中使用某些属性?
c# c pinvoke exit
1个回答
0
投票

没有干净的方法可以使进程退出。一种解决方案是修补DLL二进制文件以删除该调用,然后将其替换为nop或其他内容。那是我的建议。

否则,只是为了好玩,这里有一些示例代码,它们使用Windows API上的钩子来执行此操作。我不建议使用它,因为它可能会有一些副作用(您的电话)。它使用MinHook二进制文件进行底层的低级hack / hook工作。

这里有一些调用exit的C dll代码:

extern "C" void _stdcall CallExit()
{
  printf("Let's try an exit...\n");
  exit(1234);
  printf("I survived this!\n");
}

这里是C#调用者

class Program
{
    static void Main()
    {
        using (var hook = new MinHook())
        {
            // hook ExitProcess which is the Windows API underneath exit.
            var fake1 = hook.CreateHook<ExitProcess>("kernel32.dll", nameof(ExitProcess), Fake);
            hook.EnableHook(fake1);

            // on recent Windows, we must also hook CorExitProcess
            // because exit (defined in ucrtbased) always try it before calling ExitProcess
            // and if you only hook ExitProcess, the process hangs for some reason
            var fake2 = hook.CreateHook<CorExitProcess>("mscoree.dll", nameof(CorExitProcess), Fake);
            hook.EnableHook(fake2);

            CallExit();
            Console.ReadLine();

            hook.DisableHook(fake1);
            hook.DisableHook(fake2);
        }
    }

    static void Fake(int exitCode)
    {
        Console.WriteLine("Hmmm... nope, I want to live forever. Exit code: " + exitCode);
    }

    private delegate void ExitProcess(int uExitCode);
    private delegate void CorExitProcess(int uExitCode);

    [DllImport("MyDll.dll")]
    private static extern void CallExit();
}

[运行时(在Windows 10上测试),它显示此信息(由于某种原因,CorExitProcess被调用了两次)]

Let's try an exit...
Hmmm... nope, I want to live forever. Exit code: 1234
Hmmm... nope, I want to live forever. Exit code: 1234
Hmmm... nope, I want to live forever. Exit code: 1234
I survived this!

这是一些在C#中使用MinHook的C#互操作实用程序代码:

public sealed class MinHook : IDisposable
{
    private static readonly Lazy<IntPtr> _module = new Lazy<IntPtr>(HookNativeProcs, true);
    public static string NativeDllPath { get; private set; }

    private IntPtr _handle;

    public MinHook()
    {
        var hook = _module.Value;
        CheckError(_MH_Initialize());
    }

    public IntPtr CreateHook<T>(string libraryName, string procName, T detour)
    {
        if (libraryName == null)
            throw new ArgumentNullException(nameof(libraryName));

        if (procName == null)
            throw new ArgumentNullException(nameof(procName));

        var module = LoadLibrary(libraryName);
        if (module == IntPtr.Zero)
            throw new Win32Exception(Marshal.GetLastWin32Error());

        var address = GetProcAddress(module, procName);
        if (address == IntPtr.Zero)
            throw new Win32Exception(Marshal.GetLastWin32Error());

        var ptr = Marshal.GetFunctionPointerForDelegate<T>(detour);
        CheckError(_MH_CreateHook(address, ptr, out IntPtr original));
        return address;
    }

    public void EnableHook(IntPtr hook)
    {
        if (hook == IntPtr.Zero)
            throw new ArgumentException(null, nameof(hook));

        CheckError(_MH_EnableHook(hook));
    }

    public void DisableHook(IntPtr hook)
    {
        if (hook == IntPtr.Zero)
            throw new ArgumentException(null, nameof(hook));

        CheckError(_MH_DisableHook(hook));
    }

    public void RemoveHook(IntPtr hook)
    {
        if (hook == IntPtr.Zero)
            throw new ArgumentException(null, nameof(hook));

        CheckError(_MH_RemoveHook(hook));
    }

    public void Dispose()
    {
        var handle = Interlocked.Exchange(ref _handle, IntPtr.Zero);
        if (handle != IntPtr.Zero)
        {
            CheckError(_MH_Uninitialize());
        }
    }

    private Exception CheckError(MH_STATUS status, bool throwOnError = true)
    {
        if (status == MH_STATUS.MH_OK)
            return null;

        var ex = new Exception(status.ToString());
        if (throwOnError)
            throw ex;

        return ex;
    }

    // with this code, we support AnyCpu targets
    private static IEnumerable<string> PossibleNativePaths
    {
        get
        {
            string bd = AppDomain.CurrentDomain.BaseDirectory;
            string rsp = AppDomain.CurrentDomain.RelativeSearchPath;
            string bitness = IntPtr.Size == 8 ? "64" : "86";
            bool searchRsp = rsp != null && bd != rsp;

            // look for an env variable
            string env = GetEnvironmentVariable("MINHOOK_X" + bitness + "_DLL");
            if (env != null)
            {
                // full path?
                if (Path.IsPathRooted(env))
                {
                    yield return env;
                }
                else
                {
                    // relative path?
                    yield return Path.Combine(bd, env);
                    if (searchRsp)
                        yield return Path.Combine(rsp, env);
                }
            }

            // look in appdomain path
            string name = "minhook.x" + bitness + ".dll";
            yield return Path.Combine(bd, name);
            if (searchRsp)
                yield return Path.Combine(rsp, name);

            name = "minhook.dll";
            yield return Path.Combine(bd, name); // last resort, hoping the bitness's right, we do not recommend it
            if (searchRsp)
                yield return Path.Combine(rsp, name);
        }
    }

    private static string GetEnvironmentVariable(string name)
    {
        try
        {
            string value = Environment.GetEnvironmentVariable(name, EnvironmentVariableTarget.Process);
            if (value != null)
                return value;

            value = Environment.GetEnvironmentVariable(name, EnvironmentVariableTarget.User);
            if (value != null)
                return value;

            return Environment.GetEnvironmentVariable(name, EnvironmentVariableTarget.Machine);
        }
        catch
        {
            // probably an access denied, continue
            return null;
        }
    }

    private static IntPtr HookNativeProcs()
    {
        var path = PossibleNativePaths.FirstOrDefault(p => File.Exists(p));
        if (path == null)
            throw new Exception("Cannot determine native MinHook dll path. Process is running " + (IntPtr.Size == 8 ? "64" : "32") + "-bit.");

        NativeDllPath = path;
        var module = LoadLibrary(path);
        if (module == IntPtr.Zero)
            throw new Exception("Cannot load native MinHook dll from path '" + path + "'. Process is running " + (IntPtr.Size == 8 ? "64" : "32") + "-bit.", new Win32Exception(Marshal.GetLastWin32Error()));

        _MH_Initialize = LoadProc<MH_Initialize>(module);
        _MH_Uninitialize = LoadProc<MH_Uninitialize>(module);
        _MH_CreateHook = LoadProc<MH_CreateHook>(module);
        _MH_RemoveHook = LoadProc<MH_RemoveHook>(module);
        _MH_EnableHook = LoadProc<MH_EnableHook>(module);
        _MH_DisableHook = LoadProc<MH_DisableHook>(module);
        return module;
    }

    private static T LoadProc<T>(IntPtr module, string name = null)
    {
        if (name == null)
        {
            name = typeof(T).Name;
        }

        var address = GetProcAddress(module, name);
        if (address == IntPtr.Zero)
            throw new Exception("Cannot load library function '" + name + "' from '" + NativeDllPath + "'. Please make sure MinHook is the latest one.", new Win32Exception(Marshal.GetLastWin32Error()));

        return (T)(object)Marshal.GetDelegateForFunctionPointer(address, typeof(T));
    }

    [DllImport("kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
    private static extern IntPtr LoadLibrary(string lpFileName);

    [DllImport("kernel32", SetLastError = true, CharSet = CharSet.Ansi)]
    private static extern IntPtr GetProcAddress(IntPtr hModule, [MarshalAs(UnmanagedType.LPStr)] string lpProcName);

    [UnmanagedFunctionPointer(CallingConvention.Winapi)]
    private delegate MH_STATUS MH_Initialize();
    private static MH_Initialize _MH_Initialize;

    [UnmanagedFunctionPointer(CallingConvention.Winapi)]
    private delegate MH_STATUS MH_Uninitialize();
    private static MH_Uninitialize _MH_Uninitialize;

    [UnmanagedFunctionPointer(CallingConvention.Winapi)]
    private delegate MH_STATUS MH_CreateHook(IntPtr pTarget, IntPtr pDetour, out IntPtr ppOriginal);
    private static MH_CreateHook _MH_CreateHook;

    [UnmanagedFunctionPointer(CallingConvention.Winapi)]
    private delegate MH_STATUS MH_RemoveHook(IntPtr pTarget);
    private static MH_RemoveHook _MH_RemoveHook;

    [UnmanagedFunctionPointer(CallingConvention.Winapi)]
    private delegate MH_STATUS MH_EnableHook(IntPtr pTarget);
    private static MH_EnableHook _MH_EnableHook;

    [UnmanagedFunctionPointer(CallingConvention.Winapi)]
    private delegate MH_STATUS MH_DisableHook(IntPtr pTarget);
    private static MH_DisableHook _MH_DisableHook;
}

public enum MH_STATUS
{
    // Unknown error. Should not be returned.
    MH_UNKNOWN = -1,

    // Successful.
    MH_OK = 0,

    // MinHook is already initialized.
    MH_ERROR_ALREADY_INITIALIZED,

    // MinHook is not initialized yet, or already uninitialized.
    MH_ERROR_NOT_INITIALIZED,

    // The hook for the specified target function is already created.
    MH_ERROR_ALREADY_CREATED,

    // The hook for the specified target function is not created yet.
    MH_ERROR_NOT_CREATED,

    // The hook for the specified target function is already enabled.
    MH_ERROR_ENABLED,

    // The hook for the specified target function is not enabled yet, or already
    // disabled.
    MH_ERROR_DISABLED,

    // The specified pointer is invalid. It points the address of non-allocated
    // and/or non-executable region.
    MH_ERROR_NOT_EXECUTABLE,

    // The specified target function cannot be hooked.
    MH_ERROR_UNSUPPORTED_FUNCTION,

    // Failed to allocate memory.
    MH_ERROR_MEMORY_ALLOC,

    // Failed to change the memory protection.
    MH_ERROR_MEMORY_PROTECT,

    // The specified module is not loaded.
    MH_ERROR_MODULE_NOT_FOUND,

    // The specified function is not found.
    MH_ERROR_FUNCTION_NOT_FOUND
}
© www.soinside.com 2019 - 2024. All rights reserved.