Files
program/src/binary_patch.py
2024-11-04 20:38:25 +08:00

154 lines
5.2 KiB
Python

#!/usr/bin/python3
import lief
from pwn import *
import os
import sys
global lief_ELF_ALLOC
lief_ELF_ALLOC = 2
global lief_ELF_EXCLUDE
lief_ELF_EXECINSTR = 4
def get_binary_file_CLASS(binary, output_info=True):
CLASS = CLASS = binary.header.identity_class
str_CLASS = ""
if CLASS == binary.header.CLASS.ELF32:
str_CLASS = "ELF32"
elif CLASS == binary.header.CLASS.ELF64:
str_CLASS = "ELF64"
else:
str_CLASS = "UNKNOWN"
if output_info:
print("[\033[1;34m*\033[0m] CLASS is %s" % (str_CLASS))
return (CLASS, str_CLASS)
def get_binary_file_machine_type(binary, output_info=True):
machine_type = binary.header.machine_type
str_machine_type = ""
arch = ""
if machine_type == lief._lief.ELF.ARCH.X86_64:
str_machine_type = "x86_64"
arch = "amd64"
else:
str_machine_type = "UNKNOWN"
arch = "UNKNOWN"
print('[\033[1;34m*\033[0m] machine type is %s ==> ARCH : %s' % (str_machine_type, arch))
return (str_machine_type, arch)
def load_binary_file_information(path):
lief_binary = lief.parse(path)
CLASS, str_CLASS = get_binary_file_CLASS(lief_binary)
str_machine_type, arch = get_binary_file_machine_type(lief_binary)
pwn_binary = ''
context.arch = arch
if "ELF" in str_CLASS:
context.os = "linux"
pwn_binary = ELF(path)
return (lief_binary, pwn_binary)
# flag : lief.ELF.SEGMENT_FLAGS.PF_R | lief.ELF.SEGMENT_FLAGS.PF_W | lief.ELF.SEGMENT_FLAGS.PF_X
def add_segment(lief_binary, content, types, flags, base=0x405000):
segment = lief.ELF.Segment()
segment.type = types
segment.FLAGS.from_value(flags)
segment.content = list(content)
segment.alignment = 8
segment.add(lief._lief.ELF.Segment.FLAGS.R | lief._lief.ELF.Segment.FLAGS.X)
segment = lief_binary.add(segment, base=base)
print(segment.FLAGS.value)
return segment
def patch_by_pltsec_jmp(elf_file, symbol, start_address_of_pltsec_jmp, target_function_address, target_function_len, save_path):
# caculate the offset
jmp_offset = target_function_address - (start_address_of_pltsec_jmp + 5)
shellcode = b'\xe9' + p32(jmp_offset & 0xffffffff)
elf_file.write(start_address_of_pltsec_jmp, shellcode)
jmp_offset = elf_file.got[symbol] - (target_function_address + target_function_len + 7)
shellcode = b'\xf2\xff\x25' + p32(jmp_offset & 0xffffffff)
elf_file.write(target_function_address + target_function_len, shellcode)
elf_file.save(save_path)
def patch_strcpy(lief_binary, nbytes, save_path, output=True):
print("[\033[1;34m*\033[0m] get the length of buffer is 0x%x(%d)" % (nbytes, nbytes))
patch_strcpy_code = f"""
mov rdx, {nbytes - 1};
mov byte ptr [rdx + rsi], 0;
"""
patch_code = asm(patch_strcpy_code)
if output:
print("the assmebly code :\n %s" % patch_strcpy_code)
print("the machine code :\n %s" % patch_code)
new_segment = add_segment(lief_binary, types = lief._lief.ELF.Segment.TYPE.LOAD, flags = 5, content=patch_code)
new_segment_address = new_segment.virtual_address
#lief_binary.patch_pltgot("strcpy", new_segment.virtual_address)
os.system("rm " + save_path)
lief_binary.write(save_path)
os.system("chmod +x " + save_path)
elf_patch = ELF(save_path)
patch_by_pltsec_jmp(elf_patch, 'strcpy', elf_patch.plt['strcpy'], new_segment_address, len(patch_code), save_path)
# to do
def patch_dprintf(lief_binary, save_path, output=True):
patch_dprintf_code = f"""
push rsi;
pop rdx;
mov rax, [rsp];
push 0x7325;
push rsp
pop rsi;
push rax;
"""
patch_code = asm(patch_dprintf_code)
if output:
print("the assmebly code :\n %s" % patch_dprintf_code)
print("the machine code :\n %s" % patch_code)
new_segment = add_segment(lief_binary, types = lief._lief.ELF.Segment.TYPE.LOAD, flags = 5, content=patch_code)
new_segment_address = new_segment.virtual_address
#lief_binary.patch_pltgot("dprintf", new_segment.virtual_address)
os.system("rm " + save_path)
lief_binary.write(save_path)
os.system("chmod +x " + save_path)
elf_patch = ELF(save_path)
patch_by_pltsec_jmp(elf_patch, 'dprintf', elf_patch.plt['dprintf'], new_segment_address, len(patch_code), save_path)
def patch_recv(lief_binary, nbytes, save_path, output=True):
patch_recv_code = f"""
mov rdx, {nbytes};
"""
patch_code = asm(patch_recv_code)
if output:
print("the assmebly code :\n %s" % patch_recv_code)
print("the machine code :\n %s" % patch_code)
new_segment = add_segment(lief_binary, types = lief._lief.ELF.Segment.TYPE.LOAD, flags = 5, content=patch_code)
new_segment_address = new_segment.virtual_address
os.system("rm " + save_path)
lief_binary.write(save_path)
os.system("chmod +x " + save_path)
elf_patch = ELF(save_path)
patch_by_pltsec_jmp(elf_patch, 'recv', elf_patch.plt['recv'], new_segment_address, len(patch_code), save_path)
if __name__ == '__main__':
argv = sys.argv
argc = len(sys.argv)
path = sys.argv[1]
save_path = path + "_patch"
lief_binary, pwn_binary = load_binary_file_information(path)
if sys.argv[2] == 'dprintf':
patch_dprintf(lief_binary, save_path)
elif sys.argv[2] == 'strcpy':
patch_strcpy(lief_binary, int(sys.argv[3]), save_path)
elif sys.argv[2] == 'recv':
patch_recv(lief_binary, int(sys.argv[3]), save_path)