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,398 @@
|
|
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.h>
|
23
|
+
|
24
|
+
#ifdef RUBY1_8
|
25
|
+
#include <node.h>
|
26
|
+
#include <env.h> // from ruby
|
27
|
+
#endif
|
28
|
+
|
29
|
+
#include <dlfcn.h>
|
30
|
+
#include <stdarg.h>
|
31
|
+
#include "ruby_symbols.h"
|
32
|
+
#include "rb_call_fake.h"
|
33
|
+
#include "ruby_redirect.h"
|
34
|
+
|
35
|
+
void* rb_call_copy;
|
36
|
+
|
37
|
+
extern REDIRECTHANDLER current_redirect_handler;
|
38
|
+
|
39
|
+
#ifdef __i386__
|
40
|
+
|
41
|
+
VALUE read_eax( ) {
|
42
|
+
}
|
43
|
+
|
44
|
+
VALUE read_edx( ) {
|
45
|
+
__asm__("mov %edx, %eax");
|
46
|
+
}
|
47
|
+
|
48
|
+
VALUE read_ecx( ) {
|
49
|
+
__asm__("mov %ecx, %eax");
|
50
|
+
}
|
51
|
+
|
52
|
+
int rb_call_write_eax(int value) {
|
53
|
+
return value;
|
54
|
+
}
|
55
|
+
|
56
|
+
int is_fastcall = 1;
|
57
|
+
int is_calibrate = 0;
|
58
|
+
int vm_is_fastcall = 1;
|
59
|
+
int vm_is_calibrate = 0;
|
60
|
+
VALUE calibrate_klass;
|
61
|
+
VALUE calibrate_recv;
|
62
|
+
ID calibrate_mid;
|
63
|
+
|
64
|
+
#endif
|
65
|
+
|
66
|
+
#ifdef RUBY1_9
|
67
|
+
|
68
|
+
VMCALLMETHOD vm_call_method_copy;
|
69
|
+
|
70
|
+
typedef void rb_vm_t_;
|
71
|
+
#endif
|
72
|
+
|
73
|
+
VALUE rb_call_copy_i(
|
74
|
+
VALUE klass, VALUE recv,
|
75
|
+
ID mid,
|
76
|
+
int argc, /* OK */
|
77
|
+
const VALUE *argv, /* OK */
|
78
|
+
int scope,
|
79
|
+
VALUE self
|
80
|
+
) {
|
81
|
+
#ifdef __i386__
|
82
|
+
if (is_fastcall == 1) {
|
83
|
+
|
84
|
+
int array[7] = { (int)klass, (int)recv, mid, argc, (int)argv, scope, (int)self };
|
85
|
+
rb_call_write_eax(array);
|
86
|
+
|
87
|
+
__asm__("push %ebp\n"); // save all registers
|
88
|
+
__asm__("push %esi\n");
|
89
|
+
__asm__("push %edi\n");
|
90
|
+
__asm__("push %ebx\n");
|
91
|
+
__asm__("push %edx\n");
|
92
|
+
__asm__("push %ecx\n");
|
93
|
+
__asm__("mov 0x4(%eax), %edx\n");
|
94
|
+
__asm__("mov 0x8(%eax), %ecx\n");
|
95
|
+
__asm__("push 0x18(%eax)\n");
|
96
|
+
__asm__("push 0x14(%eax)\n");
|
97
|
+
__asm__("push 0x10(%eax)\n");
|
98
|
+
__asm__("push 0x0c(%eax)\n");
|
99
|
+
__asm__("mov (%eax), %eax\n");
|
100
|
+
__asm__("call *rb_call_copy\n");
|
101
|
+
__asm__("add $0x10, %esp\n");
|
102
|
+
__asm__("pop %ecx\n");
|
103
|
+
__asm__("pop %edx\n");
|
104
|
+
__asm__("pop %ebx\n");
|
105
|
+
__asm__("pop %edi\n");
|
106
|
+
__asm__("pop %esi\n");
|
107
|
+
__asm__("pop %ebp\n");
|
108
|
+
return read_eax();
|
109
|
+
|
110
|
+
} else if ( is_fastcall == 2) {
|
111
|
+
int array[7] = { (int)klass, (int)recv, mid, argc, (int)argv, scope, (int)self };
|
112
|
+
rb_call_write_eax(array);
|
113
|
+
|
114
|
+
__asm__("push %ebp\n"); // save all registers
|
115
|
+
__asm__("push %esi\n");
|
116
|
+
__asm__("push %edi\n");
|
117
|
+
__asm__("push %ebx\n");
|
118
|
+
__asm__("push %edx\n");
|
119
|
+
__asm__("push %ecx\n");
|
120
|
+
__asm__("mov 0x4(%eax), %edx\n");
|
121
|
+
__asm__("push 0x18(%eax)\n");
|
122
|
+
__asm__("push 0x14(%eax)\n");
|
123
|
+
__asm__("push 0x10(%eax)\n");
|
124
|
+
__asm__("push 0x0c(%eax)\n");
|
125
|
+
__asm__("push 0x08(%eax)\n");
|
126
|
+
__asm__("mov (%eax), %eax\n");
|
127
|
+
__asm__("call *rb_call_copy\n");
|
128
|
+
__asm__("add $0x14, %esp\n");
|
129
|
+
__asm__("pop %ecx\n");
|
130
|
+
__asm__("pop %edx\n");
|
131
|
+
__asm__("pop %ebx\n");
|
132
|
+
__asm__("pop %edi\n");
|
133
|
+
__asm__("pop %esi\n");
|
134
|
+
__asm__("pop %ebp\n");
|
135
|
+
return read_eax();
|
136
|
+
|
137
|
+
} else {
|
138
|
+
#endif
|
139
|
+
return ((RBCALL)rb_call_copy)(klass,recv,mid,argc,argv,scope,self);
|
140
|
+
#ifdef __i386__
|
141
|
+
}
|
142
|
+
#endif
|
143
|
+
|
144
|
+
}
|
145
|
+
|
146
|
+
#ifdef RUBY1_9
|
147
|
+
|
148
|
+
VALUE
|
149
|
+
vm_call_method_i(rb_thread_t_ * const th, rb_control_frame_t_ * const cfp,
|
150
|
+
const int num, rb_block_t_ * const blockptr, const VALUE flag,
|
151
|
+
const ID id, void * mn, const VALUE recv_, VALUE klass)
|
152
|
+
{
|
153
|
+
|
154
|
+
#ifdef __i386__
|
155
|
+
if (vm_is_fastcall == 1) {
|
156
|
+
|
157
|
+
int array[9] = { (int)th, (int)cfp, num, (int)blockptr, (int)flag, (int)id, (int)mn, (int)recv_, (int)klass };
|
158
|
+
rb_call_write_eax(array);
|
159
|
+
|
160
|
+
__asm__("push %ebp\n"); // save all registers
|
161
|
+
__asm__("push %esi\n");
|
162
|
+
__asm__("push %edi\n");
|
163
|
+
__asm__("push %ebx\n");
|
164
|
+
__asm__("push %edx\n");
|
165
|
+
__asm__("push %ecx\n");
|
166
|
+
__asm__("mov 0x4(%eax), %edx\n");
|
167
|
+
__asm__("mov 0x8(%eax), %ecx\n");
|
168
|
+
__asm__("push 0x20(%eax)\n");
|
169
|
+
__asm__("push 0x1c(%eax)\n");
|
170
|
+
__asm__("push 0x18(%eax)\n");
|
171
|
+
__asm__("push 0x14(%eax)\n");
|
172
|
+
__asm__("push 0x10(%eax)\n");
|
173
|
+
__asm__("push 0x0c(%eax)\n");
|
174
|
+
__asm__("mov (%eax), %eax\n");
|
175
|
+
__asm__("call *vm_call_method_copy\n");
|
176
|
+
__asm__("add $0x18, %esp\n");
|
177
|
+
__asm__("pop %ecx\n");
|
178
|
+
__asm__("pop %edx\n");
|
179
|
+
__asm__("pop %ebx\n");
|
180
|
+
__asm__("pop %edi\n");
|
181
|
+
__asm__("pop %esi\n");
|
182
|
+
__asm__("pop %ebp\n");
|
183
|
+
return read_eax();
|
184
|
+
|
185
|
+
} else if ( vm_is_fastcall == 2) {
|
186
|
+
int array[9] = { (int)th, (int)cfp, num, (int)blockptr, (int)flag, (int)id, (int)mn, (int)recv_, (int)klass };
|
187
|
+
rb_call_write_eax(array);
|
188
|
+
|
189
|
+
__asm__("push %ebp\n"); // save all registers
|
190
|
+
__asm__("push %esi\n");
|
191
|
+
__asm__("push %edi\n");
|
192
|
+
__asm__("push %ebx\n");
|
193
|
+
__asm__("push %edx\n");
|
194
|
+
__asm__("push %ecx\n");
|
195
|
+
__asm__("mov 0x4(%eax), %edx\n");
|
196
|
+
__asm__("push 0x20(%eax)\n");
|
197
|
+
__asm__("push 0x1c(%eax)\n");
|
198
|
+
__asm__("push 0x18(%eax)\n");
|
199
|
+
__asm__("push 0x14(%eax)\n");
|
200
|
+
__asm__("push 0x10(%eax)\n");
|
201
|
+
__asm__("push 0x0c(%eax)\n");
|
202
|
+
__asm__("push 0x08(%eax)\n");
|
203
|
+
__asm__("mov (%eax), %eax\n");
|
204
|
+
__asm__("call *vm_call_method_copy\n");
|
205
|
+
__asm__("add $0x1c, %esp\n");
|
206
|
+
__asm__("pop %ecx\n");
|
207
|
+
__asm__("pop %edx\n");
|
208
|
+
__asm__("pop %ebx\n");
|
209
|
+
__asm__("pop %edi\n");
|
210
|
+
__asm__("pop %esi\n");
|
211
|
+
__asm__("pop %ebp\n");
|
212
|
+
return read_eax();
|
213
|
+
|
214
|
+
} else {
|
215
|
+
#endif
|
216
|
+
return vm_call_method_copy(th,cfp,num,blockptr,flag,id,mn,recv_,klass);
|
217
|
+
#ifdef __i386__
|
218
|
+
}
|
219
|
+
#endif
|
220
|
+
|
221
|
+
|
222
|
+
}
|
223
|
+
|
224
|
+
VALUE
|
225
|
+
vm_call_method_fake(rb_thread_t_ * const th, rb_control_frame_t_ * const cfp,
|
226
|
+
const int num, rb_block_t_ * const blockptr, const VALUE flag,
|
227
|
+
ID id, void * mn, VALUE recv, VALUE klass)
|
228
|
+
{
|
229
|
+
VALUE klass_copy = klass;
|
230
|
+
VALUE recv_copy = recv;
|
231
|
+
ID id_copy = id;
|
232
|
+
|
233
|
+
current_redirect_handler(&klass, &recv, &id);
|
234
|
+
|
235
|
+
if (id_copy != id || klass_copy != klass || recv_copy != recv) {
|
236
|
+
mn = rb_get_method_body(klass, id, 0);
|
237
|
+
}
|
238
|
+
|
239
|
+
return vm_call_method_i(
|
240
|
+
th,
|
241
|
+
cfp,
|
242
|
+
num,
|
243
|
+
blockptr,
|
244
|
+
flag,
|
245
|
+
id,
|
246
|
+
mn,
|
247
|
+
recv,
|
248
|
+
klass);
|
249
|
+
|
250
|
+
|
251
|
+
}
|
252
|
+
|
253
|
+
#ifdef __i386__
|
254
|
+
|
255
|
+
VALUE vm_call_method_fake_regs(
|
256
|
+
_WORD eax, _WORD edx, _WORD ecx, _WORD* esp
|
257
|
+
) {
|
258
|
+
|
259
|
+
esp++;
|
260
|
+
|
261
|
+
if (vm_is_calibrate) {
|
262
|
+
if ((VALUE)esp[7] == calibrate_recv && (VALUE)esp[8] == calibrate_klass && (ID)esp[5] == calibrate_mid) {
|
263
|
+
vm_is_fastcall = 0;
|
264
|
+
} else if ( (VALUE)esp[5] == calibrate_recv ) {
|
265
|
+
vm_is_fastcall = 2;
|
266
|
+
} else {
|
267
|
+
vm_is_fastcall = 1;
|
268
|
+
}
|
269
|
+
vm_is_calibrate = 0;
|
270
|
+
}
|
271
|
+
|
272
|
+
if (vm_is_fastcall == 0) {
|
273
|
+
return vm_call_method_fake(
|
274
|
+
(rb_thread_t_*)esp[0],
|
275
|
+
(rb_control_frame_t_*)esp[1],
|
276
|
+
(int)esp[2],
|
277
|
+
(rb_block_t_*)esp[3],
|
278
|
+
(VALUE)esp[3],
|
279
|
+
(ID)esp[4],
|
280
|
+
(void*)esp[5],
|
281
|
+
(VALUE)esp[6],
|
282
|
+
(VALUE)esp[7]
|
283
|
+
);
|
284
|
+
} else if (vm_is_fastcall == 2 ) {
|
285
|
+
return vm_call_method_fake(
|
286
|
+
(rb_thread_t_*)eax,
|
287
|
+
(rb_control_frame_t_*)edx,
|
288
|
+
(int)esp[0],
|
289
|
+
(rb_block_t_*)esp[1],
|
290
|
+
(VALUE)esp[2],
|
291
|
+
(ID)esp[3],
|
292
|
+
(void*)esp[4],
|
293
|
+
(VALUE)esp[5],
|
294
|
+
(VALUE)esp[6]
|
295
|
+
);
|
296
|
+
|
297
|
+
} else {
|
298
|
+
return vm_call_method_fake(
|
299
|
+
(rb_thread_t_*)eax,
|
300
|
+
(rb_control_frame_t_*)edx,
|
301
|
+
(int)ecx,
|
302
|
+
(rb_block_t_*)esp[0],
|
303
|
+
(VALUE)esp[1],
|
304
|
+
(ID)esp[2],
|
305
|
+
(void*)esp[3],
|
306
|
+
(VALUE)esp[4],
|
307
|
+
(VALUE)esp[5]
|
308
|
+
);
|
309
|
+
|
310
|
+
}
|
311
|
+
|
312
|
+
}
|
313
|
+
|
314
|
+
#endif
|
315
|
+
|
316
|
+
#endif
|
317
|
+
|
318
|
+
|
319
|
+
VALUE
|
320
|
+
rb_call_fake(
|
321
|
+
VALUE klass, VALUE recv,
|
322
|
+
ID mid,
|
323
|
+
int argc, /* OK */
|
324
|
+
const VALUE *argv, /* OK */
|
325
|
+
int scope,
|
326
|
+
VALUE self
|
327
|
+
) {
|
328
|
+
|
329
|
+
current_redirect_handler(&klass, &recv, &mid);
|
330
|
+
return rb_call_copy_i(klass,recv,mid,argc,argv,scope,self);
|
331
|
+
|
332
|
+
}
|
333
|
+
|
334
|
+
|
335
|
+
#ifdef __i386__
|
336
|
+
|
337
|
+
VALUE
|
338
|
+
rb_call_fake_regs(
|
339
|
+
_WORD eax, _WORD edx, _WORD ecx, _WORD* esp
|
340
|
+
) {
|
341
|
+
VALUE klass;
|
342
|
+
VALUE recv;
|
343
|
+
ID mid;
|
344
|
+
int argc; /* OK */
|
345
|
+
const VALUE *argv;
|
346
|
+
int scope;
|
347
|
+
VALUE self;
|
348
|
+
|
349
|
+
esp++;
|
350
|
+
|
351
|
+
|
352
|
+
if (is_calibrate) {
|
353
|
+
|
354
|
+
if ((VALUE)edx == calibrate_recv && (VALUE)eax == calibrate_klass && (ID)ecx == calibrate_mid) {
|
355
|
+
is_fastcall = 1;
|
356
|
+
} else if ( (VALUE)edx == calibrate_recv && (VALUE)eax == calibrate_klass && (ID)esp[0] == calibrate_mid ) {
|
357
|
+
is_fastcall = 2;
|
358
|
+
} else {
|
359
|
+
is_fastcall = 0;
|
360
|
+
}
|
361
|
+
is_calibrate = 0;
|
362
|
+
return Qnil;
|
363
|
+
}
|
364
|
+
|
365
|
+
if (is_fastcall == 0) {
|
366
|
+
klass = (VALUE)esp[0];
|
367
|
+
recv = (VALUE)esp[1];
|
368
|
+
mid = (ID)esp[2];
|
369
|
+
argc = (int)esp[3];
|
370
|
+
argv = (VALUE*)esp[4];
|
371
|
+
scope = (int)esp[5];
|
372
|
+
self = (VALUE)esp[6];
|
373
|
+
} else if (is_fastcall == 2) {
|
374
|
+
klass = (VALUE)eax;
|
375
|
+
recv = (VALUE)edx;
|
376
|
+
mid = (VALUE)esp[0];
|
377
|
+
argc = (int)esp[1];
|
378
|
+
argv = (VALUE*)esp[2];
|
379
|
+
scope = (int)esp[3];
|
380
|
+
self = (VALUE)esp[4];
|
381
|
+
} else {
|
382
|
+
klass = (VALUE)eax;
|
383
|
+
recv = (VALUE)edx;
|
384
|
+
mid = (VALUE)ecx;
|
385
|
+
argc = (int)esp[0];
|
386
|
+
argv = (VALUE*)esp[1];
|
387
|
+
scope = (int)esp[2];
|
388
|
+
self = (VALUE)esp[3];
|
389
|
+
}
|
390
|
+
return rb_call_fake(klass,recv,mid,argc,argv,scope,self);
|
391
|
+
}
|
392
|
+
|
393
|
+
#endif
|
394
|
+
|
395
|
+
void
|
396
|
+
rb_call_fake_init() {
|
397
|
+
|
398
|
+
}
|
@@ -0,0 +1,138 @@
|
|
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 __RB_CALL_FAKE_H
|
23
|
+
#define __RB_CALL_FAKE_H
|
24
|
+
|
25
|
+
#include <ruby.h>
|
26
|
+
#include "ruby_version.h"
|
27
|
+
|
28
|
+
#define FASTCALL
|
29
|
+
|
30
|
+
void
|
31
|
+
rb_call_fake_init();
|
32
|
+
|
33
|
+
typedef VALUE (*RBCALL_FASTCALL) (
|
34
|
+
int argc, /* OK */
|
35
|
+
const VALUE *argv, /* OK */
|
36
|
+
int scope,
|
37
|
+
VALUE self
|
38
|
+
) FASTCALL;
|
39
|
+
|
40
|
+
typedef VALUE (*RBCALL) (
|
41
|
+
VALUE klass, VALUE recv,
|
42
|
+
ID mid,
|
43
|
+
int argc, /* OK */
|
44
|
+
const VALUE *argv, /* OK */
|
45
|
+
int scope,
|
46
|
+
VALUE self
|
47
|
+
);
|
48
|
+
|
49
|
+
//typedef void rb_control_frame_t;
|
50
|
+
|
51
|
+
|
52
|
+
#ifdef RUBY1_9
|
53
|
+
|
54
|
+
typedef void rb_block_t_;
|
55
|
+
typedef void rb_iseq_t_;
|
56
|
+
typedef void rb_thread_t_;
|
57
|
+
// from vm_core.h
|
58
|
+
typedef struct {
|
59
|
+
VALUE *pc;
|
60
|
+
VALUE *sp;
|
61
|
+
VALUE *bp;
|
62
|
+
rb_iseq_t_ *iseq;
|
63
|
+
VALUE flag;
|
64
|
+
VALUE self;
|
65
|
+
VALUE *lfp;
|
66
|
+
VALUE *dfp;
|
67
|
+
rb_iseq_t_ *block_iseq;
|
68
|
+
VALUE proc;
|
69
|
+
ID method_id;
|
70
|
+
VALUE method_class;
|
71
|
+
} rb_control_frame_t_;
|
72
|
+
|
73
|
+
typedef VALUE (*VMCALLMETHOD) (
|
74
|
+
rb_thread_t_ * th, rb_control_frame_t_ *cfp,
|
75
|
+
const int num, rb_block_t_ * blockptr, const VALUE flag,
|
76
|
+
const ID id, void * mn, const VALUE recv, VALUE klass
|
77
|
+
) ;
|
78
|
+
#endif
|
79
|
+
|
80
|
+
extern void* rb_call_copy;
|
81
|
+
|
82
|
+
#ifdef RUBY1_9
|
83
|
+
extern VMCALLMETHOD vm_call_method_copy;
|
84
|
+
VALUE
|
85
|
+
vm_call_method_fake(rb_thread_t_ * const th, rb_control_frame_t_ * const cfp,
|
86
|
+
const int num, rb_block_t_ * const blockptr, const VALUE flag,
|
87
|
+
const ID id, void * mn, const VALUE recv_, VALUE klass);
|
88
|
+
#endif
|
89
|
+
|
90
|
+
#ifdef __i386__
|
91
|
+
#define _WORD int
|
92
|
+
#else
|
93
|
+
#define _WORD long int
|
94
|
+
#endif
|
95
|
+
|
96
|
+
|
97
|
+
VALUE
|
98
|
+
rb_call_fake(
|
99
|
+
VALUE klass, VALUE recv,
|
100
|
+
ID mid,
|
101
|
+
int argc, /* OK */
|
102
|
+
const VALUE *argv, /* OK */
|
103
|
+
int scope,
|
104
|
+
VALUE self
|
105
|
+
);
|
106
|
+
|
107
|
+
#ifdef __i386__
|
108
|
+
|
109
|
+
#ifndef _WORD
|
110
|
+
#define _WORD int
|
111
|
+
#endif
|
112
|
+
|
113
|
+
VALUE
|
114
|
+
rb_call_fake_regs(
|
115
|
+
_WORD eax, _WORD edx, _WORD ecx, _WORD* esp
|
116
|
+
);
|
117
|
+
|
118
|
+
VALUE
|
119
|
+
vm_call_method_fake_regs(
|
120
|
+
_WORD eax, _WORD edx, _WORD ecx, _WORD* esp
|
121
|
+
);
|
122
|
+
|
123
|
+
#endif
|
124
|
+
|
125
|
+
|
126
|
+
extern void* rb_call_original;
|
127
|
+
|
128
|
+
#ifdef __i386__
|
129
|
+
extern int vm_is_calibrate;
|
130
|
+
extern int is_calibrate;
|
131
|
+
extern VALUE calibrate_klass;
|
132
|
+
extern VALUE calibrate_recv;
|
133
|
+
extern ID calibrate_mid;
|
134
|
+
#endif
|
135
|
+
|
136
|
+
|
137
|
+
|
138
|
+
#endif
|
@@ -0,0 +1,176 @@
|
|
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.h"
|
22
|
+
#include "restrict_def.h"
|
23
|
+
#include "ruby_symbols.h"
|
24
|
+
#include "hook.h"
|
25
|
+
|
26
|
+
#ifndef __USE_GNU
|
27
|
+
#define __USE_GNU
|
28
|
+
#endif
|
29
|
+
|
30
|
+
#include <dlfcn.h>
|
31
|
+
|
32
|
+
ID __shadow___id;
|
33
|
+
ID __unshadow___id;
|
34
|
+
ID shadow_id;
|
35
|
+
ID id_restrict_def;
|
36
|
+
|
37
|
+
typedef void NODE_;
|
38
|
+
|
39
|
+
typedef void (*RBADDMETHOD) (
|
40
|
+
VALUE klass,
|
41
|
+
ID id,
|
42
|
+
NODE_* node,
|
43
|
+
int noex
|
44
|
+
);
|
45
|
+
|
46
|
+
RBADDMETHOD rb_add_method_copy;
|
47
|
+
|
48
|
+
typedef struct AttachedThreadInfo_ {
|
49
|
+
int hook_enabled;
|
50
|
+
int hook_enable_left;
|
51
|
+
VALUE hook_proc;
|
52
|
+
int handle_method_arity;
|
53
|
+
} AttachedThreadInfo;
|
54
|
+
|
55
|
+
AttachedThreadInfo* tinfo_from_thread(VALUE thread);
|
56
|
+
|
57
|
+
int overwrite_enabled(VALUE current_thread) {
|
58
|
+
return tinfo_from_thread(current_thread)->hook_enabled ;
|
59
|
+
}
|
60
|
+
|
61
|
+
VALUE shadow_or_create(VALUE klass);
|
62
|
+
|
63
|
+
VALUE create_shadow(VALUE klass) {
|
64
|
+
if (FL_TEST(klass, FL_SINGLETON)) {
|
65
|
+
VALUE obj = rb_iv_get(klass, "__attached__");
|
66
|
+
VALUE obj_klass = rb_obj_class(obj);
|
67
|
+
VALUE shadow_of_klass = shadow_or_create(obj_klass);
|
68
|
+
|
69
|
+
VALUE retvalue = rb_class_boot(shadow_of_klass);
|
70
|
+
FL_SET(retvalue, FL_SINGLETON);
|
71
|
+
|
72
|
+
// define as __attached__ of the new singleton class the same object
|
73
|
+
rb_iv_set(retvalue, "__attached__", obj);
|
74
|
+
return retvalue;
|
75
|
+
} else {
|
76
|
+
return rb_class_new(klass);
|
77
|
+
}
|
78
|
+
}
|
79
|
+
|
80
|
+
VALUE shadow_or_create(VALUE klass) {
|
81
|
+
|
82
|
+
VALUE shadow_klass = rb_ivar_get(klass, __shadow___id);
|
83
|
+
if ( shadow_klass == Qnil ) {
|
84
|
+
shadow_klass = create_shadow(klass);
|
85
|
+
rb_ivar_set(klass, __shadow___id, shadow_klass );
|
86
|
+
rb_ivar_set(shadow_klass, __unshadow___id, klass );
|
87
|
+
}
|
88
|
+
return shadow_klass;
|
89
|
+
}
|
90
|
+
|
91
|
+
VALUE shadow_or_original(VALUE klass) {
|
92
|
+
|
93
|
+
VALUE shadow_klass = rb_ivar_get(klass, __shadow___id);
|
94
|
+
if ( shadow_klass == Qnil ) {
|
95
|
+
return klass;
|
96
|
+
}
|
97
|
+
return shadow_klass;
|
98
|
+
|
99
|
+
}
|
100
|
+
|
101
|
+
VALUE unshadow(VALUE klass) {
|
102
|
+
VALUE unshadow_klass = rb_ivar_get(klass, __unshadow___id);
|
103
|
+
if (unshadow_klass == Qnil) {
|
104
|
+
return klass;
|
105
|
+
} else {
|
106
|
+
return unshadow_klass;
|
107
|
+
}
|
108
|
+
|
109
|
+
}
|
110
|
+
|
111
|
+
void rb_add_method_fake(
|
112
|
+
VALUE klass,
|
113
|
+
ID id,
|
114
|
+
NODE_* node,
|
115
|
+
int noex
|
116
|
+
) {
|
117
|
+
if (overwrite_enabled(rb_thread_current() )) {
|
118
|
+
if (FL_TEST(klass, FL_SINGLETON)) {
|
119
|
+
// singleton method over classes are illegal
|
120
|
+
if ( strcmp( rb_class2name(klass), "Class") == 0) {
|
121
|
+
int result;
|
122
|
+
if (st_lookup(RCLASS(klass)->m_tbl,id,&result) ) {
|
123
|
+
rb_raise(rb_eSecurityError, "Illegal overwrite of singleton method %s", rb_id2name(id) );
|
124
|
+
}
|
125
|
+
} else {
|
126
|
+
rb_add_method_copy(shadow_or_create(klass),id,node,noex);
|
127
|
+
}
|
128
|
+
} else {
|
129
|
+
rb_add_method_copy(shadow_or_create(klass),id,node,noex);
|
130
|
+
}
|
131
|
+
} else {
|
132
|
+
rb_add_method_copy(klass,id,node,noex);
|
133
|
+
}
|
134
|
+
|
135
|
+
}
|
136
|
+
|
137
|
+
void shadow_redirect(VALUE* klass, VALUE* recv, ID* mid) {
|
138
|
+
// shadow redirection if restrict_def (ever)
|
139
|
+
|
140
|
+
if (overwrite_enabled(rb_thread_current())) {
|
141
|
+
*klass = shadow_or_original(*klass);
|
142
|
+
}
|
143
|
+
}
|
144
|
+
|
145
|
+
int add_method_code_changed = 0;
|
146
|
+
|
147
|
+
void init_restrict_def() {
|
148
|
+
|
149
|
+
|
150
|
+
if (!add_method_code_changed) {
|
151
|
+
|
152
|
+
void* handle = dlopen(current_libruby(),0x101);
|
153
|
+
char* rb_funcall = (char*)dlsym(handle, "rb_funcall");
|
154
|
+
Dl_info info;
|
155
|
+
dladdr(rb_funcall, &info);
|
156
|
+
|
157
|
+
unsigned char* base = (unsigned char*)info.dli_fbase;
|
158
|
+
|
159
|
+
void* rb_add_method_original = ruby_resolv(base,"rb_add_method");
|
160
|
+
|
161
|
+
int inst_size = get_instructions_size(rb_add_method_original, 256);
|
162
|
+
rb_add_method_copy = put_jmp_hook(rb_add_method_original, rb_add_method_fake, inst_size);
|
163
|
+
|
164
|
+
add_method_code_changed = 1;
|
165
|
+
}
|
166
|
+
|
167
|
+
__shadow___id = rb_intern("__shadow__");
|
168
|
+
__unshadow___id = rb_intern("__unshadow__");
|
169
|
+
shadow_id = rb_intern("shadow");
|
170
|
+
id_restrict_def = rb_intern("__restrict_def");
|
171
|
+
|
172
|
+
rb_define_method(rb_cClass, "shadow", shadow_or_original, 0);
|
173
|
+
rb_define_method(rb_cClass, "create_shadow", shadow_or_create, 0);
|
174
|
+
rb_define_method(rb_cClass, "unshadow", unshadow, 0);
|
175
|
+
|
176
|
+
}
|