# This file is part of Metasm, the Ruby assembly manipulation suite # Copyright (C) 2006-2009 Yoann GUILLOT # # Licence is LGPL, see LICENCE in the top-level directory # metasm dasm plugin: allow patching the file from the dasm interface # use P to assemble a new instruction at the current address # backup the executable file def backup_program_file f = @program.filename if File.exist?(f) and not File.exist?(f + '.bak') File.open(f + '.bak', 'wb') { |wfd| File.open(f, 'rb') { |rfd| while buf = rfd.read(1<<16) wfd.write buf end } } end end # create a backup and reopen the backend VirtualFile RW def reopen_rw(addr=nil, edata=nil) if not edata sections.each { |k, v| reopen_rw(k, v) } return true end return if not File.writable?(@program.filename) backup_program_file if not edata.data.kind_of? VirtualFile # section too small, loaded as real String # force reopen as VFile (allow hexediting in gui) return if not off = addr_to_fileoff(addr) len = edata.data.length edata.data = VirtualFile.read(@program.filename, 'rb+').dup(off, len) else edata.data.fd.reopen @program.filename, 'rb+' end end raise "cant find original file" if not @program.filename or not File.exist? @program.filename reopen_rw def patch_instrs(addr, asmsrc) sc = Metasm::Shellcode.new(cpu, addr) # pfx needed for autorequire sc.assemble(asmsrc, cpu) sc.encoded.fixup! prog_binding # allow references to dasm labels in the shellcode raw = sc.encode_string if s = get_section_at(addr) and s[0].data.kind_of? VirtualFile s[0][s[0].ptr, raw.length] = raw elsif o = addr_to_fileoff(addr) # section too small, not loaded as a VirtFile backup_program_file File.open(@program.filename, 'rb+') { |fd| fd.pos = o fd.write raw } s[0][s[0].ptr, raw.length] = raw if s else return end b = split_block(addr) # clear what we had in the rewritten space raw.length.times { |rawoff| next if not di = di_at(addr+rawoff) di.block.list.each { |ldi| @decoded.delete ldi.address } } disassemble_fast(addr) if b if b and @decoded[addr] nb = @decoded[addr].block nb.from_normal = b.from_normal nb.from_subfuncret = b.from_subfuncret nb.from_indirect = b.from_indirect end true end if gui gui.keyboard_callback[?P] = lambda { |k| addr = gui.curaddr gui.inputbox('new instructions') { |src| src = src.gsub(/;\s+/, "\n") patch_instrs(addr, src) gui.gui_update } true } end