metasm 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (192) hide show
  1. data/BUGS +11 -0
  2. data/CREDITS +17 -0
  3. data/README +270 -0
  4. data/TODO +114 -0
  5. data/doc/code_organisation.txt +146 -0
  6. data/doc/const_missing.txt +16 -0
  7. data/doc/core_classes.txt +75 -0
  8. data/doc/feature_list.txt +53 -0
  9. data/doc/index.txt +59 -0
  10. data/doc/install_notes.txt +170 -0
  11. data/doc/style.css +3 -0
  12. data/doc/use_cases.txt +18 -0
  13. data/lib/metasm.rb +80 -0
  14. data/lib/metasm/arm.rb +12 -0
  15. data/lib/metasm/arm/debug.rb +39 -0
  16. data/lib/metasm/arm/decode.rb +167 -0
  17. data/lib/metasm/arm/encode.rb +77 -0
  18. data/lib/metasm/arm/main.rb +75 -0
  19. data/lib/metasm/arm/opcodes.rb +177 -0
  20. data/lib/metasm/arm/parse.rb +130 -0
  21. data/lib/metasm/arm/render.rb +55 -0
  22. data/lib/metasm/compile_c.rb +1457 -0
  23. data/lib/metasm/dalvik.rb +8 -0
  24. data/lib/metasm/dalvik/decode.rb +196 -0
  25. data/lib/metasm/dalvik/main.rb +60 -0
  26. data/lib/metasm/dalvik/opcodes.rb +366 -0
  27. data/lib/metasm/decode.rb +213 -0
  28. data/lib/metasm/decompile.rb +2659 -0
  29. data/lib/metasm/disassemble.rb +2068 -0
  30. data/lib/metasm/disassemble_api.rb +1280 -0
  31. data/lib/metasm/dynldr.rb +1329 -0
  32. data/lib/metasm/encode.rb +333 -0
  33. data/lib/metasm/exe_format/a_out.rb +194 -0
  34. data/lib/metasm/exe_format/autoexe.rb +82 -0
  35. data/lib/metasm/exe_format/bflt.rb +189 -0
  36. data/lib/metasm/exe_format/coff.rb +455 -0
  37. data/lib/metasm/exe_format/coff_decode.rb +901 -0
  38. data/lib/metasm/exe_format/coff_encode.rb +1078 -0
  39. data/lib/metasm/exe_format/dex.rb +457 -0
  40. data/lib/metasm/exe_format/dol.rb +145 -0
  41. data/lib/metasm/exe_format/elf.rb +923 -0
  42. data/lib/metasm/exe_format/elf_decode.rb +979 -0
  43. data/lib/metasm/exe_format/elf_encode.rb +1375 -0
  44. data/lib/metasm/exe_format/macho.rb +827 -0
  45. data/lib/metasm/exe_format/main.rb +228 -0
  46. data/lib/metasm/exe_format/mz.rb +164 -0
  47. data/lib/metasm/exe_format/nds.rb +172 -0
  48. data/lib/metasm/exe_format/pe.rb +437 -0
  49. data/lib/metasm/exe_format/serialstruct.rb +246 -0
  50. data/lib/metasm/exe_format/shellcode.rb +114 -0
  51. data/lib/metasm/exe_format/xcoff.rb +167 -0
  52. data/lib/metasm/gui.rb +23 -0
  53. data/lib/metasm/gui/cstruct.rb +373 -0
  54. data/lib/metasm/gui/dasm_coverage.rb +199 -0
  55. data/lib/metasm/gui/dasm_decomp.rb +369 -0
  56. data/lib/metasm/gui/dasm_funcgraph.rb +103 -0
  57. data/lib/metasm/gui/dasm_graph.rb +1354 -0
  58. data/lib/metasm/gui/dasm_hex.rb +543 -0
  59. data/lib/metasm/gui/dasm_listing.rb +599 -0
  60. data/lib/metasm/gui/dasm_main.rb +906 -0
  61. data/lib/metasm/gui/dasm_opcodes.rb +291 -0
  62. data/lib/metasm/gui/debug.rb +1228 -0
  63. data/lib/metasm/gui/gtk.rb +884 -0
  64. data/lib/metasm/gui/qt.rb +495 -0
  65. data/lib/metasm/gui/win32.rb +3004 -0
  66. data/lib/metasm/gui/x11.rb +621 -0
  67. data/lib/metasm/ia32.rb +14 -0
  68. data/lib/metasm/ia32/compile_c.rb +1523 -0
  69. data/lib/metasm/ia32/debug.rb +193 -0
  70. data/lib/metasm/ia32/decode.rb +1167 -0
  71. data/lib/metasm/ia32/decompile.rb +564 -0
  72. data/lib/metasm/ia32/encode.rb +314 -0
  73. data/lib/metasm/ia32/main.rb +233 -0
  74. data/lib/metasm/ia32/opcodes.rb +872 -0
  75. data/lib/metasm/ia32/parse.rb +327 -0
  76. data/lib/metasm/ia32/render.rb +91 -0
  77. data/lib/metasm/main.rb +1193 -0
  78. data/lib/metasm/mips.rb +11 -0
  79. data/lib/metasm/mips/compile_c.rb +7 -0
  80. data/lib/metasm/mips/decode.rb +253 -0
  81. data/lib/metasm/mips/encode.rb +51 -0
  82. data/lib/metasm/mips/main.rb +72 -0
  83. data/lib/metasm/mips/opcodes.rb +443 -0
  84. data/lib/metasm/mips/parse.rb +51 -0
  85. data/lib/metasm/mips/render.rb +43 -0
  86. data/lib/metasm/os/gnu_exports.rb +270 -0
  87. data/lib/metasm/os/linux.rb +1112 -0
  88. data/lib/metasm/os/main.rb +1686 -0
  89. data/lib/metasm/os/remote.rb +527 -0
  90. data/lib/metasm/os/windows.rb +2027 -0
  91. data/lib/metasm/os/windows_exports.rb +745 -0
  92. data/lib/metasm/parse.rb +876 -0
  93. data/lib/metasm/parse_c.rb +3938 -0
  94. data/lib/metasm/pic16c/decode.rb +42 -0
  95. data/lib/metasm/pic16c/main.rb +17 -0
  96. data/lib/metasm/pic16c/opcodes.rb +68 -0
  97. data/lib/metasm/ppc.rb +11 -0
  98. data/lib/metasm/ppc/decode.rb +264 -0
  99. data/lib/metasm/ppc/decompile.rb +251 -0
  100. data/lib/metasm/ppc/encode.rb +51 -0
  101. data/lib/metasm/ppc/main.rb +129 -0
  102. data/lib/metasm/ppc/opcodes.rb +410 -0
  103. data/lib/metasm/ppc/parse.rb +52 -0
  104. data/lib/metasm/preprocessor.rb +1277 -0
  105. data/lib/metasm/render.rb +130 -0
  106. data/lib/metasm/sh4.rb +8 -0
  107. data/lib/metasm/sh4/decode.rb +336 -0
  108. data/lib/metasm/sh4/main.rb +292 -0
  109. data/lib/metasm/sh4/opcodes.rb +381 -0
  110. data/lib/metasm/x86_64.rb +12 -0
  111. data/lib/metasm/x86_64/compile_c.rb +1025 -0
  112. data/lib/metasm/x86_64/debug.rb +59 -0
  113. data/lib/metasm/x86_64/decode.rb +268 -0
  114. data/lib/metasm/x86_64/encode.rb +264 -0
  115. data/lib/metasm/x86_64/main.rb +135 -0
  116. data/lib/metasm/x86_64/opcodes.rb +118 -0
  117. data/lib/metasm/x86_64/parse.rb +68 -0
  118. data/misc/bottleneck.rb +61 -0
  119. data/misc/cheader-findpppath.rb +58 -0
  120. data/misc/hexdiff.rb +74 -0
  121. data/misc/hexdump.rb +55 -0
  122. data/misc/metasm-all.rb +13 -0
  123. data/misc/objdiff.rb +47 -0
  124. data/misc/objscan.rb +40 -0
  125. data/misc/pdfparse.rb +661 -0
  126. data/misc/ppc_pdf2oplist.rb +192 -0
  127. data/misc/tcp_proxy_hex.rb +84 -0
  128. data/misc/txt2html.rb +440 -0
  129. data/samples/a.out.rb +31 -0
  130. data/samples/asmsyntax.rb +77 -0
  131. data/samples/bindiff.rb +555 -0
  132. data/samples/compilation-steps.rb +49 -0
  133. data/samples/cparser_makestackoffset.rb +55 -0
  134. data/samples/dasm-backtrack.rb +38 -0
  135. data/samples/dasmnavig.rb +318 -0
  136. data/samples/dbg-apihook.rb +228 -0
  137. data/samples/dbghelp.rb +143 -0
  138. data/samples/disassemble-gui.rb +102 -0
  139. data/samples/disassemble.rb +133 -0
  140. data/samples/dump_upx.rb +95 -0
  141. data/samples/dynamic_ruby.rb +1929 -0
  142. data/samples/elf_list_needed.rb +46 -0
  143. data/samples/elf_listexports.rb +33 -0
  144. data/samples/elfencode.rb +25 -0
  145. data/samples/exeencode.rb +128 -0
  146. data/samples/factorize-headers-elfimports.rb +77 -0
  147. data/samples/factorize-headers-peimports.rb +109 -0
  148. data/samples/factorize-headers.rb +43 -0
  149. data/samples/gdbclient.rb +583 -0
  150. data/samples/generate_libsigs.rb +102 -0
  151. data/samples/hotfix_gtk_dbg.rb +59 -0
  152. data/samples/install_win_env.rb +78 -0
  153. data/samples/lindebug.rb +924 -0
  154. data/samples/linux_injectsyscall.rb +95 -0
  155. data/samples/machoencode.rb +31 -0
  156. data/samples/metasm-shell.rb +91 -0
  157. data/samples/pe-hook.rb +69 -0
  158. data/samples/pe-ia32-cpuid.rb +203 -0
  159. data/samples/pe-mips.rb +35 -0
  160. data/samples/pe-shutdown.rb +78 -0
  161. data/samples/pe-testrelocs.rb +51 -0
  162. data/samples/pe-testrsrc.rb +24 -0
  163. data/samples/pe_listexports.rb +31 -0
  164. data/samples/peencode.rb +19 -0
  165. data/samples/peldr.rb +494 -0
  166. data/samples/preprocess-flatten.rb +19 -0
  167. data/samples/r0trace.rb +308 -0
  168. data/samples/rubstop.rb +399 -0
  169. data/samples/scan_pt_gnu_stack.rb +54 -0
  170. data/samples/scanpeexports.rb +62 -0
  171. data/samples/shellcode-c.rb +40 -0
  172. data/samples/shellcode-dynlink.rb +146 -0
  173. data/samples/source.asm +34 -0
  174. data/samples/struct_offset.rb +47 -0
  175. data/samples/testpe.rb +32 -0
  176. data/samples/testraw.rb +45 -0
  177. data/samples/win32genloader.rb +132 -0
  178. data/samples/win32hooker-advanced.rb +169 -0
  179. data/samples/win32hooker.rb +96 -0
  180. data/samples/win32livedasm.rb +33 -0
  181. data/samples/win32remotescan.rb +133 -0
  182. data/samples/wintrace.rb +92 -0
  183. data/tests/all.rb +8 -0
  184. data/tests/dasm.rb +39 -0
  185. data/tests/dynldr.rb +35 -0
  186. data/tests/encodeddata.rb +132 -0
  187. data/tests/ia32.rb +82 -0
  188. data/tests/mips.rb +116 -0
  189. data/tests/parse_c.rb +239 -0
  190. data/tests/preprocessor.rb +269 -0
  191. data/tests/x86_64.rb +62 -0
  192. metadata +255 -0
