Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Hijack lives again! Improve 1.9 support.

We now look for a safe place in the stack to inject the payload and what until the stack unwinds to that point.
  • Loading branch information...
commit 1a9c5e866aed7adf169c123057bc6b8885dd2ea0 1 parent 882481f
@ileitch authored
Showing with 28 additions and 18 deletions.
  1. +28 −18 lib/hijack/gdb.rb
View
46 lib/hijack/gdb.rb
@@ -25,7 +25,7 @@ def quit
protected
def previous_frame_inner_to_this_frame?
- backtrace.first =~ /previous frame inner to this frame/i
+ backtrace.last =~ /previous frame inner to this frame/i
end
def attach_outside_gc
@@ -53,30 +53,40 @@ def attach_outside_gc
exit 1
end
- # TODO: Check for "Unable to attach to process-id 44528: No child processes (10)"
- ensure_main_thread_not_blocked_by_join
+ break_on_safe_stack_unwind
end
-
+
+ def break_on_safe_stack_unwind
+ safe = false
+ backtrace.each do |line|
+ # vm_call_method == 1.9, rb_call == 1.8
+ if line =~ /(vm_call_method|rb_call)/
+ frame = line.match(/^\#([\d]+)/)[1]
+ safe = true
+ exec("frame #{frame}")
+ exec("break")
+ exec("continue")
+ exec("delete 1")
+ break
+ end
+ end
+
+ if !safe
+ puts "=> WARNING: Did not detect a safe frame on which to set a breakpoint, hijack may fail."
+ end
+ end
+
def during_gc?
!!(call("(int)rb_during_gc()").first =~ /\$[\d]+ = 1/)
end
-
+
def detach
exec("detach")
end
-
+
def attach
exec("attach #{@pid}")
end
-
- def ensure_main_thread_not_blocked_by_join
- if backtrace.any? { |line| line =~ /rb_thread_join/ }
- puts "\n=> Unable to hijack #{@pid} because the main thread is blocked waiting for another thread to join."
- puts "=> Check that you are using the most recent version of hijack, a newer version may have solved this shortcoming."
- detach
- exit 1
- end
- end
def ensure_attached_to_ruby_process
unless backtrace.any? {|line| line =~ /(rb|ruby)_/}
@@ -87,7 +97,7 @@ def ensure_attached_to_ruby_process
end
def backtrace
- @backtrace ||= exec('bt').reverse
+ @backtrace ||= exec('bt')
end
def continue
@@ -99,7 +109,7 @@ def call(cmd)
end
def exec(str)
- puts("(gdb) #{str}") if @verbose
+ puts str if @verbose
@gdb.puts(str)
wait
end
@@ -111,6 +121,7 @@ def wait
next if result.empty?
c = @gdb.read(1)
break if c.nil?
+ STDOUT.write(c) if @verbose
line << c
break if line == "(gdb) " || line == " >"
if line[-1] == ?\n
@@ -118,7 +129,6 @@ def wait
line = ""
end
end
- puts lines.map { |l| "> #{l}" } if @verbose
lines
end
end
Please sign in to comment.
Something went wrong with that request. Please try again.