metasm 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (235) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/.hgtags +3 -0
  4. data/Gemfile +1 -0
  5. data/INSTALL +61 -0
  6. data/LICENCE +458 -0
  7. data/README +29 -21
  8. data/Rakefile +10 -0
  9. data/TODO +10 -12
  10. data/doc/code_organisation.txt +2 -0
  11. data/doc/core/DynLdr.txt +247 -0
  12. data/doc/core/ExeFormat.txt +43 -0
  13. data/doc/core/Expression.txt +220 -0
  14. data/doc/core/GNUExports.txt +27 -0
  15. data/doc/core/Ia32.txt +236 -0
  16. data/doc/core/SerialStruct.txt +108 -0
  17. data/doc/core/VirtualString.txt +145 -0
  18. data/doc/core/WindowsExports.txt +61 -0
  19. data/doc/core/index.txt +1 -0
  20. data/doc/style.css +6 -3
  21. data/doc/usage/debugger.txt +327 -0
  22. data/doc/usage/index.txt +1 -0
  23. data/doc/use_cases.txt +2 -2
  24. data/metasm.gemspec +22 -0
  25. data/{lib/metasm.rb → metasm.rb} +11 -3
  26. data/{lib/metasm → metasm}/compile_c.rb +13 -7
  27. data/metasm/cpu/arc.rb +8 -0
  28. data/metasm/cpu/arc/decode.rb +425 -0
  29. data/metasm/cpu/arc/main.rb +191 -0
  30. data/metasm/cpu/arc/opcodes.rb +588 -0
  31. data/{lib/metasm → metasm/cpu}/arm.rb +7 -5
  32. data/{lib/metasm → metasm/cpu}/arm/debug.rb +2 -2
  33. data/{lib/metasm → metasm/cpu}/arm/decode.rb +13 -12
  34. data/{lib/metasm → metasm/cpu}/arm/encode.rb +23 -8
  35. data/{lib/metasm → metasm/cpu}/arm/main.rb +0 -3
  36. data/metasm/cpu/arm/opcodes.rb +324 -0
  37. data/{lib/metasm → metasm/cpu}/arm/parse.rb +25 -13
  38. data/{lib/metasm → metasm/cpu}/arm/render.rb +2 -2
  39. data/metasm/cpu/arm64.rb +15 -0
  40. data/metasm/cpu/arm64/debug.rb +38 -0
  41. data/metasm/cpu/arm64/decode.rb +289 -0
  42. data/metasm/cpu/arm64/encode.rb +41 -0
  43. data/metasm/cpu/arm64/main.rb +105 -0
  44. data/metasm/cpu/arm64/opcodes.rb +232 -0
  45. data/metasm/cpu/arm64/parse.rb +20 -0
  46. data/metasm/cpu/arm64/render.rb +95 -0
  47. data/{lib/metasm/ppc.rb → metasm/cpu/bpf.rb} +2 -4
  48. data/metasm/cpu/bpf/decode.rb +142 -0
  49. data/metasm/cpu/bpf/main.rb +60 -0
  50. data/metasm/cpu/bpf/opcodes.rb +81 -0
  51. data/metasm/cpu/bpf/render.rb +41 -0
  52. data/metasm/cpu/cy16.rb +9 -0
  53. data/metasm/cpu/cy16/decode.rb +253 -0
  54. data/metasm/cpu/cy16/main.rb +63 -0
  55. data/metasm/cpu/cy16/opcodes.rb +78 -0
  56. data/metasm/cpu/cy16/render.rb +41 -0
  57. data/metasm/cpu/dalvik.rb +11 -0
  58. data/{lib/metasm → metasm/cpu}/dalvik/decode.rb +35 -13
  59. data/{lib/metasm → metasm/cpu}/dalvik/main.rb +51 -2
  60. data/{lib/metasm → metasm/cpu}/dalvik/opcodes.rb +19 -11
  61. data/metasm/cpu/ia32.rb +17 -0
  62. data/{lib/metasm → metasm/cpu}/ia32/compile_c.rb +5 -7
  63. data/{lib/metasm → metasm/cpu}/ia32/debug.rb +5 -5
  64. data/{lib/metasm → metasm/cpu}/ia32/decode.rb +246 -59
  65. data/{lib/metasm → metasm/cpu}/ia32/decompile.rb +7 -7
  66. data/{lib/metasm → metasm/cpu}/ia32/encode.rb +19 -13
  67. data/{lib/metasm → metasm/cpu}/ia32/main.rb +51 -8
  68. data/metasm/cpu/ia32/opcodes.rb +1424 -0
  69. data/{lib/metasm → metasm/cpu}/ia32/parse.rb +47 -16
  70. data/{lib/metasm → metasm/cpu}/ia32/render.rb +31 -4
  71. data/metasm/cpu/mips.rb +14 -0
  72. data/{lib/metasm → metasm/cpu}/mips/compile_c.rb +1 -1
  73. data/metasm/cpu/mips/debug.rb +42 -0
  74. data/{lib/metasm → metasm/cpu}/mips/decode.rb +46 -16
  75. data/{lib/metasm → metasm/cpu}/mips/encode.rb +4 -3
  76. data/{lib/metasm → metasm/cpu}/mips/main.rb +11 -4
  77. data/{lib/metasm → metasm/cpu}/mips/opcodes.rb +86 -17
  78. data/{lib/metasm → metasm/cpu}/mips/parse.rb +1 -1
  79. data/{lib/metasm → metasm/cpu}/mips/render.rb +1 -1
  80. data/{lib/metasm/dalvik.rb → metasm/cpu/msp430.rb} +1 -1
  81. data/metasm/cpu/msp430/decode.rb +247 -0
  82. data/metasm/cpu/msp430/main.rb +62 -0
  83. data/metasm/cpu/msp430/opcodes.rb +101 -0
  84. data/{lib/metasm → metasm/cpu}/pic16c/decode.rb +6 -7
  85. data/{lib/metasm → metasm/cpu}/pic16c/main.rb +0 -0
  86. data/{lib/metasm → metasm/cpu}/pic16c/opcodes.rb +1 -1
  87. data/{lib/metasm/mips.rb → metasm/cpu/ppc.rb} +4 -4
  88. data/{lib/metasm → metasm/cpu}/ppc/decode.rb +18 -12
  89. data/{lib/metasm → metasm/cpu}/ppc/decompile.rb +3 -3
  90. data/{lib/metasm → metasm/cpu}/ppc/encode.rb +2 -2
  91. data/{lib/metasm → metasm/cpu}/ppc/main.rb +17 -12
  92. data/{lib/metasm → metasm/cpu}/ppc/opcodes.rb +11 -5
  93. data/metasm/cpu/ppc/parse.rb +55 -0
  94. data/metasm/cpu/python.rb +8 -0
  95. data/metasm/cpu/python/decode.rb +136 -0
  96. data/metasm/cpu/python/main.rb +36 -0
  97. data/metasm/cpu/python/opcodes.rb +180 -0
  98. data/{lib/metasm → metasm/cpu}/sh4.rb +1 -1
  99. data/{lib/metasm → metasm/cpu}/sh4/decode.rb +48 -17
  100. data/{lib/metasm → metasm/cpu}/sh4/main.rb +13 -4
  101. data/{lib/metasm → metasm/cpu}/sh4/opcodes.rb +7 -8
  102. data/metasm/cpu/x86_64.rb +15 -0
  103. data/{lib/metasm → metasm/cpu}/x86_64/compile_c.rb +28 -17
  104. data/{lib/metasm → metasm/cpu}/x86_64/debug.rb +4 -4
  105. data/{lib/metasm → metasm/cpu}/x86_64/decode.rb +57 -15
  106. data/{lib/metasm → metasm/cpu}/x86_64/encode.rb +55 -26
  107. data/{lib/metasm → metasm/cpu}/x86_64/main.rb +14 -6
  108. data/metasm/cpu/x86_64/opcodes.rb +136 -0
  109. data/{lib/metasm → metasm/cpu}/x86_64/parse.rb +10 -2
  110. data/metasm/cpu/x86_64/render.rb +35 -0
  111. data/metasm/cpu/z80.rb +9 -0
  112. data/metasm/cpu/z80/decode.rb +313 -0
  113. data/metasm/cpu/z80/main.rb +67 -0
  114. data/metasm/cpu/z80/opcodes.rb +224 -0
  115. data/metasm/cpu/z80/render.rb +59 -0
  116. data/{lib/metasm/os/main.rb → metasm/debug.rb} +160 -401
  117. data/{lib/metasm → metasm}/decode.rb +35 -4
  118. data/{lib/metasm → metasm}/decompile.rb +15 -16
  119. data/{lib/metasm → metasm}/disassemble.rb +201 -45
  120. data/{lib/metasm → metasm}/disassemble_api.rb +651 -87
  121. data/{lib/metasm → metasm}/dynldr.rb +220 -133
  122. data/{lib/metasm → metasm}/encode.rb +10 -1
  123. data/{lib/metasm → metasm}/exe_format/a_out.rb +9 -6
  124. data/{lib/metasm → metasm}/exe_format/autoexe.rb +1 -0
  125. data/{lib/metasm → metasm}/exe_format/bflt.rb +57 -27
  126. data/{lib/metasm → metasm}/exe_format/coff.rb +11 -3
  127. data/{lib/metasm → metasm}/exe_format/coff_decode.rb +53 -20
  128. data/{lib/metasm → metasm}/exe_format/coff_encode.rb +11 -13
  129. data/{lib/metasm → metasm}/exe_format/dex.rb +13 -5
  130. data/{lib/metasm → metasm}/exe_format/dol.rb +1 -0
  131. data/{lib/metasm → metasm}/exe_format/elf.rb +93 -57
  132. data/{lib/metasm → metasm}/exe_format/elf_decode.rb +143 -34
  133. data/{lib/metasm → metasm}/exe_format/elf_encode.rb +122 -31
  134. data/metasm/exe_format/gb.rb +65 -0
  135. data/metasm/exe_format/javaclass.rb +424 -0
  136. data/{lib/metasm → metasm}/exe_format/macho.rb +204 -16
  137. data/{lib/metasm → metasm}/exe_format/main.rb +26 -3
  138. data/{lib/metasm → metasm}/exe_format/mz.rb +1 -0
  139. data/{lib/metasm → metasm}/exe_format/nds.rb +7 -4
  140. data/{lib/metasm → metasm}/exe_format/pe.rb +71 -8
  141. data/metasm/exe_format/pyc.rb +167 -0
  142. data/{lib/metasm → metasm}/exe_format/serialstruct.rb +67 -14
  143. data/{lib/metasm → metasm}/exe_format/shellcode.rb +7 -3
  144. data/metasm/exe_format/shellcode_rwx.rb +114 -0
  145. data/metasm/exe_format/swf.rb +205 -0
  146. data/{lib/metasm → metasm}/exe_format/xcoff.rb +7 -7
  147. data/metasm/exe_format/zip.rb +335 -0
  148. data/metasm/gui.rb +13 -0
  149. data/{lib/metasm → metasm}/gui/cstruct.rb +35 -41
  150. data/{lib/metasm → metasm}/gui/dasm_coverage.rb +11 -11
  151. data/{lib/metasm → metasm}/gui/dasm_decomp.rb +7 -20
  152. data/{lib/metasm → metasm}/gui/dasm_funcgraph.rb +0 -0
  153. data/metasm/gui/dasm_graph.rb +1695 -0
  154. data/{lib/metasm → metasm}/gui/dasm_hex.rb +12 -8
  155. data/{lib/metasm → metasm}/gui/dasm_listing.rb +43 -28
  156. data/{lib/metasm → metasm}/gui/dasm_main.rb +310 -53
  157. data/{lib/metasm → metasm}/gui/dasm_opcodes.rb +5 -19
  158. data/{lib/metasm → metasm}/gui/debug.rb +93 -27
  159. data/{lib/metasm → metasm}/gui/gtk.rb +162 -40
  160. data/{lib/metasm → metasm}/gui/qt.rb +12 -2
  161. data/{lib/metasm → metasm}/gui/win32.rb +179 -42
  162. data/{lib/metasm → metasm}/gui/x11.rb +59 -59
  163. data/{lib/metasm → metasm}/main.rb +389 -264
  164. data/{lib/metasm/os/remote.rb → metasm/os/gdbremote.rb} +146 -54
  165. data/{lib/metasm → metasm}/os/gnu_exports.rb +1 -1
  166. data/{lib/metasm → metasm}/os/linux.rb +628 -151
  167. data/metasm/os/main.rb +330 -0
  168. data/{lib/metasm → metasm}/os/windows.rb +132 -42
  169. data/{lib/metasm → metasm}/os/windows_exports.rb +141 -0
  170. data/{lib/metasm → metasm}/parse.rb +26 -24
  171. data/{lib/metasm → metasm}/parse_c.rb +221 -116
  172. data/{lib/metasm → metasm}/preprocessor.rb +55 -40
  173. data/{lib/metasm → metasm}/render.rb +14 -38
  174. data/misc/hexdump.rb +2 -1
  175. data/misc/lint.rb +58 -0
  176. data/misc/txt2html.rb +9 -7
  177. data/samples/bindiff.rb +3 -4
  178. data/samples/dasm-plugins/bindiff.rb +15 -0
  179. data/samples/dasm-plugins/bookmark.rb +133 -0
  180. data/samples/dasm-plugins/c_constants.rb +57 -0
  181. data/samples/dasm-plugins/colortheme_solarized.rb +125 -0
  182. data/samples/dasm-plugins/cppobj_funcall.rb +60 -0
  183. data/samples/dasm-plugins/dasm_all.rb +70 -0
  184. data/samples/dasm-plugins/demangle_cpp.rb +31 -0
  185. data/samples/dasm-plugins/deobfuscate.rb +251 -0
  186. data/samples/dasm-plugins/dump_text.rb +35 -0
  187. data/samples/dasm-plugins/export_graph_svg.rb +86 -0
  188. data/samples/dasm-plugins/findgadget.rb +75 -0
  189. data/samples/dasm-plugins/hl_opcode.rb +32 -0
  190. data/samples/dasm-plugins/hotfix_gtk_dbg.rb +19 -0
  191. data/samples/dasm-plugins/imm2off.rb +34 -0
  192. data/samples/dasm-plugins/match_libsigs.rb +93 -0
  193. data/samples/dasm-plugins/patch_file.rb +95 -0
  194. data/samples/dasm-plugins/scanfuncstart.rb +36 -0
  195. data/samples/dasm-plugins/scanxrefs.rb +26 -0
  196. data/samples/dasm-plugins/selfmodify.rb +197 -0
  197. data/samples/dasm-plugins/stringsxrefs.rb +28 -0
  198. data/samples/dasmnavig.rb +1 -1
  199. data/samples/dbg-apihook.rb +24 -9
  200. data/samples/dbg-plugins/heapscan.rb +283 -0
  201. data/samples/dbg-plugins/heapscan/compiled_heapscan_lin.c +155 -0
  202. data/samples/dbg-plugins/heapscan/compiled_heapscan_win.c +128 -0
  203. data/samples/dbg-plugins/heapscan/graphheap.rb +616 -0
  204. data/samples/dbg-plugins/heapscan/heapscan.rb +709 -0
  205. data/samples/dbg-plugins/heapscan/winheap.h +174 -0
  206. data/samples/dbg-plugins/heapscan/winheap7.h +307 -0
  207. data/samples/dbg-plugins/trace_func.rb +214 -0
  208. data/samples/disassemble-gui.rb +35 -5
  209. data/samples/disassemble.rb +31 -6
  210. data/samples/dump_upx.rb +24 -12
  211. data/samples/dynamic_ruby.rb +12 -3
  212. data/samples/exeencode.rb +6 -5
  213. data/samples/factorize-headers-peimports.rb +1 -1
  214. data/samples/lindebug.rb +175 -381
  215. data/samples/metasm-shell.rb +1 -2
  216. data/samples/peldr.rb +2 -2
  217. data/tests/all.rb +1 -1
  218. data/tests/arc.rb +26 -0
  219. data/tests/dynldr.rb +22 -4
  220. data/tests/expression.rb +55 -0
  221. data/tests/graph_layout.rb +285 -0
  222. data/tests/ia32.rb +79 -26
  223. data/tests/mips.rb +9 -2
  224. data/tests/x86_64.rb +66 -18
  225. metadata +330 -218
  226. data/lib/metasm/arm/opcodes.rb +0 -177
  227. data/lib/metasm/gui.rb +0 -23
  228. data/lib/metasm/gui/dasm_graph.rb +0 -1354
  229. data/lib/metasm/ia32.rb +0 -14
  230. data/lib/metasm/ia32/opcodes.rb +0 -873
  231. data/lib/metasm/ppc/parse.rb +0 -52
  232. data/lib/metasm/x86_64.rb +0 -12
  233. data/lib/metasm/x86_64/opcodes.rb +0 -118
  234. data/samples/gdbclient.rb +0 -583
  235. data/samples/rubstop.rb +0 -399
