Skip to content

Instantly share code, notes, and snippets.

@grittyninja
Created October 30, 2016 12:16
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save grittyninja/19f360fe875c1853ddbead1cc46bf511 to your computer and use it in GitHub Desktop.
Save grittyninja/19f360fe875c1853ddbead1cc46bf511 to your computer and use it in GitHub Desktop.
'''
Author : Cyber Security IPB
Date : October 28, 2016
Dependencies : pwntools
Script ini bisa mengganti pemanggilan fungsi dari suatu binary ELF
(32 / 64 bit). Misalnya mengubah dari "call printf" menjadi call "puts"
untuk menambal celah format string exploit. Atau mengubah pemanggilan
fungsi yang ada di program menjadi fungsi lain.
Script ini hanya mengubah pemanggilan fungsi, BUKAN parameternya. Jadi
pastikan kalau mengubah pemanggilan fungsi parameternya sama. Mengubah
pemanggilan fungsi menjadi fungsi lain yang beda parameternya will
lead to an undefined behavior.
Contoh disassembly sebelum patch:
.text:0804851F mov dword ptr [esp], offset s ; "Testing"
.text:08048526 call _puts
.text:0804852B lea eax, [esp+18h]
.text:0804852F mov [esp], eax ; format
.text:08048532 call _printf
.text:08048537 mov eax, 0
Setelah patch (`python patch.py executable 0x08048532 puts`):
.text:0804851F mov dword ptr [esp], offset s ; "Testing"
.text:08048526 call _puts
.text:0804852B lea eax, [esp+18h]
.text:0804852F mov [esp], eax ; s
.text:08048532 call _puts
.text:08048537 mov eax, 0
'''
from pwn import *
import ctypes
import struct
import sys
def get_sym_by_addr(elf, addr):
sym = None
for p in elf.symbols:
if elf.symbols[p] == addr:
sym = p
if p in elf.plt and elf.plt[p] == addr:
sym += '@plt'
break
return sym
def main():
infile = sys.argv[1]
elf = pwnlib.elf.ELF(infile)
call_addr = int(sys.argv[2].replace('0x', ''), 16)
call_instr = elf.read(call_addr, 5)
if call_instr[0] != '\xe8':
raise ValueError("%s: Not a call instruction!" % hex(call_addr))
call_offset = elf.read(call_addr+1, 4)
call_offset_int32 = ctypes.c_int(u32(call_offset)).value
called_addr = call_addr + call_offset_int32 + 5
print "The instruction at %s (%s) is calling %s (%s)." % \
(hex(call_addr), call_instr.encode('hex').upper() , hex(called_addr), str(get_sym_by_addr(elf, called_addr)))
replacement_func = sys.argv[3]
if replacement_func.startswith("0x"):
replacement_addr = int(replacement_func, 16)
print "Now I will change it to call %s (%s)." % (hex(replacement_addr), str(get_sym_by_addr(elf, replacement_addr)))
else:
if replacement_func not in elf.symbols:
raise KeyError("Function %s is not available in binary!" % replacement_func)
replacement_addr = elf.symbols[replacement_func]
print "Now I will change it to %s (@%s)." % (replacement_func, hex(replacement_addr))
patch_offset = p32((replacement_addr - call_addr - 5) & 0xffffffff)
patch_instr = '\xe8' + patch_offset
print "Change opcode in address %s from %s to %s" % (hex(call_addr), call_instr.encode('hex').upper(), patch_instr.encode('hex').upper())
outfile = infile + '.patched'
print "Writing the patch to file..."
elf.write(call_addr, patch_instr)
elf.save(outfile)
print "Patched \"%s\" ==> \"%s\"" % (infile, outfile)
if __name__ == '__main__':
if len(sys.argv) != 4:
print "Usage:\n%s ELF ADDR NEWFUNCNAME/ADDR" % sys.argv[0]
print "\nExample: change instruction of 'fstr01' executable at 0x08048532 from 'call _printf' to 'call _puts'\n%s fstr01 0x08048532 puts" % sys.argv[0]
sys.exit(1)
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment