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
@@ -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
|
+
}
|