metasm 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/BUGS +11 -0
- data/CREDITS +17 -0
- data/README +270 -0
- data/TODO +114 -0
- data/doc/code_organisation.txt +146 -0
- data/doc/const_missing.txt +16 -0
- data/doc/core_classes.txt +75 -0
- data/doc/feature_list.txt +53 -0
- data/doc/index.txt +59 -0
- data/doc/install_notes.txt +170 -0
- data/doc/style.css +3 -0
- data/doc/use_cases.txt +18 -0
- data/lib/metasm.rb +80 -0
- data/lib/metasm/arm.rb +12 -0
- data/lib/metasm/arm/debug.rb +39 -0
- data/lib/metasm/arm/decode.rb +167 -0
- data/lib/metasm/arm/encode.rb +77 -0
- data/lib/metasm/arm/main.rb +75 -0
- data/lib/metasm/arm/opcodes.rb +177 -0
- data/lib/metasm/arm/parse.rb +130 -0
- data/lib/metasm/arm/render.rb +55 -0
- data/lib/metasm/compile_c.rb +1457 -0
- data/lib/metasm/dalvik.rb +8 -0
- data/lib/metasm/dalvik/decode.rb +196 -0
- data/lib/metasm/dalvik/main.rb +60 -0
- data/lib/metasm/dalvik/opcodes.rb +366 -0
- data/lib/metasm/decode.rb +213 -0
- data/lib/metasm/decompile.rb +2659 -0
- data/lib/metasm/disassemble.rb +2068 -0
- data/lib/metasm/disassemble_api.rb +1280 -0
- data/lib/metasm/dynldr.rb +1329 -0
- data/lib/metasm/encode.rb +333 -0
- data/lib/metasm/exe_format/a_out.rb +194 -0
- data/lib/metasm/exe_format/autoexe.rb +82 -0
- data/lib/metasm/exe_format/bflt.rb +189 -0
- data/lib/metasm/exe_format/coff.rb +455 -0
- data/lib/metasm/exe_format/coff_decode.rb +901 -0
- data/lib/metasm/exe_format/coff_encode.rb +1078 -0
- data/lib/metasm/exe_format/dex.rb +457 -0
- data/lib/metasm/exe_format/dol.rb +145 -0
- data/lib/metasm/exe_format/elf.rb +923 -0
- data/lib/metasm/exe_format/elf_decode.rb +979 -0
- data/lib/metasm/exe_format/elf_encode.rb +1375 -0
- data/lib/metasm/exe_format/macho.rb +827 -0
- data/lib/metasm/exe_format/main.rb +228 -0
- data/lib/metasm/exe_format/mz.rb +164 -0
- data/lib/metasm/exe_format/nds.rb +172 -0
- data/lib/metasm/exe_format/pe.rb +437 -0
- data/lib/metasm/exe_format/serialstruct.rb +246 -0
- data/lib/metasm/exe_format/shellcode.rb +114 -0
- data/lib/metasm/exe_format/xcoff.rb +167 -0
- data/lib/metasm/gui.rb +23 -0
- data/lib/metasm/gui/cstruct.rb +373 -0
- data/lib/metasm/gui/dasm_coverage.rb +199 -0
- data/lib/metasm/gui/dasm_decomp.rb +369 -0
- data/lib/metasm/gui/dasm_funcgraph.rb +103 -0
- data/lib/metasm/gui/dasm_graph.rb +1354 -0
- data/lib/metasm/gui/dasm_hex.rb +543 -0
- data/lib/metasm/gui/dasm_listing.rb +599 -0
- data/lib/metasm/gui/dasm_main.rb +906 -0
- data/lib/metasm/gui/dasm_opcodes.rb +291 -0
- data/lib/metasm/gui/debug.rb +1228 -0
- data/lib/metasm/gui/gtk.rb +884 -0
- data/lib/metasm/gui/qt.rb +495 -0
- data/lib/metasm/gui/win32.rb +3004 -0
- data/lib/metasm/gui/x11.rb +621 -0
- data/lib/metasm/ia32.rb +14 -0
- data/lib/metasm/ia32/compile_c.rb +1523 -0
- data/lib/metasm/ia32/debug.rb +193 -0
- data/lib/metasm/ia32/decode.rb +1167 -0
- data/lib/metasm/ia32/decompile.rb +564 -0
- data/lib/metasm/ia32/encode.rb +314 -0
- data/lib/metasm/ia32/main.rb +233 -0
- data/lib/metasm/ia32/opcodes.rb +872 -0
- data/lib/metasm/ia32/parse.rb +327 -0
- data/lib/metasm/ia32/render.rb +91 -0
- data/lib/metasm/main.rb +1193 -0
- data/lib/metasm/mips.rb +11 -0
- data/lib/metasm/mips/compile_c.rb +7 -0
- data/lib/metasm/mips/decode.rb +253 -0
- data/lib/metasm/mips/encode.rb +51 -0
- data/lib/metasm/mips/main.rb +72 -0
- data/lib/metasm/mips/opcodes.rb +443 -0
- data/lib/metasm/mips/parse.rb +51 -0
- data/lib/metasm/mips/render.rb +43 -0
- data/lib/metasm/os/gnu_exports.rb +270 -0
- data/lib/metasm/os/linux.rb +1112 -0
- data/lib/metasm/os/main.rb +1686 -0
- data/lib/metasm/os/remote.rb +527 -0
- data/lib/metasm/os/windows.rb +2027 -0
- data/lib/metasm/os/windows_exports.rb +745 -0
- data/lib/metasm/parse.rb +876 -0
- data/lib/metasm/parse_c.rb +3938 -0
- data/lib/metasm/pic16c/decode.rb +42 -0
- data/lib/metasm/pic16c/main.rb +17 -0
- data/lib/metasm/pic16c/opcodes.rb +68 -0
- data/lib/metasm/ppc.rb +11 -0
- data/lib/metasm/ppc/decode.rb +264 -0
- data/lib/metasm/ppc/decompile.rb +251 -0
- data/lib/metasm/ppc/encode.rb +51 -0
- data/lib/metasm/ppc/main.rb +129 -0
- data/lib/metasm/ppc/opcodes.rb +410 -0
- data/lib/metasm/ppc/parse.rb +52 -0
- data/lib/metasm/preprocessor.rb +1277 -0
- data/lib/metasm/render.rb +130 -0
- data/lib/metasm/sh4.rb +8 -0
- data/lib/metasm/sh4/decode.rb +336 -0
- data/lib/metasm/sh4/main.rb +292 -0
- data/lib/metasm/sh4/opcodes.rb +381 -0
- data/lib/metasm/x86_64.rb +12 -0
- data/lib/metasm/x86_64/compile_c.rb +1025 -0
- data/lib/metasm/x86_64/debug.rb +59 -0
- data/lib/metasm/x86_64/decode.rb +268 -0
- data/lib/metasm/x86_64/encode.rb +264 -0
- data/lib/metasm/x86_64/main.rb +135 -0
- data/lib/metasm/x86_64/opcodes.rb +118 -0
- data/lib/metasm/x86_64/parse.rb +68 -0
- data/misc/bottleneck.rb +61 -0
- data/misc/cheader-findpppath.rb +58 -0
- data/misc/hexdiff.rb +74 -0
- data/misc/hexdump.rb +55 -0
- data/misc/metasm-all.rb +13 -0
- data/misc/objdiff.rb +47 -0
- data/misc/objscan.rb +40 -0
- data/misc/pdfparse.rb +661 -0
- data/misc/ppc_pdf2oplist.rb +192 -0
- data/misc/tcp_proxy_hex.rb +84 -0
- data/misc/txt2html.rb +440 -0
- data/samples/a.out.rb +31 -0
- data/samples/asmsyntax.rb +77 -0
- data/samples/bindiff.rb +555 -0
- data/samples/compilation-steps.rb +49 -0
- data/samples/cparser_makestackoffset.rb +55 -0
- data/samples/dasm-backtrack.rb +38 -0
- data/samples/dasmnavig.rb +318 -0
- data/samples/dbg-apihook.rb +228 -0
- data/samples/dbghelp.rb +143 -0
- data/samples/disassemble-gui.rb +102 -0
- data/samples/disassemble.rb +133 -0
- data/samples/dump_upx.rb +95 -0
- data/samples/dynamic_ruby.rb +1929 -0
- data/samples/elf_list_needed.rb +46 -0
- data/samples/elf_listexports.rb +33 -0
- data/samples/elfencode.rb +25 -0
- data/samples/exeencode.rb +128 -0
- data/samples/factorize-headers-elfimports.rb +77 -0
- data/samples/factorize-headers-peimports.rb +109 -0
- data/samples/factorize-headers.rb +43 -0
- data/samples/gdbclient.rb +583 -0
- data/samples/generate_libsigs.rb +102 -0
- data/samples/hotfix_gtk_dbg.rb +59 -0
- data/samples/install_win_env.rb +78 -0
- data/samples/lindebug.rb +924 -0
- data/samples/linux_injectsyscall.rb +95 -0
- data/samples/machoencode.rb +31 -0
- data/samples/metasm-shell.rb +91 -0
- data/samples/pe-hook.rb +69 -0
- data/samples/pe-ia32-cpuid.rb +203 -0
- data/samples/pe-mips.rb +35 -0
- data/samples/pe-shutdown.rb +78 -0
- data/samples/pe-testrelocs.rb +51 -0
- data/samples/pe-testrsrc.rb +24 -0
- data/samples/pe_listexports.rb +31 -0
- data/samples/peencode.rb +19 -0
- data/samples/peldr.rb +494 -0
- data/samples/preprocess-flatten.rb +19 -0
- data/samples/r0trace.rb +308 -0
- data/samples/rubstop.rb +399 -0
- data/samples/scan_pt_gnu_stack.rb +54 -0
- data/samples/scanpeexports.rb +62 -0
- data/samples/shellcode-c.rb +40 -0
- data/samples/shellcode-dynlink.rb +146 -0
- data/samples/source.asm +34 -0
- data/samples/struct_offset.rb +47 -0
- data/samples/testpe.rb +32 -0
- data/samples/testraw.rb +45 -0
- data/samples/win32genloader.rb +132 -0
- data/samples/win32hooker-advanced.rb +169 -0
- data/samples/win32hooker.rb +96 -0
- data/samples/win32livedasm.rb +33 -0
- data/samples/win32remotescan.rb +133 -0
- data/samples/wintrace.rb +92 -0
- data/tests/all.rb +8 -0
- data/tests/dasm.rb +39 -0
- data/tests/dynldr.rb +35 -0
- data/tests/encodeddata.rb +132 -0
- data/tests/ia32.rb +82 -0
- data/tests/mips.rb +116 -0
- data/tests/parse_c.rb +239 -0
- data/tests/preprocessor.rb +269 -0
- data/tests/x86_64.rb +62 -0
- metadata +255 -0
data/lib/metasm/arm.rb
ADDED
@@ -0,0 +1,12 @@
|
|
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/main'
|
8
|
+
require 'metasm/arm/parse'
|
9
|
+
require 'metasm/arm/encode'
|
10
|
+
require 'metasm/arm/decode'
|
11
|
+
require 'metasm/arm/render'
|
12
|
+
require 'metasm/arm/debug'
|
@@ -0,0 +1,39 @@
|
|
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/arm/opcodes'
|
8
|
+
|
9
|
+
module Metasm
|
10
|
+
class ARM
|
11
|
+
def dbg_register_pc
|
12
|
+
@dbg_register_pc ||= :pc
|
13
|
+
end
|
14
|
+
def dbg_register_flags
|
15
|
+
@dbg_register_flags ||= :flags
|
16
|
+
end
|
17
|
+
|
18
|
+
def dbg_register_list
|
19
|
+
@dbg_register_list ||= [:r0, :r1, :r2, :r3, :r4, :r5, :r6, :r7, :r8, :r9, :r10, :r11, :r12, :sp, :lr, :pc]
|
20
|
+
end
|
21
|
+
|
22
|
+
def dbg_flag_list
|
23
|
+
@dbg_flag_list ||= []
|
24
|
+
end
|
25
|
+
|
26
|
+
def dbg_register_size
|
27
|
+
@dbg_register_size ||= Hash.new(32)
|
28
|
+
end
|
29
|
+
|
30
|
+
def dbg_need_stepover(dbg, addr, di)
|
31
|
+
di and di.opcode.props[:saveip]
|
32
|
+
end
|
33
|
+
|
34
|
+
def dbg_end_stepout(dbg, addr, di)
|
35
|
+
di and di.opcode.name == 'foobar' # TODO
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,167 @@
|
|
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
|
+
require 'metasm/arm/opcodes'
|
7
|
+
require 'metasm/decode'
|
8
|
+
|
9
|
+
module Metasm
|
10
|
+
class ARM
|
11
|
+
# create the bin_mask for a given opcode
|
12
|
+
def build_opcode_bin_mask(op)
|
13
|
+
# bit = 0 if can be mutated by an field value, 1 if fixed by opcode
|
14
|
+
op.bin_mask = 0
|
15
|
+
op.fields.each { |k, (m, s)|
|
16
|
+
op.bin_mask |= m << s
|
17
|
+
}
|
18
|
+
op.bin_mask = 0xffffffff ^ op.bin_mask
|
19
|
+
end
|
20
|
+
|
21
|
+
# create the lookaside hash from the first byte of the opcode
|
22
|
+
def build_bin_lookaside
|
23
|
+
lookaside = Array.new(256) { [] }
|
24
|
+
|
25
|
+
opcode_list.each { |op|
|
26
|
+
build_opcode_bin_mask op
|
27
|
+
|
28
|
+
b = (op.bin >> 20) & 0xff
|
29
|
+
msk = (op.bin_mask >> 20) & 0xff
|
30
|
+
b &= msk
|
31
|
+
|
32
|
+
for i in b..(b | (255^msk))
|
33
|
+
lookaside[i] << op if i & msk == b
|
34
|
+
end
|
35
|
+
}
|
36
|
+
|
37
|
+
lookaside
|
38
|
+
end
|
39
|
+
|
40
|
+
def decode_findopcode(edata)
|
41
|
+
return if edata.ptr >= edata.data.length
|
42
|
+
di = DecodedInstruction.new(self)
|
43
|
+
val = edata.decode_imm(:u32, @endianness)
|
44
|
+
di.instance_variable_set('@raw', val)
|
45
|
+
di if di.opcode = @bin_lookaside[(val >> 20) & 0xff].find { |op|
|
46
|
+
(not op.props[:cond] or
|
47
|
+
((val >> @fields_shift[:cond]) & @fields_mask[:cond]) != 0xf) and
|
48
|
+
(op.bin & op.bin_mask) == (val & op.bin_mask)
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
52
|
+
def disassembler_default_func
|
53
|
+
df = DecodedFunction.new
|
54
|
+
df
|
55
|
+
end
|
56
|
+
|
57
|
+
def decode_instr_op(edata, di)
|
58
|
+
op = di.opcode
|
59
|
+
di.instruction.opname = op.name
|
60
|
+
val = di.instance_variable_get('@raw')
|
61
|
+
|
62
|
+
field_val = lambda { |f|
|
63
|
+
r = (val >> @fields_shift[f]) & @fields_mask[f]
|
64
|
+
case f
|
65
|
+
when :i16; Expression.make_signed(r, 16)
|
66
|
+
when :i24; Expression.make_signed(r, 24)
|
67
|
+
when :i8_12; ((r >> 4) & 0xf0) | (r & 0xf)
|
68
|
+
when :stype; [:lsl, :lsr, :asr, :ror][r]
|
69
|
+
when :u; [:-, :+][r]
|
70
|
+
else r
|
71
|
+
end
|
72
|
+
}
|
73
|
+
|
74
|
+
if op.props[:cond]
|
75
|
+
cd = %w[eq ne cs cc mi pl vs vc hi ls ge lt gt le al][field_val[:cond]]
|
76
|
+
if cd != 'al'
|
77
|
+
di.opcode = di.opcode.dup
|
78
|
+
di.instruction.opname = di.opcode.name.dup
|
79
|
+
di.instruction.opname[(op.props[:cond_name_off] || di.opcode.name.length), 0] = cd
|
80
|
+
if di.opcode.props[:stopexec]
|
81
|
+
di.opcode.props = di.opcode.props.dup
|
82
|
+
di.opcode.props.delete :stopexec
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
op.args.each { |a|
|
88
|
+
di.instruction.args << case a
|
89
|
+
when :rd, :rn, :rm; Reg.new field_val[a]
|
90
|
+
when :rm_rs; Reg.new field_val[:rm], field_val[:stype], Reg.new(field_val[:rs])
|
91
|
+
when :rm_is; Reg.new field_val[:rm], field_val[:stype], field_val[:shifti]*2
|
92
|
+
when :i24; Expression[field_val[a] << 2]
|
93
|
+
when :i8_r
|
94
|
+
i = field_val[:i8]
|
95
|
+
r = field_val[:rotate]*2
|
96
|
+
Expression[((i >> r) | (i << (32-r))) & 0xffff_ffff]
|
97
|
+
when :mem_rn_rm, :mem_rn_i8_12, :mem_rn_rms, :mem_rn_i12
|
98
|
+
b = Reg.new(field_val[:rn])
|
99
|
+
o = case a
|
100
|
+
when :mem_rn_rm; Reg.new(field_val[:rm])
|
101
|
+
when :mem_rn_i8_12; field_val[:i8_12]
|
102
|
+
when :mem_rn_rms; Reg.new(field_val[:rm], field_val[:stype], field_val[:shifti]*2)
|
103
|
+
when :mem_rn_i12; field_val[:i12]
|
104
|
+
end
|
105
|
+
Memref.new(b, o, field_val[:u], op.props[:baseincr])
|
106
|
+
when :reglist
|
107
|
+
di.instruction.args.last.updated = true if op.props[:baseincr]
|
108
|
+
msk = field_val[a]
|
109
|
+
l = RegList.new((0..15).map { |i| Reg.new(i) if (msk & (1 << i)) > 0 }.compact)
|
110
|
+
l.usermoderegs = true if op.props[:usermoderegs]
|
111
|
+
l
|
112
|
+
else raise SyntaxError, "Internal error: invalid argument #{a} in #{op.name}"
|
113
|
+
end
|
114
|
+
}
|
115
|
+
|
116
|
+
di.bin_length = 4
|
117
|
+
di
|
118
|
+
end
|
119
|
+
|
120
|
+
def decode_instr_interpret(di, addr)
|
121
|
+
if di.opcode.args.include? :i24
|
122
|
+
di.instruction.args[-1] = Expression[di.instruction.args[-1] + addr + 8]
|
123
|
+
end
|
124
|
+
di
|
125
|
+
end
|
126
|
+
|
127
|
+
def backtrace_binding
|
128
|
+
@backtrace_binding ||= init_backtrace_binding
|
129
|
+
end
|
130
|
+
|
131
|
+
def init_backtrace_binding
|
132
|
+
@backtrace_binding ||= {}
|
133
|
+
end
|
134
|
+
|
135
|
+
def get_backtrace_binding(di)
|
136
|
+
a = di.instruction.args.map { |arg|
|
137
|
+
case arg
|
138
|
+
when Reg; arg.symbolic
|
139
|
+
when Memref; arg.symbolic(di.address)
|
140
|
+
else arg
|
141
|
+
end
|
142
|
+
}
|
143
|
+
|
144
|
+
if binding = backtrace_binding[di.opcode.name]
|
145
|
+
bd = binding[di, *a]
|
146
|
+
else
|
147
|
+
puts "unhandled instruction to backtrace: #{di}" if $VERBOSE
|
148
|
+
# assume nothing except the 1st arg is modified
|
149
|
+
case a[0]
|
150
|
+
when Indirection, Symbol; { a[0] => Expression::Unknown }
|
151
|
+
when Expression; (x = a[0].externals.first) ? { x => Expression::Unknown } : {}
|
152
|
+
else {}
|
153
|
+
end.update(:incomplete_binding => Expression[1])
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
157
|
+
|
158
|
+
def get_xrefs_x(dasm, di)
|
159
|
+
if di.opcode.props[:setip]
|
160
|
+
[di.instruction.args.last]
|
161
|
+
else
|
162
|
+
# TODO ldr pc, ..
|
163
|
+
[]
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
@@ -0,0 +1,77 @@
|
|
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/arm/opcodes'
|
8
|
+
require 'metasm/encode'
|
9
|
+
|
10
|
+
module Metasm
|
11
|
+
class ARM
|
12
|
+
def encode_instr_op(section, instr, op)
|
13
|
+
base = op.bin
|
14
|
+
set_field = lambda { |f, v|
|
15
|
+
v = v.reduce if v.kind_of? Expression
|
16
|
+
case f
|
17
|
+
when :i8_12
|
18
|
+
base = Expression[base, :|, [[v, :&, 0xf], :|, [[v, :<<, 4], :&, 0xf00]]]
|
19
|
+
next
|
20
|
+
when :stype; v = [:lsl, :lsr, :asr, :ror].index(v)
|
21
|
+
when :u; v = [:-, :+].index(v)
|
22
|
+
end
|
23
|
+
base = Expression[base, :|, [[v, :&, @fields_mask[f]], :<<, @fields_shift[f]]]
|
24
|
+
}
|
25
|
+
|
26
|
+
val, mask, shift = 0, 0, 0
|
27
|
+
|
28
|
+
if op.props[:cond]
|
29
|
+
coff = op.props[:cond_name_off] || op.name.length
|
30
|
+
cd = instr.opname[coff, 2]
|
31
|
+
cdi = %w[eq ne cs cc mi pl vs vc hi ls ge lt gt le al].index(cd) || 14 # default = al
|
32
|
+
set_field[:cond, cdi]
|
33
|
+
end
|
34
|
+
|
35
|
+
op.args.zip(instr.args).each { |sym, arg|
|
36
|
+
case sym
|
37
|
+
when :rd, :rs, :rn, :rm; set_field[sym, arg.i]
|
38
|
+
when :rm_rs
|
39
|
+
set_field[:rm, arg.i]
|
40
|
+
set_field[:stype, arg.stype]
|
41
|
+
set_field[:rs, arg.shift.i]
|
42
|
+
when :rm_is
|
43
|
+
set_field[:rm, arg.i]
|
44
|
+
set_field[:stype, arg.stype]
|
45
|
+
set_field[:shifti, arg.shift/2]
|
46
|
+
when :mem_rn_rm, :mem_rn_rms, :mem_rn_i8_12, :mem_rn_i12
|
47
|
+
set_field[:rn, arg.base.i]
|
48
|
+
case sym
|
49
|
+
when :mem_rn_rm
|
50
|
+
set_field[:rm, arg.offset.i]
|
51
|
+
when :mem_rn_rms
|
52
|
+
set_field[:rm, arg.offset.i]
|
53
|
+
set_field[:stype, arg.offset.stype]
|
54
|
+
set_field[:rs, arg.offset.shift.i]
|
55
|
+
when :mem_rn_i8_12
|
56
|
+
set_field[:i8_12, arg.offset]
|
57
|
+
when :mem_rn_i12
|
58
|
+
set_field[:i12, arg.offset]
|
59
|
+
end
|
60
|
+
# TODO set_field[:u] etc
|
61
|
+
when :reglist
|
62
|
+
set_field[sym, arg.list.inject(0) { |rl, r| rl | (1 << r.i) }]
|
63
|
+
when :i8_r
|
64
|
+
# XXX doublecheck this
|
65
|
+
b = arg.reduce & 0xffffffff
|
66
|
+
r = (0..15).find { next true if b < 0x10 ; b = (b >> 2) | ((b & 3) << 30) }
|
67
|
+
set_field[:i8, b]
|
68
|
+
set_field[:rotate, r]
|
69
|
+
when :i16, :i24
|
70
|
+
val, mask, shift = arg, @fields_mask[sym], @fields_shift[sym]
|
71
|
+
end
|
72
|
+
}
|
73
|
+
|
74
|
+
Expression[base, :|, [[val, :<<, shift], :&, mask]].encode(:u32, @endianness)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,75 @@
|
|
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/main'
|
8
|
+
|
9
|
+
module Metasm
|
10
|
+
class ARM < CPU
|
11
|
+
class Reg
|
12
|
+
class << self
|
13
|
+
attr_accessor :s_to_i, :i_to_s
|
14
|
+
end
|
15
|
+
@i_to_s = %w[r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 sp lr pc]
|
16
|
+
@s_to_i = { 'wr' => 7, 'sb' => 9, 'sl' => 10, 'fp' => 11, 'ip' => 12, 'sp' => 13, 'lr' => 14, 'pc' => 15 }
|
17
|
+
15.times { |i| @s_to_i["r#{i}"] = i }
|
18
|
+
4.times { |i| @s_to_i["a#{i+1}"] = i }
|
19
|
+
8.times { |i| @s_to_i["v#{i+1}"] = i+4 }
|
20
|
+
|
21
|
+
attr_accessor :i, :stype, :shift, :updated
|
22
|
+
def initialize(i, stype=:lsl, shift=0)
|
23
|
+
@i = i
|
24
|
+
@stype = stype
|
25
|
+
@shift = shift
|
26
|
+
end
|
27
|
+
|
28
|
+
def symbolic
|
29
|
+
r = self.class.i_to_s[@i].to_sym
|
30
|
+
if @stype == :lsl and @shift == 0
|
31
|
+
r
|
32
|
+
else
|
33
|
+
r # TODO shift/rotate/...
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
class Memref
|
39
|
+
attr_accessor :base, :offset, :sign, :incr
|
40
|
+
def initialize(base, offset, sign=:+, incr=nil)
|
41
|
+
@base, @offset, @sign, @incr = base, offset, sign, incr
|
42
|
+
end
|
43
|
+
|
44
|
+
def symbolic(len=4, orig=nil)
|
45
|
+
o = @offset
|
46
|
+
o = o.symbolic if o.kind_of? Reg
|
47
|
+
p = Expression[@base.symbolic, @sign, o].reduce
|
48
|
+
Indirection[p, len, orig]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class RegList
|
53
|
+
attr_accessor :list, :usermoderegs
|
54
|
+
|
55
|
+
def initialize(l=[])
|
56
|
+
@list = l
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def initialize(endianness = :little)
|
61
|
+
super()
|
62
|
+
@endianness = endianness
|
63
|
+
@size = 32
|
64
|
+
end
|
65
|
+
|
66
|
+
def init_opcode_list
|
67
|
+
init_latest
|
68
|
+
@opcode_list
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
class ARM_THUMB < ARM
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
@@ -0,0 +1,177 @@
|
|
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/arm/main'
|
8
|
+
|
9
|
+
module Metasm
|
10
|
+
class ARM
|
11
|
+
private
|
12
|
+
def addop(name, bin, *args)
|
13
|
+
args << :cond if not args.delete :uncond
|
14
|
+
|
15
|
+
o = Opcode.new name, bin
|
16
|
+
o.args.concat(args & @valid_args)
|
17
|
+
(args & @valid_props).each { |p| o.props[p] = true }
|
18
|
+
args.grep(Hash).each { |h| o.props.update h }
|
19
|
+
|
20
|
+
# special args -> multiple fields
|
21
|
+
case (o.args & [:i8_r, :rm_is, :rm_rs, :mem_rn_rm, :mem_rn_i8_12, :mem_rn_rms, :mem_rn_i12]).first
|
22
|
+
when :i8_r; args << :i8 << :rotate
|
23
|
+
when :rm_is; args << :rm << :stype << :shifti
|
24
|
+
when :rm_rs; args << :rm << :stype << :rs
|
25
|
+
when :mem_rn_rm; args << :rn << :rm << :rsx << :u
|
26
|
+
when :mem_rn_i8_12; args << :rn << :i8_12 << :u
|
27
|
+
when :mem_rn_rms; args << :rn << :rm << :stype << :shifti << :u
|
28
|
+
when :mem_rn_i12; args << :rn << :i12 << :u
|
29
|
+
end
|
30
|
+
|
31
|
+
(args & @fields_mask.keys).each { |f|
|
32
|
+
o.fields[f] = [@fields_mask[f], @fields_shift[f]]
|
33
|
+
}
|
34
|
+
|
35
|
+
@opcode_list << o
|
36
|
+
end
|
37
|
+
|
38
|
+
def addop_data_s(name, op, a1, a2, *h)
|
39
|
+
addop name, op | (1 << 25), a1, a2, :i8_r, :rotate, *h
|
40
|
+
addop name, op, a1, a2, :rm_is, *h
|
41
|
+
addop name, op | (1 << 4), a1, a2, :rm_rs, *h
|
42
|
+
end
|
43
|
+
def addop_data(name, op, a1, a2)
|
44
|
+
addop_data_s name, op << 21, a1, a2
|
45
|
+
addop_data_s name+'s', (op << 21) | (1 << 20), a1, a2, :cond_name_off => name.length
|
46
|
+
end
|
47
|
+
|
48
|
+
def addop_load_puw(name, op, *a)
|
49
|
+
addop name, op, {:baseincr => :post}, :rd, :u, *a
|
50
|
+
addop name, op | (1 << 24), :rd, :u, *a
|
51
|
+
addop name, op | (1 << 24) | (1 << 21), {:baseincr => :pre}, :rd, :u, *a
|
52
|
+
end
|
53
|
+
def addop_load_lsh_o(name, op)
|
54
|
+
addop_load_puw name, op, :rsz, :mem_rn_rm, {:cond_name_off => 3}
|
55
|
+
addop_load_puw name, op | (1 << 22), :mem_rn_i8_12, {:cond_name_off => 3}
|
56
|
+
end
|
57
|
+
def addop_load_lsh
|
58
|
+
op = 9 << 4
|
59
|
+
addop_load_lsh_o 'strh', op | (1 << 5)
|
60
|
+
addop_load_lsh_o 'ldrd', op | (1 << 6)
|
61
|
+
addop_load_lsh_o 'strd', op | (1 << 6) | (1 << 5)
|
62
|
+
addop_load_lsh_o 'ldrh', op | (1 << 20) | (1 << 5)
|
63
|
+
addop_load_lsh_o 'ldrsb', op | (1 << 20) | (1 << 6)
|
64
|
+
addop_load_lsh_o 'ldrsh', op | (1 << 20) | (1 << 6) | (1 << 5)
|
65
|
+
end
|
66
|
+
|
67
|
+
def addop_load_puwt(name, op, *a)
|
68
|
+
addop_load_puw name, op, *a
|
69
|
+
addop name+'t', op | (1 << 21), {:baseincr => :post, :cond_name_off => name.length}, :rd, :u, *a
|
70
|
+
end
|
71
|
+
def addop_load_o(name, op, *a)
|
72
|
+
addop_load_puwt name, op, :mem_rn_i12, *a
|
73
|
+
addop_load_puwt name, op | (1 << 25), :mem_rn_rms, *a
|
74
|
+
end
|
75
|
+
def addop_load(name, op)
|
76
|
+
addop_load_o name, op
|
77
|
+
addop_load_o name+'b', op | (1 << 22), :cond_name_off => name.length
|
78
|
+
end
|
79
|
+
|
80
|
+
def addop_ldm_go(name, op, *a)
|
81
|
+
addop name, op, :rn, :reglist, {:cond_name_off => 3}, *a
|
82
|
+
end
|
83
|
+
def addop_ldm_w(name, op, *a)
|
84
|
+
addop_ldm_go name, op, *a # base reg untouched
|
85
|
+
addop_ldm_go name, op | (1 << 21), {:baseincr => :post}, *a # base updated
|
86
|
+
end
|
87
|
+
def addop_ldm_s(name, op)
|
88
|
+
addop_ldm_w name, op # transfer regs
|
89
|
+
addop_ldm_w name, op | (1 << 22), :usermoderegs # transfer usermode regs
|
90
|
+
end
|
91
|
+
def addop_ldm_p(name, op)
|
92
|
+
addop_ldm_s name+'a', op # target memory included
|
93
|
+
addop_ldm_s name+'b', op | (1 << 24) # target memory excluded, transfer starts at next addr
|
94
|
+
end
|
95
|
+
def addop_ldm_u(name, op)
|
96
|
+
addop_ldm_p name+'d', op # transfer made downward
|
97
|
+
addop_ldm_p name+'i', op | (1 << 23) # transfer made upward
|
98
|
+
end
|
99
|
+
def addop_ldm(name, op)
|
100
|
+
addop_ldm_u name, op
|
101
|
+
end
|
102
|
+
|
103
|
+
# ARMv6 instruction set, aka arm7/arm9
|
104
|
+
def init_arm_v6
|
105
|
+
@opcode_list = []
|
106
|
+
@valid_props << :baseincr << :cond << :cond_name_off << :usermoderegs <<
|
107
|
+
:tothumb << :tojazelle
|
108
|
+
@valid_args.concat [:rn, :rd, :rm, :crn, :crd, :crm, :cpn, :reglist, :i24,
|
109
|
+
:rm_rs, :rm_is, :i8_r, :mem_rn_rm, :mem_rn_i8_12, :mem_rn_rms, :mem_rn_i12]
|
110
|
+
@fields_mask.update :rn => 0xf, :rd => 0xf, :rs => 0xf, :rm => 0xf,
|
111
|
+
:crn => 0xf, :crd => 0xf, :crm => 0xf, :cpn => 0xf,
|
112
|
+
:rnx => 0xf, :rdx => 0xf, :rsx => 0xf,
|
113
|
+
:shifti => 0x1f, :stype => 3, :rotate => 0xf, :reglist => 0xffff,
|
114
|
+
:i8 => 0xff, :i12 => 0xfff, :i24 => 0xff_ffff, :i8_12 => 0xf0f,
|
115
|
+
:u => 1, :mask => 0xf, :sbo => 0xf, :cond => 0xf
|
116
|
+
|
117
|
+
@fields_shift.update :rn => 16, :rd => 12, :rs => 8, :rm => 0,
|
118
|
+
:crn => 16, :crd => 12, :crm => 0, :cpn => 8,
|
119
|
+
:rnx => 16, :rdx => 12, :rsx => 8,
|
120
|
+
:shifti => 7, :stype => 5, :rotate => 8, :reglist => 0,
|
121
|
+
:i8 => 0, :i12 => 0, :i24 => 0, :i8_12 => 0,
|
122
|
+
:u => 23, :mask => 16, :sbo => 12, :cond => 28
|
123
|
+
|
124
|
+
addop_data 'and', 0, :rd, :rn
|
125
|
+
addop_data 'eor', 1, :rd, :rn
|
126
|
+
addop_data 'xor', 1, :rd, :rn
|
127
|
+
addop_data 'sub', 2, :rd, :rn
|
128
|
+
addop_data 'rsb', 3, :rd, :rn
|
129
|
+
addop_data 'add', 4, :rd, :rn
|
130
|
+
addop_data 'adc', 5, :rd, :rn
|
131
|
+
addop_data 'sbc', 6, :rd, :rn
|
132
|
+
addop_data 'rsc', 7, :rd, :rn
|
133
|
+
addop_data 'tst', 8, :rdx, :rn
|
134
|
+
addop_data 'teq', 9, :rdx, :rn
|
135
|
+
addop_data 'cmp', 10, :rdx, :rn
|
136
|
+
addop_data 'cmn', 11, :rdx, :rn
|
137
|
+
addop_data 'orr', 12, :rd, :rn
|
138
|
+
addop_data 'or', 12, :rd, :rn
|
139
|
+
addop_data 'mov', 13, :rd, :rnx
|
140
|
+
addop_data 'bic', 14, :rd, :rn
|
141
|
+
addop_data 'mvn', 15, :rd, :rnx
|
142
|
+
|
143
|
+
addop 'b', 0b1010 << 24, :setip, :stopexec, :i24
|
144
|
+
addop 'bl', 0b1011 << 24, :setip, :stopexec, :i24, :saveip
|
145
|
+
addop 'bkpt', (0b00010010 << 20) | (0b0111 << 4) # other fields are available&unused, also cnd != AL is undef
|
146
|
+
addop 'blx', 0b1111101 << 25, :setip, :stopexec, :saveip, :tothumb, :h, :nocond, :i24
|
147
|
+
addop 'blx', (0b00010010 << 20) | (0b0011 << 4), :setip, :stopexec, :saveip, :tothumb, :rm
|
148
|
+
addop 'bx', (0b00010010 << 20) | (0b0001 << 4), :setip, :stopexec, :rm
|
149
|
+
addop 'bxj', (0b00010010 << 20) | (0b0010 << 4), :setip, :stopexec, :rm, :tojazelle
|
150
|
+
|
151
|
+
addop_load 'str', (1 << 26)
|
152
|
+
addop_load 'ldr', (1 << 26) | (1 << 20)
|
153
|
+
addop_load_lsh
|
154
|
+
addop_ldm 'stm', (1 << 27)
|
155
|
+
addop_ldm 'ldm', (1 << 27) | (1 << 20)
|
156
|
+
end
|
157
|
+
alias init_latest init_arm_v6
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
__END__
|
162
|
+
addop_cond 'mrs', 0b0001000011110000000000000000, :rd
|
163
|
+
addop_cond 'msr', 0b0001001010011111000000000000, :rd
|
164
|
+
addop_cond 'msrf', 0b0001001010001111000000000000, :rd
|
165
|
+
|
166
|
+
addop_cond 'mul', 0b000000000000001001 << 4, :rd, :rn, :rs, :rm
|
167
|
+
addop_cond 'mla', 0b100000000000001001 << 4, :rd, :rn, :rs, :rm
|
168
|
+
|
169
|
+
addop_cond 'swp', 0b0001000000000000000010010000, :rd, :rn, :rs, :rm
|
170
|
+
addop_cond 'swpb', 0b0001010000000000000010010000, :rd, :rn, :rs, :rm
|
171
|
+
|
172
|
+
addop_cond 'undef', 0b00000110000000000000000000010000
|
173
|
+
|
174
|
+
addop_cond 'swi', 0b00001111 << 24
|
175
|
+
|
176
|
+
addop_cond 'bkpt', 0b1001000000000000001110000
|
177
|
+
addop_cond 'movw', 0b0011 << 24, :movwimm
|