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.
Files changed (50) hide show
  1. data/AUTHORS +3 -0
  2. data/CHANGELOG +82 -0
  3. data/README +207 -0
  4. data/Rakefile +49 -0
  5. data/TODO +8 -0
  6. data/examples/hook/example1.rb +19 -0
  7. data/examples/hook/example2.rb +30 -0
  8. data/examples/hook/example3.rb +24 -0
  9. data/examples/hook/example4.rb +18 -0
  10. data/examples/hook/intercept.rb +41 -0
  11. data/examples/hook/intercept2.rb +49 -0
  12. data/examples/hook/redirect.rb +55 -0
  13. data/examples/hook/redirect_inherited.rb +28 -0
  14. data/examples/hook/shadow.rb +44 -0
  15. data/examples/instrospection/main.rb +13 -0
  16. data/examples/instrospection/source1.rb +4 -0
  17. data/examples/instrospection/source2.rb +4 -0
  18. data/ext/rallhook_base/distorm.h +401 -0
  19. data/ext/rallhook_base/extconf.rb +21 -0
  20. data/ext/rallhook_base/hook.c +165 -0
  21. data/ext/rallhook_base/hook.h +30 -0
  22. data/ext/rallhook_base/hook_rb_call.c +88 -0
  23. data/ext/rallhook_base/hook_rb_call.h +33 -0
  24. data/ext/rallhook_base/method_node.c +212 -0
  25. data/ext/rallhook_base/method_node.h +27 -0
  26. data/ext/rallhook_base/node_defs.h +294 -0
  27. data/ext/rallhook_base/rallhook.c +396 -0
  28. data/ext/rallhook_base/rb_call_fake.c +398 -0
  29. data/ext/rallhook_base/rb_call_fake.h +138 -0
  30. data/ext/rallhook_base/restrict_def.c +176 -0
  31. data/ext/rallhook_base/restrict_def.h +37 -0
  32. data/ext/rallhook_base/ruby_redirect.c +122 -0
  33. data/ext/rallhook_base/ruby_redirect.h +33 -0
  34. data/ext/rallhook_base/ruby_symbols.c +43 -0
  35. data/ext/rallhook_base/ruby_symbols.h +28 -0
  36. data/ext/rallhook_base/ruby_version.h +21 -0
  37. data/lib/rallhook/thread_hook.rb +37 -0
  38. data/lib/rallhook.rb +384 -0
  39. data/test/basic_proc.rb +45 -0
  40. data/test/integrity/test_array.rb +42 -0
  41. data/test/integrity/test_binding.rb +26 -0
  42. data/test/integrity/test_block.rb +37 -0
  43. data/test/integrity/test_call.rb +1 -0
  44. data/test/integrity/test_class_methods.rb +1 -0
  45. data/test/integrity/test_exception.rb +1 -0
  46. data/test/integrity/test_super.rb +34 -0
  47. data/test/introspection/test_call.rb +29 -0
  48. data/test/introspection/test_class_method.rb +41 -0
  49. data/test/introspection/test_file.rb +15 -0
  50. metadata +113 -0
