60 lines
1.9 KiB
Ruby
60 lines
1.9 KiB
Ruby
|
# 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
|
||
|
|
||
|
|
||
|
#
|
||
|
# this sample script fixes a bug in some GTK libs (eg debian) where at some point
|
||
|
# when you close a window an invalid memory dereference is done, which crashes the
|
||
|
# whole metasm GUI
|
||
|
#
|
||
|
# bug backtrace:
|
||
|
# 0f79e6173h libgobject-2.0.so.0!g_type_check_instance+23
|
||
|
# 0f79e3e38h libgobject-2.0.so.0!g_signal_handlers_disconnect_matched+28
|
||
|
# 0f70004c3h libgtk-x11-2.0.so.0!gtk_accel_label_set_accel_closure+c3
|
||
|
# 0f70006d3h libgtk-x11-2.0.so.0!gtk_accel_label_set_accel_widget+b3
|
||
|
# ...
|
||
|
#
|
||
|
|
||
|
require 'metasm'
|
||
|
|
||
|
include Metasm
|
||
|
|
||
|
if not pr = OS.current.find_process(ARGV.first)
|
||
|
abort "cant find target"
|
||
|
end
|
||
|
|
||
|
dbg = pr.debugger
|
||
|
|
||
|
dbg.continue
|
||
|
puts "monitoring.." if $VERBOSE
|
||
|
dbg.wait_target
|
||
|
|
||
|
while dbg.state == :stopped
|
||
|
puts "target #{dbg.state} #{dbg.info}" if $VERBOSE
|
||
|
if di = dbg.di_at(dbg.pc) and di.to_s =~ /\[(...)\]/ and reg = $1.downcase.to_sym and regval = dbg.get_reg_value(reg) and regval > 0 and regval < 4096
|
||
|
bt = dbg.stacktrace(2)
|
||
|
calladdr = bt[1][0]-5
|
||
|
dbg.disassembler.disassemble_fast(calladdr)
|
||
|
call = dbg.di_at(calladdr)
|
||
|
dbg.disassembler.disassemble_fast(call.instruction.args.first.reduce) rescue nil
|
||
|
if di = dbg.disassembler.decoded[dbg.pc] and from = dbg.disassembler.decoded[di.block.from_normal.first] and from.block.list[-2].to_s =~ /test #{reg}, #{reg}/
|
||
|
puts "fix almost null deref #{di} (#{reg}=#{regval})" if $VERBOSE
|
||
|
dbg.set_reg_value(reg, 0)
|
||
|
dbg.set_reg_value(:eip, from.block.list[-2].address)
|
||
|
else
|
||
|
dbg.kill # dont infinite loop ( TODO just dont handle the exception)
|
||
|
end
|
||
|
elsif dbg.info =~ /SEGV/
|
||
|
puts "unhandled segfault #{di}..." if $VERBOSE
|
||
|
# yep, this actually works
|
||
|
dbg.set_reg_value(:eip, di.next_addr)
|
||
|
end
|
||
|
dbg.continue
|
||
|
puts "target running" if $VERBOSE
|
||
|
dbg.wait_target
|
||
|
end
|
||
|
|
||
|
puts "target terminated" if $VERBOSE
|