rallhook 0.7.0
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/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
@@ -0,0 +1,37 @@
|
|
1
|
+
/*
|
2
|
+
|
3
|
+
This file is part of the rallhook project, http://github.com/tario
|
4
|
+
|
5
|
+
Copyright (c) 2009-2010 Roberto Dario Seminara <robertodarioseminara@gmail.com>
|
6
|
+
|
7
|
+
rallhook is free software: you can redistribute it and/or modify
|
8
|
+
it under the terms of the gnu general public license as published by
|
9
|
+
the free software foundation, either version 3 of the license, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
rallhook is distributed in the hope that it will be useful,
|
13
|
+
but without any warranty; without even the implied warranty of
|
14
|
+
merchantability or fitness for a particular purpose. see the
|
15
|
+
gnu general public license for more details.
|
16
|
+
|
17
|
+
you should have received a copy of the gnu general public license
|
18
|
+
along with rallhook. if not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
*/
|
21
|
+
#ifndef __RESTRICT_DEF_H
|
22
|
+
#define __RESTRICT_DEF_H
|
23
|
+
|
24
|
+
#include "ruby.h"
|
25
|
+
|
26
|
+
void init_restrict_def();
|
27
|
+
|
28
|
+
void disable_overwrite(VALUE current_thread);
|
29
|
+
void enable_overwrite(VALUE current_thread);
|
30
|
+
|
31
|
+
void shadow_redirect(VALUE* klass, VALUE* recv, ID* mid);
|
32
|
+
|
33
|
+
VALUE unshadow(VALUE klass) ;
|
34
|
+
|
35
|
+
VALUE shadow_or_create(VALUE klass);
|
36
|
+
|
37
|
+
#endif
|
@@ -0,0 +1,122 @@
|
|
1
|
+
/*
|
2
|
+
|
3
|
+
This file is part of the rallhook project, http://github.com/tario/rallhook
|
4
|
+
|
5
|
+
Copyright (c) 2009-2010 Roberto Dario Seminara <robertodarioseminara@gmail.com>
|
6
|
+
|
7
|
+
rallhook is free software: you can redistribute it and/or modify
|
8
|
+
it under the terms of the gnu general public license as published by
|
9
|
+
the free software foundation, either version 3 of the license, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
rallhook is distributed in the hope that it will be useful,
|
13
|
+
but without any warranty; without even the implied warranty of
|
14
|
+
merchantability or fitness for a particular purpose. see the
|
15
|
+
gnu general public license for more details.
|
16
|
+
|
17
|
+
you should have received a copy of the gnu general public license
|
18
|
+
along with rallhook. if not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
*/
|
21
|
+
#include "ruby_redirect.h"
|
22
|
+
#include "ruby_symbols.h"
|
23
|
+
#include "rb_call_fake.h"
|
24
|
+
#include "hook_rb_call.h"
|
25
|
+
#include "pthread.h"
|
26
|
+
|
27
|
+
int code_changed = 0;
|
28
|
+
|
29
|
+
REDIRECTHANDLER current_redirect_handler;
|
30
|
+
|
31
|
+
void init_redirect();
|
32
|
+
|
33
|
+
int put_redirect_handler_( REDIRECTHANDLER redirect_handler) {
|
34
|
+
current_redirect_handler = redirect_handler;
|
35
|
+
|
36
|
+
if (!code_changed) {
|
37
|
+
// insert inconditional jmp from rb_call to rb_call_copy
|
38
|
+
|
39
|
+
#ifdef __i386__
|
40
|
+
rb_call_copy = (RBCALL)hook_rb_call(rb_call_fake_regs);
|
41
|
+
#endif
|
42
|
+
|
43
|
+
#ifdef __x86_64__
|
44
|
+
rb_call_copy = (RBCALL)hook_rb_call(rb_call_fake);
|
45
|
+
#endif
|
46
|
+
// calibrate protocol of rb_call
|
47
|
+
#ifdef __i386__
|
48
|
+
is_calibrate = 1;
|
49
|
+
|
50
|
+
VALUE test_value = LONG2FIX(0);
|
51
|
+
|
52
|
+
calibrate_recv = test_value;
|
53
|
+
calibrate_klass = CLASS_OF(test_value);
|
54
|
+
calibrate_mid = rb_intern("to_s");
|
55
|
+
|
56
|
+
rb_funcall(test_value, calibrate_mid, 0);
|
57
|
+
|
58
|
+
|
59
|
+
#endif
|
60
|
+
|
61
|
+
if (!rb_call_copy) {
|
62
|
+
rb_raise( rb_eFatal, "libruby incompatible with rallhook");
|
63
|
+
}
|
64
|
+
|
65
|
+
#ifdef RUBY1_9
|
66
|
+
#ifdef __i386__
|
67
|
+
|
68
|
+
rb_eval_string("def Object.___calibrate_x(x); end");
|
69
|
+
|
70
|
+
calibrate_recv = rb_cObject;
|
71
|
+
calibrate_klass = CLASS_OF(rb_cObject);
|
72
|
+
calibrate_mid = rb_intern("___calibrate_x");
|
73
|
+
|
74
|
+
vm_call_method_copy = (VMCALLMETHOD)hook_vm_call_method(vm_call_method_fake_regs);
|
75
|
+
vm_is_calibrate = 1;
|
76
|
+
|
77
|
+
char code[256];
|
78
|
+
snprintf(code, sizeof(code), "Object.___calibrate_x(%i)", test_value);
|
79
|
+
rb_eval_string(code);
|
80
|
+
|
81
|
+
#endif
|
82
|
+
#ifdef __x86_64__
|
83
|
+
vm_call_method_copy = (VMCALLMETHOD)hook_vm_call_method(vm_call_method_fake);
|
84
|
+
#endif
|
85
|
+
|
86
|
+
if (!vm_call_method_copy) {
|
87
|
+
rb_raise( rb_eFatal, "libruby incompatible with rallhook");
|
88
|
+
}
|
89
|
+
#endif
|
90
|
+
|
91
|
+
code_changed = 1;
|
92
|
+
}
|
93
|
+
|
94
|
+
return 0;
|
95
|
+
}
|
96
|
+
|
97
|
+
|
98
|
+
pthread_mutex_t put_redirect_handler_mutex;
|
99
|
+
|
100
|
+
int put_redirect_handler( REDIRECTHANDLER redirect_handler) {
|
101
|
+
|
102
|
+
pthread_mutex_lock(&put_redirect_handler_mutex);
|
103
|
+
put_redirect_handler_(redirect_handler);
|
104
|
+
pthread_mutex_unlock(&put_redirect_handler_mutex);
|
105
|
+
}
|
106
|
+
|
107
|
+
|
108
|
+
void init_redirect() {
|
109
|
+
|
110
|
+
pthread_mutexattr_t attr;
|
111
|
+
|
112
|
+
pthread_mutexattr_init(&attr);
|
113
|
+
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
|
114
|
+
|
115
|
+
pthread_mutex_init( &put_redirect_handler_mutex, &attr);
|
116
|
+
|
117
|
+
init_hook_rb_call();
|
118
|
+
rb_call_fake_init();
|
119
|
+
}
|
120
|
+
|
121
|
+
|
122
|
+
|
@@ -0,0 +1,33 @@
|
|
1
|
+
/*
|
2
|
+
|
3
|
+
This file is part of the rallhook project, http://github.com/tario/rallhook
|
4
|
+
|
5
|
+
Copyright (c) 2009-2010 Roberto Dario Seminara <robertodarioseminara@gmail.com>
|
6
|
+
|
7
|
+
rallhook is free software: you can redistribute it and/or modify
|
8
|
+
it under the terms of the gnu general public license as published by
|
9
|
+
the free software foundation, either version 3 of the license, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
rallhook is distributed in the hope that it will be useful,
|
13
|
+
but without any warranty; without even the implied warranty of
|
14
|
+
merchantability or fitness for a particular purpose. see the
|
15
|
+
gnu general public license for more details.
|
16
|
+
|
17
|
+
you should have received a copy of the gnu general public license
|
18
|
+
along with rallhook. if not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
*/
|
21
|
+
#ifndef __RUBY_REDIRECT_H
|
22
|
+
#define __RUBY_REDIRECT_H
|
23
|
+
|
24
|
+
// Acts as facade of the division between the ruby interpreter modification
|
25
|
+
|
26
|
+
#include <ruby.h>
|
27
|
+
|
28
|
+
typedef void (*REDIRECTHANDLER) ( VALUE* klass, VALUE* recv, ID* mid );
|
29
|
+
int put_redirect_handler( REDIRECTHANDLER redirect_handler);
|
30
|
+
|
31
|
+
void init_redirect();
|
32
|
+
|
33
|
+
#endif
|
@@ -0,0 +1,43 @@
|
|
1
|
+
/*
|
2
|
+
|
3
|
+
This file is part of the rallhook project, http://github.com/tario/rallhook
|
4
|
+
|
5
|
+
Copyright (c) 2009-2010 Roberto Dario Seminara <robertodarioseminara@gmail.com>
|
6
|
+
|
7
|
+
rallhook is free software: you can redistribute it and/or modify
|
8
|
+
it under the terms of the gnu general public license as published by
|
9
|
+
the free software foundation, either version 3 of the license, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
rallhook is distributed in the hope that it will be useful,
|
13
|
+
but without any warranty; without even the implied warranty of
|
14
|
+
merchantability or fitness for a particular purpose. see the
|
15
|
+
gnu general public license for more details.
|
16
|
+
|
17
|
+
you should have received a copy of the gnu general public license
|
18
|
+
along with rallhook. if not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
*/
|
21
|
+
|
22
|
+
#include "ruby_symbols.h"
|
23
|
+
#include "ruby.h"
|
24
|
+
|
25
|
+
void* ruby_resolv(unsigned char* p_base, const char* symbol_name) {
|
26
|
+
VALUE rb_mCymbol = rb_eval_string("Cymbol");
|
27
|
+
VALUE rb_str_symbol_name = rb_str_new2(symbol_name);
|
28
|
+
|
29
|
+
VALUE rb_offset = rb_funcall(rb_mCymbol,rb_intern("resolv"), 1, rb_str_symbol_name);
|
30
|
+
|
31
|
+
unsigned long long offset = FIX2LONG(rb_offset);
|
32
|
+
|
33
|
+
return (p_base + offset);
|
34
|
+
}
|
35
|
+
|
36
|
+
|
37
|
+
const char* current_libruby() {
|
38
|
+
VALUE rb_mCymbol = rb_eval_string("Cymbol");
|
39
|
+
VALUE rb_strSharedName = rb_funcall(rb_mCymbol,rb_intern("ruby_shared_name"), 0);
|
40
|
+
|
41
|
+
return rb_string_value_ptr(&rb_strSharedName);
|
42
|
+
}
|
43
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
/*
|
2
|
+
|
3
|
+
This file is part of the rallhook project, http://github.com/tario/rallhook
|
4
|
+
|
5
|
+
Copyright (c) 2009-2010 Roberto Dario Seminara <robertodarioseminara@gmail.com>
|
6
|
+
|
7
|
+
rallhook is free software: you can redistribute it and/or modify
|
8
|
+
it under the terms of the gnu general public license as published by
|
9
|
+
the free software foundation, either version 3 of the license, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
rallhook is distributed in the hope that it will be useful,
|
13
|
+
but without any warranty; without even the implied warranty of
|
14
|
+
merchantability or fitness for a particular purpose. see the
|
15
|
+
gnu general public license for more details.
|
16
|
+
|
17
|
+
you should have received a copy of the gnu general public license
|
18
|
+
along with rallhook. if not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
*/
|
21
|
+
|
22
|
+
#ifndef __RUBY_SYMBOLS_H
|
23
|
+
#define __RUBY_SYMBOLS_H
|
24
|
+
|
25
|
+
void* ruby_resolv(unsigned char* p_base, const char* symbol_name);
|
26
|
+
const char* current_libruby();
|
27
|
+
|
28
|
+
#endif
|
@@ -0,0 +1,21 @@
|
|
1
|
+
/*
|
2
|
+
|
3
|
+
This file is part of the rallhook project, http://github.com/tario/rallhook
|
4
|
+
|
5
|
+
Copyright (c) 2009-2010 Roberto Dario Seminara <robertodarioseminara@gmail.com>
|
6
|
+
|
7
|
+
rallhook is free software: you can redistribute it and/or modify
|
8
|
+
it under the terms of the gnu general public license as published by
|
9
|
+
the free software foundation, either version 3 of the license, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
rallhook is distributed in the hope that it will be useful,
|
13
|
+
but without any warranty; without even the implied warranty of
|
14
|
+
merchantability or fitness for a particular purpose. see the
|
15
|
+
gnu general public license for more details.
|
16
|
+
|
17
|
+
you should have received a copy of the gnu general public license
|
18
|
+
along with rallhook. if not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
*/
|
21
|
+
|
@@ -0,0 +1,37 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
This file is part of the rallhook project, http://github.com/tario/
|
4
|
+
|
5
|
+
Copyright (c) 2009-2010 Roberto Dario Seminara <robertodarioseminara@gmail.com>
|
6
|
+
|
7
|
+
rallhook is free software: you can redistribute it and/or modify
|
8
|
+
it under the terms of the gnu general public license as published by
|
9
|
+
the free software foundation, either version 3 of the license, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
rallhook is distributed in the hope that it will be useful,
|
13
|
+
but without any warranty; without even the implied warranty of
|
14
|
+
merchantability or fitness for a particular purpose. see the
|
15
|
+
gnu general public license for more details.
|
16
|
+
|
17
|
+
you should have received a copy of the gnu general public license
|
18
|
+
along with rallhook. if not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
=end
|
21
|
+
class Thread
|
22
|
+
|
23
|
+
class << self
|
24
|
+
alias :original_new :new
|
25
|
+
|
26
|
+
private :original_new
|
27
|
+
|
28
|
+
def new
|
29
|
+
parent = current
|
30
|
+
original_new do
|
31
|
+
parent.acquire_attributes do
|
32
|
+
yield
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/rallhook.rb
ADDED
@@ -0,0 +1,384 @@
|
|
1
|
+
=begin
|
2
|
+
|
3
|
+
This file is part of the rallhook project, http://github.com/tario/
|
4
|
+
|
5
|
+
Copyright (c) 2009-2010 Roberto Dario Seminara <robertodarioseminara@gmail.com>
|
6
|
+
|
7
|
+
rallhook is free software: you can redistribute it and/or modify
|
8
|
+
it under the terms of the gnu general public license as published by
|
9
|
+
the free software foundation, either version 3 of the license, or
|
10
|
+
(at your option) any later version.
|
11
|
+
|
12
|
+
rallhook is distributed in the hope that it will be useful,
|
13
|
+
but without any warranty; without even the implied warranty of
|
14
|
+
merchantability or fitness for a particular purpose. see the
|
15
|
+
gnu general public license for more details.
|
16
|
+
|
17
|
+
you should have received a copy of the gnu general public license
|
18
|
+
along with rallhook. if not, see <http://www.gnu.org/licenses/>.
|
19
|
+
|
20
|
+
=end
|
21
|
+
require "rubygems"
|
22
|
+
require "rallhook_base"
|
23
|
+
require "rallhook/thread_hook"
|
24
|
+
|
25
|
+
module RallHook
|
26
|
+
#
|
27
|
+
#Internal class used for return method redirection messages
|
28
|
+
#Example:
|
29
|
+
# ...
|
30
|
+
# class X
|
31
|
+
# def foo
|
32
|
+
# end
|
33
|
+
# end
|
34
|
+
# def handle_method
|
35
|
+
# return RallHook::Redirect.new(X, X.new, :foo)
|
36
|
+
# end
|
37
|
+
# ...
|
38
|
+
#
|
39
|
+
#Note: Use x.redirect(:foo) instead (see Object#redirect )
|
40
|
+
#
|
41
|
+
class Redirect
|
42
|
+
include MethodRedirect
|
43
|
+
|
44
|
+
attr_reader :recv
|
45
|
+
|
46
|
+
def initialize(klass, recv, m, unhook = nil)
|
47
|
+
@klass = klass
|
48
|
+
@recv = recv
|
49
|
+
@method = m
|
50
|
+
@unhook = unhook
|
51
|
+
end
|
52
|
+
end
|
53
|
+
#
|
54
|
+
#Internal class used by RallHook::Helper#return_value
|
55
|
+
#
|
56
|
+
class ReturnHolder
|
57
|
+
def initialize(v)
|
58
|
+
@value = v
|
59
|
+
end
|
60
|
+
def value(*x)
|
61
|
+
@value
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
#
|
66
|
+
#This module brings together classes and methods to facilitate the handling
|
67
|
+
#
|
68
|
+
module Helper
|
69
|
+
|
70
|
+
#Equivalent to:
|
71
|
+
# recv.redirect(m, klass)
|
72
|
+
def redirect_call(klass, recv, m)
|
73
|
+
::RallHook::Redirect.new(klass,recv,m)
|
74
|
+
end
|
75
|
+
|
76
|
+
#Return a value as return value of the method being handled
|
77
|
+
#Example:
|
78
|
+
#
|
79
|
+
# include RallHook::Helper
|
80
|
+
# def handle_method
|
81
|
+
# return_value(4) # all methods called returns 4
|
82
|
+
# end
|
83
|
+
#
|
84
|
+
def return_value(v)
|
85
|
+
recv = ReturnHolder.new(v)
|
86
|
+
klass = recv.class
|
87
|
+
m = :value
|
88
|
+
redirect_call(klass, recv, m)
|
89
|
+
end
|
90
|
+
|
91
|
+
#
|
92
|
+
#This class acts as base to define classes that acts as receptors and wrappers of
|
93
|
+
#redirected methods. Allows interception of methods with its parameters and controlled recall
|
94
|
+
#in a hooking logic
|
95
|
+
#
|
96
|
+
#Example 1: basic modifications of arguments
|
97
|
+
#
|
98
|
+
# class MethodHandler
|
99
|
+
# include RallHook::Helper
|
100
|
+
#
|
101
|
+
# class FooMethodWrapper < RallHook::MethodWrapper
|
102
|
+
# def call(foo_argument)
|
103
|
+
# original_call(foo_argument + 5) # add 5 in all calls to foo
|
104
|
+
# end
|
105
|
+
# end
|
106
|
+
#
|
107
|
+
# def handle_method (klass,recv,m,method_id)
|
108
|
+
# if m == :foo
|
109
|
+
# FooMethodWrapper.redirect_handler(klass,recv,m,method_id)
|
110
|
+
# else
|
111
|
+
# nil
|
112
|
+
# end
|
113
|
+
# end
|
114
|
+
# end
|
115
|
+
#
|
116
|
+
# ... hooking using MethodHandler ( see Hook#hook, README and examples)
|
117
|
+
#
|
118
|
+
#
|
119
|
+
#Example 2: generic recall of methods
|
120
|
+
#
|
121
|
+
# class MethodHandler
|
122
|
+
# include RallHook::Helper
|
123
|
+
#
|
124
|
+
# class GenericMethodWrapper < RallHook::MethodWrapper
|
125
|
+
# def call(*x)
|
126
|
+
# # call with reyield if block_given
|
127
|
+
# if block_given?
|
128
|
+
# original_call(*x) do |*a|
|
129
|
+
# yield(*a)
|
130
|
+
# end
|
131
|
+
# else
|
132
|
+
# original_call(*x)
|
133
|
+
# end
|
134
|
+
# end
|
135
|
+
# end
|
136
|
+
#
|
137
|
+
# def handle_method (klass,recv,m,method_id)
|
138
|
+
# return GenericMethodWrapper.redirect_handler(klass,recv,m,method_id)
|
139
|
+
# end
|
140
|
+
# end
|
141
|
+
#
|
142
|
+
# ... hooking using MethodHandler ( see Hook#hook, README and examples)
|
143
|
+
#
|
144
|
+
#
|
145
|
+
class MethodWrapper
|
146
|
+
|
147
|
+
attr_accessor :klass, :recv, :method_name, :method_id
|
148
|
+
|
149
|
+
#Reactivate the hook status to intercept methods
|
150
|
+
#Allow to pass a block to enable the hook status only in that block
|
151
|
+
#
|
152
|
+
#Example:
|
153
|
+
# class MethodHandler
|
154
|
+
# include RallHook::Helper
|
155
|
+
#
|
156
|
+
# class FooMethodWrapper < RallHook::MethodWrapper
|
157
|
+
# def call(foo_argument)
|
158
|
+
# original_call(foo_argument + 5) # add 5 in all calls to foo
|
159
|
+
# rehook do # the print "hello world hooked" are intercepted too
|
160
|
+
# print "hello world hooked\n"
|
161
|
+
# end
|
162
|
+
# end
|
163
|
+
# end
|
164
|
+
#
|
165
|
+
# ... definition of handle_method that use FooMethodWrapper as redirect, etc...
|
166
|
+
#
|
167
|
+
#Note: is not necesary to use rehook to hook the nested calls in original_call
|
168
|
+
#MethodWrapper#original_call does that internally
|
169
|
+
#
|
170
|
+
def rehook
|
171
|
+
if block_given?
|
172
|
+
::RallHook::Hook.rehook do
|
173
|
+
yield
|
174
|
+
end
|
175
|
+
else
|
176
|
+
::RallHook::Hook.rehook
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
#
|
181
|
+
#Same as Hook#from
|
182
|
+
#
|
183
|
+
def from(a)
|
184
|
+
::RallHook::Hook.from(a)
|
185
|
+
self
|
186
|
+
end
|
187
|
+
|
188
|
+
#
|
189
|
+
#Recall the original method(specified in initialization parameters)
|
190
|
+
#
|
191
|
+
def original_call(*args)
|
192
|
+
mname = self.method_name
|
193
|
+
mklass = self.klass
|
194
|
+
mid = self.method_id
|
195
|
+
recv_ = self.recv
|
196
|
+
|
197
|
+
# original calls over the shadow of the class, not the original one
|
198
|
+
m = recv_.specific_method(mklass.shadow,mname)
|
199
|
+
|
200
|
+
if block_given?
|
201
|
+
from(3).rehook do
|
202
|
+
m.call(*args) do |*blockargs|
|
203
|
+
yield(*blockargs)
|
204
|
+
end
|
205
|
+
end
|
206
|
+
else
|
207
|
+
from(3).rehook do
|
208
|
+
m.call(*args)
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
#
|
214
|
+
#Target of redirection, should be implemented to intercept the call
|
215
|
+
#
|
216
|
+
def call(*args)
|
217
|
+
end
|
218
|
+
|
219
|
+
def call_with_rehook(*args)
|
220
|
+
if block_given?
|
221
|
+
call(*args) do |*x|
|
222
|
+
yield(*x)
|
223
|
+
end
|
224
|
+
else
|
225
|
+
call(*args)
|
226
|
+
end
|
227
|
+
ensure
|
228
|
+
rehook
|
229
|
+
end
|
230
|
+
|
231
|
+
#
|
232
|
+
#Makes a redirect_handler to wrap a method call with this MethodWrapper. Example:
|
233
|
+
#
|
234
|
+
# FooMethodWrapper.redirect_handler(klass,recv,m,method_id)
|
235
|
+
#
|
236
|
+
def self.redirect_handler(klass,recv,method_name, method_id)
|
237
|
+
if method_name
|
238
|
+
|
239
|
+
mw = self.new
|
240
|
+
mw.klass = klass
|
241
|
+
mw.recv = recv
|
242
|
+
mw.method_name = method_name
|
243
|
+
mw.method_id = method_id
|
244
|
+
if block_given?
|
245
|
+
yield(mw)
|
246
|
+
end
|
247
|
+
mw.redirect_with_unhook(:call_with_rehook)
|
248
|
+
else
|
249
|
+
nil
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
|
257
|
+
|
258
|
+
class HookHandler
|
259
|
+
|
260
|
+
#default method_handler of a Hook does nothing with any method call
|
261
|
+
def handle_method
|
262
|
+
nil
|
263
|
+
end
|
264
|
+
|
265
|
+
#enable the hook. Example
|
266
|
+
#
|
267
|
+
# class MethodHandler < Hook
|
268
|
+
# def handle_method
|
269
|
+
# nil # do nothing
|
270
|
+
# end
|
271
|
+
# end
|
272
|
+
#
|
273
|
+
# MethodHandler.hook do
|
274
|
+
# print "hello world\n"
|
275
|
+
# end
|
276
|
+
#
|
277
|
+
|
278
|
+
def hook
|
279
|
+
if block_given?
|
280
|
+
::RallHook::Hook.hook self do
|
281
|
+
yield
|
282
|
+
end
|
283
|
+
else
|
284
|
+
::RallHook::Hook.hook self
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
#Instance handler and activate the hook
|
289
|
+
#Example:
|
290
|
+
#
|
291
|
+
# class MethodHandler < Hook
|
292
|
+
# def handle_method
|
293
|
+
# nil # do nothing
|
294
|
+
# end
|
295
|
+
# end
|
296
|
+
#
|
297
|
+
# MethodHandler.hook do
|
298
|
+
# print "hello world\n"
|
299
|
+
# end
|
300
|
+
|
301
|
+
def self.hook
|
302
|
+
if block_given?
|
303
|
+
self.new.hook do
|
304
|
+
yield
|
305
|
+
end
|
306
|
+
else
|
307
|
+
self.new.hook
|
308
|
+
end
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
|
313
|
+
|
314
|
+
end
|
315
|
+
|
316
|
+
# To facilitate the use of hooking/redirection features,
|
317
|
+
# rallhook defines some methods in the Object class
|
318
|
+
#
|
319
|
+
|
320
|
+
class Object
|
321
|
+
|
322
|
+
|
323
|
+
# Same as redirect, but disable the hook/interception of methods (dont call handle_redirect) before
|
324
|
+
# make the call, the hook status may be restored with Hook#rehook
|
325
|
+
# Anyway, it is desirable to use MethodWrapper instead to "wrap" method calls
|
326
|
+
#
|
327
|
+
# see RallHook::Helper::MethodWrapper
|
328
|
+
#
|
329
|
+
def redirect_with_unhook(method_name, klass = nil)
|
330
|
+
if klass
|
331
|
+
::RallHook::Redirect.new(klass,self,method_name,true)
|
332
|
+
else
|
333
|
+
::RallHook::Redirect.new(self.class,self,method_name,true)
|
334
|
+
end
|
335
|
+
|
336
|
+
end
|
337
|
+
|
338
|
+
# Generates a redirect message to return it in handle_method to cause the redirection of
|
339
|
+
# the method that is beign processed with the object as receiver, the method_name the new target
|
340
|
+
# and the class as second parameter if specified
|
341
|
+
#
|
342
|
+
# Example:
|
343
|
+
# class X
|
344
|
+
# def foo(*args)
|
345
|
+
# end
|
346
|
+
# end
|
347
|
+
#
|
348
|
+
# class MethodHandler
|
349
|
+
# @@x = x.new
|
350
|
+
# def handle_method(klass, recv, m , method_id)
|
351
|
+
# if m == :bar then
|
352
|
+
# # redirect bar calls to foo in x
|
353
|
+
# return x.redirect(:foo)
|
354
|
+
# end
|
355
|
+
# nil # do nothing
|
356
|
+
# end
|
357
|
+
# end
|
358
|
+
#
|
359
|
+
# # hook using MethodHandler, etc... (see README and examples)
|
360
|
+
#
|
361
|
+
#
|
362
|
+
def redirect(method_name, klass = nil)
|
363
|
+
if klass
|
364
|
+
::RallHook::Redirect.new(klass,self,method_name)
|
365
|
+
else
|
366
|
+
::RallHook::Redirect.new(self.class,self,method_name)
|
367
|
+
end
|
368
|
+
end
|
369
|
+
|
370
|
+
def specific_method(arg1, arg2=nil)
|
371
|
+
if arg2
|
372
|
+
method_name = arg2
|
373
|
+
klass = arg1
|
374
|
+
|
375
|
+
if instance_of? Class
|
376
|
+
method(method_name)
|
377
|
+
else
|
378
|
+
klass.shadow.instance_method(method_name).unchecked_bind(self)
|
379
|
+
end
|
380
|
+
else
|
381
|
+
method(arg1)
|
382
|
+
end
|
383
|
+
end
|
384
|
+
end
|