This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
''' | |
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