So I decided I want to inject a DLL into a notepad process for educational purposes.
IntPtr hProcess = OpenProcess(ProcessAccessFlags.VirtualMemoryWrite | ProcessAccessFlags.VirtualMemoryWrite | ProcessAccessFlags.VirtualMemoryOperation, false, process.Id);
_log.Info({0}, new Win32Exception(Marshal.GetLastWin32Error()).Message);
This seems to fail with "Access is denied". The strange thing is that hProcess
is not IntPtr.Zero
and it looks like a handle. Therefore I 'm not 100% sure whether it really failed or not.
Things I tried are listed as follows.
Process.EnterDebugMode();
0x001F0FFF
The whole class is down below (not on paste bin anymore).
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;
}
}
}
new Win32Exception(Marshal.GetLastWin32Error()).Message)
has something to do with my last call? Maybe something else failed?OpenProcess()
method worked in C#? Is checking hProcess
for not being IntPtr.Zero
OK?The first place to find an answer to
How do I know whether (any function) worked?
is going to be in the documentation page for that function. For OpenProcess()
, the documentation page is https://learn.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-openprocess
Among other things, that page contains the following statements:
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.
Applying basic logic to the second statement, we conclude that
Therefore, comparing the return value to IntPtr.Zero
is OK and actually the best thing to do.
Also note that "To get extended error information, call GetLastError." is subordinate to "If the function fails". If the function succeeded, there's no detailed error information, so you have no reason to call GetLastError
and no way to interpret its result if you do call it.