WinAPI OpenProcess 拒绝访问

Access is denied from WinAPI OpenProcess

所以我决定将一个 DLL 注入记事本进程以用于教育目的。

IntPtr hProcess = OpenProcess(ProcessAccessFlags.VirtualMemoryWrite | ProcessAccessFlags.VirtualMemoryWrite | ProcessAccessFlags.VirtualMemoryOperation, false, process.Id);           
_log.Info({0}, new Win32Exception(Marshal.GetLastWin32Error()).Message);

这似乎因 "Access is denied" 而失败。奇怪的是 hProcess 不是 IntPtr.Zero 而且它看起来像句柄。所以我不是100%确定它是否真的失败了。

我试过的东西如下。

整个 class 在下方(不再在粘贴箱上)。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
using System.Threading.Tasks;

namespace Blade.Injector
{
class Injector
{
    private readonly NLog.Logger _log = NLog.LogManager.GetCurrentClassLogger();

    [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
    static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, uint dwSize, AllocationType flAllocationType, MemoryProtection flProtect);

    [Flags]
    public enum AllocationType
    {
        Commit = 0x1000,
        Reserve = 0x2000,
        Decommit = 0x4000,
        Release = 0x8000,
        Reset = 0x80000,
        Physical = 0x400000,
        TopDown = 0x100000,
        WriteWatch = 0x200000,
        LargePages = 0x20000000
    }

    [Flags]
    public enum MemoryProtection
    {
        Execute = 0x10,
        ExecuteRead = 0x20,
        ExecuteReadWrite = 0x40,
        ExecuteWriteCopy = 0x80,
        NoAccess = 0x01,
        ReadOnly = 0x02,
        ReadWrite = 0x04,
        WriteCopy = 0x08,
        GuardModifierflag = 0x100,
        NoCacheModifierflag = 0x200,
        WriteCombineModifierflag = 0x400
    }

    [DllImport("kernel32.dll", SetLastError = true)]
    [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
    [SuppressUnmanagedCodeSecurity]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool CloseHandle(IntPtr hObject);

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern IntPtr OpenProcess(ProcessAccessFlags processAccess, bool bInheritHandle, int processId);

    [Flags]
    public enum ProcessAccessFlags : uint
    {
        All = 0x001F0FFF,
        Terminate = 0x00000001,
        CreateThread = 0x00000002,
        VirtualMemoryOperation = 0x00000008,
        VirtualMemoryRead = 0x00000010,
        VirtualMemoryWrite = 0x00000020,
        DuplicateHandle = 0x00000040,
        CreateProcess = 0x000000080,
        SetQuota = 0x00000100,
        SetInformation = 0x00000200,
        QueryInformation = 0x00000400,
        QueryLimitedInformation = 0x00001000,
        Synchronize = 0x00100000
    }        

    private const string DllFile = @"C:\Poison.dll";

    public void List()
    {
        var processes = Process.GetProcesses().Where(p => !string.IsNullOrEmpty(p.MainWindowTitle)).ToList();

        foreach (var process in processes)
        {
            _log.Info("{0} -> {1}", process.MainWindowTitle, process.Id);
        }
    }

    public bool Inject(int pid)
    {                                       
        Process.EnterDebugMode();

        Process process = Process.GetProcessById(pid);                        

        foreach (ProcessModule module in process.Modules)
        {
            if (module.FileName.Equals(DllFile))
            {
                _log.Info("{0} already inside process.", module.FileName);
                return false;
            }
        }

        _log.Info("Opening process. Last Win32 error is now '{0}'.", new Win32Exception(Marshal.GetLastWin32Error()).Message);
        IntPtr hProcess = OpenProcess(ProcessAccessFlags.VirtualMemoryWrite | ProcessAccessFlags.VirtualMemoryWrite | ProcessAccessFlags.VirtualMemoryOperation, false, process.Id);           
        _log.Info("Opening process resulted in message '{0}'.", new Win32Exception(Marshal.GetLastWin32Error()).Message);

        _log.Info("Allocating memory for dll file.");            
        IntPtr allocAddress = VirtualAllocEx(hProcess, IntPtr.Zero, (uint)Encoding.Unicode.GetByteCount(DllFile.ToCharArray()), AllocationType.Commit, MemoryProtection.ReadWrite);
        _log.Info("Allocating memory for '{0}' resulted in '{1}'.", DllFile, new Win32Exception(Marshal.GetLastWin32Error()).Message);

        CloseHandle(hProcess);

        foreach (ProcessModule module in process.Modules)
        {
            if (module.FileName.Equals(DllFile))
            {
                _log.Info("Success! {0} inside process.", module.FileName);
            }
        }

        return true;
    }

}
}

第一个找到答案的地方

How do I know whether (any function) worked?

将出现在该功能的文档页面中。对于 OpenProcess(),文档页面是 https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-openprocess

除其他外,该页面包含以下语句:

If the function succeeds, the return value is an open handle to the specified process.

If the function fails, the return value is NULL. To get extended error information, call GetLastError.

将基本逻辑应用于第二个陈述,我们得出结论

  • 如果 return 值不为 NULL,函数没有失败。

因此,将 return 值与 IntPtr.Zero 进行比较是可以的,实际上是最好的做法。

另请注意“要获取扩展错误信息,请调用 GetLastError”。从属于“如果功能失败”。如果函数成功,则没有详细的错误信息,因此您没有理由调用 GetLastError,如果调用它也无法解释其结果。