rallhook 0.7.0
Sign up to get free protection for your applications and to get access to all the features.
- data/AUTHORS +3 -0
- data/CHANGELOG +82 -0
- data/README +207 -0
- data/Rakefile +49 -0
- data/TODO +8 -0
- data/examples/hook/example1.rb +19 -0
- data/examples/hook/example2.rb +30 -0
- data/examples/hook/example3.rb +24 -0
- data/examples/hook/example4.rb +18 -0
- data/examples/hook/intercept.rb +41 -0
- data/examples/hook/intercept2.rb +49 -0
- data/examples/hook/redirect.rb +55 -0
- data/examples/hook/redirect_inherited.rb +28 -0
- data/examples/hook/shadow.rb +44 -0
- data/examples/instrospection/main.rb +13 -0
- data/examples/instrospection/source1.rb +4 -0
- data/examples/instrospection/source2.rb +4 -0
- data/ext/rallhook_base/distorm.h +401 -0
- data/ext/rallhook_base/extconf.rb +21 -0
- data/ext/rallhook_base/hook.c +165 -0
- data/ext/rallhook_base/hook.h +30 -0
- data/ext/rallhook_base/hook_rb_call.c +88 -0
- data/ext/rallhook_base/hook_rb_call.h +33 -0
- data/ext/rallhook_base/method_node.c +212 -0
- data/ext/rallhook_base/method_node.h +27 -0
- data/ext/rallhook_base/node_defs.h +294 -0
- data/ext/rallhook_base/rallhook.c +396 -0
- data/ext/rallhook_base/rb_call_fake.c +398 -0
- data/ext/rallhook_base/rb_call_fake.h +138 -0
- data/ext/rallhook_base/restrict_def.c +176 -0
- data/ext/rallhook_base/restrict_def.h +37 -0
- data/ext/rallhook_base/ruby_redirect.c +122 -0
- data/ext/rallhook_base/ruby_redirect.h +33 -0
- data/ext/rallhook_base/ruby_symbols.c +43 -0
- data/ext/rallhook_base/ruby_symbols.h +28 -0
- data/ext/rallhook_base/ruby_version.h +21 -0
- data/lib/rallhook/thread_hook.rb +37 -0
- data/lib/rallhook.rb +384 -0
- data/test/basic_proc.rb +45 -0
- data/test/integrity/test_array.rb +42 -0
- data/test/integrity/test_binding.rb +26 -0
- data/test/integrity/test_block.rb +37 -0
- data/test/integrity/test_call.rb +1 -0
- data/test/integrity/test_class_methods.rb +1 -0
- data/test/integrity/test_exception.rb +1 -0
- data/test/integrity/test_super.rb +34 -0
- data/test/introspection/test_call.rb +29 -0
- data/test/introspection/test_class_method.rb +41 -0
- data/test/introspection/test_file.rb +15 -0
- metadata +113 -0
data/AUTHORS
ADDED
data/CHANGELOG
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
0.7.0 Concurrency support, any thread can hook without affect the hook state of the other threads
|
2
|
+
|
3
|
+
Restrictions about overwrite instance methods disabled
|
4
|
+
|
5
|
+
Added class shadows to confine the behaviour added throught methods to hook state
|
6
|
+
|
7
|
+
Implemented UboundMethod#unchecked_bind to bind methods of different classes
|
8
|
+
|
9
|
+
0.6.1 Fixed bug on binding of class methods in Object#specific_method
|
10
|
+
|
11
|
+
0.6.0 Implemented method UboundMethod#body
|
12
|
+
|
13
|
+
Improved compatibility of test cases with ruby1.9 and ruby1.8 behaviour
|
14
|
+
|
15
|
+
Implemented Object#specific_method to lookup methods by klass and method_id
|
16
|
+
|
17
|
+
Delete overload of Object#method
|
18
|
+
|
19
|
+
0.5.0 Security Improved: Restricted define of singleton methods over classes when hook is enabled
|
20
|
+
|
21
|
+
Added special check for Object#binding to avoid change the binding behaviour with method redirection
|
22
|
+
|
23
|
+
Security improved: Added hook of rb_add_method to avoid the overwriting of any method
|
24
|
+
|
25
|
+
Security improved: Fixed leaks of hooking methods by making all methods called over Hook illegal if hook state is enabled
|
26
|
+
|
27
|
+
More helpers to make easier to use. (see MethodHandler class)
|
28
|
+
|
29
|
+
Documented methods and classes to generate useful RDoc
|
30
|
+
|
31
|
+
Internal refactoring to split the logic of rallhook, hooking, method_handle invoke, etc... and the modification of the ruby interpreter with hook calls, etc...
|
32
|
+
|
33
|
+
0.4.1 Fixed bug in the hook module
|
34
|
+
|
35
|
+
0.4.0 Fixed bug in the version numbering
|
36
|
+
|
37
|
+
0.3.1 Added new method of intercept calls
|
38
|
+
|
39
|
+
Changed interface of handlling of methods (see README and examples) to avoid errors in the handling of yield functions in ruby1.8
|
40
|
+
|
41
|
+
New internal method of hook fixe many many bugs
|
42
|
+
|
43
|
+
Fixed fastcall convention calls in i386, hooks and detection of calling convention
|
44
|
+
|
45
|
+
Fixed compatibility issues with ruby1.8 and ruby1.9 in i386
|
46
|
+
|
47
|
+
Rakefile configured to build extensions automatically at gem install
|
48
|
+
|
49
|
+
0.3.0: Compatibility with ruby1.8 on i386 (tested with ruby 1.8.6 patchlevel 111 in ubuntu 8.04)
|
50
|
+
|
51
|
+
Compatibility with ruby1.9 on i386 (tested with ruby 1.9.0 in ubuntu 8.04)
|
52
|
+
|
53
|
+
Compatiblity with ruby1.8 on x86_64 (tested with ruby 1.8.7 patchlevel 72 in ubuntu 9.04)
|
54
|
+
|
55
|
+
Compatibility with ruby1.9 on x86_64 (tested with ruby 1.9.0 r17482 in ubuntu 9.04)
|
56
|
+
|
57
|
+
New method introspection features (see README for examples)
|
58
|
+
|
59
|
+
|
60
|
+
0.2.1: Fixed issue #3: corrupted block arguments in hooking ( http://github.com/tario/rallhook/issues/issue/3 )
|
61
|
+
|
62
|
+
Added testcase to test the issue #3
|
63
|
+
|
64
|
+
Added some automatic tests of integrity of the modified interpreter
|
65
|
+
|
66
|
+
0.2.0: Fixed RAII issues in RallHook::hook method
|
67
|
+
|
68
|
+
Changed version of package to 0.2.0 to avoid "malformed" version number
|
69
|
+
|
70
|
+
0.2.0-rc1: Added "TagContainer trick" to fix the issue #2: undesirable nest at super call with block ( http://github.com/tario/rallhook/issues/issue/2 )
|
71
|
+
|
72
|
+
Added klass parameter to hooked_send, fixing the issue #1: undesirable nest at super call ( http://github.com/tario/rallhook/issues/issue/1 )
|
73
|
+
|
74
|
+
Added classes and methods to read method body info as the file and line where that method was defined
|
75
|
+
obj.method(:foo).body.file
|
76
|
+
obj.method(:foo).body.line
|
77
|
+
|
78
|
+
|
79
|
+
0.1.1: Changed hooking and unhooking mechanism in the call of the handler of hooks
|
80
|
+
to make it internal at rallhooking (calling of hook and unhook from the call method are unnecesary now)
|
81
|
+
|
82
|
+
0.1.0: implemented basic hooking as PoC of rallhook, basic example works fine
|
data/README
ADDED
@@ -0,0 +1,207 @@
|
|
1
|
+
= rallhook - An ruby absolute method hooker
|
2
|
+
|
3
|
+
This package contains rallhook, a ruby C extension to intercept ruby methods calls at interpreter level in a transparent way from ruby itself.
|
4
|
+
|
5
|
+
== Installation
|
6
|
+
|
7
|
+
=== Prerequisites
|
8
|
+
|
9
|
+
* ruby-cymbol >= 0.1.0 (found at http://github.com/tario/ruby-cymbol)
|
10
|
+
* ruby debug info ( apt-get install libruby1.8-dbg or libruby1.9-dbg on debian based systems)
|
11
|
+
* ruby development package ( apt-get install ruby1.8-dev or ruby1.9-dev on debian based systems)
|
12
|
+
* objdump
|
13
|
+
* distorm ( found at https://code.google.com/p/distorm/ )
|
14
|
+
|
15
|
+
|
16
|
+
=== Gem installation
|
17
|
+
|
18
|
+
* Download the last version of the gem from http://github.com/tario/ruby-cpp/downloads
|
19
|
+
* Install the gem with the following;
|
20
|
+
|
21
|
+
gem install rallhook-X.X.X.gem
|
22
|
+
|
23
|
+
== Usage
|
24
|
+
|
25
|
+
=== Basic Example
|
26
|
+
|
27
|
+
test.rb:
|
28
|
+
|
29
|
+
require "rubygems"
|
30
|
+
require "rallhook"
|
31
|
+
|
32
|
+
include RallHook
|
33
|
+
|
34
|
+
class MethodHandler < HookHandler
|
35
|
+
|
36
|
+
def handle_method (klass,self_,m, method_id)
|
37
|
+
|
38
|
+
# print to the standar output details about the method called
|
39
|
+
print "method call #{m}:#{method_id} over #{self_}:#{self_.class} \n"
|
40
|
+
nil # do nothing
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
MethodHandler.hook do
|
45
|
+
# all ruby calls in this block are intercepted by hook_recv::call
|
46
|
+
|
47
|
+
[1,2,3].each do |x|
|
48
|
+
print x,"\n"
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
standard output:
|
54
|
+
|
55
|
+
method call each:4001 over 123:Array
|
56
|
+
method call print:7697 over main:Object
|
57
|
+
method call write:7649 over #<IO:0x7fb15e54fad0>:IO
|
58
|
+
method call to_s:3137 over 1:Fixnum
|
59
|
+
1method call write:7649 over #<IO:0x7fb15e54fad0>:IO
|
60
|
+
|
61
|
+
method call print:7697 over main:Object
|
62
|
+
method call write:7649 over #<IO:0x7fb15e54fad0>:IO
|
63
|
+
method call to_s:3137 over 2:Fixnum
|
64
|
+
2method call write:7649 over #<IO:0x7fb15e54fad0>:IO
|
65
|
+
|
66
|
+
method call print:7697 over main:Object
|
67
|
+
method call write:7649 over #<IO:0x7fb15e54fad0>:IO
|
68
|
+
method call to_s:3137 over 3:Fixnum
|
69
|
+
3method call write:7649 over #<IO:0x7fb15e54fad0>:IO
|
70
|
+
|
71
|
+
=== Redirecting calls
|
72
|
+
|
73
|
+
require "rubygems"
|
74
|
+
require "rallhook"
|
75
|
+
|
76
|
+
include RallHook
|
77
|
+
|
78
|
+
class MethodHandler < HookHandler
|
79
|
+
include RallHook::Helper
|
80
|
+
|
81
|
+
def handle_method (klass,recv,m,method_id)
|
82
|
+
|
83
|
+
if m == :foo
|
84
|
+
# redirects the calls of method foo to method bar on the same object
|
85
|
+
return redirect_call(klass,recv, :bar)
|
86
|
+
end
|
87
|
+
|
88
|
+
if m == :bar
|
89
|
+
# redirects the calls of method bar to method bar on the method_handler
|
90
|
+
return redirect_call(self.class,self, :bar)
|
91
|
+
end
|
92
|
+
|
93
|
+
nil # do nothing
|
94
|
+
end
|
95
|
+
|
96
|
+
def bar
|
97
|
+
print "bar in MethodHandler\n"
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
class X
|
102
|
+
def foo
|
103
|
+
print "foo in X\n"
|
104
|
+
end
|
105
|
+
def bar
|
106
|
+
print "bar in X\n"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
print "WITHOUT HOOK:\n"
|
111
|
+
|
112
|
+
x = X.new
|
113
|
+
x.foo
|
114
|
+
x.bar
|
115
|
+
|
116
|
+
print "WITH HOOK:\n"
|
117
|
+
|
118
|
+
MethodHandler.hook do
|
119
|
+
# all ruby calls in this block are intercepted by hook_recv::call
|
120
|
+
x = X.new
|
121
|
+
x.foo # redirected to X#bar
|
122
|
+
x.bar # redirected to MethodHandler#bar
|
123
|
+
|
124
|
+
end
|
125
|
+
|
126
|
+
=== Wrap Calls
|
127
|
+
require "rubygems"
|
128
|
+
require "rallhook"
|
129
|
+
|
130
|
+
include RallHook
|
131
|
+
|
132
|
+
class MethodHandler < HookHandler
|
133
|
+
include RallHook::Helper
|
134
|
+
|
135
|
+
class FooMethodWrapper < MethodWrapper
|
136
|
+
def call(*x)
|
137
|
+
# call with reyield if block_given
|
138
|
+
if block_given?
|
139
|
+
original_call(*x) do |*a|
|
140
|
+
yield(*a)
|
141
|
+
end
|
142
|
+
# add "�bar?"
|
143
|
+
yield("bar?")
|
144
|
+
else
|
145
|
+
original_call(*x)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def handle_method (klass,recv,m,method_id)
|
151
|
+
if m == :each
|
152
|
+
return FooMethodWrapper.redirect_handler(klass,recv,m,method_id)
|
153
|
+
end
|
154
|
+
nil # do nothing
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
print "calling Array#each without hook\n"
|
159
|
+
[1,2,3,4].each do |x|
|
160
|
+
print x.inspect, " "
|
161
|
+
end
|
162
|
+
print "\n"
|
163
|
+
|
164
|
+
print "calling Array#each WITH hook\n"
|
165
|
+
MethodHandler.hook do
|
166
|
+
|
167
|
+
# 1 2 3 4 "bar?"
|
168
|
+
[1,2,3,4].each do |x|
|
169
|
+
print x.inspect," "
|
170
|
+
end
|
171
|
+
print "\n"
|
172
|
+
|
173
|
+
end
|
174
|
+
|
175
|
+
|
176
|
+
=== Method Instrospection new features example
|
177
|
+
|
178
|
+
source1.rb
|
179
|
+
|
180
|
+
class X
|
181
|
+
def foo
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
source2.rb
|
186
|
+
|
187
|
+
class Y < X
|
188
|
+
def foo
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
main.rb
|
193
|
+
|
194
|
+
require "rallhook"
|
195
|
+
require "source1.rb"
|
196
|
+
require "source2.rb"
|
197
|
+
|
198
|
+
x = X.new
|
199
|
+
y = Y.new
|
200
|
+
|
201
|
+
print x.method(:foo).body.file,"\n" # source1.rb
|
202
|
+
print y.method(:foo).body.file,"\n" # source2.rb
|
203
|
+
|
204
|
+
print y.method(X,:foo).body.file,"\n" # source1.rb
|
205
|
+
print y.method(Y,:foo).body.file,"\n" # source2.rb
|
206
|
+
|
207
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rake/rdoctask'
|
5
|
+
require 'rake/gempackagetask'
|
6
|
+
|
7
|
+
spec = Gem::Specification.new do |s|
|
8
|
+
s.name = 'rallhook'
|
9
|
+
s.version = '0.7.0'
|
10
|
+
s.author = 'Dario Seminara'
|
11
|
+
s.email = 'robertodarioseminara@gmail.com'
|
12
|
+
s.platform = Gem::Platform::RUBY
|
13
|
+
s.summary = 'Allow hooking of all method invocations transparently to control and / or monitor the behavior of a ruby program'
|
14
|
+
s.homepage = "http://github.com/tario/rallhook"
|
15
|
+
s.has_rdoc = true
|
16
|
+
s.add_dependency "ruby-cymbol", ">= 0.1.0"
|
17
|
+
s.extra_rdoc_files = [ 'README' ]
|
18
|
+
s.rdoc_options << '--main' << 'README'
|
19
|
+
s.extensions = FileList["ext/**/extconf.rb"].to_a
|
20
|
+
s.files = Dir.glob("{examples,lib,test}/**/*.rb") + Dir.glob("ext/**/*.c") + Dir.glob("ext/**/*.h") + Dir.glob("ext/**/extconf.rb") +
|
21
|
+
[ 'AUTHORS', 'CHANGELOG', 'README', 'Rakefile', 'TODO' ]
|
22
|
+
end
|
23
|
+
|
24
|
+
desc 'Run tests'
|
25
|
+
task :default => [ :test ]
|
26
|
+
|
27
|
+
Rake::TestTask.new('test') do |t|
|
28
|
+
t.libs << 'test'
|
29
|
+
t.pattern = '{test}/**/test_*.rb'
|
30
|
+
t.verbose = true
|
31
|
+
end
|
32
|
+
|
33
|
+
desc 'Generate RDoc'
|
34
|
+
Rake::RDocTask.new :rdoc do |rd|
|
35
|
+
rd.rdoc_dir = 'doc'
|
36
|
+
rd.rdoc_files.add 'lib', 'ext', 'README'
|
37
|
+
rd.main = 'README'
|
38
|
+
end
|
39
|
+
|
40
|
+
desc 'Build Gem'
|
41
|
+
Rake::GemPackageTask.new spec do |pkg|
|
42
|
+
pkg.need_tar = true
|
43
|
+
end
|
44
|
+
|
45
|
+
desc 'Clean up'
|
46
|
+
task :clean => [ :clobber_rdoc, :clobber_package ]
|
47
|
+
|
48
|
+
desc 'Clean up'
|
49
|
+
task :clobber => [ :clean ]
|
data/TODO
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
* Threading support
|
2
|
+
* Tests cases for 1.0.0 interface
|
3
|
+
* More integrity testcases (with use of ruby core methods)
|
4
|
+
* Security testcases (hook bypass checks, security tests)
|
5
|
+
* Win32 compatibility
|
6
|
+
* Delete distorm dependency
|
7
|
+
* Delete libruby debuginfo dependency
|
8
|
+
* Make rallhook functionality transparent (backtraces, exceptions, etc ...)
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "rallhook"
|
3
|
+
|
4
|
+
include RallHook
|
5
|
+
|
6
|
+
class HookProc
|
7
|
+
def handle_method (klass,self_,m,method_id)
|
8
|
+
|
9
|
+
# print to the standard output details about the method called
|
10
|
+
print "method call #{m}:#{method_id} over #{self_}:#{self_.class}\n"
|
11
|
+
nil # do nothing
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
hook_proc = HookProc.new
|
16
|
+
Hook.hook hook_proc do
|
17
|
+
print 2+2,"\n"
|
18
|
+
print [1,2,3].inject{|x,y| x+y},"\n"
|
19
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "rallhook"
|
3
|
+
|
4
|
+
include RallHook
|
5
|
+
|
6
|
+
class HookProc
|
7
|
+
def handle_method (klass,self_,m,method_id)
|
8
|
+
|
9
|
+
# print to the standard output details about the method called
|
10
|
+
print "method call #{m}:#{method_id} over #{self_}:#{self_.class}\n"
|
11
|
+
nil # do nothing
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class X
|
16
|
+
def foo
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class Y <X
|
21
|
+
def foo
|
22
|
+
super
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
hook_proc = HookProc.new
|
27
|
+
Hook.hook hook_proc do
|
28
|
+
y = Y.new
|
29
|
+
y.foo
|
30
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "rallhook"
|
3
|
+
|
4
|
+
include RallHook
|
5
|
+
|
6
|
+
class MethodHandler
|
7
|
+
def handle_method (klass,self_,m,method_id)
|
8
|
+
|
9
|
+
# print to the standard output details about the method called
|
10
|
+
print "method call #{m}:#{method_id} over #{self_}:#{self_.class}\n"
|
11
|
+
nil # do nothing
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
mhandler = MethodHandler.new
|
16
|
+
|
17
|
+
Hook.hook mhandler do
|
18
|
+
# all ruby calls in this block are intercepted by hook_recv::call
|
19
|
+
|
20
|
+
[1,2,3].each do |x|
|
21
|
+
print x,"\n"
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "rallhook"
|
3
|
+
|
4
|
+
include RallHook
|
5
|
+
|
6
|
+
class MethodHandler < RallHook::HookHandler
|
7
|
+
def handle_method (klass,self_,m,method_id)
|
8
|
+
|
9
|
+
# print to the standard output details about the method called
|
10
|
+
print "method call #{m}:#{method_id} over #{self_}:#{self_.class}\n"
|
11
|
+
nil # do nothing
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
MethodHandler.hook do
|
16
|
+
print 2+2,"\n"
|
17
|
+
print [1,2,3].inject{|x,y| x+y},"\n"
|
18
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "rallhook"
|
3
|
+
|
4
|
+
include RallHook
|
5
|
+
|
6
|
+
class MethodHandler
|
7
|
+
include RallHook::Helper
|
8
|
+
|
9
|
+
class FooMethodWrapper < MethodWrapper
|
10
|
+
def call(a)
|
11
|
+
# replace the a parameter with a+5
|
12
|
+
original_call(a+5)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def handle_method (klass,recv,m, method_id)
|
17
|
+
|
18
|
+
if m == :foo
|
19
|
+
return FooMethodWrapper.redirect_handler(klass,recv,m,method_id)
|
20
|
+
end
|
21
|
+
|
22
|
+
nil # do nothing
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
class X
|
28
|
+
def foo(a)
|
29
|
+
print "foo in X with a = #{a}\n"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
x = X.new
|
33
|
+
print "calling X#foo without hook\n"
|
34
|
+
x.foo 4 # "foo in X with a = 4"
|
35
|
+
|
36
|
+
print "calling X#foo WITH hook\n"
|
37
|
+
mhandler = MethodHandler.new
|
38
|
+
Hook.hook mhandler do
|
39
|
+
x.foo 4 # "foo in X with a = 9" :)
|
40
|
+
end
|
41
|
+
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "rallhook"
|
3
|
+
|
4
|
+
include RallHook
|
5
|
+
|
6
|
+
class MethodHandler
|
7
|
+
include RallHook::Helper
|
8
|
+
|
9
|
+
class FooMethodWrapper < MethodWrapper
|
10
|
+
def call(*x)
|
11
|
+
# call with reyield if block_given
|
12
|
+
if block_given?
|
13
|
+
original_call(*x) do |*a|
|
14
|
+
yield(*a)
|
15
|
+
end
|
16
|
+
# add "�bar?"
|
17
|
+
yield("bar?")
|
18
|
+
else
|
19
|
+
original_call(*x)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def handle_method (klass,recv,m,method_id)
|
25
|
+
if m == :each
|
26
|
+
return FooMethodWrapper.redirect_handler(klass,recv,m,method_id)
|
27
|
+
end
|
28
|
+
nil # do nothing
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
print "calling Array#each without hook\n"
|
33
|
+
[1,2,3,4].each do |x|
|
34
|
+
print x.inspect, " "
|
35
|
+
end
|
36
|
+
print "\n"
|
37
|
+
|
38
|
+
print "calling Array#each WITH hook\n"
|
39
|
+
mhandler = MethodHandler.new
|
40
|
+
Hook.hook mhandler do
|
41
|
+
|
42
|
+
# 1 2 3 4 "bar?"
|
43
|
+
[1,2,3,4].each do |x|
|
44
|
+
print x.inspect," "
|
45
|
+
end
|
46
|
+
print "\n"
|
47
|
+
|
48
|
+
end
|
49
|
+
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "rallhook"
|
3
|
+
|
4
|
+
include RallHook
|
5
|
+
|
6
|
+
class MethodHandler
|
7
|
+
include RallHook::Helper
|
8
|
+
|
9
|
+
def handle_method (klass,recv,m,method_id)
|
10
|
+
|
11
|
+
if m == :foo
|
12
|
+
# redirects the calls of method foo to method bar on the same object
|
13
|
+
return redirect_call(klass,recv, :bar)
|
14
|
+
end
|
15
|
+
|
16
|
+
if m == :bar
|
17
|
+
# redirects the calls of method bar to method bar on the method_handler
|
18
|
+
return redirect_call(self.class,self, :bar)
|
19
|
+
end
|
20
|
+
|
21
|
+
nil # do nothing
|
22
|
+
end
|
23
|
+
|
24
|
+
def bar
|
25
|
+
print "bar in MethodHandler\n"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class X
|
30
|
+
def foo
|
31
|
+
print "foo in X\n"
|
32
|
+
end
|
33
|
+
def bar
|
34
|
+
print "bar in X\n"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
mhandler = MethodHandler.new
|
39
|
+
|
40
|
+
print "WITHOUT HOOK:\n"
|
41
|
+
|
42
|
+
x = X.new
|
43
|
+
x.foo
|
44
|
+
x.bar
|
45
|
+
|
46
|
+
print "WITH HOOK:\n"
|
47
|
+
|
48
|
+
Hook.hook mhandler do
|
49
|
+
# all ruby calls in this block are intercepted by hook_recv::call
|
50
|
+
x = X.new
|
51
|
+
x.foo # redirected to X#bar
|
52
|
+
x.bar # redirected to MethodHandler#bar
|
53
|
+
|
54
|
+
end
|
55
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "rallhook"
|
3
|
+
|
4
|
+
include RallHook
|
5
|
+
|
6
|
+
class MethodHandler
|
7
|
+
include RallHook::Helper
|
8
|
+
|
9
|
+
def handle_method (klass,recv,m,method_id)
|
10
|
+
|
11
|
+
print "called method #{m} over #{recv}\n"
|
12
|
+
|
13
|
+
if m == :inherited
|
14
|
+
return redirect_call(klass,recv,:ssss)
|
15
|
+
end
|
16
|
+
|
17
|
+
nil # do nothing
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
mhandler = MethodHandler.new
|
22
|
+
Hook.hook mhandler do
|
23
|
+
# all ruby calls in this block are intercepted by hook_recv::call
|
24
|
+
class N
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "rallhook"
|
3
|
+
|
4
|
+
include RallHook
|
5
|
+
|
6
|
+
class MethodHandler < RallHook::HookHandler
|
7
|
+
def handle_method (klass,self_,m,method_id)
|
8
|
+
# print to the standard output details about the method called
|
9
|
+
print "method call #{m}:#{method_id} over #{self_}:#{self_.class}\n"
|
10
|
+
nil # do nothing
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class X
|
15
|
+
def foo
|
16
|
+
print "outside of hook foo\n"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
x = X.new
|
21
|
+
|
22
|
+
x.foo
|
23
|
+
|
24
|
+
MethodHandler.hook do
|
25
|
+
class X
|
26
|
+
def foo
|
27
|
+
print "inside of hook foo\n"
|
28
|
+
end
|
29
|
+
|
30
|
+
def bar
|
31
|
+
print "inside of hook bar\n"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
x.foo
|
36
|
+
x.bar
|
37
|
+
end
|
38
|
+
|
39
|
+
x.foo
|
40
|
+
begin
|
41
|
+
x.bar # NoMethodError
|
42
|
+
rescue NoMethodError
|
43
|
+
print "there is no method bar in X outside the hook\n"
|
44
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require "rallhook"
|
3
|
+
require "source1.rb"
|
4
|
+
require "source2.rb"
|
5
|
+
|
6
|
+
x = X.new
|
7
|
+
y = Y.new
|
8
|
+
|
9
|
+
print "definition of method :foo in #{x}: ", x.method(:foo).body.file,"\n" # source1.rb
|
10
|
+
print "definition of method :foo in #{y}: ", y.method(:foo).body.file,"\n" # source2.rb
|
11
|
+
|
12
|
+
print "definition of method :foo of class X in object #{y}: ", y.method(X,:foo).body.file,"\n" # source1.rb
|
13
|
+
print "definition of method :foo of class Y in object #{y}: ", y.method(Y,:foo).body.file,"\n" # source1.rb
|