original notes from obsidian

WinAPI Lists

Contains most used WinAPI - links, functionality, parameters, returns, interesting remarks, and personal notes


LPVOID VirtualAlloc(
 LPVOID lpAddress,
 SIZE_T dwSize,
 DWORD flAllocationType,
 DWORD flProtect

LPVOID = Memory Pointer = LongPtr

  1. lpAddress = Memory allocation address

    • 0 = API choose the location automatically

  2. dwSize = Size of the allocation

  3. flAllocationType = Memory allocation type

    • Usually MEM_COMMIT | MEM_RESERVE = 0x3000

  4. flProtect = Memory protection flags

    • Usually 0x40 = RWX

    • But you know, better to alloc --> VMProtect --> Write Mem --> VMProtect --> run (but more on that later)

OpenProcess - Retrieve a handle to a remote process - based on PID

HANDLE OpenProcess(
 DWORD dwDesiredAccess,
 BOOL bInheritHandle,
 DWORD dwProcessId

dwDesiredAccess = Access right to obtain in target process. usually PROCESS_ALL_ACCESS (0x001F0FF)

bInheritHandle = True/False on whether the handle can be inherited to child process or not. Usually False, because we just don't care.

dwProcessId = Target Process's PID

VirtualAllocEx - Allocate memory in a remote process

LPVOID VirtualAllocEx(
 HANDLE hProcess,
 LPVOID lpAddress,
 SIZE_T dwSize,
 DWORD flAllocationType,
 DWORD flProtect

hProcess = Target process's handle lpAddress = Start address. Usually 0, so VirtualAllocEx can automatically choose the starting address for us

  • (Driploader changes this to trick EDR solutions, but that's another story)

dwSize = Length to allocate. Usually shellcode's length flAllocationType = Type of allocation. Usually MEM_COMMIT | MEM_RESERVE = 0x3000 flProtect = Memory protection type. Usually 0x20 (Read) or 0x40 (RWX)

VirtualProtect - Change memory protection

BOOL VirtualProtect(
 LPVOID lpAddress,
 SIZE_T dwSize,
 DWORD flNewProtect,
 PDWORD lpflOldProtect

lpAddress = IntPtr - Page address - Start pointer of the memory address dwSize = UInt32 - Size of area wish to modify. 1 ~ 0xFFF is same. Usually 3. flNewProtect = UInt32 - Memory protection constant. RWX = 0x40, RX = 0x20 lpflOldProtect = [ref] UInt32 = Current memory protection

WriteProcessMemory - Write to a region of a memory in a remote process

BOOL WriteProcessMemory(
 HANDLE hProcess,
 LPVOID lpBaseAddress,
 LPCVOID lpBuffer,
 SIZE_T nSize,
 SIZE_T *lpNumberOfBytesWritten

hProcess = Handle to target process lpBaseAddress = Starting address to write memory. Usually alloc returned from VirtualAllocEx lpBuffer = Address of source byte array to be copied nSize = Length/Size of the lpBuffer. Usually shellcode length lpNumberOfBytesWritten = Pointer to a location in memory to output how much data was copied

  • Usually used with out keyword from C#

  • Pass by reference, not value - because it's a pointer that will hold data copied.


HANDLE CreateRemoteThread(
 HANDLE hProcess,
 SIZE_T dwStackSize,
 LPVOID lpParameter,
 DWORD dwCreationFlags,
 LPDWORD lpThreadId

hProcess = Handle to the target process lpThreadAttributes = Thread attribute. Usually 0, unless PPID spoofing... but that's another story. dwStackSize = Usually 0 lpStartAddress = Start address of the thread. Usually alloc from VirtualAllocEx. This is where the shellcode starts. lpParameter = Pointer to variables if parameter. Since shellcodes usually don't have parameters, usually 0. dwCreationFlags = Usually IntPtr.Zero lpThreadId = Usually 0.

ReadProcessMemory = Read memory from remote process

BOOL ReadProcessMemory(
 HANDLE hProcess,
 LPCVOID lpBaseAddress,
 LPVOID lpBuffer,
 SIZE_T nSize,
 SIZE_T *lpNumberOfBytesRead

hProcess = IntPtr / Handle to remote process lpBaseAddress = IntPtr / Base address to start reading from lpBuffer = byte[] / Destination buffer to copy the content from nSize = int / Number of bytes to be read lpNumberOfBytesRead = out / Number of bytes that were ACTUALLY read


byte[] addrBuf = new byte[IntPtr.Size];
IntPtr nRead = IntPtr.Zero;
ReadProcessMemory(hProcess, ptrToImageBaseAddress, addrBuf, addrBuf.Length, out nRead);

CreateProcessW - Create a Process

BOOL CreateProcessW(
 LPCWSTR lpApplicationName,
 LPWSTR lpCommandLine,
 BOOL bInheritHandles,
 DWORD dwCreationFlags,
 LPVOID lpEnvironment,
 LPCWSTR lpCurrentDirectory,

lpApplicationName = Name of the application - Usually null lpCommandLine = Full commandline to be executed - Usually full path of executable lpProcessAttribute & lpThreadAttribute = Specify security descriptor - Usually null and false dwCreationFlag = Creation Flag. CREATE_SUSPENDED = 0x4 lpEnvironMent, lpCurrentDirectory = Straight forward, but usually null for default. lpStartupInfo = STARTUPINFO Structure that includes values related with how new process should be configured. Included in PInvoke.net's cheatsheet lpProcessInformation = PROCESS_INFORMATION structure with handles, threads, pid, tid. Provided in PInvoke.net.



bool result = CreateProcess(null, @"C:\windows\system32\svchost.exe", IntPtr.Zero, IntPtr.Zero, false, 0x4, IntPtr.Zero, null, ref si, out pi); 

ZwQueryInformationProcess - Return PEB information inside a PI (Process Information) variable

NTSTATUS WINAPI ZwQueryInformationProcess(
 _In_ HANDLE ProcessHandle,
 _In_ PROCESSINFOCLASS ProcessInformationClass,
 _Out_ PVOID ProcessInformation,
 _In_ ULONG ProcessInformationLength,
 _Out_opt_ PULONG ReturnLength

NTSTATUS (return type) = hex value from the kernel showing the status of the call.

ProcessHandle = IntPtr / Handle to process from PROCESS_INFORMATION structure ProcessInformationClass = Usually 0 ProcessInformation = ref PROCESS_BASIC_INFORMATION() / structure PorcesInformationLength = uint / Size of input structure (6 IntPtr) ReturnLength = ref uint variable that hold the size of fetched data


uint tmp = 0; 
IntPtr hProcess = pi.hProcess;
// PROCESS_BASIC_INFORMATION has 6 IntPtr, thus (IntPtr.Size*6)
ZwQueryInformationProcess(hProcess, 0, ref bi, (uint)(IntPtr.Size*6), ref tmp);

// Now "bi" has the PEB address. 
IntPtr ptrToImageBase = (IntPtr)((Int64)bi.PebAddress + 0x10); 

GetCurrentProcess - Return current process's handle

static extern IntPtr GetCurrentProcess();

CreateNamedPipe - Creates a named pipe

HANDLE CreateNamedPipeA(
 LPCSTR lpName,
 DWORD dwOpenMode,
 DWORD dwPipeMode,
 DWORD nMaxInstances,
 DWORD nOutBufferSize,
 DWORD nInBufferSize,
 DWORD nDefaultTimeOut,

lpName = string = Name of the pipe (ex. \\.\pipe\pipe_name) dwOpenMode = uint = Mode of the pipe = Mostly 3 = PIPE_ACCESES_DUPLEX dwPipeMode = uint = Mode of the pipe operation = PIPE_TYPE_BYTE|PIPE_WAIT, Usually 0. nMaxInstances = uint = Maximum number of instances of the pipe. Anything 1~255. nOutBufferSize = uint = Number of bytes to use for input/output buffer. Usually 0x1000 bytes. nInBufferSize = uint = Number of bytes to use for input/output buffer. Usually 0x1000 bytes. nDefaultTimeout = uint = Default timeout. Usually 0. lpSecurityAttributes = IntPtr = SID of clients that can interact with the pipe. Usually NULL/IntPtr.Zero, because we want any clients to connect to our dummy pipe server.

ConnectNamedPipe - Connect to a named pipe

BOOL ConnectNamedPipe(
 HANDLE hNamedPipe,
 LPOVERLAPPED lpOverlapped

hNamedPipe = IntPTr =Handle to the named pipe to connect to lpOverlapped = IntPtr = Pointer to a structure for advnaced cases. Usually IntPtr.Zero/Null for us.

ImpersonateNamedPipeClient - Impersonate the access token of the pipe client that connected to our pipe server. Stolen token will be assigned to the current thread of the process.

BOOL ImpersonateNamedPipeClient(
 HANDLE hNamedPipe

hNamedPipe = IntPtr = Handle to the named pipe (server).

OpenThreadToken - Open thread's token. Used for confirmation that impersonation was successful.

BOOL OpenThreadToken(
 HANDLE ThreadHandle,
 DWORD DesiredAccess,
 BOOL OpenAsSelf,
 PHANDLE TokenHandle

ThreadHandle = IntPtr = Handle to the thread to check its token. In this case, we want to check our thread from our process. So just use GetCurrentThread. DesiredAccess = uint = Desired Access to the thread. Usually TOKEN_ALL_ACCESS = 0xF01FF OpenAsSelf = bool = Should API use security context of current process? Usually false/no, because we are using the impersonated token of the target process. TokenHandle = IntPtr hToken; out hToken = (Out) pointer that will be populated with a handle to the token that is opened.

GetTokenInformation - Return token information from the token handle. One of those "Call twice" weird API.

BOOL GetTokenInformation(
 HANDLE TokenHandle,
 LPVOID TokenInformation,
 DWORD TokenInformationLength,
 PDWORD ReturnLength

TokenHandle = IntPtr = Token Handle. Usually retrieved through OpenThreadToken TokenInformationClass = uint = Enum of token information. Usually 1, which is TokenUser (SID) value. TokenInformation = IntPtr = Pointer to output buffer that will be populated by the API. TokenInformationLength = int = Size of output buffer ReturnLength = out int = Output length.

So this winAPI need to be called twice. It's because we don't know required size of the buffer.


[DllImport("advapi32.dll", SetLastError = true)]
static extern bool GetTokenInformation(IntPtr TokenHandle, uint TokenInformationClass, IntPtr TokenInformation, int TokenInformationLength, out int ReturnLength);

int TokenInfLength = 0;

// Calling first time, because we don't know TokenInformationLength
GetTokenInformation(hToken, 1, IntPtr.Zero, TokenInfLength, out TokenInfLength);

// Calling second time, because we now KNOW TokenInformationLength. Allocate memory of TokenInformation with the length of TokenInformationLength, and call again.
IntPtr TokenInformation = Marshal.AllocHGlobal((IntPtr)TokenInfLength);
GetTokenInformation(hToken, 1, TokenInformation, TokenInfLength, out TokenInfLength);

ConvertSidToStringSid - Convert binary SID to string SID

BOOL ConvertSidToStringSidW(
 PSID Sid,
 LPWSTR *StringSid

Sid = IntPtr = Pointer to the SID. It's inside output buffer from GetTokenInformation. This needs to be extracted from a structure. StringSid = out IntPtr = Output string that will contain the SID string.


// Setting structure of SID. Used for SID extraction later on. 
public struct SID_AND_ATTRIBUTES
 public IntPtr Sid;
 public int Attributes;
public struct TOKEN_USER

[DllImport("advapi32", CharSet = CharSet.Auto, SetLastError = true)]
static extern bool ConvertSidToStringSid(IntPtr pSID, out IntPtr ptrSid);

// Extracting SID(TokenUser) from the TokenInformation structure 
TOKEN_USER TokenUser = (TOKEN_USER)Marshal.PtrToStructure(TokenInformation, typeof(TOKEN_USER));

// Pointer to contain output SID string 
IntPtr pstr = IntPtr.zero;
Boolean ok = ConvertSidToStringSid(TokenUser.User.Sid, out pstr);

// Converting pointer to actual string 
string sidstr = Marshal.PtrToStringAuto(pstr);
Console.WriteLine(@"[+] Sid: ", sidstr); 

Last updated