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,46 @@
|
|
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
|
+
# this script reads a list of elf files, and lists its dependencies recursively
|
10
|
+
# libraries are searched in LD_LIBRARY_PATH, /usr/lib and /lib
|
11
|
+
# includes the elf interpreter
|
12
|
+
# can be useful when chrooting a binary
|
13
|
+
#
|
14
|
+
|
15
|
+
require 'metasm'
|
16
|
+
|
17
|
+
|
18
|
+
paths = ENV['LD_LIBRARY_PATH'].to_s.split(':') + %w[/usr/lib /lib]
|
19
|
+
todo = ARGV.map { |file| (file[0] == ?/) ? file : "./#{file}" }
|
20
|
+
done = []
|
21
|
+
while src = todo.shift
|
22
|
+
puts src
|
23
|
+
# could do a simple ELF.decode_file, but this is quicker
|
24
|
+
elf = Metasm::ELF.decode_file_header(src)
|
25
|
+
|
26
|
+
if s = elf.segments.find { |s_| s_.type == 'INTERP' }
|
27
|
+
interp = elf.encoded[s.offset, s.filesz].data.chomp("\0")
|
28
|
+
if not done.include? interp
|
29
|
+
puts interp
|
30
|
+
done << interp
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
elf.decode_tags
|
35
|
+
elf.decode_segments_tags_interpret
|
36
|
+
deps = elf.tag['NEEDED'].to_a - done
|
37
|
+
done.concat deps
|
38
|
+
|
39
|
+
deps.each { |dep|
|
40
|
+
if not path = paths.find { |path_| File.exist? File.join(path_, dep) }
|
41
|
+
$stderr.puts "cannot find #{dep} for #{src}"
|
42
|
+
else
|
43
|
+
todo << File.join(path, dep)
|
44
|
+
end
|
45
|
+
}
|
46
|
+
end
|
@@ -0,0 +1,33 @@
|
|
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
|
+
# this script takes a list of dll filenames as arguments, and outputs each lib export
|
8
|
+
# libname, followed by the list of the exported symbol names, in a format usable
|
9
|
+
# by the Elf class autoimport functionnality (see metasm/os/linux.rb)
|
10
|
+
#
|
11
|
+
|
12
|
+
require 'metasm'
|
13
|
+
|
14
|
+
bd = 'GLOBAL'
|
15
|
+
bd = 'WEAK' if ARGV.delete '--weak'
|
16
|
+
obj = true if ARGV.delete '--obj'
|
17
|
+
|
18
|
+
ARGV.each { |f|
|
19
|
+
e = Metasm::ELF.decode_file(f)
|
20
|
+
next if not e.tag['SONAME']
|
21
|
+
puts e.tag['SONAME']
|
22
|
+
line = ''
|
23
|
+
e.symbols.find_all { |s|
|
24
|
+
s.name and (obj ? s.type != 'FUNC' : s.type == 'FUNC') and s.shndx != 'UNDEF' and s.bind == bd
|
25
|
+
}.map { |s| ' ' << s.name }.sort.each { |s|
|
26
|
+
if line.length + s.length >= 160
|
27
|
+
puts line
|
28
|
+
line = ''
|
29
|
+
end
|
30
|
+
line << s
|
31
|
+
}
|
32
|
+
puts line if not line.empty?
|
33
|
+
}
|
@@ -0,0 +1,25 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# This file is part of Metasm, the Ruby assembly manipulation suite
|
4
|
+
# Copyright (C) 2006-2009 Yoann GUILLOT
|
5
|
+
#
|
6
|
+
# Licence is LGPL, see LICENCE in the top-level directory
|
7
|
+
|
8
|
+
require 'metasm'
|
9
|
+
$opts = { :execlass => Metasm::ELF, :exetype => :lib }
|
10
|
+
load File.join(File.dirname(__FILE__), 'exeencode.rb')
|
11
|
+
|
12
|
+
__END__
|
13
|
+
.pt_gnu_stack rw
|
14
|
+
// .nointerp // to disable the dynamic section, eg for stuff with int80 only
|
15
|
+
.text
|
16
|
+
.entrypoint
|
17
|
+
push bla
|
18
|
+
push fmt
|
19
|
+
call printf
|
20
|
+
push 0
|
21
|
+
call exit
|
22
|
+
|
23
|
+
.data
|
24
|
+
bla db "world", 0
|
25
|
+
fmt db "Hello, %s !\n", 0
|
@@ -0,0 +1,128 @@
|
|
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
|
+
# this sample shows how to compile an executable file from source
|
9
|
+
# use --exe PE to compile a PE/ELF/MachO etc
|
10
|
+
# use --cpu MIPS/--16/--be to change the CPU
|
11
|
+
# the arg is a source file (c or asm) (some arch may not yet support C compiling)
|
12
|
+
# defaults to encoding a shellcode, use --exe to override (or the scripts samples/{elf,pe}encode)
|
13
|
+
# to compile a shellcode to a cstring, use --cstring
|
14
|
+
#
|
15
|
+
|
16
|
+
require 'metasm'
|
17
|
+
require 'optparse'
|
18
|
+
|
19
|
+
$opts ||= {}
|
20
|
+
$opts = {
|
21
|
+
:execlass => Metasm::Shellcode,
|
22
|
+
:cpu => Metasm::Ia32.new,
|
23
|
+
:exetype => :bin,
|
24
|
+
:macros => {}
|
25
|
+
}.merge($opts)
|
26
|
+
|
27
|
+
OptionParser.new { |opt|
|
28
|
+
opt.on('-o file', 'output filename') { |f| $opts[:outfilename] = f }
|
29
|
+
opt.on('-f') { $opts[:overwrite_outfile] = true }
|
30
|
+
opt.on('--c', 'parse source as a C file') { $opts[:srctype] = 'c' }
|
31
|
+
opt.on('--asm', 'parse asm as an ASM file') { $opts[:srctype] = 'asm' }
|
32
|
+
opt.on('--stdin', 'parse source on stdin') { ARGV << '-' }
|
33
|
+
opt.on('-v', '-W', 'verbose') { $VERBOSE=true }
|
34
|
+
opt.on('-d', 'debug') { $DEBUG=$VERBOSE=true }
|
35
|
+
opt.on('-D var=val', 'define a preprocessor macro') { |v| v0, v1 = v.split('=', 2) ; $opts[:macros][v0] = v1 }
|
36
|
+
opt.on('--cstring', 'encode output as a C string') { $opts[:to_string] = :c }
|
37
|
+
opt.on('--jsstring', 'encode output as a js string') { $opts[:to_string] = :js }
|
38
|
+
opt.on('--string', 'encode output as a string to stdout') { $opts[:to_string] = :inspect }
|
39
|
+
opt.on('--varname name', 'the variable name for string output') { |v| $opts[:varname] = v }
|
40
|
+
opt.on('-e class', '--exe class', 'use a specific ExeFormat class') { |c| $opts[:execlass] = Metasm.const_get(c) }
|
41
|
+
opt.on('--cpu cpu', 'use a specific CPU class') { |c| $opts[:cpu] = Metasm.const_get(c).new }
|
42
|
+
# must come after --cpu in commandline
|
43
|
+
opt.on('--16', 'set cpu in 16bit mode') { $opts[:cpu].size = 16 }
|
44
|
+
opt.on('--le', 'set cpu in little-endian mode') { $opts[:cpu].endianness = :little }
|
45
|
+
opt.on('--be', 'set cpu in big-endian mode') { $opts[:cpu].endianness = :big }
|
46
|
+
opt.on('--fno-pic', 'generate position-dependant code') { $opts[:cpu].generate_PIC = false }
|
47
|
+
opt.on('--shared', 'generate shared library') { $opts[:exetype] = :lib }
|
48
|
+
opt.on('--ruby-module-hack', 'use the dynldr module hack to use any ruby lib available for ruby symbols') { $opts[:dldrhack] = true }
|
49
|
+
}.parse!
|
50
|
+
|
51
|
+
src = $opts[:macros].map { |k, v| "#define #{k} #{v}\n" }.join
|
52
|
+
|
53
|
+
if file = ARGV.shift
|
54
|
+
$opts[:srctype] ||= 'c' if file =~ /\.c$/
|
55
|
+
if file == '-'
|
56
|
+
src << $stdin.read
|
57
|
+
else
|
58
|
+
src << File.read(file)
|
59
|
+
end
|
60
|
+
else
|
61
|
+
$opts[:srctype] ||= $opts[:srctype_data]
|
62
|
+
src << DATA.read # the text after __END__ in this file
|
63
|
+
end
|
64
|
+
|
65
|
+
if $opts[:outfilename] and not $opts[:overwrite_outfile] and File.exist?($opts[:outfilename])
|
66
|
+
abort "Error: target file exists !"
|
67
|
+
end
|
68
|
+
|
69
|
+
if $opts[:srctype] == 'c'
|
70
|
+
exe = $opts[:execlass].compile_c($opts[:cpu], src, file)
|
71
|
+
else
|
72
|
+
exe = $opts[:execlass].assemble($opts[:cpu], src, file)
|
73
|
+
end
|
74
|
+
|
75
|
+
if $opts[:to_string]
|
76
|
+
str = exe.encode_string
|
77
|
+
|
78
|
+
$opts[:varname] ||= File.basename(file.to_s)[/^\w+/] || 'sc' # derive varname from filename
|
79
|
+
case $opts[:to_string]
|
80
|
+
when :inspect
|
81
|
+
str = "#{$opts[:varname]} = #{str.inspect}"
|
82
|
+
when :c
|
83
|
+
str = ["unsigned char #{$opts[:varname]}[#{str.length}] = "] + str.scan(/.{1,19}/m).map { |l|
|
84
|
+
'"' + l.unpack('C*').map { |c| '\\x%02x' % c }.join + '"'
|
85
|
+
}
|
86
|
+
str.last << ?;
|
87
|
+
when :js
|
88
|
+
str << 0 if str.length & 1 != 0
|
89
|
+
str = ["#{$opts[:varname]} = "] + str.scan(/.{2,20}/m).map { |l|
|
90
|
+
'"' + l.unpack($opts[:cpu].endianness == :little ? 'v*' : 'n*').map { |c| '%%u%04x' % c }.join + '"+'
|
91
|
+
}
|
92
|
+
str.last[-1] = ?;
|
93
|
+
end
|
94
|
+
|
95
|
+
if of = $opts[:outfilename]
|
96
|
+
abort "Error: target file #{of.inspect} exists !" if File.exists? of and not $opts[:overwrite_outfile]
|
97
|
+
File.open(of, 'w') { |fd| fd.puts str }
|
98
|
+
puts "saved to file #{of.inspect}"
|
99
|
+
else
|
100
|
+
puts str
|
101
|
+
end
|
102
|
+
else
|
103
|
+
of = $opts[:outfilename] ||= 'a.out'
|
104
|
+
abort "Error: target file #{of.inspect} exists !" if File.exists? of and not $opts[:overwrite_outfile]
|
105
|
+
Metasm::DynLdr.compile_binary_module_hack(exe) if $opts[:dldrhack]
|
106
|
+
exe.encode_file(of, $opts[:exetype])
|
107
|
+
puts "saved to file #{of.inspect}"
|
108
|
+
end
|
109
|
+
|
110
|
+
__END__
|
111
|
+
#include <asm/unistd.h>
|
112
|
+
jmp getip
|
113
|
+
gotip:
|
114
|
+
mov eax, __NR_write
|
115
|
+
mov ebx, 1
|
116
|
+
pop ecx
|
117
|
+
mov edx, strend-str
|
118
|
+
int 80h
|
119
|
+
|
120
|
+
mov eax, __NR_exit
|
121
|
+
mov ebx, 1
|
122
|
+
int 80h
|
123
|
+
|
124
|
+
getip:
|
125
|
+
call gotip
|
126
|
+
|
127
|
+
str db "Hello, world!", 0xa
|
128
|
+
strend:
|
@@ -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
|
+
# this exemple illustrates the use of the cparser/preprocessor #factorize functionnality:
|
8
|
+
# it generates code that references to the functions imported by an ELF executable
|
9
|
+
# usage: factorize-imports.rb <exe> [<path to include dir>] [<additional func names>... !<func to exclude>]
|
10
|
+
#
|
11
|
+
|
12
|
+
require 'metasm'
|
13
|
+
include Metasm
|
14
|
+
|
15
|
+
require 'optparse'
|
16
|
+
opts = { :hdrs => [], :defs => {}, :path => [] }
|
17
|
+
OptionParser.new { |opt|
|
18
|
+
opt.on('-o outfile') { |f| opts[:outfile] = f }
|
19
|
+
opt.on('-H additional_header') { |f| opts[:hdrs] << f }
|
20
|
+
opt.on('--exe executable') { |f| opts[:exe] = f }
|
21
|
+
opt.on('-I path', '--includepath path') { |f| opts[:path] << f }
|
22
|
+
opt.on('-D var') { |f| k, v = f.split('=', 2) ; opts[:defs].update k => (v || '') }
|
23
|
+
opt.on('--gcc') { opts[:gcc] = true }
|
24
|
+
opt.on('--vs', '--visualstudio') { opts[:vs] = true }
|
25
|
+
}.parse!(ARGV)
|
26
|
+
|
27
|
+
exe = AutoExe.decode_file_header(opts[:exe] || ARGV.shift)
|
28
|
+
opts[:path] ||= [ARGV.shift] if not ARGV.empty?
|
29
|
+
|
30
|
+
case exe
|
31
|
+
when PE
|
32
|
+
exe.decode_imports
|
33
|
+
funcnames = exe.imports.map { |id| id.imports.map { |i| i.name } }
|
34
|
+
when ELF
|
35
|
+
exe.decode_segments_dynamic
|
36
|
+
funcnames = exe.symbols.map { |s| s.name if s.shndx == 'UNDEF' and s.type == 'FUNC' }
|
37
|
+
opts[:hdrs] << 'stdio.h' << 'stdlib.h' << 'unistd.h'
|
38
|
+
opts[:gcc] = true if not opts[:vs]
|
39
|
+
else raise "unsupported #{exe.class}"
|
40
|
+
end
|
41
|
+
|
42
|
+
funcnames = funcnames.flatten.compact.uniq.sort
|
43
|
+
|
44
|
+
ARGV.each { |n|
|
45
|
+
if n[0] == ?!
|
46
|
+
funcnames.delete n[1..-1]
|
47
|
+
else
|
48
|
+
funcnames |= [n]
|
49
|
+
end
|
50
|
+
}
|
51
|
+
|
52
|
+
src = opts[:hdrs].map { |h| "#include <#{h}>" }.join("\n")
|
53
|
+
|
54
|
+
parser = Ia32.new.new_cparser
|
55
|
+
parser.prepare_gcc if opts[:gcc]
|
56
|
+
parser.prepare_visualstudio if opts[:vs]
|
57
|
+
pp = parser.lexer
|
58
|
+
pp.warn_redefinition = false
|
59
|
+
pp.include_search_path[0, 0] = opts[:path]
|
60
|
+
opts[:defs].each { |k, v| pp.define k, v }
|
61
|
+
parser.factorize_init
|
62
|
+
parser.parse src
|
63
|
+
|
64
|
+
|
65
|
+
# delete imports not present in the header files
|
66
|
+
funcnames.delete_if { |f|
|
67
|
+
if not parser.toplevel.symbol[f]
|
68
|
+
puts "// #{f.inspect} is not defined in the headers"
|
69
|
+
true
|
70
|
+
end
|
71
|
+
}
|
72
|
+
|
73
|
+
parser.parse "void *fnptr[] = { #{funcnames.map { |f| '&'+f }.join(', ')} };"
|
74
|
+
|
75
|
+
outfd = (opts[:outfile] ? File.open(opts[:outfile], 'w') : $stdout)
|
76
|
+
outfd.puts parser.factorize_final
|
77
|
+
outfd.close
|
@@ -0,0 +1,109 @@
|
|
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
|
+
# this exemple illustrates the use of the cparser/preprocessor #factorize functionnality:
|
8
|
+
# it generates code that references to the functions imported by a windows executable
|
9
|
+
# usage: factorize-imports.rb <exe> <exe2> <path to visual studio installation> [<additional func names>... ^<func to exclude>]
|
10
|
+
#
|
11
|
+
|
12
|
+
require 'metasm'
|
13
|
+
include Metasm
|
14
|
+
|
15
|
+
require 'optparse'
|
16
|
+
opts = { :hdrs => [], :defs => {}, :path => [], :exe => [] }
|
17
|
+
OptionParser.new { |opt|
|
18
|
+
opt.on('-o outfile') { |f| opts[:outfile] = f }
|
19
|
+
opt.on('-H additional_header') { |f| opts[:hdrs] << f }
|
20
|
+
opt.on('-e exe', '--exe executable') { |f| opts[:exe] << f }
|
21
|
+
opt.on('-I path', '--includepath path') { |f| opts[:path] << f }
|
22
|
+
opt.on('-D var') { |f| k, v = f.split('=', 2) ; opts[:defs].update k => (v || '') }
|
23
|
+
opt.on('--ddk') { opts[:ddk] = true }
|
24
|
+
opt.on('--vspath path') { |f| opts[:vspath] = f }
|
25
|
+
}.parse!(ARGV)
|
26
|
+
|
27
|
+
ARGV.delete_if { |e|
|
28
|
+
next if not File.file? e
|
29
|
+
opts[:exe] << e
|
30
|
+
}
|
31
|
+
|
32
|
+
if opts[:vspath] ||= ARGV.shift
|
33
|
+
opts[:vspath] = opts[:vspath].tr('\\', '/')
|
34
|
+
opts[:vspath] = opts[:vspath].chop if opts[:vspath][-1] == ?/
|
35
|
+
if opts[:ddk]
|
36
|
+
opts[:path] << (opts[:vspath]+'/ddk') << (opts[:vspath]+'/api') << (opts[:vspath]+'/crt')
|
37
|
+
else
|
38
|
+
opts[:vspath] = opts[:vspath][0...-3] if opts[:vspath][-3..-1] == '/VC'
|
39
|
+
opts[:path] << (opts[:vspath]+'/VC/platformsdk/include') << (opts[:vspath]+'/VC/include')
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
funcnames = opts[:exe].map { |e|
|
44
|
+
pe = PE.decode_file_header(e)
|
45
|
+
pe.decode_imports
|
46
|
+
if not pe.imports
|
47
|
+
puts "#{e} has no imports"
|
48
|
+
next
|
49
|
+
end
|
50
|
+
pe.imports.map { |id| id.imports.map { |i| i.name } }
|
51
|
+
}.flatten.compact.uniq.sort
|
52
|
+
|
53
|
+
ARGV.each { |n|
|
54
|
+
if n[0] == ?! or n[0] == ?- or n[0] == ?^
|
55
|
+
funcnames.delete n[1..-1]
|
56
|
+
else
|
57
|
+
funcnames |= [n]
|
58
|
+
end
|
59
|
+
}
|
60
|
+
exit if funcnames.empty?
|
61
|
+
|
62
|
+
src = <<EOS + opts[:hdrs].to_a.map { |h| "#include <#{h}>\n" }.join
|
63
|
+
#ifdef DDK
|
64
|
+
#define NO_INTERLOCKED_INTRINSICS
|
65
|
+
typedef struct _CONTEXT CONTEXT; // needed by ntddk.h, but this will pollute the factorized output..
|
66
|
+
typedef CONTEXT *PCONTEXT;
|
67
|
+
#define dllimport stdcall // wtff
|
68
|
+
#define SORTPP_PASS // C_ASSERT proprocessor assert..
|
69
|
+
#define _MSC_EXTENSIONS // __volatile stuff
|
70
|
+
#include <ntddk.h>
|
71
|
+
#include <stdio.h>
|
72
|
+
#else
|
73
|
+
#define WIN32_LEAN_AND_MEAN
|
74
|
+
#include <windows.h>
|
75
|
+
#include <winternl.h>
|
76
|
+
#endif
|
77
|
+
EOS
|
78
|
+
|
79
|
+
parser = Ia32.new.new_cparser
|
80
|
+
parser.prepare_visualstudio
|
81
|
+
pp = parser.lexer
|
82
|
+
pp.warn_redefinition = false
|
83
|
+
pp.define('_WIN32_WINNT', '0x0600')
|
84
|
+
pp.define('DDK') if opts[:ddk]
|
85
|
+
pp.define_strong('IN', '__attribute__((in))')
|
86
|
+
pp.define_strong('__in', '__attribute__((in))')
|
87
|
+
pp.define_strong('OUT', '__attribute__((out))')
|
88
|
+
pp.define_strong('__out', '__attribute__((out))')
|
89
|
+
pp.include_search_path = opts[:path]
|
90
|
+
opts[:defs].each { |k, v| pp.define k, v }
|
91
|
+
parser.factorize_init
|
92
|
+
parser.parse src
|
93
|
+
|
94
|
+
|
95
|
+
outfd = (opts[:outfile] ? File.open(opts[:outfile], 'w') : $stdout)
|
96
|
+
|
97
|
+
# delete imports not present in the header files
|
98
|
+
funcnames.delete_if { |f|
|
99
|
+
if not parser.toplevel.symbol[f]
|
100
|
+
puts "// #{f.inspect} is not defined in the headers"
|
101
|
+
outfd.puts "// #{f.inspect} is not defined in the headers" if opts[:outfile]
|
102
|
+
true
|
103
|
+
end
|
104
|
+
}
|
105
|
+
|
106
|
+
parser.parse "void *fnptr[] = { #{funcnames.map { |f| '&'+f }.join(', ')} };"
|
107
|
+
|
108
|
+
outfd.puts parser.factorize_final
|
109
|
+
outfd.close
|
@@ -0,0 +1,43 @@
|
|
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
|
+
# this exemple illustrates the use of the cparser/preprocessor #factorize functionnality:
|
8
|
+
# we write some code using standard headers, and the factorize call on CParser
|
9
|
+
# gives us back the macro/C definitions that we use in our code, so that we can
|
10
|
+
# get rid of the header
|
11
|
+
# Argument: C file to factorize, [path to visual studio installation]
|
12
|
+
# with a single argument, uses GCC standard headers
|
13
|
+
#
|
14
|
+
|
15
|
+
require 'metasm'
|
16
|
+
include Metasm
|
17
|
+
|
18
|
+
abort 'target needed' if not file = ARGV.shift
|
19
|
+
|
20
|
+
visualstudiopath = ARGV.shift
|
21
|
+
if visualstudiopath
|
22
|
+
stub = <<EOS
|
23
|
+
// add the path to the visual studio std headers
|
24
|
+
#ifdef __METASM__
|
25
|
+
#pragma include_dir #{(visualstudiopath+'/platformsdk/include').inspect}
|
26
|
+
#pragma include_dir #{(visualstudiopath+'/include').inspect}
|
27
|
+
#pragma prepare_visualstudio
|
28
|
+
#pragma no_warn_redefinition
|
29
|
+
#endif
|
30
|
+
EOS
|
31
|
+
else
|
32
|
+
stub = <<EOS
|
33
|
+
#ifdef __METASM__
|
34
|
+
#pragma prepare_gcc
|
35
|
+
#endif
|
36
|
+
EOS
|
37
|
+
end
|
38
|
+
stub << "#line 0\n"
|
39
|
+
|
40
|
+
# to trace only pp macros (using eg an asm source), use Preprocessor#factorize instead
|
41
|
+
|
42
|
+
puts Ia32.new.new_cparser.factorize(stub + File.read(file), file)
|
43
|
+
|