ileitch-hijack 0.1.8 → 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +1 -1
- data/TODO +0 -3
- data/lib/hijack/console.rb +1 -6
- data/lib/hijack/gdb.rb +39 -11
- data/lib/hijack/payload.rb +7 -13
- data/tasks/gem.rake +1 -1
- metadata +2 -2
data/README.rdoc
CHANGED
@@ -14,7 +14,7 @@ Hijack uses DRb over a unix socket file, so you need to be on the same machine a
|
|
14
14
|
|
15
15
|
== Using ruby-debug
|
16
16
|
|
17
|
-
Hijack can be used
|
17
|
+
Hijack can be used to start ruby-debug in your target process, for example:
|
18
18
|
|
19
19
|
$ hijack 61378
|
20
20
|
=> Hijacked 61378 (/opt/local/bin/thin) (ruby 1.8.7 [i686-darwin9])
|
data/TODO
CHANGED
@@ -1,5 +1,2 @@
|
|
1
|
-
* Use thread local stdout & stderr capture.
|
2
|
-
* assigning a variable doesn't work
|
3
1
|
* Improve startup experience
|
4
|
-
* Require actual remote script if possible so that if it defines any classes we can dump those too.
|
5
2
|
* Add a hijack_exec helper to execute a local .rb on the target
|
data/lib/hijack/console.rb
CHANGED
@@ -8,7 +8,6 @@ module Hijack
|
|
8
8
|
$stdout.write(str)
|
9
9
|
$stdout.flush
|
10
10
|
Payload.inject(@pid)
|
11
|
-
signal_drb_start
|
12
11
|
connect
|
13
12
|
$stdout.write("\b" * str.size)
|
14
13
|
$stdout.flush
|
@@ -32,15 +31,11 @@ module Hijack
|
|
32
31
|
end
|
33
32
|
end
|
34
33
|
|
35
|
-
def
|
36
|
-
Process.kill('USR2', @pid.to_i)
|
34
|
+
def connect
|
37
35
|
loop do
|
38
36
|
break if File.exists?(Hijack.socket_path_for(@pid))
|
39
37
|
sleep 0.01
|
40
38
|
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def connect
|
44
39
|
@remote = DRbObject.new(nil, Hijack.socket_for(@pid))
|
45
40
|
end
|
46
41
|
|
data/lib/hijack/gdb.rb
CHANGED
@@ -3,35 +3,63 @@
|
|
3
3
|
module Hijack
|
4
4
|
class GDB
|
5
5
|
def initialize(pid)
|
6
|
+
@pid = pid
|
6
7
|
@verbose = Hijack.options[:gdb_debug]
|
7
|
-
exec_path = File.join(Config::CONFIG['bindir'], Config::CONFIG['RUBY_INSTALL_NAME'] + Config::CONFIG['EXEEXT'])
|
8
|
-
|
9
|
-
wait
|
8
|
+
@exec_path = File.join(Config::CONFIG['bindir'], Config::CONFIG['RUBY_INSTALL_NAME'] + Config::CONFIG['EXEEXT'])
|
9
|
+
attach
|
10
10
|
end
|
11
11
|
|
12
|
-
def
|
13
|
-
backtrace.any? {|line| line =~ /
|
12
|
+
def ensure_attached_to_ruby_process
|
13
|
+
unless backtrace.any? {|line| line =~ /rb_/}
|
14
|
+
puts "\n=> #{@pid} doesn't appear to be a Ruby process!"
|
15
|
+
detach
|
16
|
+
exit 1
|
17
|
+
end
|
14
18
|
end
|
15
19
|
|
16
|
-
def
|
17
|
-
backtrace.any? {|line| line =~ /rb_thread_join/}
|
20
|
+
def ensure_main_thread_not_blocked_by_join
|
21
|
+
if backtrace.any? {|line| line =~ /rb_thread_join/}
|
22
|
+
puts "\n=> Unable to hijack #{@pid} because the main thread is blocked waiting for another thread to join."
|
23
|
+
puts "=> Check that you are using the most recent version of hijack, a newer version may have solved this shortcoming."
|
24
|
+
detach
|
25
|
+
exit 1
|
26
|
+
end
|
18
27
|
end
|
19
28
|
|
20
29
|
def eval(cmd)
|
21
|
-
set_trap_pending
|
22
|
-
set_breakpoint
|
23
|
-
continue
|
24
|
-
clear_breakpoint
|
25
30
|
call("(void)rb_eval_string(#{cmd.strip.gsub(/"/, '\"').inspect})")
|
26
31
|
end
|
27
32
|
|
28
33
|
def detach
|
34
|
+
return unless @gdb
|
29
35
|
exec('detach')
|
30
36
|
exec('quit')
|
37
|
+
@backtrace = nil
|
31
38
|
@gdb.close
|
39
|
+
@gdb = nil
|
32
40
|
end
|
33
41
|
|
34
42
|
protected
|
43
|
+
def attach
|
44
|
+
loop do
|
45
|
+
@gdb = IO.popen("gdb -q #{@exec_path} #{@pid} 2>&1", 'r+')
|
46
|
+
wait
|
47
|
+
if backtrace.first =~ /Previous frame inner to this frame/
|
48
|
+
detach
|
49
|
+
sleep 0.1
|
50
|
+
else
|
51
|
+
break
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
ensure_attached_to_ruby_process
|
56
|
+
ensure_main_thread_not_blocked_by_join
|
57
|
+
set_trap_pending
|
58
|
+
set_breakpoint
|
59
|
+
continue
|
60
|
+
clear_breakpoint
|
61
|
+
end
|
62
|
+
|
35
63
|
def backtrace
|
36
64
|
@backtrace ||= exec('bt').reverse
|
37
65
|
end
|
data/lib/hijack/payload.rb
CHANGED
@@ -1,20 +1,15 @@
|
|
1
1
|
module Hijack
|
2
2
|
class Payload
|
3
3
|
def self.inject(pid)
|
4
|
-
gdb =
|
5
|
-
|
6
|
-
puts
|
7
|
-
|
8
|
-
exit 1
|
9
|
-
end
|
10
|
-
if gdb.main_thread_blocked_by_join?
|
11
|
-
puts "\n=> Unable to hijack #{pid} because the main thread is blocked waiting for another thread to join."
|
12
|
-
puts "=> Check that you are using the most recent version of hijack, a newer version may have solved this shortcoming."
|
13
|
-
gdb.detach
|
14
|
-
exit 1
|
4
|
+
gdb = nil
|
5
|
+
trap('SIGINT') do
|
6
|
+
puts
|
7
|
+
@received_sigint = true
|
15
8
|
end
|
9
|
+
gdb = GDB.new(pid)
|
16
10
|
gdb.eval(payload(pid))
|
17
11
|
gdb.detach
|
12
|
+
exit if @received_sigint
|
18
13
|
end
|
19
14
|
|
20
15
|
def self.payload(pid)
|
@@ -108,8 +103,7 @@ module Hijack
|
|
108
103
|
end
|
109
104
|
end
|
110
105
|
end
|
111
|
-
|
112
|
-
Signal.trap('USR2') { Hijack.start(__hijack_context) }
|
106
|
+
Hijack.start(self)
|
113
107
|
RUBY
|
114
108
|
end
|
115
109
|
end
|
data/tasks/gem.rake
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ileitch-hijack
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ian Leitch
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-09-
|
12
|
+
date: 2009-09-19 21:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|