fix: make DLL + func + EOP work

This commit is contained in:
Dobin
2024-04-14 11:47:47 +01:00
parent 368b14934d
commit b4671c8690
6 changed files with 141 additions and 59 deletions
+34 -3
View File
@@ -1,12 +1,43 @@
<!DOCTYPE html>
<html>
<head>
{% include 'header.html' %}
</head>
<body>
{% include 'navigation.html' %}
<h1> IAT </h1> <div class="indent">
<h2> Exports </h2>
<table class="table">
<tr>
<th>Name</th>
<th>Address</th>
<th>Size (Approx)</th>
</tr>
{% for export in exports %}
<tr>
<td>{{export["name"]}}</td>
<td>{{export["addr"] | hexint}}</td>
<td>{{export["size"]}}</td>
</tr>
{% endfor %}
</table>
<h2> IAT </h2>
{% for dll in iat %} {% for dll in iat %}
<h2>DLL: {{dll}}</h2> <h3>DLL: {{dll}}</h3>
<ul> <ul>
{% for entry in iat[dll] %} {% for entry in iat[dll] %}
<li> {{ entry.dll_name }}: {{ entry.func_name }} ({{ entry.iat_vaddr }})</li> <li> {{ entry.dll_name }}: {{ entry.func_name }} ({{ entry.iat_vaddr | hexint }})</li>
{% endfor%} {% endfor%}
</ul> </ul>
{% endfor %} {% endfor %}
</div>
</body>
</html>
+9 -1
View File
@@ -20,7 +20,11 @@ def index():
def exe_view(exe_name): def exe_view(exe_name):
path = "{}/{}".format(PATH_EXES, exe_name) path = "{}/{}".format(PATH_EXES, exe_name)
superpe = SuperPe(path) 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") @views.route("/exes")
@@ -30,3 +34,7 @@ def exes_view():
exes.append(file) exes.append(file)
return render_template('exes.html', exes=exes) return render_template('exes.html', exes=exes)
@views.app_template_filter('hexint')
def hex_filter(s):
return hex(s)
-3
View File
@@ -57,9 +57,6 @@ class PeBackdoor:
if exp.name.decode() == name: if exp.name.decode() == name:
#print(hex(exp.address), exp.name.decode()) #print(hex(exp.address), exp.name.decode())
addr = exp.address addr = exp.address
logger.info(f'Using DLL Export "{name}" at RVA 0x{addr:X} . Attempting to hijack it...')
return addr return addr
+46
View File
@@ -224,6 +224,33 @@ class SuperPe():
return res 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 ## Helpers
def get_physical_address(self, virtual_address) -> int: def get_physical_address(self, virtual_address) -> int:
@@ -235,12 +262,31 @@ class SuperPe():
# Calculate the difference between the VA and the section's virtual address # Calculate the difference between the VA and the section's virtual address
virtual_offset = virtual_address - section.VirtualAddress virtual_offset = virtual_address - section.VirtualAddress
# Add the difference to the section's pointer to raw data # 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 return virtual_offset
#physical_address = section.PointerToRawData + virtual_offset #physical_address = section.PointerToRawData + virtual_offset
#return physical_address #return physical_address
return None 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): def write_pe_to_file(self, outfile: str):
self.pe.write(outfile) self.pe.write(outfile)
+11 -11
View File
@@ -44,19 +44,21 @@ def inject_exe(
superpe = SuperPe(exe_in) superpe = SuperPe(exe_in)
pe_backdoorer = PeBackdoor(superpe, main_shc, carrier_invoke_style) pe_backdoorer = PeBackdoor(superpe, main_shc, carrier_invoke_style)
# Find a nice location for the shellcode
shellcode_offset: int = 0 shellcode_offset: int = 0
if superpe.is_dll(): # DLL if superpe.is_dll() and settings.dllfunc != "" and carrier_invoke_style == CarrierInvokeStyle.ChangeEntryPoint:
shellcode_offset = 0 # Special case. put it at the beginning of the exported DLL function
else: # EXE logger.info("--[ Overwrite DLL function {} with shellcode".format(settings.dllfunc))
pass rva = pe_backdoorer.getExportEntryPoint(settings.dllfunc)
if True: 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() sect = superpe.get_code_section()
if sect == None: if sect == None:
raise Exception('Could not find code section in input PE file!') raise Exception('Could not find code section in input PE file!')
sect_name = sect.Name.decode().rstrip('\x00') sect_name = sect.Name.decode().rstrip('\x00')
sect_size = sect.Misc_VirtualSize # Better than: SizeOfRawData sect_size = sect.Misc_VirtualSize # Better than: SizeOfRawData
if sect_size < l: if sect_size < l:
raise Exception("Shellcode too large: {} > {}".format( raise Exception("Shellcode too large: {} > {}".format(
l, sect_size l, sect_size
@@ -79,13 +81,11 @@ def inject_exe(
logger.info("---( Rewire: DLL function: {} ".format(settings.dllfunc)) logger.info("---( Rewire: DLL function: {} ".format(settings.dllfunc))
if carrier_invoke_style == CarrierInvokeStyle.ChangeEntryPoint: if carrier_invoke_style == CarrierInvokeStyle.ChangeEntryPoint:
#raise Exception("--( Inject DLL: Change Entry Point unsupported when set ".format( # Handled above, without arriving here
# settings.dllfunc)) raise Exception("We should not land here")
pass
elif carrier_invoke_style == CarrierInvokeStyle.BackdoorCallInstr: elif carrier_invoke_style == CarrierInvokeStyle.BackdoorCallInstr:
addr = pe_backdoorer.getExportEntryPoint(settings.dllfunc) addr = pe_backdoorer.getExportEntryPoint(settings.dllfunc)
logger.info("--( Inject DLL: Patch {} (0x{:X})".format( logger.info("--( Inject DLL: Patch {} (0x{:X})".format(
settings.dllfunc, addr)) settings.dllfunc, addr))
pe_backdoorer.backdoor_function(addr, shellcode_rva) pe_backdoorer.backdoor_function(addr, shellcode_rva)
+9 -9
View File
@@ -28,7 +28,7 @@ def test_exe():
prepare_project("unittest", settings) prepare_project("unittest", settings)
# 7z, peb-walk, change-entrypoint # 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.source_style = FunctionInvokeStyle.peb_walk
settings.carrier_invoke_style = CarrierInvokeStyle.ChangeEntryPoint settings.carrier_invoke_style = CarrierInvokeStyle.ChangeEntryPoint
settings.inject_exe_in = PATH_EXES + "7z.exe" settings.inject_exe_in = PATH_EXES + "7z.exe"
@@ -37,7 +37,7 @@ def test_exe():
print("Error") print("Error")
# 7z, peb-walk, hijack # 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.source_style = FunctionInvokeStyle.peb_walk
settings.carrier_invoke_style = CarrierInvokeStyle.BackdoorCallInstr settings.carrier_invoke_style = CarrierInvokeStyle.BackdoorCallInstr
settings.inject_exe_in = PATH_EXES + "7z.exe" settings.inject_exe_in = PATH_EXES + "7z.exe"
@@ -46,7 +46,7 @@ def test_exe():
print("Error") print("Error")
# procexp, iat-reuse, change-entrypoint # 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.source_style = FunctionInvokeStyle.iat_reuse
settings.carrier_invoke_style = CarrierInvokeStyle.ChangeEntryPoint settings.carrier_invoke_style = CarrierInvokeStyle.ChangeEntryPoint
settings.inject_exe_in = PATH_EXES + "procexp64.exe" settings.inject_exe_in = PATH_EXES + "procexp64.exe"
@@ -55,7 +55,7 @@ def test_exe():
print("Error") print("Error")
# procexp, iat-reuse, backdoor # 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.source_style = FunctionInvokeStyle.iat_reuse
settings.carrier_invoke_style = CarrierInvokeStyle.BackdoorCallInstr settings.carrier_invoke_style = CarrierInvokeStyle.BackdoorCallInstr
settings.inject_exe_in = PATH_EXES + "procexp64.exe" settings.inject_exe_in = PATH_EXES + "procexp64.exe"
@@ -73,7 +73,7 @@ def test_dll():
settings.prep_web("unittest") settings.prep_web("unittest")
prepare_project("unittest", settings) 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.source_style = FunctionInvokeStyle.peb_walk
settings.carrier_invoke_style = CarrierInvokeStyle.ChangeEntryPoint settings.carrier_invoke_style = CarrierInvokeStyle.ChangeEntryPoint
settings.inject_exe_in = PATH_EXES + "libbz2-1.dll" settings.inject_exe_in = PATH_EXES + "libbz2-1.dll"
@@ -81,7 +81,7 @@ def test_dll():
if start(settings) != 0: if start(settings) != 0:
print("Error") 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.source_style = FunctionInvokeStyle.peb_walk
settings.carrier_invoke_style = CarrierInvokeStyle.BackdoorCallInstr settings.carrier_invoke_style = CarrierInvokeStyle.BackdoorCallInstr
settings.inject_exe_in = PATH_EXES + "libbz2-1.dll" settings.inject_exe_in = PATH_EXES + "libbz2-1.dll"
@@ -89,8 +89,8 @@ def test_dll():
if start(settings) != 0: if start(settings) != 0:
print("Error") print("Error")
print("Test: libbz2-1.dll, peb-walk, change-entrypoint, func=BZ2_bzdopen") print("Test DLL 3/6: libbz2-1.dll, peb-walk, change-entrypoint, func=BZ2_bzDecompress")
settings.dllfunc = "BZ2_bzdopen" settings.dllfunc = "BZ2_bzDecompress"
settings.source_style = FunctionInvokeStyle.peb_walk settings.source_style = FunctionInvokeStyle.peb_walk
settings.carrier_invoke_style = CarrierInvokeStyle.ChangeEntryPoint settings.carrier_invoke_style = CarrierInvokeStyle.ChangeEntryPoint
settings.inject_exe_in = PATH_EXES + "libbz2-1.dll" settings.inject_exe_in = PATH_EXES + "libbz2-1.dll"
@@ -98,7 +98,7 @@ def test_dll():
if start(settings) != 0: if start(settings) != 0:
print("Error") 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.dllfunc = "BZ2_bzdopen"
settings.source_style = FunctionInvokeStyle.peb_walk settings.source_style = FunctionInvokeStyle.peb_walk
settings.carrier_invoke_style = CarrierInvokeStyle.BackdoorCallInstr settings.carrier_invoke_style = CarrierInvokeStyle.BackdoorCallInstr