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,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
|
+
|