@@ -0,0 +1,128 @@
1
+ typedef uintptr_t VALUE;
2
+ static VALUE const_WindowsHeap;
3
+ VALUE rb_ary_new(void);
4
+ VALUE rb_ary_push(VALUE, VALUE);
5
+ extern VALUE *rb_cObject __attribute__((import));
6
+ VALUE rb_const_get(VALUE, VALUE);
7
+ void rb_define_method(VALUE, char*, VALUE(*)(), int);
8
+ VALUE rb_funcall(VALUE recv, unsigned int id, int nargs, ...);
9
+ VALUE rb_intern(char*);
10
+ VALUE rb_iv_get(VALUE, char*);
11
+ VALUE rb_hash_aset(VALUE, VALUE, VALUE);
12
+ VALUE rb_hash_aref(VALUE, VALUE);
13
+ VALUE rb_uint2inum(VALUE);
14
+ VALUE rb_num2ulong(VALUE);
15
+ char *rb_string_value_ptr(VALUE*);
16
+ VALUE rb_gc_enable(void);
17
+ VALUE rb_gc_disable(void);
18
+
19
+ #include "winheap.h"
20
+
21
+ #define INT2FIX(i) (((i) << 1) | 1)
22
+
23
+ static VALUE m_WindowsHeap23scan_heap_segment(VALUE self, VALUE vfirst, VALUE vlen)
24
+ {
25
+ char *heapcpy;
26
+ struct _HEAP_ENTRY *he;
27
+ VALUE chunks;
28
+ VALUE first = rb_num2ulong(vfirst);
29
+ VALUE len = vlen >> 1;
30
+ VALUE off;
31
+ VALUE page;
32
+ VALUE sz;
33
+
34
+ chunks = rb_iv_get(self, "@chunks");
35
+ page = rb_funcall(self, rb_intern("pagecache"), 2, vfirst, INT2FIX(len));
36
+ heapcpy = rb_string_value_ptr(&page);
37
+
38
+ rb_gc_disable();
39
+ off = 0;
40
+ while (off < len) {
41
+ he = heapcpy + off;
42
+ if (he->Flags & 1) {
43
+ sz = (VALUE)he->Size*8;
44
+ if (sz > he->UnusedBytes)
45
+ sz -= he->UnusedBytes;
46
+ else
47
+ sz = 0;
48
+ rb_hash_aset(chunks, rb_uint2inum(first+off+sizeof(*he)), INT2FIX(sz));
49
+ }
50
+ off += he->Size*8;
51
+ }
52
+ rb_gc_enable();
53
+
54
+ return 4;
55
+ }
56
+
57
+ static VALUE m_WindowsHeap23scan_heap_segment_xr(VALUE self, VALUE vfirst, VALUE vlen)
58
+ {
59
+ char *heapcpy;
60
+ struct _HEAP_ENTRY *he;
61
+ VALUE chunks;
62
+ VALUE first = rb_num2ulong(vfirst);
63
+ VALUE len = vlen >> 1;
64
+ VALUE off;
65
+ VALUE page;
66
+ VALUE xrchunksto = rb_iv_get(self, "@xrchunksto");
67
+ VALUE xrchunksfrom = rb_iv_get(self, "@xrchunksfrom");
68
+
69
+ chunks = rb_iv_get(self, "@chunks");
70
+ page = rb_funcall(self, rb_intern("pagecache"), 2, vfirst, INT2FIX(len));
71
+ heapcpy = rb_string_value_ptr(&page);
72
+
73
+ rb_gc_disable();
74
+ off = 0;
75
+ VALUE *ptr0, base, cklen;
76
+ while (off < len) {
77
+ he = heapcpy + off;
78
+ // address of the chunk
79
+ base = first + off + sizeof(*he);
80
+ if ((he->Flags & 1) &&
81
+ (((cklen = rb_hash_aref(chunks, rb_uint2inum(base)))|4) != 4)) {
82
+ cklen /= 2*sizeof(void*); // /2 == FIX2INT
83
+ // pointer to the data for the chunk in our copy of the heap from pagecache
84
+ ptr0 = (VALUE*)(heapcpy + off + sizeof(*he));
85
+ VALUE tabto = 0;
86
+ VALUE tabfrom;
87
+ while (cklen--) {
88
+ VALUE p = *ptr0++;
89
+ //if (p == base) // ignore self-references
90
+ // continue;
91
+ if ((rb_hash_aref(chunks, rb_uint2inum(p))|4) != 4) {
92
+ if (!tabto) {
93
+ tabto = rb_ary_new();
94
+ rb_hash_aset(xrchunksto, rb_uint2inum(base), tabto);
95
+ }
96
+ rb_ary_push(tabto, rb_uint2inum(p));
97
+
98
+ tabfrom = rb_hash_aref(xrchunksfrom, rb_uint2inum(p));
99
+ if ((tabfrom|4) == 4) {
100
+ tabfrom = rb_ary_new();
101
+ rb_hash_aset(xrchunksfrom, rb_uint2inum(p), tabfrom);
102
+ }
103
+ rb_ary_push(tabfrom, rb_uint2inum(base));
104
+ }
105
+ }
106
+ }
107
+ if (!he->Size)
108
+ break;
109
+ off += he->Size*8;
110
+ }
111
+ rb_gc_enable();
112
+
113
+ return 4;
114
+ }
115
+
116
+ static void do_init_once(void)
117
+ {
118
+ const_WindowsHeap = rb_const_get(*rb_cObject, rb_intern("Metasm"));
119
+ const_WindowsHeap = rb_const_get(const_WindowsHeap, rb_intern("WindowsHeap"));
120
+ rb_define_method(const_WindowsHeap, "scan_heap_segment", m_WindowsHeap23scan_heap_segment, 2);
121
+ rb_define_method(const_WindowsHeap, "scan_heap_segment_xr", m_WindowsHeap23scan_heap_segment_xr, 2);
122
+ }
123
+
124
+ int Init_compiled_heapscan_win __attribute__((export))(void)
125
+ {
126
+ do_init_once();
127
+ return 0;
128
+ }
@@ -0,0 +1,616 @@
1
+ # This file is part of Metasm, the Ruby assembly manipulation suite
2
+ # Copyright (C) 2006-2009 Yoann GUILLOT
3
+ #
4
+ # Licence is LGPL, see LICENCE in the top-level directory
5
+
6
+ module ::Metasm
7
+ module Gui
8
+ class GraphHeapWidget < GraphViewWidget
9
+ attr_accessor :heap, :addr_struct, :snapped
10
+ # addr_struct = 0x234 => AllocCStruct
11
+
12
+ def set_color_arrow(b1, b2)
13
+ if b1 == @caret_box or b2 == @caret_box
14
+ draw_color :arrow_hl
15
+ else
16
+ draw_color :arrow_cond
17
+ end
18
+ end
19
+
20
+ def setup_contextmenu(b, m)
21
+ addsubmenu(m, '_follow pointer') {
22
+ next if not lm = b[:line_member][@caret_y]
23
+ addr = b[:line_struct][@caret_y][lm]
24
+ next if not @heap.chunks[addr]
25
+ if lm.kind_of?(::Integer)
26
+ t = b[:line_struct][@caret_y].struct.type
27
+ else
28
+ t = lm.type
29
+ end
30
+ if t.pointer? and t.pointed.untypedef.kind_of? C::Union
31
+ @heap.chunk_struct[addr] ||= t.pointed.untypedef
32
+ end
33
+ st = @heap.chunk_struct[addr] || create_struct(addr)
34
+ ed = @dasm.get_edata_at(addr)
35
+ @addr_struct[addr] = @heap.cp.decode_c_struct(st.name, ed.data, ed.ptr)
36
+ gui_update
37
+ }
38
+ addsubmenu(m, '_hide box') {
39
+ @selected_boxes.each { |sb|
40
+ @addr_struct.delete sb.id if @addr_struct.length > 1
41
+ }
42
+ @curcontext.root_addrs = struct_find_roots(@addr_struct.keys.first)
43
+ gui_update
44
+ }
45
+ super(b, m)
46
+ end
47
+
48
+ def keypress(k)
49
+ case k
50
+ when ?u
51
+ # update display (refresh struct member values)
52
+ @parent_widget.parent_widget.console.commands['refresh'][]
53
+ gui_update
54
+ when ?t
55
+ # change struct field type
56
+ if @selected_boxes.length > 1
57
+ # mass-retype chunks
58
+ st = @addr_struct[@selected_boxes[0].id].struct
59
+ inputbox("replacement struct for selected chunks", :text => st.name) { |n|
60
+ next if not nst = @heap.cp.toplevel.struct[n]
61
+ @selected_boxes.each { |sb|
62
+ as = @addr_struct[sb.id]
63
+ @heap.chunk_struct[sb.id] = nst
64
+ @addr_struct[sb.id] = @heap.cp.decode_c_struct(n, as.str, as.stroff)
65
+ }
66
+ gui_update
67
+ }
68
+ elsif b = @caret_box
69
+ if @caret_y == 0
70
+ as = @addr_struct[b.id]
71
+ st = as.struct
72
+ inputbox("replacement struct for #{st.name}", :text => st.name) { |n|
73
+ next if not nst = @heap.cp.toplevel.struct[n]
74
+ @heap.chunk_struct[b.id] = nst
75
+ @addr_struct[b.id] = @heap.cp.decode_c_struct(n, as.str, as.stroff)
76
+ gui_update
77
+ }
78
+ elsif m = b[:line_member][@caret_y]
79
+ if m.kind_of?(Integer)
80
+ # XXX Array, need to find the outer struct
81
+ mn = b[:line_text_col][@caret_y].map { |l, c| l }.join[/(\S*)\[/, 1]
82
+ ar = b[:line_struct][@caret_y]
83
+ st = b[:line_struct][0...@caret_y].reverse.compact.find { |st_| st_.struct.kind_of?(C::Struct) and st_[mn].struct == ar.struct }
84
+ raise '?' if not st
85
+ st = st.struct
86
+ m = st.fldlist[mn]
87
+ else
88
+ st = b[:line_struct][@caret_y].struct
89
+ end
90
+ inputbox("new type for #{m.name}", :text => m.dump_def(@heap.cp.toplevel)[0].join(' ')) { |nn|
91
+ nil while @heap.cp.readtok
92
+ @heap.cp.lexer.feed nn
93
+ if not v = C::Variable.parse_type(@heap.cp, @heap.cp.toplevel, true)
94
+ nil while @heap.cp.readtok
95
+ raise 'bad type'
96
+ end
97
+ v.parse_declarator(@heap.cp, @heap.cp.toplevel)
98
+ nt = v.type
99
+ nsz = @heap.cp.sizeof(nt)
100
+ osz = @heap.cp.sizeof(m)
101
+ if nsz > osz and st.kind_of?(C::Struct)
102
+ idx = st.members.index(m)
103
+ # eat next members
104
+ while nsz > osz
105
+ break if idx+1 >= st.members.length
106
+ sz = @heap.cp.sizeof(st.members.delete_at(idx+1))
107
+ osz += sz
108
+ end
109
+ end
110
+ if nsz < osz and st.kind_of?(C::Struct)
111
+ idx = st.members.index(m)
112
+ pos = st.offsetof(@heap.cp, m)
113
+ # fill gap with bytes
114
+ idx += 1
115
+ while nsz < osz
116
+ st.members[idx, 0] = [C::Variable.new(('unk_%x' % (pos+nsz)), C::BaseType.new(:__int8, :unsigned))]
117
+ idx += 1
118
+ nsz += 1
119
+ end
120
+ end
121
+ m.type = nt
122
+ st.update_member_cache(@heap.cp)
123
+ gui_update
124
+ }
125
+
126
+ end
127
+ end
128
+ when ?n
129
+ # rename struct field
130
+ if b = @caret_box
131
+ if @caret_y == 0
132
+ st = @addr_struct[b.id].struct
133
+ inputbox("new name for #{st.name}", :text => st.name) { |nn|
134
+ raise "struct #{nn} already exists (try 't')" if @heap.cp.toplevel.struct[nn]
135
+ @heap.cp.toplevel.struct[nn] = @heap.cp.toplevel.struct.delete(st.name)
136
+ st.name = nn
137
+ gui_update
138
+ }
139
+ elsif m = b[:line_member][@caret_y]
140
+ if m.kind_of?(Integer)
141
+ mn = b[:line_text_col][@caret_y].map { |l, c| l }.join[/(\S*)\[/, 1]
142
+ ar = b[:line_struct][@caret_y]
143
+ st = b[:line_struct][0...@caret_y].reverse.compact.find { |st_| st_.struct.kind_of?(C::Struct) and st_[mn].struct == ar.struct }
144
+ raise '?' if not st
145
+ st = st.struct
146
+ m = st.fldlist[mn]
147
+ else
148
+ st = b[:line_struct][@caret_y].struct
149
+ end
150
+ inputbox("new name for #{m.name}", :text => m.name) { |nn|
151
+ m.name = nn
152
+ st.update_member_cache(@heap.cp)
153
+ gui_update
154
+ }
155
+ end
156
+ end
157
+ when ?e
158
+ # edit struct field value under the cursor
159
+ if b = @caret_box
160
+ # TODO b[:struct][line], b.[:member][line] (int for Arrays)
161
+ st = b[:line_struct][@caret_y]
162
+ mb = b[:line_member][@caret_y]
163
+ if st and mb
164
+ if mb.kind_of?(C::Variable) and mb.type.kind_of?(C::Array) and mb.type.type.kind_of?(C::BaseType) and mb.type.type.name == :char
165
+ defval = st[mb].to_array.pack('C*').gsub(/\0*$/, '').gsub(/[^\x20-\x7e]/, '.')
166
+ string = true
167
+ else
168
+ defval = st[mb]
169
+ string = false
170
+ end
171
+ inputbox("new value for #{mb.respond_to?(:name) ? mb.name : mb}", :text => defval.to_s) { |nn|
172
+ if string
173
+ am = st[mb]
174
+ (nn.unpack('C*') + [0]).each_with_index { |b_, i| am[i] = b_ }
175
+ else
176
+ st[mb] = Expression.parse_string(nn).reduce
177
+ end
178
+ gui_update
179
+ }
180
+ end
181
+ end
182
+ when ?x
183
+ # show heap xrefs to the hilighted chunk
184
+ if b = @caret_box
185
+ list = [['address', 'size']]
186
+ @heap.xrchunksfrom[b.id].to_a.each { |a|
187
+ list << [Expression[a], Expression[@heap.chunks[a]]]
188
+ }
189
+ if list.length == 1
190
+ messagebox "no xref to #{Expression[b.id]}"
191
+ else
192
+ listwindow("heap xrefs to #{Expression[b.id]}", list) { |i| @parent_widget.focus_addr(i[0], nil, true) }
193
+ end
194
+ end
195
+ when ?I
196
+ # insert new field in struct
197
+ if b = @caret_box
198
+ if m = b[:line_member][@caret_y]
199
+ if m.kind_of?(Integer)
200
+ # XXX Array, need to find the outer struct
201
+ mn = b[:line_text_col][@caret_y].map { |l, c| l }.join[/(\S*)\[/, 1]
202
+ ar = b[:line_struct][@caret_y]
203
+ st = b[:line_struct][0...@caret_y].reverse.compact.find { |st_| st_.struct.kind_of?(C::Struct) and st_[mn].struct == ar.struct }
204
+ raise '?' if not st
205
+ st = st.struct
206
+ m = st.fldlist[mn]
207
+ else
208
+ st = b[:line_struct][@caret_y].struct
209
+ end
210
+ inputbox("new type to insert before #{m.name}", :text => m.dump_def(@heap.cp.toplevel)[0].join(' ')) { |nn|
211
+ nil while @heap.cp.readtok
212
+ @heap.cp.lexer.feed nn
213
+ if not v = C::Variable.parse_type(@heap.cp, @heap.cp.toplevel, true)
214
+ nil while @heap.cp.readtok
215
+ raise 'bad type'
216
+ end
217
+ v.parse_declarator(@heap.cp, @heap.cp.toplevel)
218
+ nt = v.type
219
+ idx = st.members.index(m)
220
+ pos = st.offsetof(@heap.cp, m)
221
+ name = oname = v.name || ('unk_%x_new' % pos)
222
+ cntr = 0
223
+ while st.members.find { |m_| m_.name == name }
224
+ name = oname + "_#{cntr+=1}"
225
+ end
226
+ st.members[idx, 0] = [C::Variable.new(name, nt)]
227
+ st.update_member_cache(@heap.cp)
228
+ gui_update
229
+ }
230
+
231
+ end
232
+ end
233
+ when ?S
234
+ # delete structure field
235
+ if b = @caret_box
236
+ if m = b[:line_member][@caret_y]
237
+ if m.kind_of?(Integer)
238
+ # XXX Array, need to find the outer struct
239
+ mn = b[:line_text_col][@caret_y].map { |l, c| l }.join[/(\S*)\[/, 1]
240
+ ar = b[:line_struct][@caret_y]
241
+ st = b[:line_struct][0...@caret_y].reverse.compact.find { |st_| st_.struct.kind_of?(C::Struct) and st_[mn].struct == ar.struct }
242
+ raise '?' if not st
243
+ st = st.struct
244
+ m = st.fldlist[mn]
245
+ else
246
+ st = b[:line_struct][@caret_y].struct
247
+ end
248
+ inputbox("delete #{m.name} ?") { |nn|
249
+ idx = st.members.index(m)
250
+ st.members.delete_at(idx)
251
+ st.update_member_cache(@heap.cp)
252
+ gui_update
253
+ }
254
+
255
+ end
256
+ end
257
+ when ?+
258
+ # append blocks linked from the currently shown blocks to the display
259
+ @addr_struct.keys.each { |ak|
260
+ @heap.xrchunksto[ak].to_a.each { |nt|
261
+ next if @addr_struct[nt]
262
+ # TODO check if the pointer is a some_struct*
263
+ st = @heap.chunk_struct[nt] || create_struct(nt)
264
+ ed = @dasm.get_edata_at(nt)
265
+ @addr_struct[nt] = @heap.cp.decode_c_struct(st.name, ed.data, ed.ptr)
266
+ }
267
+ }
268
+ gui_update
269
+ when ?-
270
+ # remove graph leaves in an attempt to undo ?+
271
+ unk = @addr_struct.keys.find_all { |ak|
272
+ (@heap.xrchunksto[ak].to_a & @addr_struct.keys).empty?
273
+ }
274
+ unk.each { |ak| @addr_struct.delete ak if @addr_struct.length > 1 }
275
+ gui_update
276
+ else return super(k)
277
+ end
278
+ true
279
+ end
280
+
281
+ # create the graph objects in ctx
282
+ def build_ctx(ctx)
283
+ # create boxes
284
+ todo = ctx.root_addrs.dup & @addr_struct.keys
285
+ todo << @addr_struct.keys.first if todo.empty?
286
+ done = []
287
+ while a = todo.shift
288
+ next if done.include? a
289
+ done << a
290
+ ctx.new_box a, :line_text_col => [], :line_address => [], :line_struct => [], :line_member => []
291
+ todo.concat @heap.xrchunksto[a].to_a & @addr_struct.keys
292
+ end
293
+
294
+ # link boxes
295
+ if (@heap.xrchunksto[ctx.box.first.id].to_a & @addr_struct.keys).length == ctx.box.length - 1
296
+ ot = ctx.box[0].id
297
+ ctx.box[1..-1].each { |b_|
298
+ ctx.link_boxes(ot, b_.id)
299
+ }
300
+ else
301
+ ctx.box.each { |b|
302
+ @heap.xrchunksto[b.id].to_a.each { |t|
303
+ ctx.link_boxes(b.id, t) if @addr_struct[t]
304
+ }
305
+ }
306
+ end
307
+
308
+ if snapped
309
+ @datadiff = {}
310
+ end
311
+
312
+ # calc box dimensions/text
313
+ ctx.box.each { |b|
314
+ colstr = []
315
+ curaddr = b.id
316
+ curst = @addr_struct[b.id]
317
+ curmb = nil
318
+ margin = ''
319
+ start_addr = curaddr
320
+ if snapped
321
+ ghosts = snapped[curaddr]
322
+ end
323
+ line = 0
324
+ render = lambda { |str, col| colstr << [str, col] }
325
+ nl = lambda {
326
+ b[:line_address][line] = curaddr
327
+ b[:line_text_col][line] = colstr
328
+ b[:line_struct][line] = curst
329
+ b[:line_member][line] = curmb
330
+ colstr = []
331
+ line += 1
332
+ }
333
+ render_val = lambda { |v|
334
+ if v.kind_of?(::Integer)
335
+ if v > 0x100
336
+ render['0x%X' % v, :text]
337
+ elsif v < -0x100
338
+ render['-0x%X' % -v, :text]
339
+ else
340
+ render[v.to_s, :text]
341
+ end
342
+ elsif not v
343
+ render['NULL', :text]
344
+ else
345
+ render[v.to_s, :text]
346
+ end
347
+ }
348
+ render_st = nil
349
+ render_st_ar = lambda { |ast, m|
350
+ elemt = m.type.untypedef.type.untypedef
351
+ if elemt.kind_of?(C::BaseType) and elemt.name == :char
352
+ render[margin, :text]
353
+ render["#{m.type.type.to_s[1...-1]} #{m.name}[#{m.type.length}] = #{ast[m].to_array.pack('C*').sub(/\0.*$/m, '').inspect}", :text]
354
+ nl[]
355
+ curaddr += ast.cp.sizeof(m)
356
+ else
357
+ t = m.type.type.to_s[1...-1]
358
+ tsz = ast.cp.sizeof(m.type.type)
359
+ fust = curst
360
+ fumb = curmb
361
+ curst = ast[m]
362
+ ast[m].to_array.each_with_index { |v, i|
363
+ curmb = i
364
+ render[margin, :text]
365
+ if elemt.kind_of?(C::Union)
366
+ if m.type.untypedef.type.kind_of?(C::Union)
367
+ render[elemt.kind_of?(C::Struct) ? 'struct ' : 'union ', :text]
368
+ render["#{elemt.name} ", :text] if elemt.name
369
+ else # typedef
370
+ render["#{elemt.to_s[1...-1]} ", :text]
371
+ end
372
+ render_st[v]
373
+ render[" #{m.name}[#{i}]", :text]
374
+ else
375
+ render["#{t} #{m.name}[#{i}] = ", :text]
376
+ render_val[v]
377
+ @datadiff[curaddr] = true if ghosts and ghosts.all? { |g| g[curaddr-start_addr, tsz] == ghosts[0][curaddr-start_addr, tsz] } and ghosts[0][curaddr-start_addr, tsz] != ast.str[curaddr, tsz].to_str
378
+ end
379
+ render[';', :text]
380
+ nl[]
381
+ curaddr += tsz
382
+ }
383
+ curst = fust
384
+ curmb = fumb
385
+ end
386
+ }
387
+ render_st = lambda { |ast|
388
+ st_addr = curaddr
389
+ oldst = curst
390
+ oldmb = curmb
391
+ oldmargin = margin
392
+ render['{', :text]
393
+ nl[]
394
+ margin += ' '
395
+ curst = ast
396
+ ast.struct.members.each { |m|
397
+ curmb = m
398
+ curaddr = st_addr + ast.struct.offsetof(@heap.cp, m)
399
+
400
+ if bo = ast.struct.bitoffsetof(@heap.cp, m)
401
+ # float curaddr to make ghost hilight work on bitfields
402
+ curaddr += (1+bo[0])/1000.0
403
+ end
404
+
405
+ if m.type.untypedef.kind_of?(C::Array)
406
+ render_st_ar[ast, m]
407
+ elsif m.type.untypedef.kind_of?(C::Union)
408
+ render[margin, :text]
409
+ if m.type.kind_of?(C::Union)
410
+ render[m.type.kind_of?(C::Struct) ? 'struct ' : 'union ', :text]
411
+ render["#{m.type.name} ", :text] if m.type.name
412
+ else # typedef
413
+ render["#{m.type.to_s[1...-1]} ", :text]
414
+ end
415
+ oca = curaddr
416
+ render_st[ast[m]]
417
+ nca = curaddr
418
+ curaddr = oca
419
+ render[" #{m.name if m.name};", :text]
420
+ nl[]
421
+ curaddr = nca
422
+ else
423
+ render[margin, :text]
424
+ render["#{m.type.to_s[1...-1]} ", :text]
425
+ render["#{m.name} = ", :text]
426
+ render_val[ast[m]]
427
+ tsz = ast.cp.sizeof(m)
428
+ # TODO bit-level multighosting
429
+ if ghosts and ghosts.all? { |g| g[curaddr.to_i-start_addr, tsz] == ghosts[0][curaddr.to_i-start_addr, tsz] } and ghosts[0][curaddr.to_i-start_addr, tsz] != ast.str[curaddr.to_i, tsz].to_str
430
+ if bo
431
+ ft = C::BaseType.new((bo[0] + bo[1] > 32) ? :__int64 : :__int32)
432
+ v1 = @heap.cp.decode_c_value(ghosts[0][curaddr.to_i-start_addr, tsz], ft, 0)
433
+ v2 = @heap.cp.decode_c_value(ast.str[curaddr.to_i, tsz], ft, 0)
434
+ @datadiff[curaddr] = true if (v1 >> bo[0]) & ((1 << bo[1])-1) != (v2 >> bo[0]) & ((1 << bo[1])-1)
435
+ else
436
+ @datadiff[curaddr] = true
437
+ end
438
+ end
439
+ render[';', :text]
440
+
441
+ if m.type.kind_of?(C::Pointer) and m.type.type.kind_of?(C::BaseType) and m.type.type.name == :char
442
+ if s = @dasm.decode_strz(ast[m], 32)
443
+ render[" // #{s.inspect}", :comment]
444
+ end
445
+ end
446
+ nl[]
447
+ curaddr += tsz
448
+ curaddr = curaddr.to_i if bo
449
+ end
450
+ }
451
+ margin = oldmargin
452
+ curst = oldst
453
+ curmb = oldmb
454
+ render[margin, :text]
455
+ render['}', :text]
456
+ }
457
+ ast = @addr_struct[curaddr]
458
+ render["struct #{ast.struct.name} *#{'0x%X' % curaddr} = ", :text]
459
+ render_st[ast]
460
+ render[';', :text]
461
+ nl[]
462
+
463
+ b.w = b[:line_text_col].map { |strc| strc.map { |s, c| s }.join.length }.max.to_i * @font_width + 2
464
+ b.w += 1 if b.w % 2 == 0
465
+ b.h = line * @font_height
466
+ }
467
+ end
468
+
469
+ def struct_find_roots(addr)
470
+ addr = @addr_struct.keys.find { |a| addr >= a and addr < a+@addr_struct[a].sizeof } if not @addr_struct[addr]
471
+
472
+ todo = [addr]
473
+ done = []
474
+ roots = []
475
+ default_root = nil
476
+ while a = todo.shift
477
+ if done.include?(a) # cycle
478
+ default_root ||= a
479
+ next
480
+ end
481
+ done << a
482
+ newf = @heap.xrchunksfrom[a].to_a & @addr_struct.keys
483
+ if newf.empty?
484
+ roots << a
485
+ else
486
+ todo.concat newf
487
+ end
488
+ end
489
+ roots << default_root if roots.empty? and default_root
490
+
491
+ roots
492
+ end
493
+
494
+ def focus_addr(addr, fu=nil)
495
+ return if @parent_widget and not addr = @parent_widget.normalize(addr)
496
+
497
+ # move window / change curcontext
498
+ if b = @curcontext.box.find { |b_| b_[:line_address].index(addr) }
499
+ @caret_box, @caret_x, @caret_y = b, 0, b[:line_address].rindex(addr)
500
+ @curcontext.view_x += (width/2 / @zoom - width/2)
501
+ @curcontext.view_y += (height/2 / @zoom - height/2)
502
+ @zoom = 1.0
503
+
504
+ focus_xy(b.x, b.y + @caret_y*@font_height)
505
+ update_caret
506
+ elsif addr_struct and (@addr_struct[addr] or @addr_struct.find { |a, s| addr >= a and addr < a+s.sizeof })
507
+ @curcontext = Graph.new 'testic'
508
+ @curcontext.root_addrs = struct_find_roots(addr)
509
+ @want_focus_addr = addr
510
+ gui_update
511
+ elsif @heap.chunks[addr]
512
+ @want_focus_addr = addr
513
+ do_focus_addr(addr)
514
+ else
515
+ return
516
+ end
517
+ true
518
+ end
519
+
520
+ def do_focus_addr(addr)
521
+ st = @heap.chunk_struct[addr] || create_struct(addr)
522
+
523
+ ed = @dasm.get_edata_at(addr)
524
+ @addr_struct = { addr => @heap.cp.decode_c_struct(st.name, ed.data, ed.ptr) }
525
+ gui_update
526
+ end
527
+
528
+ # create the struct chunk_<addr>, register it in @heap.chunk_struct
529
+ def create_struct(addr)
530
+ raise "no chunk here" if not @heap.chunks[addr]
531
+
532
+ ptsz = @dasm.cpu.size/8
533
+
534
+ # check if this is a c++ object with RTTI info
535
+ vptr = @dasm.decode_dword(addr)
536
+ rtti = @dasm.decode_dword(vptr-ptsz)
537
+ case OS.shortname
538
+ when 'winos'
539
+ typeinfo = @dasm.decode_dword(rtti+3*ptsz) if rtti
540
+ if typeinfo and s = @dasm.decode_strz(typeinfo+3*ptsz)
541
+ rtti_name = s[/^(.*)@@$/, 1] # remove trailing @@
542
+ end
543
+ when 'linos'
544
+ typeinfo = @dasm.decode_dword(rtti+ptsz) if rtti
545
+ if typeinfo and s = @dasm.decode_strz(typeinfo)
546
+ rtti_name = s[/^[0-9]+(.*)$/, 1] # remove leading number
547
+ end
548
+ end
549
+
550
+ if rtti_name and st = @heap.cp.toplevel.struct[rtti_name]
551
+ return @heap.chunk_struct[addr] = st
552
+ end
553
+
554
+ st = C::Struct.new
555
+ st.name = rtti_name || "chunk_#{'%x' % addr}"
556
+ st.members = []
557
+ li = 0
558
+ (@heap.chunks[addr] / ptsz).times { |i|
559
+ n = 'unk_%x' % (ptsz*i)
560
+ v = @dasm.decode_dword(addr+ptsz*i)
561
+ if i == 0 and rtti_name
562
+ t = C::Pointer.new(C::Pointer.new(C::BaseType.new(:void)))
563
+ n = 'vtable'
564
+ elsif @heap.chunks[v]
565
+ t = C::Pointer.new(C::BaseType.new(:void))
566
+ else
567
+ t = C::BaseType.new("__int#{ptsz*8}".to_sym, :unsigned)
568
+ end
569
+ st.members << C::Variable.new(n, t)
570
+ li = i+1
571
+ }
572
+ (@heap.chunks[addr] % ptsz).times { |i|
573
+ n = 'unk_%x' % (ptsz*li+i)
574
+ t = C::BaseType.new(:char, :unsigned)
575
+ st.members << C::Variable.new(n, t)
576
+ }
577
+ @heap.cp.toplevel.struct[st.name] = st
578
+ @heap.chunk_struct[addr] = st
579
+ end
580
+
581
+ def snap
582
+ if not snapped
583
+ @datadiff = {}
584
+ ocb = @parent_widget.bg_color_callback
585
+ @parent_widget.bg_color_callback = lambda { |a|
586
+ if @datadiff[a]
587
+ 'f88'
588
+ elsif ocb
589
+ ocb[a]
590
+ end
591
+ }
592
+ end
593
+ @snapped = {}
594
+ @addr_struct.each { |a, ast|
595
+ @snapped[a] = [ast.str[ast.stroff, ast.sizeof].to_str]
596
+ }
597
+ end
598
+
599
+ def snap_add
600
+ return snap if not snapped
601
+ @addr_struct.each { |a, ast|
602
+ (@snapped[a] ||= []) << ast.str[ast.stroff, ast.sizeof].to_str
603
+ }
604
+ end
605
+
606
+ def get_cursor_pos
607
+ [super, addr_struct]
608
+ end
609
+
610
+ def set_cursor_pos(p)
611
+ s, @addr_struct = p
612
+ super(s)
613
+ end
614
+ end
615
+ end
616
+ end