metasm 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|