@@ -0,0 +1,59 @@
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
+
7
+ require 'metasm/x86_64/opcodes'
8
+
9
+ module Metasm
10
+ class X86_64
11
+ def dbg_register_pc
12
+ @dbg_register_pc ||= :rip
13
+ end
14
+ def dbg_register_flags
15
+ @dbg_register_flags ||= :rflags
16
+ end
17
+
18
+ def dbg_register_list
19
+ @dbg_register_list ||= [:rax, :rbx, :rcx, :rdx, :rsi, :rdi, :rbp, :rsp, :r8, :r9, :r10, :r11, :r12, :r13, :r14, :r15, :rip]
20
+ end
21
+
22
+ def dbg_register_size
23
+ @dbg_register_size ||= Hash.new(64).update(:cs => 16, :ds => 16, :es => 16, :fs => 16, :gs => 16)
24
+ end
25
+
26
+ def dbg_func_arg(dbg, argnr)
27
+ if dbg.class.name =~ /win/i
28
+ list = [:rcx, :rdx, :r8, :r9]
29
+ off = 0x20
30
+ else
31
+ list = [:rdi, :rsi, :rdx, :rcx, :r8, :r9]
32
+ off = 0
33
+ end
34
+ if r = list[argnr]
35
+ dbg.get_reg_value(r)
36
+ else
37
+ argnr -= list.length
38
+ dbg.memory_read_int(Expression[:esp, :+, off + 8 + 8*argnr])
39
+ end
40
+ end
41
+ def dbg_func_arg_set(dbg, argnr, arg)
42
+ if dbg.class.name =~ /win/i
43
+ list = []
44
+ off = 0x20
45
+ else
46
+ list = []
47
+ off = 0
48
+ end
49
+ if r = list[argnr]
50
+ dbg.set_reg_value(r, arg)
51
+ else
52
+ argnr -= list.length
53
+ dbg.memory_write_int(Expression[:esp, :+, off + 8 + 8*argnr], arg)
54
+ end
55
+ end
56
+
57
+ # what's left is inherited from Ia32
58
+ end
59
+ end
@@ -0,0 +1,268 @@
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
+
7
+ require 'metasm/x86_64/opcodes'
8
+ require 'metasm/decode'
9
+
10
+ module Metasm
11
+ class X86_64
12
+ class ModRM
13
+ def self.decode(edata, byte, endianness, adsz, opsz, seg=nil, regclass=Reg, pfx={})
14
+ m = (byte >> 6) & 3
15
+ rm = byte & 7
16
+
17
+ if m == 3
18
+ rm |= 8 if pfx[:rex_b]
19
+ return regclass.new(rm, opsz)
20
+ end
21
+
22
+ adsz ||= 64
23
+
24
+ # mod 0/1/2 m 4 => sib
25
+ # mod 0 m 5 => rip+imm
26
+ # sib: i 4 => no index, b 5 => no base
27
+
28
+ s = i = b = imm = nil
29
+ if rm == 4
30
+ sib = edata.get_byte.to_i
31
+
32
+ ii = (sib >> 3) & 7
33
+ ii |= 8 if pfx[:rex_x]
34
+ if ii != 4
35
+ s = 1 << ((sib >> 6) & 3)
36
+ i = Reg.new(ii, adsz)
37
+ end
38
+
39
+ bb = sib & 7
40
+ if bb == 5 and m == 0
41
+ m = 2 # :i32 follows
42
+ else
43
+ bb |= 8 if pfx[:rex_b]
44
+ b = Reg.new(bb, adsz)
45
+ end
46
+ elsif rm == 5 and m == 0
47
+ b = Reg.new(16, adsz)
48
+ m = 2 # :i32 follows
49
+ else
50
+ rm |= 8 if pfx[:rex_b]
51
+ b = Reg.new(rm, adsz)
52
+ end
53
+
54
+ case m
55
+ when 1; itype = :i8
56
+ when 2; itype = :i32
57
+ end
58
+ imm = Expression[edata.decode_imm(itype, endianness)] if itype
59
+
60
+ if imm and imm.reduce.kind_of? Integer and imm.reduce < -0x100_0000
61
+ # probably a base address -> unsigned
62
+ imm = Expression[imm.reduce & ((1 << adsz) - 1)]
63
+ end
64
+
65
+ new adsz, opsz, s, i, b, imm, seg
66
+ end
67
+ end
68
+
69
+ def decode_prefix(instr, byte)
70
+ x = super(instr, byte)
71
+ if instr.prefix.delete :rex
72
+ # rex ignored if not last
73
+ instr.prefix.delete :rex_b
74
+ instr.prefix.delete :rex_x
75
+ instr.prefix.delete :rex_r
76
+ instr.prefix.delete :rex_w
77
+ end
78
+ if byte & 0xf0 == 0x40
79
+ x = instr.prefix[:rex] = byte
80
+ instr.prefix[:rex_b] = 1 if byte & 1 > 0
81
+ instr.prefix[:rex_x] = 1 if byte & 2 > 0
82
+ instr.prefix[:rex_r] = 1 if byte & 4 > 0
83
+ instr.prefix[:rex_w] = 1 if byte & 8 > 0
84
+ end
85
+ x
86
+ end
87
+
88
+ def decode_instr_op(edata, di)
89
+ before_ptr = edata.ptr
90
+ op = di.opcode
91
+ di.instruction.opname = op.name
92
+ bseq = edata.read(op.bin.length).unpack('C*') # decode_findopcode ensures that data >= op.length
93
+ pfx = di.instruction.prefix || {}
94
+
95
+ field_val = lambda { |f|
96
+ if fld = op.fields[f]
97
+ (bseq[fld[0]] >> fld[1]) & @fields_mask[f]
98
+ end
99
+ }
100
+ field_val_r = lambda { |f|
101
+ v = field_val[f]
102
+ v |= 8 if v and (op.fields[f][1] == 3 ? pfx[:rex_r] : pfx[:rex_b]) # gruick ?
103
+ v
104
+ }
105
+
106
+ opsz = op.props[:argsz] || (pfx[:rex_w] ? 64 : (pfx[:opsz] ? 16 : (op.props[:auto64] ? 64 : 32)))
107
+ adsz = pfx[:adsz] ? 32 : 64
108
+ mmxsz = (op.props[:xmmx] && pfx[:opsz]) ? 128 : 64
109
+
110
+ op.args.each { |a|
111
+ di.instruction.args << case a
112
+ when :reg; Reg.new field_val_r[a], opsz
113
+ when :eeec; CtrlReg.new field_val_r[a]
114
+ when :eeed; DbgReg.new field_val_r[a]
115
+ when :seg2, :seg2A, :seg3, :seg3A; SegReg.new field_val[a]
116
+ when :regmmx; SimdReg.new field_val_r[a], mmxsz
117
+ when :regxmm; SimdReg.new field_val_r[a], 128
118
+
119
+ when :farptr; Farptr.decode edata, @endianness, opsz
120
+ when :i8, :u8, :i16, :u16, :i32, :u32, :i64, :u64; Expression[edata.decode_imm(a, @endianness)]
121
+ when :i # 64bit constants are sign-extended from :i32
122
+ type = (opsz == 64 ? op.props[:imm64] ? :a64 : :i32 : "#{op.props[:unsigned_imm] ? 'a' : 'i'}#{opsz}".to_sym )
123
+ v = edata.decode_imm(type, @endianness)
124
+ v &= 0xffff_ffff_ffff_ffff if opsz == 64 and op.props[:unsigned_imm] and v.kind_of? Integer
125
+ Expression[v]
126
+
127
+ when :mrm_imm; ModRM.new(adsz, opsz, nil, nil, nil, Expression[edata.decode_imm("a#{adsz}".to_sym, @endianness)], pfx[:seg])
128
+ when :modrm, :modrmA; ModRM.decode edata, field_val[a], @endianness, adsz, opsz, pfx[:seg], Reg, pfx
129
+ when :modrmmmx; ModRM.decode edata, field_val[:modrm], @endianness, adsz, mmxsz, pfx[:seg], SimdReg, pfx
130
+ when :modrmxmm; ModRM.decode edata, field_val[:modrm], @endianness, adsz, 128, pfx[:seg], SimdReg, pfx
131
+
132
+ when :regfp; FpReg.new field_val[a]
133
+ when :imm_val1; Expression[1]
134
+ when :imm_val3; Expression[3]
135
+ when :reg_cl; Reg.new 1, 8
136
+ when :reg_eax; Reg.new 0, opsz
137
+ when :reg_dx; Reg.new 2, 16
138
+ when :regfp0; FpReg.new nil
139
+ else raise SyntaxError, "Internal error: invalid argument #{a} in #{op.name}"
140
+ end
141
+ }
142
+
143
+ di.bin_length += edata.ptr - before_ptr
144
+
145
+ if op.name == 'movsx' or op.name == 'movzx' or op.name == 'movsxd'
146
+ if op.name == 'movsxd'
147
+ di.instruction.args[1].sz = 32
148
+ elsif opsz == 8
149
+ di.instruction.args[1].sz = 8
150
+ else
151
+ di.instruction.args[1].sz = 16
152
+ end
153
+ if pfx[:rex_w]
154
+ di.instruction.args[0].sz = 64
155
+ elsif pfx[:opsz]
156
+ di.instruction.args[0].sz = 16
157
+ else
158
+ di.instruction.args[0].sz = 32
159
+ end
160
+ end
161
+
162
+ # sil => bh
163
+ di.instruction.args.each { |a| a.val += 12 if a.kind_of? Reg and a.sz == 8 and not pfx[:rex] and a.val >= 4 and a.val <= 8 }
164
+
165
+ pfx.delete :seg
166
+ case pfx.delete(:rep)
167
+ when :nz
168
+ if di.opcode.props[:strop]
169
+ pfx[:rep] = 'rep'
170
+ elsif di.opcode.props[:stropz]
171
+ pfx[:rep] = 'repnz'
172
+ end
173
+ when :z
174
+ if di.opcode.props[:strop]
175
+ pfx[:rep] = 'rep'
176
+ elsif di.opcode.props[:stropz]
177
+ pfx[:rep] = 'repz'
178
+ end
179
+ end
180
+
181
+ di
182
+ end
183
+
184
+ def decode_instr_interpret(di, addr)
185
+ super(di, addr)
186
+
187
+ # [rip + 42] => [rip - addr + foo]
188
+ if m = di.instruction.args.grep(ModRM).first and
189
+ ((m.b and m.b.val == 16) or (m.i and m.i.val == 16)) and
190
+ m.imm and m.imm.reduce.kind_of?(Integer)
191
+ m.imm = Expression[[:-, di.address + di.bin_length], :+, di.address+di.bin_length+m.imm.reduce]
192
+ end
193
+
194
+ di
195
+ end
196
+
197
+ def opsz(di)
198
+ if di and di.instruction.prefix and di.instruction.prefix[:rex_w]; 64
199
+ elsif di and di.instruction.prefix and di.instruction.prefix[:opsz]; 16
200
+ elsif di and di.opcode.props[:auto64]; 64
201
+ else 32
202
+ end
203
+ end
204
+
205
+ def register_symbols
206
+ [:rax, :rcx, :rdx, :rbx, :rsp, :rbp, :rsi, :rdi, :r8, :r9, :r10, :r11, :r12, :r13, :r14, :r15]
207
+ end
208
+
209
+ # returns a DecodedFunction from a parsed C function prototype
210
+ def decode_c_function_prototype(cp, sym, orig=nil)
211
+ sym = cp.toplevel.symbol[sym] if sym.kind_of?(::String)
212
+ df = DecodedFunction.new
213
+ orig ||= Expression[sym.name]
214
+
215
+ new_bt = lambda { |expr, rlen|
216
+ df.backtracked_for << BacktraceTrace.new(expr, orig, expr, rlen ? :r : :x, rlen)
217
+ }
218
+
219
+ # return instr emulation
220
+ if sym.has_attribute 'noreturn' or sym.has_attribute '__noreturn__'
221
+ df.noreturn = true
222
+ else
223
+ new_bt[Indirection[:rsp, @size/8, orig], nil]
224
+ end
225
+
226
+ # register dirty (MS standard ABI)
227
+ [:rax, :rcx, :rdx, :r8, :r9, :r10, :r11].each { |r|
228
+ df.backtrace_binding.update r => Expression::Unknown
229
+ }
230
+
231
+ if cp.lexer.definition['__MS_X86_64_ABI__']
232
+ reg_args = [:rcx, :rdx, :r8, :r9]
233
+ else
234
+ reg_args = [:rdi, :rsi, :rdx, :rcx, :r8, :r9]
235
+ end
236
+
237
+ al = cp.typesize[:ptr]
238
+ df.backtrace_binding[:rsp] = Expression[:rsp, :+, al]
239
+
240
+ # scan args for function pointers
241
+ # TODO walk structs/unions..
242
+ stackoff = al
243
+ sym.type.args.to_a.zip(reg_args).each { |a, r|
244
+ if not r
245
+ r = Indirection[[:rsp, :+, stackoff], al, orig]
246
+ stackoff += (cp.sizeof(a) + al - 1) / al * al
247
+ end
248
+ if a.type.untypedef.kind_of? C::Pointer
249
+ pt = a.type.untypedef.type.untypedef
250
+ if pt.kind_of? C::Function
251
+ new_bt[r, nil]
252
+ df.backtracked_for.last.detached = true
253
+ elsif pt.kind_of? C::Struct
254
+ new_bt[r, al]
255
+ else
256
+ new_bt[r, cp.sizeof(nil, pt)]
257
+ end
258
+ end
259
+ }
260
+
261
+ df
262
+ end
263
+
264
+ def backtrace_update_function_binding_check(dasm, faddr, f, b)
265
+ # TODO save regs according to ABI
266
+ end
267
+ end
268
+ end
@@ -0,0 +1,264 @@
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
+
7
+ require 'metasm/x86_64/opcodes'
8
+ require 'metasm/encode'
9
+
10
+ module Metasm
11
+ class X86_64
12
+ class ModRM
13
+ def self.encode_reg(reg, mregval = 0)
14
+ v = reg.kind_of?(Reg) ? reg.val_enc : reg.val & 7
15
+ 0xc0 | (mregval << 3) | v
16
+ end
17
+
18
+ def encode(reg = 0, endianness = :little)
19
+ reg = reg.val if reg.kind_of? Ia32::Argument
20
+
21
+ ret = EncodedData.new << (reg << 3)
22
+
23
+ # add bits in the first octet of ret.data (1.9 compatibility layer)
24
+ or_bits = lambda { |v| # rape me
25
+ if ret.data[0].kind_of? Integer
26
+ ret.data[0] |= v
27
+ else
28
+ ret.data[0] = (ret.data[0].unpack('C').first | v).chr
29
+ end
30
+ }
31
+
32
+ if not self.b and not self.i
33
+ # imm only, use sib
34
+ or_bits[4]
35
+ imm = self.imm || Expression[0]
36
+ [ret << ((4 << 3) | 5) << imm.encode(:i32, endianness)]
37
+
38
+ elsif (self.b and self.b.val == 16) or (self.i and self.i.val == 16) # rip+imm (rip == addr of the octet after the current instr)
39
+ # should have been filtered by #parse, but just in case
40
+ raise "invalid rip addressing #{self}" if (self.i and self.b) or (self.s and self.s != 1)
41
+ or_bits[5]
42
+ imm = self.imm || Expression[0]
43
+ [ret << imm.encode(:i32, endianness)]
44
+
45
+ elsif not self.b and self.s != 1
46
+ # sib with no b
47
+ raise EncodeError, "Invalid ModRM #{self}" if @i.val == 4 # XXX 12 ?
48
+ or_bits[4]
49
+ s = {8=>3, 4=>2, 2=>1}[@s]
50
+ imm = self.imm || Expression[0]
51
+ fu = (s << 6) | (@i.val_enc << 3) | 5
52
+ fu = fu.chr if s >= 2 # rb1.9 encoding fix
53
+ [ret << fu << imm.encode(:i32, endianness)]
54
+ else
55
+ imm = @imm.reduce if self.imm
56
+ imm = nil if imm == 0
57
+
58
+ if not self.i or (not self.b and self.s == 1)
59
+ # no sib byte (except for [esp])
60
+ @s, @i, @b = nil, nil, @s if not self.b
61
+ or_bits[@b.val_enc]
62
+ ret << 0x24 if @b.val_enc == 4 # XXX val_enc ?
63
+ else
64
+ # sib
65
+ or_bits[4]
66
+
67
+ @b, @i = @i, @b if @s == 1 and (@i.val_enc == 4 or @b.val_enc == 5)
68
+
69
+ raise EncodeError, "Invalid ModRM #{self}" if @i.val == 4
70
+
71
+ s = {8=>3, 4=>2, 2=>1, 1=>0}[@s]
72
+ fu = (s << 6) | (@i.val_enc << 3) | @b.val_enc
73
+ fu = fu.chr if s >= 2 # rb1.9 encoding fix
74
+ ret << fu
75
+ end
76
+
77
+ imm ||= 0 if @b.val_enc == 5
78
+ if imm
79
+ case Expression.in_range?(imm, :i8)
80
+ when true
81
+ or_bits[1<<6]
82
+ [ret << Expression.encode_imm(imm, :i8, endianness)]
83
+ when false
84
+ or_bits[2<<6]
85
+ [ret << Expression.encode_imm(imm, :a32, endianness)]
86
+ when nil
87
+ rets = ret.dup
88
+ or_bits[1<<6]
89
+ ret << @imm.encode(:i8, endianness)
90
+ rets, ret = ret, rets # or_bits[] modifies ret directly
91
+ or_bits[2<<6]
92
+ ret << @imm.encode(:a32, endianness)
93
+ [ret, rets]
94
+ end
95
+ else
96
+ [ret]
97
+ end
98
+ end
99
+ end
100
+ end
101
+
102
+ # returns all forms of the encoding of instruction i using opcode op
103
+ # program may be used to create a new label for relative jump/call
104
+ def encode_instr_op(program, i, op)
105
+ base = op.bin.dup
106
+ oi = op.args.zip(i.args)
107
+ set_field = lambda { |f, v|
108
+ fld = op.fields[f]
109
+ base[fld[0]] |= v << fld[1]
110
+ }
111
+
112
+ #
113
+ # handle prefixes and bit fields
114
+ #
115
+ pfx = i.prefix.map { |k, v|
116
+ case k
117
+ when :jmp; {:jmp => 0x3e, :nojmp => 0x2e}[v]
118
+ when :lock; 0xf0
119
+ when :rep; {'repnz' => 0xf2, 'repz' => 0xf3, 'rep' => 0xf2}[v] # TODO
120
+ end
121
+ }.compact.pack 'C*'
122
+ pfx << op.props[:needpfx] if op.props[:needpfx]
123
+
124
+ rex_w = rex_r = rex_x = rex_b = nil
125
+ if op.name == 'movsx' or op.name == 'movzx' or op.name == 'movsxd'
126
+ case i.args[0].sz
127
+ when 64; rex_w = 1
128
+ when 32
129
+ when 16; pfx << 0x66
130
+ end
131
+ else
132
+ opsz = op.props[:argsz] || i.prefix[:sz]
133
+ oi.each { |oa, ia|
134
+ case oa
135
+ when :reg, :reg_eax, :modrm, :modrmA, :mrm_imm
136
+ raise EncodeError, "Incompatible arg size in #{i}" if ia.sz and opsz and opsz != ia.sz
137
+ opsz = ia.sz
138
+ end
139
+ }
140
+ opsz ||= 64 if op.props[:auto64]
141
+ opsz = op.props[:opsz] if op.props[:opsz] # XXX ?
142
+ case opsz
143
+ when 64; rex_w = 1 if not op.props[:auto64]
144
+ when 32; raise EncodeError, "Incompatible arg size in #{i}" if op.props[:auto64]
145
+ when 16; pfx << 0x66
146
+ end
147
+ end
148
+ opsz ||= @size
149
+
150
+ # addrsize override / segment override / rex_bx
151
+ if mrm = i.args.grep(ModRM).first
152
+ mrm.encode(0, @endianness) if mrm.b or mrm.i # may reorder b/i, which must be correct for rex
153
+ rex_b = 1 if mrm.b and mrm.b.val_rex.to_i > 0
154
+ rex_x = 1 if mrm.i and mrm.i.val_rex.to_i > 0
155
+ pfx << 0x67 if (mrm.b and mrm.b.sz == 32) or (mrm.i and mrm.i.sz == 32) or op.props[:adsz] == 32
156
+ pfx << [0x26, 0x2E, 0x36, 0x3E, 0x64, 0x65][mrm.seg.val] if mrm.seg
157
+ elsif op.props[:adsz] == 32
158
+ pfx << 0x67
159
+ end
160
+
161
+
162
+ #
163
+ # encode embedded arguments
164
+ #
165
+ postponed = []
166
+ oi.each { |oa, ia|
167
+ case oa
168
+ when :reg
169
+ set_field[oa, ia.val_enc]
170
+ if op.fields[:reg][1] == 3
171
+ rex_r = ia.val_rex
172
+ else
173
+ rex_b = ia.val_rex
174
+ end
175
+ when :seg3, :seg3A, :seg2, :seg2A, :eeec, :eeed, :regfp, :regxmm, :regmmx
176
+ set_field[oa, ia.val & 7]
177
+ rex_r = 1 if ia.val > 7
178
+ pfx << 0x66 if oa == :regmmx and op.props[:xmmx] and ia.sz == 128
179
+ when :imm_val1, :imm_val3, :reg_cl, :reg_eax, :reg_dx, :regfp0
180
+ # implicit
181
+ when :modrm, :modrmA, :modrmmmx, :modrmxmm
182
+ # postpone, but we must set rex now
183
+ case ia
184
+ when ModRM
185
+ ia.encode(0, @endianness) # could swap b/i
186
+ rex_x = ia.i.val_rex if ia.i
187
+ rex_b = ia.b.val_rex if ia.b
188
+ when Reg
189
+ rex_b = ia.val_rex
190
+ else
191
+ rex_b = ia.val >> 3
192
+ end
193
+ postponed << [oa, ia]
194
+ else
195
+ postponed << [oa, ia]
196
+ end
197
+ }
198
+
199
+ if !(op.args & [:modrm, :modrmA, :modrmxmm, :modrmmmx]).empty?
200
+ # reg field of modrm
201
+ regval = (base[-1] >> 3) & 7
202
+ base.pop
203
+ end
204
+
205
+ # convert label name for jmp/call/loop to relative offset
206
+ if op.props[:setip] and op.name[0, 3] != 'ret' and i.args.first.kind_of? Expression
207
+ postlabel = program.new_label('post'+op.name)
208
+ target = postponed.first[1]
209
+ target = target.rexpr if target.kind_of? Expression and target.op == :+ and not target.lexpr
210
+ postponed.first[1] = Expression[target, :-, postlabel]
211
+ end
212
+
213
+ if rex_w == 1 or rex_r == 1 or rex_b == 1 or rex_x == 1 or i.args.grep(Reg).find { |r| r.sz == 8 and r.val >= 4 and r.val < 8 }
214
+ rex ||= 0x40
215
+ rex |= 1 if rex_b.to_i > 0
216
+ rex |= 2 if rex_x.to_i > 0
217
+ rex |= 4 if rex_r.to_i > 0
218
+ rex |= 8 if rex_w.to_i > 0
219
+ end
220
+ pfx << rex if rex
221
+ ret = EncodedData.new(pfx + base.pack('C*'))
222
+
223
+ postponed.each { |oa, ia|
224
+ case oa
225
+ when :farptr; ed = ia.encode(@endianness, "a#{opsz}".to_sym)
226
+ when :modrm, :modrmA, :modrmmmx, :modrmxmm
227
+ if ia.kind_of? ModRM
228
+ ed = ia.encode(regval, @endianness)
229
+ if ed.kind_of?(::Array)
230
+ if ed.length > 1
231
+ # we know that no opcode can have more than 1 modrm
232
+ ary = []
233
+ ed.each { |m| ary << (ret.dup << m) }
234
+ ret = ary
235
+ next
236
+ else
237
+ ed = ed.first
238
+ end
239
+ end
240
+ else
241
+ ed = ModRM.encode_reg(ia, regval)
242
+ end
243
+ when :mrm_imm; ed = ia.imm.encode("a#{op.props[:adsz] || 64}".to_sym, @endianness)
244
+ when :i8, :u8, :i16, :u16, :i32, :u32, :i64, :u64; ed = ia.encode(oa, @endianness)
245
+ when :i
246
+ type = (opsz == 64 ? op.props[:imm64] ? :a64 : :i32 : "#{op.props[:unsigned_imm] ? 'a' : 'i'}#{opsz}".to_sym)
247
+ ed = ia.encode(type, @endianness)
248
+ else raise SyntaxError, "Internal error: want to encode field #{oa.inspect} as arg in #{i}"
249
+ end
250
+
251
+ if ret.kind_of?(::Array)
252
+ ret.each { |e| e << ed }
253
+ else
254
+ ret << ed
255
+ end
256
+ }
257
+
258
+ # we know that no opcode with setip accept both modrm and immediate arg, so ret is not an ::Array
259
+ ret.add_export(postlabel, ret.virtsize) if postlabel
260
+
261
+ ret
262
+ end
263
+ end
264
+ end