PInvoke

  • Platform Invoke aka P/Invoke allows you to access functions in unmanaged libraries from your managed C# code
  • functions are declared with extern and DllImport keywords

OpenProcess Api:

[DllImport("kernel32.dll", SetLastError = true)]
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
internal static extern IntPtr OpenProcess(
    PROCESS_ACCESS_RIGHTS dwDesiredAccess, 
    bool bInheritHandle,
    int dwProcessId);
  • settings SetLastError to true allows you to get the error code of the last API that was called
  • DefaultDllImport protects against DLL Hijacking by forcing the application to look in System32

One of the downsides of P/Invoke is that we dont have access to Windows headers like Windows.h so we need to add the headers to our code:

[Flags]
internal enum PROCESS_ACCESS_RIGHTS : uint
{
    PROCESS_TERMINATE = 0x00000001,
    PROCESS_CREATE_THREAD = 0x00000002,
    PROCESS_SET_SESSIONID = 0x00000004,
    PROCESS_VM_OPERATION = 0x00000008,
    PROCESS_VM_READ = 0x00000010,
    PROCESS_VM_WRITE = 0x00000020,
    PROCESS_DUP_HANDLE = 0x00000040,
    PROCESS_CREATE_PROCESS = 0x00000080,
    PROCESS_SET_QUOTA = 0x00000100,
    PROCESS_SET_INFORMATION = 0x00000200,
    PROCESS_QUERY_INFORMATION = 0x00000400,
    PROCESS_SUSPEND_RESUME = 0x00000800,
    PROCESS_QUERY_LIMITED_INFORMATION = 0x00001000,
    PROCESS_SET_LIMITED_INFORMATION = 0x00002000,
    PROCESS_ALL_ACCESS = 0x001FFFFF,
    PROCESS_DELETE = 0x00010000,
    PROCESS_READ_CONTROL = 0x00020000,
    PROCESS_WRITE_DAC = 0x00040000,
    PROCESS_WRITE_OWNER = 0x00080000,
    PROCESS_SYNCHRONIZE = 0x00100000,
    PROCESS_STANDARD_RIGHTS_REQUIRED = 0x000F0000
}

Marshalling

  • Windows APIs have two variants: A(ANSI) and W(Unicode, aka 'wide')
    • LoadLibraryA , LoadLibraryW, CreateProcessA , CreateProcessW
    • The main difference between A and W are the types of encoding used for strings
  • PInvoke needs a way to marashal managed C# strings as C# only has a single string type
  • This is done by adding the CharSet attribute
// ANSI
[DllImport("KERNEL32.dll", SetLastError = true, CharSet = CharSet.Ansi)]
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
internal static extern IntPtr LoadLibraryA(string libFileName);

// Unicode
[DllImport("KERNEL32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
internal static extern IntPtr LoadLibraryW(string libFileName);