@@ -0,0 +1,401 @@
1
+ /* diStorm3 1.0.0 */
2
+
3
+ /*
4
+ distorm.h
5
+
6
+ diStorm3 - Powerful disassembler for X86/AMD64
7
+ http://ragestorm.net/distorm/
8
+ distorm at gmail dot com
9
+ Copyright (C) 2010 Gil Dabah
10
+
11
+ This program is free software: you can redistribute it and/or modify
12
+ it under the terms of the GNU General Public License as published by
13
+ the Free Software Foundation, either version 3 of the License, or
14
+ (at your option) any later version.
15
+
16
+ This program is distributed in the hope that it will be useful,
17
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
18
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
+ GNU General Public License for more details.
20
+
21
+ You should have received a copy of the GNU General Public License
22
+ along with this program. If not, see <http://www.gnu.org/licenses/>
23
+ */
24
+
25
+
26
+ #ifndef DISTORM_H
27
+ #define DISTORM_H
28
+
29
+ /*
30
+ * 64 bit offsets support:
31
+ * If the diStorm library you use was compiled with 64 bits offsets,
32
+ * make sure you compile your own code with the following macro set:
33
+ * SUPPORT_64BIT_OFFSET
34
+ * Otherwise comment it out, or you will get a linker error of an unresolved symbol...
35
+ */
36
+
37
+ /* TINYC has a problem with some 64bits library functions, so pass. */
38
+ #ifndef __TINYC__
39
+ #ifndef _LIB /* Used only for library. */
40
+ /* Comment out the following line to disable 64 bits support */
41
+ #define SUPPORT_64BIT_OFFSET
42
+ #endif
43
+ #endif
44
+
45
+ /* If your compiler doesn't support stdint.h, define your own 64 bits type. */
46
+ #ifdef SUPPORT_64BIT_OFFSET
47
+ #ifdef _MSC_VER
48
+ #define OFFSET_INTEGER unsigned __int64
49
+ #else
50
+ #include <stdint.h>
51
+ #define OFFSET_INTEGER uint64_t
52
+ #endif
53
+ #else
54
+ /* 32 bit offsets are used. */
55
+ #define OFFSET_INTEGER unsigned long
56
+ #endif
57
+
58
+ #ifdef _MSC_VER
59
+ /* Since MSVC isn't shipped with stdint.h, we will have our own: */
60
+ typedef signed __int64 int64_t;
61
+ typedef unsigned __int64 uint64_t;
62
+ typedef signed __int32 int32_t;
63
+ typedef unsigned __int32 uint32_t;
64
+ typedef signed __int16 int16_t;
65
+ typedef unsigned __int16 uint16_t;
66
+ typedef signed __int8 int8_t;
67
+ typedef unsigned __int8 uint8_t;
68
+ #endif
69
+
70
+ /* Support C++ compilers */
71
+ #ifdef __cplusplus
72
+ extern "C" {
73
+ #endif
74
+
75
+ /* Decodes modes of the disassembler, 16 bits or 32 bits or 64 bits for AMD64, x86-64. */
76
+ typedef enum {Decode16Bits = 0, Decode32Bits = 1, Decode64Bits = 2} _DecodeType;
77
+
78
+ typedef OFFSET_INTEGER _OffsetType;
79
+
80
+ typedef struct {
81
+ _OffsetType codeOffset;
82
+ const uint8_t* code;
83
+ int codeLen; /* Using signed integer makes it easier to detect an underflow. */
84
+ _DecodeType dt;
85
+ unsigned int features;
86
+ } _CodeInfo;
87
+
88
+ typedef enum { O_NONE, O_REG, O_IMM, O_IMM1, O_IMM2, O_DISP, O_SMEM, O_MEM, O_PC, O_PTR } _OperandType;
89
+
90
+ typedef union {
91
+ /* Used by O_IMM: */
92
+ int8_t sbyte;
93
+ uint8_t byte;
94
+ int16_t sword;
95
+ uint16_t word;
96
+ int32_t sdword;
97
+ uint32_t dword;
98
+ int64_t sqword;
99
+ uint64_t qword;
100
+
101
+ /* Used by O_PC: */
102
+ _OffsetType addr;
103
+
104
+ /* Used by O_PTR: */
105
+ struct {
106
+ uint16_t seg;
107
+ /* Can be 16 or 32 bits, size is in ops[n].size. */
108
+ uint32_t off;
109
+ } ptr;
110
+ /* Used by O_IMM1 (i1) and O_IMM2 (i2). */
111
+ struct {
112
+ uint32_t i1;
113
+ uint32_t i2;
114
+ } ex;
115
+ } _Value;
116
+
117
+ typedef struct {
118
+ /* Type of operand:
119
+ O_NONE: operand is to be ignored.
120
+ O_REG: index holds global register index.
121
+ O_IMM: instruction.imm.
122
+ O_IMM1: instruction.imm.ex.i1.
123
+ O_IMM2: instruction.imm.ex.i2.
124
+ O_DISP: memory dereference with displacement only, instruction.disp.
125
+ O_SMEM: simple memory dereference with optional displacement (a single register memory dereference).
126
+ O_MEM: complex memory dereference (optional fields: s/i/b/disp).
127
+ O_PC: the relative address of a branch instruction (instruction.imm.addr).
128
+ O_PTR: the absolute target address of a far branch instruction (instruction.imm.ptr.seg/off).
129
+ */
130
+ uint8_t type; /* _OperandType */
131
+
132
+ /* Index of:
133
+ O_REG: holds global register index
134
+ O_SMEM: holds the 'base' register. E.G: [ECX], [EBX+0x1234] are both in operand.index.
135
+ O_MEM: holds the 'index' register. E.G: [EAX*4] is in operand.index.
136
+ */
137
+ uint8_t index;
138
+
139
+ /* Size of:
140
+ O_REG: register
141
+ O_IMM: instruction.imm
142
+ O_IMM1: instruction.imm.ex.i1
143
+ O_IMM2: instruction.imm.ex.i2
144
+ O_DISP: instruction.disp
145
+ O_SMEM: size of indirection.
146
+ O_MEM: size of indirection.
147
+ O_PC: size of the relative offset
148
+ O_PTR: size of instruction.imm.ptr.off (16 or 32)
149
+ */
150
+ uint16_t size;
151
+ } _Operand;
152
+
153
+ #define OPCODE_ID_NONE 0
154
+ /* Instruction could not be disassembled. */
155
+ #define FLAG_NOT_DECODABLE ((uint16_t)-1)
156
+ /* The instruction locks memory access. */
157
+ #define FLAG_LOCK (1 << 0)
158
+ /* The instruction is prefixed with a REPNZ. */
159
+ #define FLAG_REPNZ (1 << 1)
160
+ /* The instruction is prefixed with a REP, this can be a REPZ, it depends on the specific instruction. */
161
+ #define FLAG_REP (1 << 2)
162
+ /* Indicates there is a hint taken for Jcc instructions only. */
163
+ #define FLAG_HINT_TAKEN (1 << 3)
164
+ /* Indicates there is a hint non-taken for Jcc instructions only. */
165
+ #define FLAG_HINT_NOT_TAKEN (1 << 4)
166
+ /* The Imm value is signed extended. */
167
+ #define FLAG_IMM_SIGNED (1 << 5)
168
+
169
+ /* No register was defined. */
170
+ #define R_NONE ((uint8_t)-1)
171
+
172
+ #define REGS64_BASE (0)
173
+ #define REGS32_BASE (16)
174
+ #define REGS16_BASE (32)
175
+ #define REGS8_BASE (48)
176
+ #define REGS8_REX_BASE (64)
177
+ #define SREGS_BASE (68)
178
+ /* #define RIP 74 */
179
+ #define FPUREGS_BASE (75)
180
+ #define MMXREGS_BASE (83)
181
+ #define SSEREGS_BASE (91)
182
+ #define AVXREGS_BASE (107)
183
+ #define CREGS_BASE (123)
184
+ #define DREGS_BASE (132)
185
+
186
+ /*
187
+ * Operand Size or Adderss size are stored inside the flags:
188
+ * 0 - 16 bits
189
+ * 1 - 32 bits
190
+ * 2 - 64 bits
191
+ * 3 - reserved
192
+ *
193
+ * If you call these macros more than once, you will have to clean the bits before doing so.
194
+ */
195
+ #define FLAG_SET_OPSIZE(di, size) ((di->flags) |= (((size) & 3) << 6))
196
+ #define FLAG_SET_ADDRSIZE(di, size) ((di->flags) |= (((size) & 3) << 8))
197
+ #define FLAG_GET_OPSIZE(flags) (((flags) >> 6) & 3)
198
+ #define FLAG_GET_ADDRSIZE(flags) (((flags) >> 8) & 3)
199
+ /* To get the LOCK/REPNZ/REP prefixes. */
200
+ #define FLAG_GET_PREFIX(flags) ((flags) & 7)
201
+
202
+ /*
203
+ * Macros to extract segment registers from segmentInfo:
204
+ */
205
+ #define SEGMENT_DEFAULT 0x80
206
+ #define SEGMENT_SET(di, seg) ((di->segment) |= seg)
207
+ #define SEGMENT_GET(segment) (((segment) == R_NONE) ? R_NONE : ((segment) & 0x7f))
208
+ #define SEGMENT_IS_DEFAULT(segment) (((segment) & SEGMENT_DEFAULT) == SEGMENT_DEFAULT)
209
+
210
+ #define OPERANDS_NO (4)
211
+
212
+ typedef struct {
213
+ /* Virtual address of first byte of instruction. */
214
+ _OffsetType addr;
215
+ /* Size of the whole instruction. */
216
+ uint8_t size;
217
+ /* General flags of instruction, holds prefixes and more, if FLAG_NOT_DECODABLE, instruction is invalid. */
218
+ uint16_t flags;
219
+ /* Segment information of memory indirection, default segment, or overriden one, can be -1. */
220
+ uint8_t segment;
221
+ /* Used by ops[n].type == O_MEM. Base global register index (might be R_NONE), scale size (2/4/8), ignored for 0 or 1. */
222
+ uint8_t base, scale;
223
+ uint8_t dispSize;
224
+ /* ID of opcode in the global opcode table. Use for mnemonic look up. */
225
+ uint16_t opcode;
226
+ /* Up to four operands per instruction, ignored if ops[n].type == O_NONE. */
227
+ _Operand ops[OPERANDS_NO];
228
+ /* Used by ops[n].type == O_SMEM/O_MEM/O_DISP. Its size is dispSize. */
229
+ uint64_t disp;
230
+ /* Used by ops[n].type == O_IMM/O_IMM1&O_IMM2/O_PTR/O_PC. Its size is ops[n].size. */
231
+ _Value imm;
232
+ /* Unused prefixes mask, for each bit that is set that prefix is not used (LSB is byte [addr + 0]). */
233
+ uint16_t unusedPrefixesMask;
234
+ /* Meta defines the instruction set class, and the flow control flags. Use META macros. */
235
+ uint8_t meta;
236
+ } _DInst;
237
+
238
+ /* Static size of strings. Do not change this value. */
239
+ #define MAX_TEXT_SIZE (32)
240
+ typedef struct {
241
+ unsigned int length;
242
+ unsigned char p[MAX_TEXT_SIZE]; /* p is a null terminated string. */
243
+ } _WString;
244
+
245
+ /*
246
+ * Old decoded instruction structure in text format.
247
+ * Used only for backward compatibility with diStorm64.
248
+ * This structure holds all information the disassembler generates per instruction.
249
+ */
250
+ typedef struct {
251
+ _WString mnemonic; /* Mnemonic of decoded instruction, prefixed if required by REP, LOCK etc. */
252
+ _WString operands; /* Operands of the decoded instruction, up to 3 operands, comma-seperated. */
253
+ _WString instructionHex; /* Hex dump - little endian, including prefixes. */
254
+ unsigned int size; /* Size of decoded instruction. */
255
+ _OffsetType offset; /* Start offset of the decoded instruction. */
256
+ } _DecodedInst;
257
+
258
+ /* Get the ISC of the instruction, used with the definitions below. */
259
+ #define META_GET_ISC(meta) (((meta) >> 3) & 0x1f)
260
+ /* Get the flow control flags of the instruction, see 'features for decompose' below. */
261
+ #define META_GET_FC(meta) ((meta) & 0x7)
262
+
263
+ /*
264
+ * Instructions Set classes:
265
+ * if you want a better understanding of the available classes, look at disOps project, file: x86sets.py.
266
+ */
267
+ /* Indicates the instruction belongs to the General Integer set. */
268
+ #define ISC_INTEGER 1
269
+ /* Indicates the instruction belongs to the 387 FPU set. */
270
+ #define ISC_FPU 2
271
+ /* Indicates the instruction belongs to the P6 set. */
272
+ #define ISC_P6 3
273
+ /* Indicates the instruction belongs to the MMX set. */
274
+ #define ISC_MMX 4
275
+ /* Indicates the instruction belongs to the SSE set. */
276
+ #define ISC_SSE 5
277
+ /* Indicates the instruction belongs to the SSE2 set. */
278
+ #define ISC_SSE2 6
279
+ /* Indicates the instruction belongs to the SSE3 set. */
280
+ #define ISC_SSE3 7
281
+ /* Indicates the instruction belongs to the SSSE3 set. */
282
+ #define ISC_SSSE3 8
283
+ /* Indicates the instruction belongs to the SSE4.1 set. */
284
+ #define ISC_SSE4_1 9
285
+ /* Indicates the instruction belongs to the SSE4.2 set. */
286
+ #define ISC_SSE4_2 10
287
+ /* Indicates the instruction belongs to the AMD's SSE4.A set. */
288
+ #define ISC_SSE4_A 11
289
+ /* Indicates the instruction belongs to the 3DNow! set. */
290
+ #define ISC_3DNOW 12
291
+ /* Indicates the instruction belongs to the 3DNow! Extensions set. */
292
+ #define ISC_3DNOWEXT 13
293
+ /* Indicates the instruction belongs to the VMX (Intel) set. */
294
+ #define ISC_VMX 14
295
+ /* Indicates the instruction belongs to the SVM (AMD) set. */
296
+ #define ISC_SVM 15
297
+ /* Indicates the instruction belongs to the AVX (Intel) set. */
298
+ #define ISC_AVX 16
299
+ /* Indicates the instruction belongs to the FMA (Intel) set. */
300
+ #define ISC_FMA 17
301
+ /* Indicates the instruction belongs to the AES/AVX (Intel) set. */
302
+ #define ISC_AES 18
303
+ /* Indicates the instruction belongs to the CLMUL (Intel) set. */
304
+ #define ISC_CLMUL 19
305
+
306
+ /* Features for decompose: */
307
+ #define DF_NONE 0
308
+ /* The decoder will limit addresses to a maximum of 16 bits. */
309
+ #define DF_MAXIMUM_ADDR16 1
310
+ /* The decoder will limit addresses to a maximum of 32 bits. */
311
+ #define DF_MAXIMUM_ADDR32 2
312
+ /* The decoder will return only flow control instructions (and filter the others internally). */
313
+ #define DF_RETURN_FC_ONLY 4
314
+ /* The decoder will stop and return to the caller when the instruction 'CALL' (near and far) was decoded. */
315
+ #define DF_STOP_ON_CALL 8
316
+ /* The decoder will stop and return to the caller when the instruction 'RET' (near and far) was decoded. */
317
+ #define DF_STOP_ON_RET 0x10
318
+ /* The decoder will stop and return to the caller when the instruction system-call/ret was decoded. */
319
+ #define DF_STOP_ON_SYS 0x20
320
+ /* The decoder will stop and return to the caller when any of the branch 'JMP', (near and far) instructions were decoded. */
321
+ #define DF_STOP_ON_BRANCH 0x40
322
+ /* The decoder will stop and return to the caller when any of the conditional branch instruction were decoded. */
323
+ #define DF_STOP_ON_COND_BRANCH 0x80
324
+ /* The decoder will stop and return to the caller when the instruction 'INT' (INT, INT1, INTO, INT 3) was decoded. */
325
+ #define DF_STOP_ON_INT 0x100
326
+ /* The decoder will stop and return to the caller when any flow control instruction was decoded. */
327
+ #define DF_STOP_ON_FLOW_CONTROL (DF_STOP_ON_CALL | DF_STOP_ON_RET | DF_STOP_ON_SYS | DF_STOP_ON_BRANCH | DF_STOP_ON_COND_BRANCH | DF_STOP_ON_INT)
328
+
329
+ /* Indicates the instruction is not a flow-control instruction. */
330
+ #define FC_NONE 0
331
+ /* Indicates the instruction is one of: CALL, CALL FAR. */
332
+ #define FC_CALL 1
333
+ /* Indicates the instruction is one of: RET, IRET, RETF. */
334
+ #define FC_RET 2
335
+ /* Indicates the instruction is one of: SYSCALL, SYSRET, SYSENTER, SYSEXIT. */
336
+ #define FC_SYS 3
337
+ /* Indicates the instruction is one of: JMP, JMP FAR. */
338
+ #define FC_BRANCH 4
339
+ /*
340
+ * Indicates the instruction is one of:
341
+ * JCXZ, JO, JNO, JB, JAE, JZ, JNZ, JBE, JA, JS, JNS, JP, JNP, JL, JGE, JLE, JG, LOOP, LOOPZ, LOOPNZ.
342
+ */
343
+ #define FC_COND_BRANCH 5
344
+ /* Indiciates the instruction is one of: INT, INT1, INT 3, INTO, UD2. */
345
+ #define FC_INT 6
346
+
347
+ /* Return code of the decoding function. */
348
+ typedef enum {DECRES_NONE, DECRES_SUCCESS, DECRES_MEMORYERR, DECRES_INPUTERR, DECRES_FILTERED} _DecodeResult;
349
+
350
+ #ifndef _LIB /* Don't redefine those exports when compiling the library itself, only for library-user project. */
351
+
352
+ /* distorm_decode
353
+ * Input:
354
+ * offset - Origin of the given code (virtual address that is), NOT an offset in code.
355
+ * code - Pointer to the code buffer to be disassembled.
356
+ * length - Amount of bytes that should be decoded from the code buffer.
357
+ * dt - Decoding mode, 16 bits (Decode16Bits), 32 bits (Decode32Bits) or AMD64 (Decode64Bits).
358
+ * result - Array of type _DecodeInst which will be used by this function in order to return the disassembled instructions.
359
+ * maxInstructions - The maximum number of entries in the result array that you pass to this function, so it won't exceed its bound.
360
+ * usedInstructionsCount - Number of the instruction that successfully were disassembled and written to the result array.
361
+ * Output: usedInstructionsCount will hold the number of entries used in the result array
362
+ * and the result array itself will be filled with the disassembled instructions.
363
+ * Return: DECRES_SUCCESS on success (no more to disassemble), DECRES_INPUTERR on input error (null code buffer, invalid decoding mode, etc...),
364
+ * DECRES_MEMORYERR when there are not enough entries to use in the result array, BUT YOU STILL have to check for usedInstructionsCount!
365
+ * Side-Effects: Even if the return code is DECRES_MEMORYERR, there might STILL be data in the
366
+ * array you passed, this function will try to use as much entries as possible!
367
+ * Notes: 1)The minimal size of maxInstructions is 15.
368
+ * 2)You will have to synchronize the offset,code and length by yourself if you pass code fragments and not a complete code block!
369
+ */
370
+ #ifdef SUPPORT_64BIT_OFFSET
371
+ _DecodeResult distorm_decompose64(const _CodeInfo* ci, _DInst result[], unsigned int maxInstructions, unsigned int* usedInstructionsCount);
372
+ _DecodeResult distorm_decode64(_OffsetType codeOffset, const unsigned char* code, int codeLen, _DecodeType dt, _DecodedInst result[], unsigned int maxInstructions, unsigned int* usedInstructionsCount);
373
+ void distorm_format64(const _CodeInfo* ci, const _DInst* di, _DecodedInst* result);
374
+ #define distorm_decompose distorm_decompose64
375
+ #define distorm_decode distorm_decode64
376
+ #define distorm_format distorm_format64
377
+ #else
378
+ _DecodeResult distorm_decompose32(const _CodeInfo* ci, _DInst result[], unsigned int maxInstructions, unsigned int* usedInstructionsCount);
379
+ _DecodeResult distorm_decode32(_OffsetType codeOffset, const unsigned char* code, int codeLen, _DecodeType dt, _DecodedInst result[], unsigned int maxInstructions, unsigned int* usedInstructionsCount);
380
+ void distorm_format32(const _CodeInfo* ci, const _DInst* di, _DecodedInst* result);
381
+ #define distorm_decompose distorm_decompose32
382
+ #define distorm_decode distorm_decode32
383
+ #define distorm_format distorm_format32
384
+ #endif
385
+
386
+ /*
387
+ * distorm_version
388
+ * Input:
389
+ * none
390
+ *
391
+ * Output: unsigned int - version of compiled library.
392
+ */
393
+ extern unsigned int distorm_version();
394
+
395
+ #endif /* _LIB */
396
+
397
+ #ifdef __cplusplus
398
+ } /* End Of Extern */
399
+ #endif
400
+
401
+ #endif /* DISTORM_H */
@@ -0,0 +1,21 @@
1
+ require 'mkmf'
2
+ dir_config('rallhook_base')
3
+ CONFIG['CC'] = 'gcc'
4
+
5
+ ruby_version = Config::CONFIG["ruby_version"]
6
+ ruby_version = ruby_version.split(".")[0..1].join(".")
7
+
8
+ $LIBS = $LIBS + " -ldistorm64"
9
+
10
+ if ruby_version == "1.8"
11
+ $CFLAGS = $CFLAGS + " -DRUBY1_8"
12
+ elsif ruby_version == "1.9"
13
+ $CFLAGS = $CFLAGS + " -DRUBY1_9"
14
+ else
15
+ print "ERROR: unknown ruby version: #{ruby_version}\n"
16
+ print "try passing the rubyversion by argument (1.8 or 1.9)\n"
17
+ end
18
+
19
+ create_makefile('rallhook_base')
20
+
21
+
@@ -0,0 +1,165 @@
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 "hook.h"
23
+ #include <sys/mman.h>
24
+ #include "distorm.h"
25
+ #include "string.h"
26
+ #include "errno.h"
27
+ #include "ruby.h"
28
+
29
+ int get_instructions_size(void* code, int size) {
30
+ _DecodedInst decodedInstructions[32];
31
+
32
+ _OffsetType offset = 0;
33
+
34
+ unsigned int decodedInstructionsCount;
35
+
36
+ #ifdef __x86_64__
37
+ _DecodeType dt = Decode64Bits;
38
+ #elif __i386__
39
+ _DecodeType dt = Decode32Bits;
40
+ #else
41
+ #error "unknown architecture"
42
+ #endif
43
+
44
+ distorm_decode(offset, code, size, dt, decodedInstructions, 32, &decodedInstructionsCount);
45
+
46
+ int i;
47
+ int totalsize = 0;
48
+ int minsize = get_jmp_size();
49
+ for (i = 0; i < decodedInstructionsCount; i++) {
50
+ totalsize = totalsize + decodedInstructions[i].size;
51
+ if (totalsize >= minsize) {
52
+ return totalsize;
53
+ }
54
+ }
55
+
56
+ return totalsize;
57
+
58
+ }
59
+
60
+
61
+ void unprotect(void* ptr) {
62
+ #if __x86_64__
63
+ unsigned long int mask = 0xFFFFFFFFFFFF000;
64
+ int ret = mprotect( (void*) ( ( (unsigned long int)ptr ) & mask ), 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC);
65
+
66
+ if (ret == -1) {
67
+ rb_bug("mprotect failed: %s", strerror(errno));
68
+ }
69
+ #elif __i386__
70
+ unsigned int mask = 0xFFFFFFFFFFFF000;
71
+ int ret = mprotect( (void*) ( ( (unsigned int)ptr ) & mask ), 0x1000, PROT_READ | PROT_WRITE | PROT_EXEC);
72
+
73
+ if (ret == -1) {
74
+ rb_bug("mprotect failed: %s", strerror(errno));
75
+ }
76
+ #else
77
+ #error "unknow architecture"
78
+ #endif
79
+ }
80
+
81
+ void inconditional_jump(void* where, void* to) {
82
+
83
+ #if __x86_64__
84
+ unsigned char* p = (unsigned char*)where;
85
+
86
+ p[0] = 0x48; // movl XXX, %rax
87
+ p[1] = 0xb8;
88
+
89
+ void** address = (void**)(p+2);
90
+
91
+ p[10] = 0xff; // jmp %rax
92
+ p[11] = 0xe0;
93
+
94
+ *address = to;
95
+ #elif __i386__
96
+ unsigned char* p = (unsigned char*)where;
97
+
98
+ p[0] = 0x68; // pushl
99
+ void** address = (void**)(p+1);
100
+ *address = to;
101
+ p[5] = 0xc3; // ret
102
+ #else
103
+ #error "unknow architecture"
104
+ #endif
105
+ }
106
+
107
+ void* put_jmp_hook_with_regs(void* function_address, void* fake_function, int instructions_size) {
108
+ typedef unsigned char uchar;
109
+
110
+ uchar* p_copy = (uchar*)malloc(0x1000);
111
+ uchar* p = (uchar*)function_address;
112
+ uchar* p_regs = (uchar*)malloc(0x1000);
113
+
114
+ unprotect(p_copy);
115
+ unprotect(p);
116
+ unprotect(p_regs);
117
+
118
+ memcpy(p_copy, p, instructions_size);
119
+
120
+ p_regs[0] = 0x54; // push esp
121
+ p_regs[1] = 0x51; // push ecx
122
+ p_regs[2] = 0x52; // push edx
123
+ p_regs[3] = 0x50; // push eax
124
+ p_regs[4] = 0xb8; // movl %eax, ???????
125
+ p_regs[9] = 0xff; // call *%eax
126
+ p_regs[10] = 0xd0; //
127
+ p_regs[11] = 0x83; // add $0x10, %esp
128
+ p_regs[12] = 0xc4; //
129
+ p_regs[13] = 0x10; //
130
+ p_regs[14] = 0xc3; // ret
131
+
132
+ *((void**)(p_regs+5))=fake_function;
133
+
134
+ inconditional_jump(p, p_regs);
135
+ inconditional_jump(p_copy+instructions_size, p+instructions_size);
136
+
137
+ return (void*)p_copy;
138
+ }
139
+
140
+ void* put_jmp_hook(void* function_address, void* fake_function, int instructions_size) {
141
+ typedef unsigned char uchar;
142
+
143
+ uchar* p_copy = (uchar*)malloc(0x1000);
144
+ uchar* p = (uchar*)function_address;
145
+
146
+ unprotect(p_copy);
147
+ unprotect(p);
148
+
149
+ memcpy(p_copy, p, instructions_size);
150
+
151
+ inconditional_jump(p, fake_function);
152
+ inconditional_jump(p_copy+instructions_size, p+instructions_size);
153
+
154
+ return (void*)p_copy;
155
+ }
156
+
157
+ int get_jmp_size() {
158
+ #if __x86_64__
159
+ return 12;
160
+ #elif __i386__
161
+ return 6;
162
+ #else
163
+ #error "unknown architecture"
164
+ #endif
165
+ }
@@ -0,0 +1,30 @@
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 __HOOK_H
22
+ #define __HOOK_H
23
+
24
+ void* put_jmp_hook(void* function_address, void* fake_function, int instructions_size);
25
+ void* put_jmp_hook_with_regs(void* function_address, void* fake_function, int instructions_size);
26
+ int get_jmp_size();
27
+
28
+ extern int get_instructions_size(void* code, int size);
29
+
30
+ #endif
@@ -0,0 +1,88 @@
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 "hook_rb_call.h"
23
+ #include "hook.h"
24
+ #include "ruby_symbols.h"
25
+ #include "ruby_version.h"
26
+ #include "distorm.h"
27
+
28
+ #ifndef __USE_GNU
29
+ #define __USE_GNU
30
+ #endif
31
+
32
+ #include <dlfcn.h>
33
+
34
+ void* rb_call_original = 0;
35
+ void* vm_call_method_original = 0;
36
+
37
+ void* hook_vm_call_method(void *fake_function) {
38
+ if (vm_call_method_original == 0) {
39
+ return 0;
40
+ }
41
+ int inst_size = get_instructions_size(vm_call_method_original, 256);
42
+
43
+ #ifdef __i386__
44
+ return put_jmp_hook_with_regs(vm_call_method_original, fake_function, inst_size);
45
+ #endif
46
+
47
+ #ifdef __x86_64__
48
+ return put_jmp_hook(vm_call_method_original, fake_function, inst_size);
49
+ #endif
50
+
51
+ }
52
+
53
+ void* hook_rb_call(void* fake_function) {
54
+ if (rb_call_original == 0) {
55
+ return 0;
56
+ }
57
+ int inst_size = get_instructions_size(rb_call_original, 256);
58
+
59
+ #ifdef __i386__
60
+ return put_jmp_hook_with_regs(rb_call_original, fake_function, inst_size);
61
+ #endif
62
+
63
+ #ifdef __x86_64__
64
+ return put_jmp_hook(rb_call_original, fake_function, inst_size);
65
+ #endif
66
+
67
+ }
68
+
69
+ void init_hook_rb_call() {
70
+ void* handle = dlopen(current_libruby(),0x101);
71
+ char* rb_funcall = (char*)dlsym(handle, "rb_funcall");
72
+ Dl_info info;
73
+ dladdr(rb_funcall, &info);
74
+
75
+ unsigned char* base = (unsigned char*)info.dli_fbase;
76
+
77
+ #ifdef RUBY1_8
78
+ rb_call_original = ruby_resolv(base, "rb_call");
79
+ #endif
80
+
81
+ // in the ruby 1.9 source, the rb_call0 acts as rb_call (and vm_call0 acts as rb_call0)
82
+ #ifdef RUBY1_9
83
+ vm_call_method_original = ruby_resolv(base, "vm_call_method");
84
+ rb_call_original = ruby_resolv(base, "rb_call0");
85
+ #endif
86
+
87
+ }
88
+