Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
def test_add_multiples_sections(self):
sample_file = get_sample('PE/PE32_x86_binary_Notepad++.zip')
sample_dir = os.path.join(self.tmp_dir, "Notepad++")
sample = os.path.join(sample_dir, "notepad++.exe")
output = os.path.join(sample_dir, "notepad++_sections.exe")
zip_ref = zipfile.ZipFile(sample_file, 'r')
zip_ref.extractall(self.tmp_dir)
zip_ref.close()
notepadpp = lief.parse(sample)
# Add 20 sections to the binary
for i in range(20):
section = lief.PE.Section(".section_{}".format(i))
section.content = [i & 0xFF for i in range(0x200)]
notepadpp.add_section(section)
builder = lief.PE.Builder(notepadpp)
builder.build()
builder.write(output)
st = os.stat(output)
os.chmod(output, st.st_mode | stat.S_IEXEC)
if sys.platform.startswith("win"):
subprocess_flags = 0x8000000 # win32con.CREATE_NO_WINDOW?
p = Popen(["START", output], shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, creationflags=subprocess_flags)
time.sleep(3)
q = Popen(["taskkill", "/im", "notepad++_sections.exe"], shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
binary32 = PE.Binary("pwn.exe", PE.PE_TYPE.PE32)
# Start with 0x100 bytes of \cc
section_text = PE.Section(".text")
section_text.content = tobytes(x86.Int3().get_code() * 0x100)
section_text.virtual_address = 0x1000
# Init data section
data_raw = ''
for obj in data.keys():
data[obj] = binary32.optional_header.imagebase + len(data_raw) + 0x2000
data_raw += obj
section_data = PE.Section(".data")
section_data.content = tobytes(data_raw)
section_data.virtual_address = 0x2000
section_text = binary32.add_section(section_text, PE.SECTION_TYPES.TEXT)
section_data = binary32.add_section(section_data, PE.SECTION_TYPES.DATA)
binary32.optional_header.addressof_entrypoint = section_text.virtual_address
for library in imports.keys():
lib = binary32.add_library(library)
for function in imports[library].keys():
lib.add_entry(function)
for library in imports.keys():
for function in imports[library].keys():
for k, v in funcs.items():
for f in v:
func_addr = pe_loader.predict_function_rva(k, f[0])
offset = code_rva if func_num == 1 else 0 # dirty hack to adjust function address
addr = struct.pack(pack_fmt, pe_loader.optional_header.imagebase + data_rva - offset + func_addr)
# TO DO, number of bytes should be adjusted automatically
for i in range(4):
code_cnt[code_cnt.index(f[1])] = addr[i]
# set .text section fields
text_sect = lief.PE.Section(".text")
text_sect.virtual_address = code_rva
text_sect.content = code_cnt
text_sect = pe_loader.add_section(text_sect, lief.PE.SECTION_TYPES.TEXT)
# set .data section fields
data_sect = lief.PE.Section(".data")
data_sect.virtual_address = data_rva
data_sect.content = list(map(ord, data_cnt))
data_sect = pe_loader.add_section(data_sect, lief.PE.SECTION_TYPES.DATA)
pe_loader.optional_header.addressof_entrypoint = text_sect.virtual_address
builder = lief.PE.Builder(pe_loader)
builder.build_imports(True)
builder.build()
builder.write(out_file_name)
print("{0} was successfully created!".format(out_file_name))
# always find the .text section at offset 0x1000.
for idx, r in enumerate(self.regions):
if r.addr == addr + 0x1000:
break
else:
return False
pe = lief.PE.Binary(
"sample.bin",
lief.PE.PE_TYPE.PE32_PLUS if is64bit else lief.PE.PE_TYPE.PE32
)
while idx < len(self.regions)-1:
r, r2 = self.regions[idx:idx+2]
s = lief.PE.Section(".sec%d" % len(pe.sections))
s.virtual_address = r.addr - addr
s.content = bytearray(self.readv(r.addr, r.size))
s.characteristics = (
lief.PE.SECTION_CHARACTERISTICS.MEM_READ |
lief.PE.SECTION_CHARACTERISTICS.MEM_WRITE |
lief.PE.SECTION_CHARACTERISTICS.MEM_EXECUTE
)
s = pe.add_section(s, lief.PE.SECTION_TYPES.TEXT)
# It seems we're not interested in the next memory page.
if r.addr + r.size != r2.addr:
break
idx += 1
builder = lief.PE.Builder(pe)
0x6a, 0x00, # push 0x00 uType
0x68, 0x00, 0x20, 0x40, 0x00, # push VA(title)
0x68, 0x10, 0x20, 0x40, 0x00, # push VA(message)
0x6a, 0x00, # push 0 hWnd
0xFF, 0x15, 0x54, 0x30, 0x40, 0x00, # call MessageBoxA
0x6A, 0x00, # push 0 uExitCode
0xFF, 0x15, 0x4C, 0x30, 0x40, 0x00 # call ExitProcess
]
binary32 = PE.Binary("pe_from_scratch", PE.PE_TYPE.PE32)
section_text = PE.Section(".text")
section_text.content = code
section_text.virtual_address = 0x1000
section_data = PE.Section(".data")
section_data.content = data
section_data.virtual_address = 0x2000
section_text = binary32.add_section(section_text, PE.SECTION_TYPES.TEXT)
section_data = binary32.add_section(section_data, PE.SECTION_TYPES.DATA)
print(section_text)
print(section_data)
binary32.optional_header.addressof_entrypoint = section_text.virtual_address
kernel32 = binary32.add_library("kernel32.dll")
kernel32.add_entry("ExitProcess")
user32 = binary32.add_library("user32.dll")
user32.add_entry("MessageBoxA")
else:
# code_rva and data_rva from DEFAULT section
pass
# Add function addresses
for k, v in funcs.items():
for f in v:
func_addr = pe_loader.predict_function_rva(k, f[0])
offset = code_rva if func_num == 1 else 0 # dirty hack to adjust function address
addr = struct.pack(pack_fmt, pe_loader.optional_header.imagebase + data_rva - offset + func_addr)
# TO DO, number of bytes should be adjusted automatically
for i in range(4):
code_cnt[code_cnt.index(f[1])] = addr[i]
# set .text section fields
text_sect = lief.PE.Section(".text")
text_sect.virtual_address = code_rva
text_sect.content = code_cnt
text_sect = pe_loader.add_section(text_sect, lief.PE.SECTION_TYPES.TEXT)
# set .data section fields
data_sect = lief.PE.Section(".data")
data_sect.virtual_address = data_rva
data_sect.content = list(map(ord, data_cnt))
data_sect = pe_loader.add_section(data_sect, lief.PE.SECTION_TYPES.DATA)
pe_loader.optional_header.addressof_entrypoint = text_sect.virtual_address
builder = lief.PE.Builder(pe_loader)
builder.build_imports(True)
builder.build()
builder.write(out_file_name)
def create_new_entry(self, seed=None):
# create a new section with jump to old entry point, and change entry point
# DRAFT: this may have a few technical issues with it (not accounting for relocations), but is a proof of concept for functionality
random.seed(seed)
binary = lief.PE.parse(self.bytez)
# get entry point
entry_point = binary.optional_header.addressof_entrypoint
# get name of section
entryname = binary.section_from_rva(entry_point).name
# create a new section
new_section = lief.PE.Section(entryname + "".join(chr(random.randrange(
ord('.'), ord('z'))) for _ in range(3))) # e.g., ".text" + 3 random characters
# push [old_entry_point]; ret
new_section.content = [
0x68] + list(struct.pack("