> For the complete documentation index, see [llms.txt](https://106-sam.gitbook.io/ejptv2-notes/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://106-sam.gitbook.io/ejptv2-notes/crto/malware-essentials/.net-and-p-invoke.md).

# .Net & P/Invoke

### P/Invoke

\
The injection examples in the previous lesson are all written in C but it's often useful to write injection code in other languages. The aim of this lesson is to introduce [Platform Invoke](https://learn.microsoft.com/en-us/dotnet/standard/native-interop/pinvoke) (aka P/Invoke) and how it can be used to access the Win32 APis from C#.

In short, P/Invoke allows you to access functions in unmanaged libraries from your managed C# code. These functions are declared with the `extern` keyword and `DLLimport` attribute.  For example, the [OpenProcess](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-openprocess) API could be declared like this:&#x20;

```
[DllImport("kernel32.dll", SetLastError = true)]
[DefaultDllImportSearchPaths(DllImportSearchPath.System32)]
internal static extern IntPtr OpenProcess(
    PROCESS_ACCESS_RIGHTS dwDesiredAccess,
    bool bInheritHandle,
    int dwProcessId
);
```

Setting `SetLastError` to true allows you to recover the error code of the last API that was called (akin to [GetLastError](https://learn.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-getlasterror)) using the .NET Marshal class, `Marshal.GetLastWin32Error()` .

Using the `DefaultDllImportSearchPaths` attribute protects against DLL hijacking by forcing the application to look in System32, rather than other locations such as its own working directory.<br>

One of the pain points of P/Invoke is that we don't have access to the Windows headers, like `Windows.h` and therefore lack the type definitions for structs and enums such as `PROCESS_ACCESS_RIGHT` . We therefore have to manually add these 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&#x20;

Many windows APIs have two variants: A (ANSI) and W (Unicode, aka 'wide'). Examples include LoadLibraryA & LoadLibraryW and CreateProcessA & CreateProcessW. The difference between these is the type of encoding used for strings. Windows represents Unicode as UTF-16 and ANSI as UTF-8. C# doesn't really expose this concept, it just has a `single` string type. The P/Invoke engine therefore needs a hint as to how to marshal managed C# strings into the correct encoding for the API being called. This is easily 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);
```

### Resources

The most well-known resource (albeit quite temperamental for going offline) for pre-made P/Invoke code is [pinvoke.net](https://pinvoke.net). In most cases you'll be able to find signature definitions for APIs (like [OpenProcess](https://pinvoke.net/default.aspx/kernel32.OpenProcess)) so that you don't have to translate them manually from the API documentation.
