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
|
@@ -0,0 +1,135 @@
|
|
|
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/ia32'
|
|
9
|
+
|
|
10
|
+
module Metasm
|
|
11
|
+
|
|
12
|
+
# The x86_64, 64-bit extension of the x86 CPU (x64, em64t, amd64...)
|
|
13
|
+
class X86_64 < Ia32
|
|
14
|
+
# FpReg, SegReg, Farptr unchanged
|
|
15
|
+
# XXX ST(15) ?
|
|
16
|
+
|
|
17
|
+
# Simd extended to 16 regs, xmm only (mmx gone with 80387)
|
|
18
|
+
class SimdReg < Ia32::SimdReg
|
|
19
|
+
double_map 64 => (0..15).map { |n| "mm#{n}" },
|
|
20
|
+
128 => (0..15).map { |n| "xmm#{n}" }
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# general purpose registers, all sizes
|
|
24
|
+
# 8 new gprs (r8..r15), set bit R in the REX prefix to reference them (or X/B if in ModRM)
|
|
25
|
+
# aonethusaontehsanothe with 8bit subreg: with no rex prefix, refers to ah ch dh bh (as usual)
|
|
26
|
+
# but whenever the prefix is present, those become unavailable and encodie spl..dil (low byte of rsp/rdi)
|
|
27
|
+
class Reg < Ia32::Reg
|
|
28
|
+
double_map 8 => %w{ al cl dl bl spl bpl sil dil r8b r9b r10b r11b r12b r13b r14b r15b ah ch dh bh},
|
|
29
|
+
16 => %w{ ax cx dx bx sp bp si di r8w r9w r10w r11w r12w r13w r14w r15w},
|
|
30
|
+
32 => %w{eax ecx edx ebx esp ebp esi edi r8d r9d r10d r11d r12d r13d r14d r15d eip},
|
|
31
|
+
64 => %w{rax rcx rdx rbx rsp rbp rsi rdi r8 r9 r10 r11 r12 r13 r14 r15 rip}
|
|
32
|
+
|
|
33
|
+
Sym = @i_to_s[64].map { |s| s.to_sym }
|
|
34
|
+
|
|
35
|
+
# returns a symbolic representation of the register:
|
|
36
|
+
# cx => :rcx & 0xffff
|
|
37
|
+
# ah => (:rax >> 8) & 0xff
|
|
38
|
+
# XXX in x64, 32bits operations are zero-extended to 64bits (eg mov rax, 0x1234_ffff_ffff ; add eax, 1 => rax == 0
|
|
39
|
+
def symbolic(di=nil)
|
|
40
|
+
s = Sym[@val]
|
|
41
|
+
s = di.next_addr if s == :rip and di
|
|
42
|
+
if @sz == 8 and to_s[-1] == ?h
|
|
43
|
+
Expression[[Sym[@val-16], :>>, 8], :&, 0xff]
|
|
44
|
+
elsif @sz == 8
|
|
45
|
+
Expression[s, :&, 0xff]
|
|
46
|
+
elsif @sz == 16
|
|
47
|
+
Expression[s, :&, 0xffff]
|
|
48
|
+
elsif @sz == 32
|
|
49
|
+
Expression[s, :&, 0xffffffff]
|
|
50
|
+
else
|
|
51
|
+
s
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# checks if two registers have bits in common
|
|
56
|
+
def share?(other)
|
|
57
|
+
raise 'TODO'
|
|
58
|
+
# XXX TODO wtf does formula this do ?
|
|
59
|
+
other.val % (other.sz >> 1) == @val % (@sz >> 1) and (other.sz != @sz or @sz != 8 or other.val == @val)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# returns the part of @val to encode in an instruction field
|
|
63
|
+
def val_enc
|
|
64
|
+
if @sz == 8 and @val >= 16; @val-12 # ah, bh, ch, dh
|
|
65
|
+
elsif @val >= 16 # rip
|
|
66
|
+
else @val & 7 # others
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# returns the part of @val to encode in an instruction's rex prefix
|
|
71
|
+
def val_rex
|
|
72
|
+
if @sz == 8 and @val >= 16 # ah, bh, ch, dh: rex forbidden
|
|
73
|
+
elsif @val >= 16 # rip
|
|
74
|
+
else @val >> 3 # others
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# ModRM represents indirections (eg dword ptr [eax+4*ebx+12h])
|
|
80
|
+
# 16bit mode unavailable in x64
|
|
81
|
+
# opcodes use 64bit addressing by default, use adsz override (67h) prefix to switch to 32
|
|
82
|
+
# immediate values are encoded as :i32 sign-extended to 64bits
|
|
83
|
+
class ModRM < Ia32::ModRM
|
|
84
|
+
# mod 0/1/2 m 4 => sib
|
|
85
|
+
# mod 0 m 5 => rip+imm
|
|
86
|
+
# sib: i 4 => no index, b 5 => no base
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
class DbgReg < Ia32::DbgReg
|
|
90
|
+
simple_map((0..15).map { |i| [i, "dr#{i}"] })
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
class CtrlReg < Ia32::CtrlReg
|
|
94
|
+
simple_map((0..15).map { |i| [i, "cr#{i}"] })
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Create a new instance of an X86 cpu
|
|
98
|
+
# arguments (any order)
|
|
99
|
+
# - instruction set (386, 486, sse2...) [latest]
|
|
100
|
+
# - endianness [:little]
|
|
101
|
+
def initialize(*a)
|
|
102
|
+
super(:latest)
|
|
103
|
+
@size = 64
|
|
104
|
+
a.delete @size
|
|
105
|
+
@endianness = (a & [:big, :little]).first || :little
|
|
106
|
+
a.delete @endianness
|
|
107
|
+
@family = a.pop || :latest
|
|
108
|
+
raise "Invalid arguments #{a.inspect}" if not a.empty?
|
|
109
|
+
raise "Invalid X86_64 family #{@family.inspect}" if not respond_to?("init_#@family")
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# defines some preprocessor macros to say who we are:
|
|
113
|
+
# TODO
|
|
114
|
+
def tune_prepro(pp)
|
|
115
|
+
super(pp, :itsmeX64) # ask Ia32's to just call super()
|
|
116
|
+
pp.define_weak('_M_AMD64')
|
|
117
|
+
pp.define_weak('_M_X64')
|
|
118
|
+
pp.define_weak('__amd64__')
|
|
119
|
+
pp.define_weak('__x86_64__')
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def str_to_reg(str)
|
|
123
|
+
# X86_64::Reg != Ia32::Reg
|
|
124
|
+
Reg.from_str(str) if Reg.s_to_i.has_key? str
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def shortname
|
|
128
|
+
"x64#{'_be' if @endianness == :big}"
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
X64 = X86_64
|
|
133
|
+
AMD64 = X86_64
|
|
134
|
+
|
|
135
|
+
end
|
|
@@ -0,0 +1,118 @@
|
|
|
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/main'
|
|
8
|
+
require 'metasm/ia32/opcodes'
|
|
9
|
+
|
|
10
|
+
module Metasm
|
|
11
|
+
class X86_64
|
|
12
|
+
def init_cpu_constants
|
|
13
|
+
super()
|
|
14
|
+
@valid_args.concat [:i32, :u32, :i64, :u64] - @valid_args
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def init_386_common_only
|
|
18
|
+
super()
|
|
19
|
+
# :imm64 => accept a real int64 as :i argument
|
|
20
|
+
# :auto64 => ignore rex_w, always 64-bit op
|
|
21
|
+
# :op32no64 => if write to a 32-bit reg, dont zero the top 32-bits of dest
|
|
22
|
+
@valid_props |= [:imm64, :auto64, :op32no64]
|
|
23
|
+
@opcode_list.delete_if { |o| o.bin[0].to_i & 0xf0 == 0x40 } # now REX prefix
|
|
24
|
+
@opcode_list.each { |o|
|
|
25
|
+
o.props[:imm64] = true if o.bin == [0xB8] # mov reg, <true imm64>
|
|
26
|
+
o.props[:auto64] = true if o.name =~ /^(j|loop|(call|enter|leave|lgdt|lidt|lldt|ltr|pop|push|ret)$)/
|
|
27
|
+
#o.props[:op32no64] = true if o.name =~ // # TODO are there any instr here ?
|
|
28
|
+
}
|
|
29
|
+
addop 'movsxd', [0x63], :mrm
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# all x86_64 cpu understand <= sse2 instrs
|
|
33
|
+
def init_x8664_only
|
|
34
|
+
init_386_common_only
|
|
35
|
+
init_386_only
|
|
36
|
+
init_387_only # 387 indeed
|
|
37
|
+
init_486_only
|
|
38
|
+
init_pentium_only
|
|
39
|
+
init_p6_only
|
|
40
|
+
init_sse_only
|
|
41
|
+
init_sse2_only
|
|
42
|
+
|
|
43
|
+
@opcode_list.delete_if { |o|
|
|
44
|
+
o.args.include?(:seg2) or
|
|
45
|
+
o.args.include?(:seg2A) or
|
|
46
|
+
%w[aaa aad aam aas bound daa das
|
|
47
|
+
lds les loadall arpl pusha pushad popa popad].include?(o.name)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
addop 'swapgs', [0x0F, 0x01, 0xF8]
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def init_sse3
|
|
54
|
+
init_x8664_only
|
|
55
|
+
init_sse3_only
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def init_vmx
|
|
59
|
+
init_sse3
|
|
60
|
+
init_vmx_only
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def init_all
|
|
64
|
+
init_vmx
|
|
65
|
+
init_sse42_only
|
|
66
|
+
init_3dnow_only
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
alias init_latest init_all
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def addop_macrostr(name, bin, type)
|
|
73
|
+
super(name, bin, type)
|
|
74
|
+
bin = bin.dup
|
|
75
|
+
bin[0] |= 1
|
|
76
|
+
addop(name+'q', bin) { |o| o.props[:opsz] = 64 ; o.props[type] = true }
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def addop_post(op)
|
|
80
|
+
if op.fields[:d] or op.fields[:w] or op.fields[:s] or op.args.first == :regfp0
|
|
81
|
+
return super(op)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
dupe = lambda { |o|
|
|
85
|
+
dop = Opcode.new o.name.dup, o.bin.dup
|
|
86
|
+
dop.fields, dop.props, dop.args = o.fields.dup, o.props.dup, o.args.dup
|
|
87
|
+
dop
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
@opcode_list << op
|
|
91
|
+
|
|
92
|
+
if op.args == [:i] or op.args == [:farptr] or op.name[0, 3] == 'ret'
|
|
93
|
+
# define opsz-override version for ambiguous opcodes
|
|
94
|
+
op16 = dupe[op]
|
|
95
|
+
op16.name << '.i16'
|
|
96
|
+
op16.props[:opsz] = 16
|
|
97
|
+
@opcode_list << op16
|
|
98
|
+
# push call ret jz can't 32bit
|
|
99
|
+
op64 = dupe[op]
|
|
100
|
+
op64.name << '.i64'
|
|
101
|
+
op64.props[:opsz] = 64
|
|
102
|
+
@opcode_list << op64
|
|
103
|
+
elsif op.props[:strop] or op.props[:stropz] or op.args.include? :mrm_imm or
|
|
104
|
+
op.args.include? :modrm or op.args.include? :modrmA or op.name =~ /loop|xlat/
|
|
105
|
+
# define adsz-override version for ambiguous opcodes (movsq)
|
|
106
|
+
# XXX loop pfx 67 = rip+ecx, 66/rex ignored
|
|
107
|
+
op32 = dupe[op]
|
|
108
|
+
op32.name << '.a32'
|
|
109
|
+
op32.props[:adsz] = 32
|
|
110
|
+
@opcode_list << op32
|
|
111
|
+
op64 = dupe[op]
|
|
112
|
+
op64.name << '.a64'
|
|
113
|
+
op64.props[:adsz] = 64
|
|
114
|
+
@opcode_list << op64
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
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/x86_64/encode'
|
|
9
|
+
require 'metasm/parse'
|
|
10
|
+
|
|
11
|
+
module Metasm
|
|
12
|
+
class X86_64
|
|
13
|
+
def parse_parser_instruction(lexer, instr)
|
|
14
|
+
case instr.raw.downcase
|
|
15
|
+
when '.mode', '.bits'
|
|
16
|
+
if tok = lexer.readtok and tok.type == :string and tok.raw == '64'
|
|
17
|
+
lexer.skip_space
|
|
18
|
+
raise instr, 'syntax error' if ntok = lexer.nexttok and ntok.type != :eol
|
|
19
|
+
else
|
|
20
|
+
raise instr, 'invalid cpu mode, 64bit only'
|
|
21
|
+
end
|
|
22
|
+
else super(lexer, instr)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def parse_prefix(i, pfx)
|
|
27
|
+
super(i, pfx) or (i.prefix[:sz] = 64 if pfx == 'code64')
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# needed due to how ruby inheritance works wrt constants
|
|
31
|
+
def parse_argregclasslist
|
|
32
|
+
[Reg, SimdReg, SegReg, DbgReg, CtrlReg, FpReg]
|
|
33
|
+
end
|
|
34
|
+
# same inheritance sh*t
|
|
35
|
+
def parse_modrm(lex, tok, cpu)
|
|
36
|
+
ModRM.parse(lex, tok, cpu)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def parse_instruction_checkproto(i)
|
|
40
|
+
# check ah vs rex prefix
|
|
41
|
+
return if i.args.find { |a| a.kind_of? Reg and a.sz == 8 and a.val >= 16 and
|
|
42
|
+
op = opcode_list.find { |op_| op_.name == i.opname } and
|
|
43
|
+
((not op.props[:auto64] and i.args.find { |aa| aa.respond_to? :sz and aa.sz == 64 }) or
|
|
44
|
+
i.args.find { |aa| aa.kind_of? Reg and aa.val >= 8 and aa.val < 16 } or # XXX mov ah, cr12...
|
|
45
|
+
i.args.grep(ModRM).find { |aa| (aa.b and aa.b.val >= 8 and aa.b.val < 16) or (aa.i and aa.i.val >= 8 and aa.i.val < 16) })
|
|
46
|
+
}
|
|
47
|
+
super(i)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# check if the argument matches the opcode's argument spec
|
|
51
|
+
def parse_arg_valid?(o, spec, arg)
|
|
52
|
+
return if arg.kind_of? ModRM and ((arg.b and arg.b.val == 16 and arg.i) or (arg.i and arg.i.val == 16 and (arg.b or arg.s != 1)))
|
|
53
|
+
return if arg.kind_of? Reg and arg.sz >= 32 and arg.val == 16 # eip/rip only in modrm
|
|
54
|
+
return if o.props[:auto64] and arg.respond_to? :sz and arg.sz == 32
|
|
55
|
+
if o.name == 'movsxd'
|
|
56
|
+
return if not arg.kind_of? Reg and not arg.kind_of? ModRM
|
|
57
|
+
arg.sz ||= 32
|
|
58
|
+
if spec == :reg
|
|
59
|
+
return if not arg.kind_of? Reg
|
|
60
|
+
return arg.sz >= 32
|
|
61
|
+
else
|
|
62
|
+
return arg.sz == 32
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
super(o, spec, arg)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
data/misc/bottleneck.rb
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
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
|
+
# A script to help finding performance bottlenecks:
|
|
7
|
+
#
|
|
8
|
+
# $ ruby-prof myscript.rb
|
|
9
|
+
# => String#+ gets called 50k times and takes 30s
|
|
10
|
+
#
|
|
11
|
+
# $ LOGCALLER='String#+' ruby -r bottleneck myscript.rb
|
|
12
|
+
# => String#+ called 40k times from:
|
|
13
|
+
# stuff.rb:42 in Myclass#uglymethod from
|
|
14
|
+
# stuff.rb:32 in Myclass#initialize
|
|
15
|
+
#
|
|
16
|
+
# now you know what to rewrite
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def log_caller(cls, meth, singleton=false, histlen=nil)
|
|
21
|
+
histlen ||= ENV.fetch('LOGCALLER_MAXHIST', 16).to_i
|
|
22
|
+
dec_meth = 'm_' + meth.to_s.gsub(/[^\w]/) { |c| c.unpack('H*')[0] }
|
|
23
|
+
malias = dec_meth + '_log_caller'
|
|
24
|
+
mcntr = '$' + dec_meth + '_counter'
|
|
25
|
+
eval <<EOS
|
|
26
|
+
|
|
27
|
+
#{cls.kind_of?(Class) ? 'class' : 'module'} #{cls}
|
|
28
|
+
#{'class << self' if singleton}
|
|
29
|
+
alias #{malias} #{meth}
|
|
30
|
+
|
|
31
|
+
def #{meth}(*a, &b)
|
|
32
|
+
#{mcntr}[caller[0, #{histlen}]] += 1
|
|
33
|
+
#{malias}(*a, &b)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
#{'end' if singleton}
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
#{mcntr} = Hash.new(0)
|
|
40
|
+
|
|
41
|
+
at_exit {
|
|
42
|
+
total = #{mcntr}.inject(0) { |a, (k, v)| a+v }
|
|
43
|
+
puts "\#{total} callers of #{cls} #{meth}:"
|
|
44
|
+
#{mcntr}.sort_by { |k, v|
|
|
45
|
+
-v
|
|
46
|
+
}[0, 4].each { |k, v|
|
|
47
|
+
puts " \#{'%.2f%%' % (100.0*v/total)} - \#{v} times from", k, ''
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
EOS
|
|
52
|
+
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
ENV['LOGCALLER'].to_s.split(';').map { |lc|
|
|
56
|
+
next if not lc =~ /^(.*)([.#])(.*)$/
|
|
57
|
+
cls, sg, meth = $1, $2, $3.to_sym
|
|
58
|
+
sg = { '.' => true, '#' => false }[sg]
|
|
59
|
+
cls = cls.split('::').inject(::Object) { |o, cst| o.const_get(cst) }
|
|
60
|
+
log_caller(cls, meth, sg)
|
|
61
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
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
|
+
# shows the preprocessor path to find a specific line
|
|
8
|
+
# usage: ruby chdr-find.rb 'regex pattern' list of files.h
|
|
9
|
+
#
|
|
10
|
+
|
|
11
|
+
def gets
|
|
12
|
+
l = $ungets
|
|
13
|
+
$ungets = nil
|
|
14
|
+
l || super()
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def parse(root=false)
|
|
18
|
+
want = false
|
|
19
|
+
ret = []
|
|
20
|
+
while l = gets
|
|
21
|
+
case l = l.strip
|
|
22
|
+
when /^#if/
|
|
23
|
+
ret << l
|
|
24
|
+
r = parse(true)
|
|
25
|
+
if r.empty?
|
|
26
|
+
ret.pop
|
|
27
|
+
else
|
|
28
|
+
want = true
|
|
29
|
+
rr = r.pop
|
|
30
|
+
ret.concat r.map { |l_| (l_[0,3] == '#el' ? ' ' : ' ') << l_ }
|
|
31
|
+
ret << rr
|
|
32
|
+
end
|
|
33
|
+
when /^#el/
|
|
34
|
+
if not root
|
|
35
|
+
$ungets = l
|
|
36
|
+
break
|
|
37
|
+
end
|
|
38
|
+
ret << l
|
|
39
|
+
r = parse
|
|
40
|
+
want = true if not r.empty?
|
|
41
|
+
ret.concat r
|
|
42
|
+
when /^#endif/
|
|
43
|
+
if not root
|
|
44
|
+
$ungets = l
|
|
45
|
+
break
|
|
46
|
+
end
|
|
47
|
+
ret << l
|
|
48
|
+
break
|
|
49
|
+
when /#$srch/ #, /^#include/
|
|
50
|
+
want = true
|
|
51
|
+
ret << l
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
want ? ret : []
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
$srch = ARGV.shift
|
|
58
|
+
puts parse
|
data/misc/hexdiff.rb
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# This file is part of Metasm, the Ruby assembly manipulation suite
|
|
3
|
+
# Copyright (C) 2006-2009 Yoann GUILLOT
|
|
4
|
+
#
|
|
5
|
+
# Licence is LGPL, see LICENCE in the top-level directory
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
synclen = 6
|
|
10
|
+
ctxlen = 16
|
|
11
|
+
|
|
12
|
+
file1 = ('x'*ctxlen) + File.read(ARGV.shift)
|
|
13
|
+
file2 = ('x'*ctxlen) + File.read(ARGV.shift)
|
|
14
|
+
|
|
15
|
+
count1 = count2 = ctxlen
|
|
16
|
+
|
|
17
|
+
# prints the string in 80 cols
|
|
18
|
+
# with the first column filled with +pfx+
|
|
19
|
+
def show(pfx, str)
|
|
20
|
+
loop do
|
|
21
|
+
if str.length > 79
|
|
22
|
+
len = 79 - str[0...79][/\S+$/].to_s.length
|
|
23
|
+
len = 79 if len == 0
|
|
24
|
+
puts pfx + str[0...len]
|
|
25
|
+
str = str[len..-1]
|
|
26
|
+
else
|
|
27
|
+
puts pfx + str
|
|
28
|
+
break
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
loop do
|
|
34
|
+
w1 = file1[count1]
|
|
35
|
+
w2 = file2[count2]
|
|
36
|
+
break if not w1 and not w2
|
|
37
|
+
if w1 == w2
|
|
38
|
+
count1 += 1
|
|
39
|
+
count2 += 1
|
|
40
|
+
else
|
|
41
|
+
diff1 = diff2 = nil
|
|
42
|
+
catch(:resynced) {
|
|
43
|
+
1000.times { |depth|
|
|
44
|
+
(-depth..depth).map { |d|
|
|
45
|
+
if d == 0
|
|
46
|
+
[depth, depth]
|
|
47
|
+
elsif d < 0
|
|
48
|
+
[depth, depth+d]
|
|
49
|
+
elsif d > 0
|
|
50
|
+
[depth-d, depth]
|
|
51
|
+
end
|
|
52
|
+
}.each { |dc1, dc2|
|
|
53
|
+
next if !(0...synclen).all? { |i| file1[count1 + dc1 + i] == file2[count2 + dc2 + i] }
|
|
54
|
+
|
|
55
|
+
puts "@#{(count1-ctxlen).to_s 16} #{(count2-ctxlen).to_s 16}"
|
|
56
|
+
show ' ', file1[count1-ctxlen, ctxlen].inspect
|
|
57
|
+
if dc1 > 0
|
|
58
|
+
show '-', file1[count1, dc1].inspect
|
|
59
|
+
end
|
|
60
|
+
if dc2 > 0
|
|
61
|
+
show '+', file2[count2, dc2].inspect
|
|
62
|
+
end
|
|
63
|
+
count1 += dc1
|
|
64
|
+
count2 += dc2
|
|
65
|
+
show ' ', file1[count1, ctxlen].inspect
|
|
66
|
+
puts
|
|
67
|
+
|
|
68
|
+
throw :resynced
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
raise 'nomatch..'
|
|
72
|
+
}
|
|
73
|
+
end
|
|
74
|
+
end
|