metasm 1.0.1 → 1.0.2
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.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/.hgtags +3 -0
- data/Gemfile +1 -0
- data/INSTALL +61 -0
- data/LICENCE +458 -0
- data/README +29 -21
- data/Rakefile +10 -0
- data/TODO +10 -12
- data/doc/code_organisation.txt +2 -0
- data/doc/core/DynLdr.txt +247 -0
- data/doc/core/ExeFormat.txt +43 -0
- data/doc/core/Expression.txt +220 -0
- data/doc/core/GNUExports.txt +27 -0
- data/doc/core/Ia32.txt +236 -0
- data/doc/core/SerialStruct.txt +108 -0
- data/doc/core/VirtualString.txt +145 -0
- data/doc/core/WindowsExports.txt +61 -0
- data/doc/core/index.txt +1 -0
- data/doc/style.css +6 -3
- data/doc/usage/debugger.txt +327 -0
- data/doc/usage/index.txt +1 -0
- data/doc/use_cases.txt +2 -2
- data/metasm.gemspec +22 -0
- data/{lib/metasm.rb → metasm.rb} +11 -3
- data/{lib/metasm → metasm}/compile_c.rb +13 -7
- data/metasm/cpu/arc.rb +8 -0
- data/metasm/cpu/arc/decode.rb +425 -0
- data/metasm/cpu/arc/main.rb +191 -0
- data/metasm/cpu/arc/opcodes.rb +588 -0
- data/{lib/metasm → metasm/cpu}/arm.rb +7 -5
- data/{lib/metasm → metasm/cpu}/arm/debug.rb +2 -2
- data/{lib/metasm → metasm/cpu}/arm/decode.rb +13 -12
- data/{lib/metasm → metasm/cpu}/arm/encode.rb +23 -8
- data/{lib/metasm → metasm/cpu}/arm/main.rb +0 -3
- data/metasm/cpu/arm/opcodes.rb +324 -0
- data/{lib/metasm → metasm/cpu}/arm/parse.rb +25 -13
- data/{lib/metasm → metasm/cpu}/arm/render.rb +2 -2
- data/metasm/cpu/arm64.rb +15 -0
- data/metasm/cpu/arm64/debug.rb +38 -0
- data/metasm/cpu/arm64/decode.rb +289 -0
- data/metasm/cpu/arm64/encode.rb +41 -0
- data/metasm/cpu/arm64/main.rb +105 -0
- data/metasm/cpu/arm64/opcodes.rb +232 -0
- data/metasm/cpu/arm64/parse.rb +20 -0
- data/metasm/cpu/arm64/render.rb +95 -0
- data/{lib/metasm/ppc.rb → metasm/cpu/bpf.rb} +2 -4
- data/metasm/cpu/bpf/decode.rb +142 -0
- data/metasm/cpu/bpf/main.rb +60 -0
- data/metasm/cpu/bpf/opcodes.rb +81 -0
- data/metasm/cpu/bpf/render.rb +41 -0
- data/metasm/cpu/cy16.rb +9 -0
- data/metasm/cpu/cy16/decode.rb +253 -0
- data/metasm/cpu/cy16/main.rb +63 -0
- data/metasm/cpu/cy16/opcodes.rb +78 -0
- data/metasm/cpu/cy16/render.rb +41 -0
- data/metasm/cpu/dalvik.rb +11 -0
- data/{lib/metasm → metasm/cpu}/dalvik/decode.rb +35 -13
- data/{lib/metasm → metasm/cpu}/dalvik/main.rb +51 -2
- data/{lib/metasm → metasm/cpu}/dalvik/opcodes.rb +19 -11
- data/metasm/cpu/ia32.rb +17 -0
- data/{lib/metasm → metasm/cpu}/ia32/compile_c.rb +5 -7
- data/{lib/metasm → metasm/cpu}/ia32/debug.rb +5 -5
- data/{lib/metasm → metasm/cpu}/ia32/decode.rb +246 -59
- data/{lib/metasm → metasm/cpu}/ia32/decompile.rb +7 -7
- data/{lib/metasm → metasm/cpu}/ia32/encode.rb +19 -13
- data/{lib/metasm → metasm/cpu}/ia32/main.rb +51 -8
- data/metasm/cpu/ia32/opcodes.rb +1424 -0
- data/{lib/metasm → metasm/cpu}/ia32/parse.rb +47 -16
- data/{lib/metasm → metasm/cpu}/ia32/render.rb +31 -4
- data/metasm/cpu/mips.rb +14 -0
- data/{lib/metasm → metasm/cpu}/mips/compile_c.rb +1 -1
- data/metasm/cpu/mips/debug.rb +42 -0
- data/{lib/metasm → metasm/cpu}/mips/decode.rb +46 -16
- data/{lib/metasm → metasm/cpu}/mips/encode.rb +4 -3
- data/{lib/metasm → metasm/cpu}/mips/main.rb +11 -4
- data/{lib/metasm → metasm/cpu}/mips/opcodes.rb +86 -17
- data/{lib/metasm → metasm/cpu}/mips/parse.rb +1 -1
- data/{lib/metasm → metasm/cpu}/mips/render.rb +1 -1
- data/{lib/metasm/dalvik.rb → metasm/cpu/msp430.rb} +1 -1
- data/metasm/cpu/msp430/decode.rb +247 -0
- data/metasm/cpu/msp430/main.rb +62 -0
- data/metasm/cpu/msp430/opcodes.rb +101 -0
- data/{lib/metasm → metasm/cpu}/pic16c/decode.rb +6 -7
- data/{lib/metasm → metasm/cpu}/pic16c/main.rb +0 -0
- data/{lib/metasm → metasm/cpu}/pic16c/opcodes.rb +1 -1
- data/{lib/metasm/mips.rb → metasm/cpu/ppc.rb} +4 -4
- data/{lib/metasm → metasm/cpu}/ppc/decode.rb +18 -12
- data/{lib/metasm → metasm/cpu}/ppc/decompile.rb +3 -3
- data/{lib/metasm → metasm/cpu}/ppc/encode.rb +2 -2
- data/{lib/metasm → metasm/cpu}/ppc/main.rb +17 -12
- data/{lib/metasm → metasm/cpu}/ppc/opcodes.rb +11 -5
- data/metasm/cpu/ppc/parse.rb +55 -0
- data/metasm/cpu/python.rb +8 -0
- data/metasm/cpu/python/decode.rb +136 -0
- data/metasm/cpu/python/main.rb +36 -0
- data/metasm/cpu/python/opcodes.rb +180 -0
- data/{lib/metasm → metasm/cpu}/sh4.rb +1 -1
- data/{lib/metasm → metasm/cpu}/sh4/decode.rb +48 -17
- data/{lib/metasm → metasm/cpu}/sh4/main.rb +13 -4
- data/{lib/metasm → metasm/cpu}/sh4/opcodes.rb +7 -8
- data/metasm/cpu/x86_64.rb +15 -0
- data/{lib/metasm → metasm/cpu}/x86_64/compile_c.rb +28 -17
- data/{lib/metasm → metasm/cpu}/x86_64/debug.rb +4 -4
- data/{lib/metasm → metasm/cpu}/x86_64/decode.rb +57 -15
- data/{lib/metasm → metasm/cpu}/x86_64/encode.rb +55 -26
- data/{lib/metasm → metasm/cpu}/x86_64/main.rb +14 -6
- data/metasm/cpu/x86_64/opcodes.rb +136 -0
- data/{lib/metasm → metasm/cpu}/x86_64/parse.rb +10 -2
- data/metasm/cpu/x86_64/render.rb +35 -0
- data/metasm/cpu/z80.rb +9 -0
- data/metasm/cpu/z80/decode.rb +313 -0
- data/metasm/cpu/z80/main.rb +67 -0
- data/metasm/cpu/z80/opcodes.rb +224 -0
- data/metasm/cpu/z80/render.rb +59 -0
- data/{lib/metasm/os/main.rb → metasm/debug.rb} +160 -401
- data/{lib/metasm → metasm}/decode.rb +35 -4
- data/{lib/metasm → metasm}/decompile.rb +15 -16
- data/{lib/metasm → metasm}/disassemble.rb +201 -45
- data/{lib/metasm → metasm}/disassemble_api.rb +651 -87
- data/{lib/metasm → metasm}/dynldr.rb +220 -133
- data/{lib/metasm → metasm}/encode.rb +10 -1
- data/{lib/metasm → metasm}/exe_format/a_out.rb +9 -6
- data/{lib/metasm → metasm}/exe_format/autoexe.rb +1 -0
- data/{lib/metasm → metasm}/exe_format/bflt.rb +57 -27
- data/{lib/metasm → metasm}/exe_format/coff.rb +11 -3
- data/{lib/metasm → metasm}/exe_format/coff_decode.rb +53 -20
- data/{lib/metasm → metasm}/exe_format/coff_encode.rb +11 -13
- data/{lib/metasm → metasm}/exe_format/dex.rb +13 -5
- data/{lib/metasm → metasm}/exe_format/dol.rb +1 -0
- data/{lib/metasm → metasm}/exe_format/elf.rb +93 -57
- data/{lib/metasm → metasm}/exe_format/elf_decode.rb +143 -34
- data/{lib/metasm → metasm}/exe_format/elf_encode.rb +122 -31
- data/metasm/exe_format/gb.rb +65 -0
- data/metasm/exe_format/javaclass.rb +424 -0
- data/{lib/metasm → metasm}/exe_format/macho.rb +204 -16
- data/{lib/metasm → metasm}/exe_format/main.rb +26 -3
- data/{lib/metasm → metasm}/exe_format/mz.rb +1 -0
- data/{lib/metasm → metasm}/exe_format/nds.rb +7 -4
- data/{lib/metasm → metasm}/exe_format/pe.rb +71 -8
- data/metasm/exe_format/pyc.rb +167 -0
- data/{lib/metasm → metasm}/exe_format/serialstruct.rb +67 -14
- data/{lib/metasm → metasm}/exe_format/shellcode.rb +7 -3
- data/metasm/exe_format/shellcode_rwx.rb +114 -0
- data/metasm/exe_format/swf.rb +205 -0
- data/{lib/metasm → metasm}/exe_format/xcoff.rb +7 -7
- data/metasm/exe_format/zip.rb +335 -0
- data/metasm/gui.rb +13 -0
- data/{lib/metasm → metasm}/gui/cstruct.rb +35 -41
- data/{lib/metasm → metasm}/gui/dasm_coverage.rb +11 -11
- data/{lib/metasm → metasm}/gui/dasm_decomp.rb +7 -20
- data/{lib/metasm → metasm}/gui/dasm_funcgraph.rb +0 -0
- data/metasm/gui/dasm_graph.rb +1695 -0
- data/{lib/metasm → metasm}/gui/dasm_hex.rb +12 -8
- data/{lib/metasm → metasm}/gui/dasm_listing.rb +43 -28
- data/{lib/metasm → metasm}/gui/dasm_main.rb +310 -53
- data/{lib/metasm → metasm}/gui/dasm_opcodes.rb +5 -19
- data/{lib/metasm → metasm}/gui/debug.rb +93 -27
- data/{lib/metasm → metasm}/gui/gtk.rb +162 -40
- data/{lib/metasm → metasm}/gui/qt.rb +12 -2
- data/{lib/metasm → metasm}/gui/win32.rb +179 -42
- data/{lib/metasm → metasm}/gui/x11.rb +59 -59
- data/{lib/metasm → metasm}/main.rb +389 -264
- data/{lib/metasm/os/remote.rb → metasm/os/gdbremote.rb} +146 -54
- data/{lib/metasm → metasm}/os/gnu_exports.rb +1 -1
- data/{lib/metasm → metasm}/os/linux.rb +628 -151
- data/metasm/os/main.rb +330 -0
- data/{lib/metasm → metasm}/os/windows.rb +132 -42
- data/{lib/metasm → metasm}/os/windows_exports.rb +141 -0
- data/{lib/metasm → metasm}/parse.rb +26 -24
- data/{lib/metasm → metasm}/parse_c.rb +221 -116
- data/{lib/metasm → metasm}/preprocessor.rb +55 -40
- data/{lib/metasm → metasm}/render.rb +14 -38
- data/misc/hexdump.rb +2 -1
- data/misc/lint.rb +58 -0
- data/misc/txt2html.rb +9 -7
- data/samples/bindiff.rb +3 -4
- data/samples/dasm-plugins/bindiff.rb +15 -0
- data/samples/dasm-plugins/bookmark.rb +133 -0
- data/samples/dasm-plugins/c_constants.rb +57 -0
- data/samples/dasm-plugins/colortheme_solarized.rb +125 -0
- data/samples/dasm-plugins/cppobj_funcall.rb +60 -0
- data/samples/dasm-plugins/dasm_all.rb +70 -0
- data/samples/dasm-plugins/demangle_cpp.rb +31 -0
- data/samples/dasm-plugins/deobfuscate.rb +251 -0
- data/samples/dasm-plugins/dump_text.rb +35 -0
- data/samples/dasm-plugins/export_graph_svg.rb +86 -0
- data/samples/dasm-plugins/findgadget.rb +75 -0
- data/samples/dasm-plugins/hl_opcode.rb +32 -0
- data/samples/dasm-plugins/hotfix_gtk_dbg.rb +19 -0
- data/samples/dasm-plugins/imm2off.rb +34 -0
- data/samples/dasm-plugins/match_libsigs.rb +93 -0
- data/samples/dasm-plugins/patch_file.rb +95 -0
- data/samples/dasm-plugins/scanfuncstart.rb +36 -0
- data/samples/dasm-plugins/scanxrefs.rb +26 -0
- data/samples/dasm-plugins/selfmodify.rb +197 -0
- data/samples/dasm-plugins/stringsxrefs.rb +28 -0
- data/samples/dasmnavig.rb +1 -1
- data/samples/dbg-apihook.rb +24 -9
- data/samples/dbg-plugins/heapscan.rb +283 -0
- data/samples/dbg-plugins/heapscan/compiled_heapscan_lin.c +155 -0
- data/samples/dbg-plugins/heapscan/compiled_heapscan_win.c +128 -0
- data/samples/dbg-plugins/heapscan/graphheap.rb +616 -0
- data/samples/dbg-plugins/heapscan/heapscan.rb +709 -0
- data/samples/dbg-plugins/heapscan/winheap.h +174 -0
- data/samples/dbg-plugins/heapscan/winheap7.h +307 -0
- data/samples/dbg-plugins/trace_func.rb +214 -0
- data/samples/disassemble-gui.rb +35 -5
- data/samples/disassemble.rb +31 -6
- data/samples/dump_upx.rb +24 -12
- data/samples/dynamic_ruby.rb +12 -3
- data/samples/exeencode.rb +6 -5
- data/samples/factorize-headers-peimports.rb +1 -1
- data/samples/lindebug.rb +175 -381
- data/samples/metasm-shell.rb +1 -2
- data/samples/peldr.rb +2 -2
- data/tests/all.rb +1 -1
- data/tests/arc.rb +26 -0
- data/tests/dynldr.rb +22 -4
- data/tests/expression.rb +55 -0
- data/tests/graph_layout.rb +285 -0
- data/tests/ia32.rb +79 -26
- data/tests/mips.rb +9 -2
- data/tests/x86_64.rb +66 -18
- metadata +330 -218
- data/lib/metasm/arm/opcodes.rb +0 -177
- data/lib/metasm/gui.rb +0 -23
- data/lib/metasm/gui/dasm_graph.rb +0 -1354
- data/lib/metasm/ia32.rb +0 -14
- data/lib/metasm/ia32/opcodes.rb +0 -873
- data/lib/metasm/ppc/parse.rb +0 -52
- data/lib/metasm/x86_64.rb +0 -12
- data/lib/metasm/x86_64/opcodes.rb +0 -118
- data/samples/gdbclient.rb +0 -583
- data/samples/rubstop.rb +0 -399
|
@@ -52,15 +52,17 @@ extern VALUE *rb_cObject __attribute__((import));
|
|
|
52
52
|
extern VALUE *rb_eRuntimeError __attribute__((import));
|
|
53
53
|
extern VALUE *rb_eArgError __attribute__((import));
|
|
54
54
|
|
|
55
|
-
#define Qfalse ((VALUE)0)
|
|
56
|
-
#define Qtrue ((VALUE)2)
|
|
57
|
-
#define Qnil ((VALUE)4)
|
|
58
|
-
|
|
59
55
|
// allows generating a ruby1.9 dynldr.so from ruby1.8
|
|
60
56
|
#ifndef DYNLDR_RUBY_19
|
|
61
57
|
#define DYNLDR_RUBY_19 #{RUBY_VERSION >= '1.9' ? 1 : 0}
|
|
62
58
|
#endif
|
|
63
59
|
|
|
60
|
+
#if #{RUBY_VERSION >= '2.0' ? 1 : 0}
|
|
61
|
+
// flonums. WHY?
|
|
62
|
+
// also breaks Qtrue/Qnil
|
|
63
|
+
#define rb_float_new rb_float_new_in_heap
|
|
64
|
+
#endif
|
|
65
|
+
|
|
64
66
|
#if DYNLDR_RUBY_19
|
|
65
67
|
#define T_STRING 0x05
|
|
66
68
|
#define T_ARRAY 0x07
|
|
@@ -90,7 +92,8 @@ VALUE rb_ull2inum(unsigned long long);
|
|
|
90
92
|
VALUE rb_num2ulong(VALUE);
|
|
91
93
|
unsigned long long rb_num2ull(VALUE);
|
|
92
94
|
VALUE rb_str_new(const char* ptr, long len); // alloc + memcpy + 0term
|
|
93
|
-
VALUE
|
|
95
|
+
VALUE rb_ary_new();
|
|
96
|
+
VALUE rb_ary_push(VALUE, VALUE);
|
|
94
97
|
VALUE rb_float_new(double);
|
|
95
98
|
|
|
96
99
|
VALUE rb_intern(char *);
|
|
@@ -163,7 +166,7 @@ static VALUE memory_write(VALUE self, VALUE addr, VALUE val)
|
|
|
163
166
|
static VALUE memory_write_int(VALUE self, VALUE addr, VALUE val)
|
|
164
167
|
{
|
|
165
168
|
*(uintptr_t *)VAL2INT(addr) = VAL2INT(val);
|
|
166
|
-
return
|
|
169
|
+
return 1;
|
|
167
170
|
}
|
|
168
171
|
|
|
169
172
|
static VALUE str_ptr(VALUE self, VALUE str)
|
|
@@ -200,7 +203,7 @@ static VALUE sym_addr(VALUE self, VALUE lib, VALUE func)
|
|
|
200
203
|
|
|
201
204
|
if (TYPE(func) != T_STRING && TYPE(func) != T_FIXNUM)
|
|
202
205
|
rb_raise(*rb_eArgError, "Invalid func");
|
|
203
|
-
|
|
206
|
+
|
|
204
207
|
if (TYPE(func) == T_FIXNUM)
|
|
205
208
|
p = os_load_sym_ord(h, VAL2INT(func));
|
|
206
209
|
else
|
|
@@ -224,7 +227,7 @@ static VALUE invoke(VALUE self, VALUE ptr, VALUE args, VALUE flags)
|
|
|
224
227
|
{
|
|
225
228
|
if (TYPE(args) != T_ARRAY || ARY_LEN(args) > 64)
|
|
226
229
|
rb_raise(*rb_eArgError, "bad args");
|
|
227
|
-
|
|
230
|
+
|
|
228
231
|
uintptr_t flags_v = VAL2INT(flags);
|
|
229
232
|
uintptr_t ptr_v = VAL2INT(ptr);
|
|
230
233
|
unsigned i, argsz;
|
|
@@ -241,7 +244,7 @@ static VALUE invoke(VALUE self, VALUE ptr, VALUE args, VALUE flags)
|
|
|
241
244
|
ret = do_invoke_stdcall(ptr_v, argsz, args_c);
|
|
242
245
|
else
|
|
243
246
|
ret = do_invoke(ptr_v, argsz, args_c);
|
|
244
|
-
|
|
247
|
+
|
|
245
248
|
if (flags_v & 4)
|
|
246
249
|
return rb_ull2inum((unsigned __int64)ret);
|
|
247
250
|
else if (flags_v & 8)
|
|
@@ -257,23 +260,27 @@ static VALUE invoke(VALUE self, VALUE ptr, VALUE args, VALUE flags)
|
|
|
257
260
|
// callback generated by callback_alloc
|
|
258
261
|
// heavy stack magick at work here !
|
|
259
262
|
// TODO float args / float retval / ret __int64
|
|
260
|
-
uintptr_t do_callback_handler(uintptr_t ori_retaddr, uintptr_t caller_id, uintptr_t arg0)
|
|
263
|
+
uintptr_t do_callback_handler(uintptr_t ori_retaddr, uintptr_t caller_id, uintptr_t arg0, uintptr_t arg_ecx __attribute__((register(ecx))), uintptr_t arg_edx __attribute__((register(edx))))
|
|
261
264
|
{
|
|
262
265
|
uintptr_t *addr = &arg0;
|
|
263
266
|
unsigned i, ret;
|
|
264
|
-
VALUE args =
|
|
267
|
+
VALUE args = rb_ary_new();
|
|
268
|
+
|
|
269
|
+
// __fastcall callback args
|
|
270
|
+
|
|
271
|
+
rb_ary_push(args, INT2VAL(arg_ecx));
|
|
272
|
+
rb_ary_push(args, INT2VAL(arg_edx));
|
|
265
273
|
|
|
266
274
|
// copy our args to a ruby-accessible buffer
|
|
267
|
-
for (i=
|
|
268
|
-
|
|
269
|
-
RArray(args)->len = 8U; // len == 8, no need to ARY_LEN/EMBED stuff
|
|
275
|
+
for (i=2U ; i<10U ; ++i)
|
|
276
|
+
rb_ary_push(args, INT2VAL(*addr++));
|
|
270
277
|
|
|
271
278
|
ret = rb_funcall(dynldr, rb_intern("callback_run"), 2, INT2VAL(caller_id), args);
|
|
272
279
|
|
|
273
280
|
// dynldr.callback will give us the arity (in bytes) of the callback in args[0]
|
|
274
281
|
// we just put the stack lifting offset in caller_id for the asm stub to use
|
|
275
282
|
caller_id = VAL2INT(ARY_PTR(args)[0]);
|
|
276
|
-
|
|
283
|
+
|
|
277
284
|
return VAL2INT(ret);
|
|
278
285
|
}
|
|
279
286
|
|
|
@@ -290,7 +297,7 @@ static VALUE invoke(VALUE self, VALUE ptr, VALUE args, VALUE flags)
|
|
|
290
297
|
{
|
|
291
298
|
if (TYPE(args) != T_ARRAY || ARY_LEN(args) > 16)
|
|
292
299
|
rb_raise(*rb_eArgError, "bad args");
|
|
293
|
-
|
|
300
|
+
|
|
294
301
|
uintptr_t flags_v = VAL2INT(flags);
|
|
295
302
|
uintptr_t ptr_v = VAL2INT(ptr);
|
|
296
303
|
int i, argsz;
|
|
@@ -312,7 +319,7 @@ static VALUE invoke(VALUE self, VALUE ptr, VALUE args, VALUE flags)
|
|
|
312
319
|
args_c[4], args_c[5], args_c[6], args_c[7],
|
|
313
320
|
args_c[8], args_c[9], args_c[10], args_c[11],
|
|
314
321
|
args_c[12], args_c[13], args_c[14], args_c[15]);
|
|
315
|
-
|
|
322
|
+
|
|
316
323
|
if (flags_v & 8)
|
|
317
324
|
return rb_float_new(fake_float());
|
|
318
325
|
|
|
@@ -324,18 +331,16 @@ uintptr_t do_callback_handler(uintptr_t cb_id __attribute__((register(rax))),
|
|
|
324
331
|
uintptr_t arg4, uintptr_t arg5, uintptr_t arg6, uintptr_t arg7)
|
|
325
332
|
{
|
|
326
333
|
uintptr_t ret;
|
|
327
|
-
VALUE args =
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
ptr[6] = INT2VAL(arg6);
|
|
338
|
-
ptr[7] = INT2VAL(arg7);
|
|
334
|
+
VALUE args = rb_ary_new();
|
|
335
|
+
|
|
336
|
+
rb_ary_push(args, INT2VAL(arg0));
|
|
337
|
+
rb_ary_push(args, INT2VAL(arg1));
|
|
338
|
+
rb_ary_push(args, INT2VAL(arg2));
|
|
339
|
+
rb_ary_push(args, INT2VAL(arg3));
|
|
340
|
+
rb_ary_push(args, INT2VAL(arg4));
|
|
341
|
+
rb_ary_push(args, INT2VAL(arg5));
|
|
342
|
+
rb_ary_push(args, INT2VAL(arg6));
|
|
343
|
+
rb_ary_push(args, INT2VAL(arg7));
|
|
339
344
|
|
|
340
345
|
ret = rb_funcall(dynldr, rb_intern("callback_run"), 2, INT2VAL(cb_id), args);
|
|
341
346
|
|
|
@@ -379,8 +384,7 @@ static void *wstrcaseruby(short *s1, int len)
|
|
|
379
384
|
{
|
|
380
385
|
int i = 0;
|
|
381
386
|
int match = 0;
|
|
382
|
-
|
|
383
|
-
static char *want = "ruby"; // cant contain the same letter twice
|
|
387
|
+
char *want = "ruby"; // cant contain the same letter twice
|
|
384
388
|
|
|
385
389
|
while (i < len) {
|
|
386
390
|
if (want[match] == (s1[i] | 0x20)) { // downcase cmp
|
|
@@ -474,11 +478,11 @@ int load_ruby_imports(uintptr_t rbaddr)
|
|
|
474
478
|
if (rbaddr)
|
|
475
479
|
ruby_module = find_ruby_module_mem(rbaddr);
|
|
476
480
|
else
|
|
477
|
-
|
|
481
|
+
ruby_module = find_ruby_module_peb();
|
|
478
482
|
|
|
479
483
|
if (!ruby_module)
|
|
480
484
|
return 0;
|
|
481
|
-
|
|
485
|
+
|
|
482
486
|
ptr = &ruby_import_table;
|
|
483
487
|
table = (char*)ptr;
|
|
484
488
|
|
|
@@ -494,7 +498,7 @@ int load_ruby_imports(uintptr_t rbaddr)
|
|
|
494
498
|
|
|
495
499
|
#ifdef __x86_64__
|
|
496
500
|
#define DLL_PROCESS_ATTACH 1
|
|
497
|
-
|
|
501
|
+
int DllMain(void *handle, int reason, void *res)
|
|
498
502
|
{
|
|
499
503
|
if (reason == DLL_PROCESS_ATTACH)
|
|
500
504
|
return load_ruby_imports(0);
|
|
@@ -509,7 +513,7 @@ EOS
|
|
|
509
513
|
do_invoke_fastcall:
|
|
510
514
|
push ebp
|
|
511
515
|
mov ebp, esp
|
|
512
|
-
|
|
516
|
+
|
|
513
517
|
// load ecx/edx, fix arg/argcount
|
|
514
518
|
mov eax, [ebp+16]
|
|
515
519
|
mov ecx, [eax]
|
|
@@ -627,7 +631,7 @@ EOS
|
|
|
627
631
|
# save the shared library
|
|
628
632
|
bin.encode_file(modulename, :lib)
|
|
629
633
|
end
|
|
630
|
-
|
|
634
|
+
|
|
631
635
|
def self.compile_binary_module_hack(bin)
|
|
632
636
|
# this is a hack
|
|
633
637
|
# we need the module to use ruby symbols
|
|
@@ -720,8 +724,7 @@ EOS
|
|
|
720
724
|
# find the path of the binary module
|
|
721
725
|
# if none exists, create a path writeable by the current user
|
|
722
726
|
def self.find_bin_path
|
|
723
|
-
fname = ['dynldr', host_arch, host_cpu.shortname,
|
|
724
|
-
('19' if RUBY_VERSION >= '1.9')].compact.join('-') + '.so'
|
|
727
|
+
fname = ['dynldr', host_arch, host_cpu.shortname, RUBY_VERSION.gsub('.', '')].join('-') + '.so'
|
|
725
728
|
dir = File.dirname(__FILE__)
|
|
726
729
|
binmodule = File.join(dir, fname)
|
|
727
730
|
if not File.exists? binmodule or File.stat(binmodule).mtime < File.stat(__FILE__).mtime
|
|
@@ -765,7 +768,7 @@ EOS
|
|
|
765
768
|
else raise LoadError, "Unsupported host platform #{RUBY_PLATFORM}"
|
|
766
769
|
end
|
|
767
770
|
end
|
|
768
|
-
|
|
771
|
+
|
|
769
772
|
# returns whether we run on linux or windows
|
|
770
773
|
def self.host_arch
|
|
771
774
|
case RUBY_PLATFORM
|
|
@@ -788,16 +791,73 @@ EOS
|
|
|
788
791
|
cp.parse(src)
|
|
789
792
|
end
|
|
790
793
|
|
|
791
|
-
# compile a C fragment into a
|
|
794
|
+
# compile a C fragment into a Shellcode_RWX, honors the host ABI
|
|
792
795
|
def self.compile_c(src)
|
|
793
796
|
# XXX could we reuse self.cp ? (for its macros etc)
|
|
794
797
|
cp = C::Parser.new(host_exe.new(host_cpu))
|
|
795
798
|
cp.parse(src)
|
|
796
|
-
sc =
|
|
799
|
+
sc = Shellcode_RWX.new(host_cpu)
|
|
797
800
|
asm = host_cpu.new_ccompiler(cp, sc).compile
|
|
798
801
|
sc.assemble(asm)
|
|
799
802
|
end
|
|
800
803
|
|
|
804
|
+
# maps a Shellcode_RWX in memory, fixup stdlib relocations
|
|
805
|
+
# returns the Shellcode_RWX, with the base_r/w/x initialized to the allocated memory
|
|
806
|
+
def self.sc_map_resolve(sc)
|
|
807
|
+
sc_map_resolve_addthunks(sc)
|
|
808
|
+
|
|
809
|
+
sc.base_r = memory_alloc(sc.encoded_r.length) if sc.encoded_r.length > 0
|
|
810
|
+
sc.base_w = memory_alloc(sc.encoded_w.length) if sc.encoded_w.length > 0
|
|
811
|
+
sc.base_x = memory_alloc(sc.encoded_x.length) if sc.encoded_x.length > 0
|
|
812
|
+
|
|
813
|
+
locals = sc.encoded_r.export.keys | sc.encoded_w.export.keys | sc.encoded_x.export.keys
|
|
814
|
+
exts = sc.encoded_r.reloc_externals(locals) | sc.encoded_w.reloc_externals(locals) | sc.encoded_x.reloc_externals(locals)
|
|
815
|
+
bd = {}
|
|
816
|
+
exts.uniq.each { |ext| bd[ext] = sym_addr(lib_from_sym(ext), ext) or raise rescue raise "unknown symbol #{ext.inspect}" }
|
|
817
|
+
sc.fixup_check(bd)
|
|
818
|
+
|
|
819
|
+
memory_write sc.base_r, sc.encoded_r.data if sc.encoded_r.length > 0
|
|
820
|
+
memory_write sc.base_w, sc.encoded_w.data if sc.encoded_w.length > 0
|
|
821
|
+
memory_write sc.base_x, sc.encoded_x.data if sc.encoded_x.length > 0
|
|
822
|
+
|
|
823
|
+
memory_perm sc.base_r, sc.encoded_r.length, 'r' if sc.encoded_r.length > 0
|
|
824
|
+
memory_perm sc.base_w, sc.encoded_w.length, 'rw' if sc.encoded_w.length > 0
|
|
825
|
+
memory_perm sc.base_x, sc.encoded_x.length, 'rx' if sc.encoded_x.length > 0
|
|
826
|
+
|
|
827
|
+
sc
|
|
828
|
+
end
|
|
829
|
+
|
|
830
|
+
def self.sc_map_resolve_addthunks(sc)
|
|
831
|
+
case host_cpu.shortname
|
|
832
|
+
when 'x64'
|
|
833
|
+
# patch 'call moo' into 'call thunk; thunk: jmp qword [moo_ptr]'
|
|
834
|
+
# this is similar to ELF PLT section, allowing code to call
|
|
835
|
+
# into a library mapped more than 4G away
|
|
836
|
+
# XXX handles only 'call extern', not 'lea reg, extern' or anything else
|
|
837
|
+
# in this case, the linker will still raise an 'immediate overflow'
|
|
838
|
+
# during fixup_check in sc_map_resolve
|
|
839
|
+
[sc.encoded_r, sc.encoded_w, sc.encoded_x].each { |edata|
|
|
840
|
+
edata.reloc.dup.each { |off, rel|
|
|
841
|
+
# target only call extern / jmp.i32 extern
|
|
842
|
+
next if rel.type != :i32
|
|
843
|
+
next if rel.target.op != :-
|
|
844
|
+
next if edata.export[rel.target.rexpr] != off+4
|
|
845
|
+
next if edata.export[rel.target.lexpr]
|
|
846
|
+
opc = edata.data[off-1, 1].unpack('C')[0]
|
|
847
|
+
next if opc != 0xe8 and opc != 0xe9
|
|
848
|
+
|
|
849
|
+
thunk_sc = Shellcode.new(host_cpu).share_namespace(sc)
|
|
850
|
+
thunk = thunk_sc.assemble(<<EOS).encoded
|
|
851
|
+
1: jmp qword [rip]
|
|
852
|
+
dq #{rel.target.lexpr}
|
|
853
|
+
EOS
|
|
854
|
+
edata << thunk
|
|
855
|
+
rel.target.lexpr = thunk.inv_export[0]
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
end
|
|
859
|
+
end
|
|
860
|
+
|
|
801
861
|
# retrieve the library where a symbol is to be found (uses AutoImport)
|
|
802
862
|
def self.lib_from_sym(symname)
|
|
803
863
|
case host_arch
|
|
@@ -821,7 +881,7 @@ EOS
|
|
|
821
881
|
cp.toplevel.symbol.delete v.name
|
|
822
882
|
lib = fromlib || lib_from_sym(v.name)
|
|
823
883
|
addr = sym_addr(lib, v.name)
|
|
824
|
-
|
|
884
|
+
if addr == 0 or addr == -1 or addr == 0xffff_ffff or addr == 0xffffffff_ffffffff
|
|
825
885
|
api_not_found(lib, v)
|
|
826
886
|
next
|
|
827
887
|
end
|
|
@@ -912,11 +972,11 @@ EOS
|
|
|
912
972
|
flags |= 4 if proto.type.type.integral? and cp.sizeof(nil, proto.type.type) == 8
|
|
913
973
|
flags |= 8 if proto.type.type.float?
|
|
914
974
|
class << self ; self ; end.send(:define_method, name) { |*a|
|
|
915
|
-
raise ArgumentError, "bad arg count for #{name}: #{a.length} for #{proto.type.args.length}" if a.length != proto.type.args.length and not proto.type.varargs
|
|
975
|
+
raise ArgumentError, "bad arg count for #{name}: #{a.length} for #{proto.type.args.to_a.length}" if a.length != proto.type.args.to_a.length and not proto.type.varargs
|
|
916
976
|
|
|
917
977
|
# convert the arglist suitably for raw_invoke
|
|
918
978
|
auto_cb = [] # list of automatic C callbacks generated from lambdas
|
|
919
|
-
a = a.zip(proto.type.args).map { |ra, fa|
|
|
979
|
+
a = a.zip(proto.type.args.to_a).map { |ra, fa|
|
|
920
980
|
aa = convert_rb2c(fa, ra, :cb_list => auto_cb)
|
|
921
981
|
if fa and fa.type.integral? and cp.sizeof(fa) == 8 and host_cpu.size == 32
|
|
922
982
|
aa = [aa & 0xffff_ffff, (aa >> 32) & 0xffff_ffff]
|
|
@@ -965,6 +1025,10 @@ EOS
|
|
|
965
1025
|
raise "invalid callback #{'%x' % id} not in #{@@callback_table.keys.map { |c| c.to_s(16) }}" if not cb
|
|
966
1026
|
|
|
967
1027
|
rawargs = args.dup
|
|
1028
|
+
if host_cpu.shortname == 'ia32' and (not cb[:proto_ori] or not cb[:proto_ori].has_attribute('fastcall'))
|
|
1029
|
+
rawargs.shift
|
|
1030
|
+
rawargs.shift
|
|
1031
|
+
end
|
|
968
1032
|
ra = cb[:proto] ? cb[:proto].args.map { |fa| convert_cbargs_c2rb(fa, rawargs) } : []
|
|
969
1033
|
|
|
970
1034
|
# run it
|
|
@@ -995,6 +1059,7 @@ EOS
|
|
|
995
1059
|
# XXX val is an integer, how to decode Floats etc ? raw binary ptr ?
|
|
996
1060
|
def self.convert_c2rb(formal, val)
|
|
997
1061
|
formal = formal.type if formal.kind_of? C::Variable
|
|
1062
|
+
val &= (1 << 8*cp.sizeof(formal))-1 if formal.integral?
|
|
998
1063
|
val = Expression.make_signed(val, 8*cp.sizeof(formal)) if formal.integral? and formal.signed?
|
|
999
1064
|
val = nil if formal.pointer? and val == 0
|
|
1000
1065
|
val
|
|
@@ -1019,13 +1084,8 @@ EOS
|
|
|
1019
1084
|
if (v and v.initializer) or cp.toplevel.statements.find { |st| st.kind_of? C::Asm }
|
|
1020
1085
|
cp.toplevel.statements.delete_if { |st| st.kind_of? C::Asm }
|
|
1021
1086
|
cp.toplevel.symbol.delete v.name if v
|
|
1022
|
-
sc = compile_c(proto)
|
|
1023
|
-
|
|
1024
|
-
sc.base_addr = ptr
|
|
1025
|
-
# TODO fixup external calls
|
|
1026
|
-
memory_write ptr, sc.encode_string
|
|
1027
|
-
memory_perm ptr, sc.encoded.length, 'rwx'
|
|
1028
|
-
ptr
|
|
1087
|
+
sc = sc_map_resolve(compile_c(proto))
|
|
1088
|
+
sc.base_x
|
|
1029
1089
|
elsif not v
|
|
1030
1090
|
raise 'empty prototype'
|
|
1031
1091
|
else
|
|
@@ -1044,6 +1104,7 @@ EOS
|
|
|
1044
1104
|
cb[:id] = id
|
|
1045
1105
|
cb[:proc] = b
|
|
1046
1106
|
cb[:proto] = proto
|
|
1107
|
+
cb[:proto_ori] = ori
|
|
1047
1108
|
cb[:abi_stackfix] = proto.args.inject(0) { |s, a| s + [cp.sizeof(a), cp.typesize[:ptr]].max } if ori and ori.has_attribute('stdcall')
|
|
1048
1109
|
cb[:abi_stackfix] = proto.args[2..-1].to_a.inject(0) { |s, a| s + [cp.sizeof(a), cp.typesize[:ptr]].max } if ori and ori.has_attribute('fastcall') # supercedes stdcall
|
|
1049
1110
|
@@callback_table[id] = cb
|
|
@@ -1058,29 +1119,34 @@ EOS
|
|
|
1058
1119
|
# finds a free callback id, allocates a new page if needed
|
|
1059
1120
|
def self.callback_find_id
|
|
1060
1121
|
if not id = @@callback_addrs.find { |a| not @@callback_table[a] }
|
|
1061
|
-
|
|
1122
|
+
page_size = 4096
|
|
1123
|
+
cb_page = memory_alloc(page_size)
|
|
1062
1124
|
sc = Shellcode.new(host_cpu, cb_page)
|
|
1063
1125
|
case sc.cpu.shortname
|
|
1064
1126
|
when 'ia32'
|
|
1065
|
-
|
|
1066
|
-
nrcb = 128 # TODO should be 4096/5, but the parser/compiler is really too slow
|
|
1067
|
-
nrcb.times {
|
|
1068
|
-
@@callback_addrs << addr
|
|
1069
|
-
sc.parse "call #{CALLBACK_TARGET}"
|
|
1070
|
-
addr += 5
|
|
1071
|
-
}
|
|
1127
|
+
asm = "call #{CALLBACK_TARGET}"
|
|
1072
1128
|
when 'x64'
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1129
|
+
if (cb_page - CALLBACK_TARGET).abs >= 0x7fff_f000
|
|
1130
|
+
# cannot directly 'jmp CB_T'
|
|
1131
|
+
asm = "1: mov rax, #{CALLBACK_TARGET} push rax lea rax, [rip-$_+1b] ret"
|
|
1132
|
+
else
|
|
1133
|
+
asm = "1: lea rax, [rip-$_+1b] jmp #{CALLBACK_TARGET}"
|
|
1134
|
+
end
|
|
1135
|
+
else
|
|
1136
|
+
raise 'Who are you?'
|
|
1137
|
+
end
|
|
1138
|
+
|
|
1139
|
+
# fill the page with valid callbacks
|
|
1140
|
+
loop do
|
|
1141
|
+
off = sc.encoded.length
|
|
1142
|
+
sc.assemble asm
|
|
1143
|
+
break if sc.encoded.length > page_size
|
|
1144
|
+
@@callback_addrs << (cb_page + off)
|
|
1080
1145
|
end
|
|
1081
|
-
|
|
1082
|
-
memory_write cb_page, sc.encode_string
|
|
1083
|
-
memory_perm cb_page,
|
|
1146
|
+
|
|
1147
|
+
memory_write cb_page, sc.encode_string[0, page_size]
|
|
1148
|
+
memory_perm cb_page, page_size, 'rx'
|
|
1149
|
+
|
|
1084
1150
|
raise 'callback_alloc bouh' if not id = @@callback_addrs.find { |a| not @@callback_table[a] }
|
|
1085
1151
|
end
|
|
1086
1152
|
id
|
|
@@ -1090,23 +1156,17 @@ EOS
|
|
|
1090
1156
|
# returns the raw pointer to the code page
|
|
1091
1157
|
# if given a block, run the block and then undefine all the C functions & free memory
|
|
1092
1158
|
def self.new_func_c(src)
|
|
1093
|
-
sc = compile_c(src)
|
|
1094
|
-
|
|
1095
|
-
sc.base_addr = ptr
|
|
1096
|
-
bd = sc.encoded.binding(ptr)
|
|
1097
|
-
sc.encoded.reloc_externals.uniq.each { |ext| bd[ext] = sym_addr(lib_from_sym(ext), ext) or raise "unknown symbol #{ext}" }
|
|
1098
|
-
sc.encoded.fixup(bd)
|
|
1099
|
-
memory_write ptr, sc.encode_string
|
|
1100
|
-
memory_perm ptr, sc.encoded.length, 'rwx'
|
|
1159
|
+
sc = sc_map_resolve(compile_c(src))
|
|
1160
|
+
|
|
1101
1161
|
parse_c(src) # XXX the Shellcode parser may have defined stuff / interpreted C another way...
|
|
1102
1162
|
defs = []
|
|
1103
1163
|
cp.toplevel.symbol.dup.each_value { |v|
|
|
1104
1164
|
next if not v.kind_of? C::Variable
|
|
1105
1165
|
cp.toplevel.symbol.delete v.name
|
|
1106
1166
|
next if not v.type.kind_of? C::Function or not v.initializer
|
|
1107
|
-
next if not off = sc.
|
|
1167
|
+
next if not off = sc.encoded_x.export[v.name]
|
|
1108
1168
|
rbname = c_func_name_to_rb(v.name)
|
|
1109
|
-
new_caller_for(v, rbname,
|
|
1169
|
+
new_caller_for(v, rbname, sc.base_x+off)
|
|
1110
1170
|
defs << rbname
|
|
1111
1171
|
}
|
|
1112
1172
|
if block_given?
|
|
@@ -1114,16 +1174,20 @@ EOS
|
|
|
1114
1174
|
yield
|
|
1115
1175
|
ensure
|
|
1116
1176
|
defs.each { |d| class << self ; self ; end.send(:remove_method, d) }
|
|
1117
|
-
memory_free
|
|
1177
|
+
memory_free sc.base_r if sc.base_r
|
|
1178
|
+
memory_free sc.base_w if sc.base_w
|
|
1179
|
+
memory_free sc.base_x if sc.base_x
|
|
1118
1180
|
end
|
|
1119
1181
|
else
|
|
1120
|
-
|
|
1182
|
+
sc.base_x
|
|
1121
1183
|
end
|
|
1122
1184
|
end
|
|
1123
1185
|
|
|
1124
1186
|
# compile an asm sequence, callable with the ABI of the C prototype given
|
|
1125
1187
|
# function name comes from the prototype
|
|
1126
|
-
|
|
1188
|
+
# the shellcode is mapped in read-only memory unless selfmodifyingcode is true
|
|
1189
|
+
# note that you can use a .data section for simple writable non-executable memory
|
|
1190
|
+
def self.new_func_asm(proto, asm, selfmodifyingcode=false)
|
|
1127
1191
|
proto += "\n;"
|
|
1128
1192
|
old = cp.toplevel.symbol.keys
|
|
1129
1193
|
parse_c(proto)
|
|
@@ -1133,24 +1197,24 @@ EOS
|
|
|
1133
1197
|
raise "invalid func proto #{proto}" if not f.name or not f.type.kind_of? C::Function or f.initializer
|
|
1134
1198
|
cp.toplevel.symbol.delete f.name
|
|
1135
1199
|
|
|
1136
|
-
sc =
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
memory_write ptr, sc.encode_string
|
|
1142
|
-
memory_perm ptr, sc.encoded.length, 'rwx'
|
|
1200
|
+
sc = Shellcode_RWX.assemble(host_cpu, asm)
|
|
1201
|
+
sc = sc_map_resolve(sc)
|
|
1202
|
+
if selfmodifyingcode
|
|
1203
|
+
memory_perm sc.base_x, sc.encoded_x.length, 'rwx'
|
|
1204
|
+
end
|
|
1143
1205
|
rbname = c_func_name_to_rb(f.name)
|
|
1144
|
-
new_caller_for(f, rbname,
|
|
1206
|
+
new_caller_for(f, rbname, sc.base_x)
|
|
1145
1207
|
if block_given?
|
|
1146
1208
|
begin
|
|
1147
1209
|
yield
|
|
1148
1210
|
ensure
|
|
1149
1211
|
class << self ; self ; end.send(:remove_method, rbname)
|
|
1150
|
-
memory_free
|
|
1212
|
+
memory_free sc.base_r if sc.base_r
|
|
1213
|
+
memory_free sc.base_w if sc.base_w
|
|
1214
|
+
memory_free sc.base_x
|
|
1151
1215
|
end
|
|
1152
1216
|
else
|
|
1153
|
-
|
|
1217
|
+
sc.base_x
|
|
1154
1218
|
end
|
|
1155
1219
|
end
|
|
1156
1220
|
|
|
@@ -1234,69 +1298,70 @@ EOS
|
|
|
1234
1298
|
when :windows
|
|
1235
1299
|
|
|
1236
1300
|
new_api_c <<EOS, 'kernel32'
|
|
1237
|
-
#define PAGE_NOACCESS 0x01
|
|
1238
|
-
#define PAGE_READONLY 0x02
|
|
1239
|
-
#define PAGE_READWRITE 0x04
|
|
1240
|
-
#define PAGE_WRITECOPY 0x08
|
|
1241
|
-
#define PAGE_EXECUTE 0x10
|
|
1242
|
-
#define PAGE_EXECUTE_READ 0x20
|
|
1243
|
-
#define PAGE_EXECUTE_READWRITE 0x40
|
|
1244
|
-
#define PAGE_EXECUTE_WRITECOPY 0x80
|
|
1245
|
-
#define PAGE_GUARD 0x100
|
|
1246
|
-
#define PAGE_NOCACHE 0x200
|
|
1247
|
-
#define PAGE_WRITECOMBINE 0x400
|
|
1248
|
-
|
|
1249
|
-
#define MEM_COMMIT 0x1000
|
|
1250
|
-
#define MEM_RESERVE 0x2000
|
|
1251
|
-
#define MEM_DECOMMIT 0x4000
|
|
1252
|
-
#define MEM_RELEASE 0x8000
|
|
1253
|
-
#define MEM_FREE 0x10000
|
|
1254
|
-
#define MEM_PRIVATE 0x20000
|
|
1255
|
-
#define MEM_MAPPED 0x40000
|
|
1256
|
-
#define MEM_RESET 0x80000
|
|
1257
|
-
#define MEM_TOP_DOWN 0x100000
|
|
1258
|
-
#define MEM_WRITE_WATCH 0x200000
|
|
1259
|
-
#define MEM_PHYSICAL 0x400000
|
|
1260
|
-
#define MEM_LARGE_PAGES 0x20000000
|
|
1261
|
-
#define MEM_4MB_PAGES 0x80000000
|
|
1301
|
+
#define PAGE_NOACCESS 0x01
|
|
1302
|
+
#define PAGE_READONLY 0x02
|
|
1303
|
+
#define PAGE_READWRITE 0x04
|
|
1304
|
+
#define PAGE_WRITECOPY 0x08
|
|
1305
|
+
#define PAGE_EXECUTE 0x10
|
|
1306
|
+
#define PAGE_EXECUTE_READ 0x20
|
|
1307
|
+
#define PAGE_EXECUTE_READWRITE 0x40
|
|
1308
|
+
#define PAGE_EXECUTE_WRITECOPY 0x80
|
|
1309
|
+
#define PAGE_GUARD 0x100
|
|
1310
|
+
#define PAGE_NOCACHE 0x200
|
|
1311
|
+
#define PAGE_WRITECOMBINE 0x400
|
|
1312
|
+
|
|
1313
|
+
#define MEM_COMMIT 0x1000
|
|
1314
|
+
#define MEM_RESERVE 0x2000
|
|
1315
|
+
#define MEM_DECOMMIT 0x4000
|
|
1316
|
+
#define MEM_RELEASE 0x8000
|
|
1317
|
+
#define MEM_FREE 0x10000
|
|
1318
|
+
#define MEM_PRIVATE 0x20000
|
|
1319
|
+
#define MEM_MAPPED 0x40000
|
|
1320
|
+
#define MEM_RESET 0x80000
|
|
1321
|
+
#define MEM_TOP_DOWN 0x100000
|
|
1322
|
+
#define MEM_WRITE_WATCH 0x200000
|
|
1323
|
+
#define MEM_PHYSICAL 0x400000
|
|
1324
|
+
#define MEM_LARGE_PAGES 0x20000000
|
|
1325
|
+
#define MEM_4MB_PAGES 0x80000000
|
|
1262
1326
|
|
|
1263
1327
|
__stdcall uintptr_t VirtualAlloc(uintptr_t addr, uintptr_t size, int type, int prot);
|
|
1264
1328
|
__stdcall uintptr_t VirtualFree(uintptr_t addr, uintptr_t size, int freetype);
|
|
1265
1329
|
__stdcall uintptr_t VirtualProtect(uintptr_t addr, uintptr_t size, int prot, int *oldprot);
|
|
1266
1330
|
EOS
|
|
1267
|
-
|
|
1331
|
+
|
|
1268
1332
|
# allocate some memory suitable for code allocation (ie VirtualAlloc)
|
|
1269
1333
|
def self.memory_alloc(sz)
|
|
1270
1334
|
virtualalloc(nil, sz, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE)
|
|
1271
1335
|
end
|
|
1272
|
-
|
|
1336
|
+
|
|
1273
1337
|
# free memory allocated through memory_alloc
|
|
1274
1338
|
def self.memory_free(addr)
|
|
1275
1339
|
virtualfree(addr, 0, MEM_RELEASE)
|
|
1276
1340
|
end
|
|
1277
|
-
|
|
1341
|
+
|
|
1278
1342
|
# change memory permissions - perm in [r rw rx rwx]
|
|
1279
1343
|
def self.memory_perm(addr, len, perm)
|
|
1280
1344
|
perm = { 'r' => PAGE_READONLY, 'rw' => PAGE_READWRITE, 'rx' => PAGE_EXECUTE_READ,
|
|
1281
1345
|
'rwx' => PAGE_EXECUTE_READWRITE }[perm.to_s.downcase]
|
|
1282
1346
|
virtualprotect(addr, len, perm, str_ptr([0].pack('C')*8))
|
|
1283
1347
|
end
|
|
1284
|
-
|
|
1348
|
+
|
|
1285
1349
|
when :linux
|
|
1286
|
-
|
|
1350
|
+
|
|
1287
1351
|
new_api_c <<EOS
|
|
1288
|
-
#define PROT_READ
|
|
1352
|
+
#define PROT_READ 0x1
|
|
1289
1353
|
#define PROT_WRITE 0x2
|
|
1290
|
-
#define PROT_EXEC
|
|
1354
|
+
#define PROT_EXEC 0x4
|
|
1291
1355
|
|
|
1292
|
-
#define MAP_PRIVATE
|
|
1356
|
+
#define MAP_PRIVATE 0x2
|
|
1357
|
+
#define MAP_FIXED 0x10
|
|
1293
1358
|
#define MAP_ANONYMOUS 0x20
|
|
1294
1359
|
|
|
1295
1360
|
uintptr_t mmap(uintptr_t addr, uintptr_t length, int prot, int flags, uintptr_t fd, uintptr_t offset);
|
|
1296
1361
|
uintptr_t munmap(uintptr_t addr, uintptr_t length);
|
|
1297
1362
|
uintptr_t mprotect(uintptr_t addr, uintptr_t len, int prot);
|
|
1298
1363
|
EOS
|
|
1299
|
-
|
|
1364
|
+
|
|
1300
1365
|
# allocate some memory suitable for code allocation (ie mmap)
|
|
1301
1366
|
def self.memory_alloc(sz)
|
|
1302
1367
|
@mmaps ||= {} # save size for mem_free
|
|
@@ -1304,26 +1369,48 @@ EOS
|
|
|
1304
1369
|
@mmaps[a] = sz
|
|
1305
1370
|
a
|
|
1306
1371
|
end
|
|
1307
|
-
|
|
1372
|
+
|
|
1308
1373
|
# free memory allocated through memory_alloc
|
|
1309
1374
|
def self.memory_free(addr)
|
|
1310
1375
|
munmap(addr, @mmaps[addr])
|
|
1311
1376
|
end
|
|
1312
|
-
|
|
1377
|
+
|
|
1313
1378
|
# change memory permissions - perm 'rwx'
|
|
1314
1379
|
# on PaX-enabled systems, this may need a non-mprotect-restricted ruby interpreter
|
|
1380
|
+
# if a mapping 'rx' is denied, will try to create a file and mmap() it rx in place
|
|
1315
1381
|
def self.memory_perm(addr, len, perm)
|
|
1316
1382
|
perm = perm.to_s.downcase
|
|
1317
1383
|
len += (addr & 0xfff) + 0xfff
|
|
1318
1384
|
len &= ~0xfff
|
|
1319
1385
|
addr &= ~0xfff
|
|
1386
|
+
|
|
1320
1387
|
p = 0
|
|
1321
|
-
p |= PROT_READ
|
|
1322
|
-
p |= PROT_WRITE if perm.include?
|
|
1323
|
-
p |= PROT_EXEC
|
|
1324
|
-
|
|
1388
|
+
p |= PROT_READ if perm.include?('r')
|
|
1389
|
+
p |= PROT_WRITE if perm.include?('w')
|
|
1390
|
+
p |= PROT_EXEC if perm.include?('x')
|
|
1391
|
+
|
|
1392
|
+
ret = mprotect(addr, len, p)
|
|
1393
|
+
|
|
1394
|
+
if ret != 0 and perm.include?('x') and not perm.include?('w') and len > 0 and @memory_perm_wd ||= find_write_dir
|
|
1395
|
+
# We are on a PaX-mprotected system. Try to use a file mapping to work aroud.
|
|
1396
|
+
Dir.chdir(@memory_perm_wd) {
|
|
1397
|
+
fname = 'tmp_mprot_%d_%x' % [Process.pid, addr]
|
|
1398
|
+
data = memory_read(addr, len)
|
|
1399
|
+
begin
|
|
1400
|
+
File.open(fname, 'w') { |fd| fd.write data }
|
|
1401
|
+
# reopen to ensure filesystem flush
|
|
1402
|
+
rret = File.open(fname, 'r') { |fd| mmap(addr, len, p, MAP_FIXED|MAP_PRIVATE, fd.fileno, 0) }
|
|
1403
|
+
raise 'hax' if data != memory_read(addr, len)
|
|
1404
|
+
ret = 0 if rret == addr
|
|
1405
|
+
ensure
|
|
1406
|
+
File.unlink(fname) rescue nil
|
|
1407
|
+
end
|
|
1408
|
+
}
|
|
1409
|
+
end
|
|
1410
|
+
|
|
1411
|
+
ret
|
|
1325
1412
|
end
|
|
1326
|
-
|
|
1413
|
+
|
|
1327
1414
|
end
|
|
1328
1415
|
end
|
|
1329
1416
|
end
|