metasm 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (192) hide show
  1. data/BUGS +11 -0
  2. data/CREDITS +17 -0
  3. data/README +270 -0
  4. data/TODO +114 -0
  5. data/doc/code_organisation.txt +146 -0
  6. data/doc/const_missing.txt +16 -0
  7. data/doc/core_classes.txt +75 -0
  8. data/doc/feature_list.txt +53 -0
  9. data/doc/index.txt +59 -0
  10. data/doc/install_notes.txt +170 -0
  11. data/doc/style.css +3 -0
  12. data/doc/use_cases.txt +18 -0
  13. data/lib/metasm.rb +80 -0
  14. data/lib/metasm/arm.rb +12 -0
  15. data/lib/metasm/arm/debug.rb +39 -0
  16. data/lib/metasm/arm/decode.rb +167 -0
  17. data/lib/metasm/arm/encode.rb +77 -0
  18. data/lib/metasm/arm/main.rb +75 -0
  19. data/lib/metasm/arm/opcodes.rb +177 -0
  20. data/lib/metasm/arm/parse.rb +130 -0
  21. data/lib/metasm/arm/render.rb +55 -0
  22. data/lib/metasm/compile_c.rb +1457 -0
  23. data/lib/metasm/dalvik.rb +8 -0
  24. data/lib/metasm/dalvik/decode.rb +196 -0
  25. data/lib/metasm/dalvik/main.rb +60 -0
  26. data/lib/metasm/dalvik/opcodes.rb +366 -0
  27. data/lib/metasm/decode.rb +213 -0
  28. data/lib/metasm/decompile.rb +2659 -0
  29. data/lib/metasm/disassemble.rb +2068 -0
  30. data/lib/metasm/disassemble_api.rb +1280 -0
  31. data/lib/metasm/dynldr.rb +1329 -0
  32. data/lib/metasm/encode.rb +333 -0
  33. data/lib/metasm/exe_format/a_out.rb +194 -0
  34. data/lib/metasm/exe_format/autoexe.rb +82 -0
  35. data/lib/metasm/exe_format/bflt.rb +189 -0
  36. data/lib/metasm/exe_format/coff.rb +455 -0
  37. data/lib/metasm/exe_format/coff_decode.rb +901 -0
  38. data/lib/metasm/exe_format/coff_encode.rb +1078 -0
  39. data/lib/metasm/exe_format/dex.rb +457 -0
  40. data/lib/metasm/exe_format/dol.rb +145 -0
  41. data/lib/metasm/exe_format/elf.rb +923 -0
  42. data/lib/metasm/exe_format/elf_decode.rb +979 -0
  43. data/lib/metasm/exe_format/elf_encode.rb +1375 -0
  44. data/lib/metasm/exe_format/macho.rb +827 -0
  45. data/lib/metasm/exe_format/main.rb +228 -0
  46. data/lib/metasm/exe_format/mz.rb +164 -0
  47. data/lib/metasm/exe_format/nds.rb +172 -0
  48. data/lib/metasm/exe_format/pe.rb +437 -0
  49. data/lib/metasm/exe_format/serialstruct.rb +246 -0
  50. data/lib/metasm/exe_format/shellcode.rb +114 -0
  51. data/lib/metasm/exe_format/xcoff.rb +167 -0
  52. data/lib/metasm/gui.rb +23 -0
  53. data/lib/metasm/gui/cstruct.rb +373 -0
  54. data/lib/metasm/gui/dasm_coverage.rb +199 -0
  55. data/lib/metasm/gui/dasm_decomp.rb +369 -0
  56. data/lib/metasm/gui/dasm_funcgraph.rb +103 -0
  57. data/lib/metasm/gui/dasm_graph.rb +1354 -0
  58. data/lib/metasm/gui/dasm_hex.rb +543 -0
  59. data/lib/metasm/gui/dasm_listing.rb +599 -0
  60. data/lib/metasm/gui/dasm_main.rb +906 -0
  61. data/lib/metasm/gui/dasm_opcodes.rb +291 -0
  62. data/lib/metasm/gui/debug.rb +1228 -0
  63. data/lib/metasm/gui/gtk.rb +884 -0
  64. data/lib/metasm/gui/qt.rb +495 -0
  65. data/lib/metasm/gui/win32.rb +3004 -0
  66. data/lib/metasm/gui/x11.rb +621 -0
  67. data/lib/metasm/ia32.rb +14 -0
  68. data/lib/metasm/ia32/compile_c.rb +1523 -0
  69. data/lib/metasm/ia32/debug.rb +193 -0
  70. data/lib/metasm/ia32/decode.rb +1167 -0
  71. data/lib/metasm/ia32/decompile.rb +564 -0
  72. data/lib/metasm/ia32/encode.rb +314 -0
  73. data/lib/metasm/ia32/main.rb +233 -0
  74. data/lib/metasm/ia32/opcodes.rb +872 -0
  75. data/lib/metasm/ia32/parse.rb +327 -0
  76. data/lib/metasm/ia32/render.rb +91 -0
  77. data/lib/metasm/main.rb +1193 -0
  78. data/lib/metasm/mips.rb +11 -0
  79. data/lib/metasm/mips/compile_c.rb +7 -0
  80. data/lib/metasm/mips/decode.rb +253 -0
  81. data/lib/metasm/mips/encode.rb +51 -0
  82. data/lib/metasm/mips/main.rb +72 -0
  83. data/lib/metasm/mips/opcodes.rb +443 -0
  84. data/lib/metasm/mips/parse.rb +51 -0
  85. data/lib/metasm/mips/render.rb +43 -0
  86. data/lib/metasm/os/gnu_exports.rb +270 -0
  87. data/lib/metasm/os/linux.rb +1112 -0
  88. data/lib/metasm/os/main.rb +1686 -0
  89. data/lib/metasm/os/remote.rb +527 -0
  90. data/lib/metasm/os/windows.rb +2027 -0
  91. data/lib/metasm/os/windows_exports.rb +745 -0
  92. data/lib/metasm/parse.rb +876 -0
  93. data/lib/metasm/parse_c.rb +3938 -0
  94. data/lib/metasm/pic16c/decode.rb +42 -0
  95. data/lib/metasm/pic16c/main.rb +17 -0
  96. data/lib/metasm/pic16c/opcodes.rb +68 -0
  97. data/lib/metasm/ppc.rb +11 -0
  98. data/lib/metasm/ppc/decode.rb +264 -0
  99. data/lib/metasm/ppc/decompile.rb +251 -0
  100. data/lib/metasm/ppc/encode.rb +51 -0
  101. data/lib/metasm/ppc/main.rb +129 -0
  102. data/lib/metasm/ppc/opcodes.rb +410 -0
  103. data/lib/metasm/ppc/parse.rb +52 -0
  104. data/lib/metasm/preprocessor.rb +1277 -0
  105. data/lib/metasm/render.rb +130 -0
  106. data/lib/metasm/sh4.rb +8 -0
  107. data/lib/metasm/sh4/decode.rb +336 -0
  108. data/lib/metasm/sh4/main.rb +292 -0
  109. data/lib/metasm/sh4/opcodes.rb +381 -0
  110. data/lib/metasm/x86_64.rb +12 -0
  111. data/lib/metasm/x86_64/compile_c.rb +1025 -0
  112. data/lib/metasm/x86_64/debug.rb +59 -0
  113. data/lib/metasm/x86_64/decode.rb +268 -0
  114. data/lib/metasm/x86_64/encode.rb +264 -0
  115. data/lib/metasm/x86_64/main.rb +135 -0
  116. data/lib/metasm/x86_64/opcodes.rb +118 -0
  117. data/lib/metasm/x86_64/parse.rb +68 -0
  118. data/misc/bottleneck.rb +61 -0
  119. data/misc/cheader-findpppath.rb +58 -0
  120. data/misc/hexdiff.rb +74 -0
  121. data/misc/hexdump.rb +55 -0
  122. data/misc/metasm-all.rb +13 -0
  123. data/misc/objdiff.rb +47 -0
  124. data/misc/objscan.rb +40 -0
  125. data/misc/pdfparse.rb +661 -0
  126. data/misc/ppc_pdf2oplist.rb +192 -0
  127. data/misc/tcp_proxy_hex.rb +84 -0
  128. data/misc/txt2html.rb +440 -0
  129. data/samples/a.out.rb +31 -0
  130. data/samples/asmsyntax.rb +77 -0
  131. data/samples/bindiff.rb +555 -0
  132. data/samples/compilation-steps.rb +49 -0
  133. data/samples/cparser_makestackoffset.rb +55 -0
  134. data/samples/dasm-backtrack.rb +38 -0
  135. data/samples/dasmnavig.rb +318 -0
  136. data/samples/dbg-apihook.rb +228 -0
  137. data/samples/dbghelp.rb +143 -0
  138. data/samples/disassemble-gui.rb +102 -0
  139. data/samples/disassemble.rb +133 -0
  140. data/samples/dump_upx.rb +95 -0
  141. data/samples/dynamic_ruby.rb +1929 -0
  142. data/samples/elf_list_needed.rb +46 -0
  143. data/samples/elf_listexports.rb +33 -0
  144. data/samples/elfencode.rb +25 -0
  145. data/samples/exeencode.rb +128 -0
  146. data/samples/factorize-headers-elfimports.rb +77 -0
  147. data/samples/factorize-headers-peimports.rb +109 -0
  148. data/samples/factorize-headers.rb +43 -0
  149. data/samples/gdbclient.rb +583 -0
  150. data/samples/generate_libsigs.rb +102 -0
  151. data/samples/hotfix_gtk_dbg.rb +59 -0
  152. data/samples/install_win_env.rb +78 -0
  153. data/samples/lindebug.rb +924 -0
  154. data/samples/linux_injectsyscall.rb +95 -0
  155. data/samples/machoencode.rb +31 -0
  156. data/samples/metasm-shell.rb +91 -0
  157. data/samples/pe-hook.rb +69 -0
  158. data/samples/pe-ia32-cpuid.rb +203 -0
  159. data/samples/pe-mips.rb +35 -0
  160. data/samples/pe-shutdown.rb +78 -0
  161. data/samples/pe-testrelocs.rb +51 -0
  162. data/samples/pe-testrsrc.rb +24 -0
  163. data/samples/pe_listexports.rb +31 -0
  164. data/samples/peencode.rb +19 -0
  165. data/samples/peldr.rb +494 -0
  166. data/samples/preprocess-flatten.rb +19 -0
  167. data/samples/r0trace.rb +308 -0
  168. data/samples/rubstop.rb +399 -0
  169. data/samples/scan_pt_gnu_stack.rb +54 -0
  170. data/samples/scanpeexports.rb +62 -0
  171. data/samples/shellcode-c.rb +40 -0
  172. data/samples/shellcode-dynlink.rb +146 -0
  173. data/samples/source.asm +34 -0
  174. data/samples/struct_offset.rb +47 -0
  175. data/samples/testpe.rb +32 -0
  176. data/samples/testraw.rb +45 -0
  177. data/samples/win32genloader.rb +132 -0
  178. data/samples/win32hooker-advanced.rb +169 -0
  179. data/samples/win32hooker.rb +96 -0
  180. data/samples/win32livedasm.rb +33 -0
  181. data/samples/win32remotescan.rb +133 -0
  182. data/samples/wintrace.rb +92 -0
  183. data/tests/all.rb +8 -0
  184. data/tests/dasm.rb +39 -0
  185. data/tests/dynldr.rb +35 -0
  186. data/tests/encodeddata.rb +132 -0
  187. data/tests/ia32.rb +82 -0
  188. data/tests/mips.rb +116 -0
  189. data/tests/parse_c.rb +239 -0
  190. data/tests/preprocessor.rb +269 -0
  191. data/tests/x86_64.rb +62 -0
  192. metadata +255 -0
@@ -0,0 +1,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
+