metasm 1.0.1 → 1.0.2

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.
Files changed (235) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +1 -0
  3. data/.hgtags +3 -0
  4. data/Gemfile +1 -0
  5. data/INSTALL +61 -0
  6. data/LICENCE +458 -0
  7. data/README +29 -21
  8. data/Rakefile +10 -0
  9. data/TODO +10 -12
  10. data/doc/code_organisation.txt +2 -0
  11. data/doc/core/DynLdr.txt +247 -0
  12. data/doc/core/ExeFormat.txt +43 -0
  13. data/doc/core/Expression.txt +220 -0
  14. data/doc/core/GNUExports.txt +27 -0
  15. data/doc/core/Ia32.txt +236 -0
  16. data/doc/core/SerialStruct.txt +108 -0
  17. data/doc/core/VirtualString.txt +145 -0
  18. data/doc/core/WindowsExports.txt +61 -0
  19. data/doc/core/index.txt +1 -0
  20. data/doc/style.css +6 -3
  21. data/doc/usage/debugger.txt +327 -0
  22. data/doc/usage/index.txt +1 -0
  23. data/doc/use_cases.txt +2 -2
  24. data/metasm.gemspec +22 -0
  25. data/{lib/metasm.rb → metasm.rb} +11 -3
  26. data/{lib/metasm → metasm}/compile_c.rb +13 -7
  27. data/metasm/cpu/arc.rb +8 -0
  28. data/metasm/cpu/arc/decode.rb +425 -0
  29. data/metasm/cpu/arc/main.rb +191 -0
  30. data/metasm/cpu/arc/opcodes.rb +588 -0
  31. data/{lib/metasm → metasm/cpu}/arm.rb +7 -5
  32. data/{lib/metasm → metasm/cpu}/arm/debug.rb +2 -2
  33. data/{lib/metasm → metasm/cpu}/arm/decode.rb +13 -12
  34. data/{lib/metasm → metasm/cpu}/arm/encode.rb +23 -8
  35. data/{lib/metasm → metasm/cpu}/arm/main.rb +0 -3
  36. data/metasm/cpu/arm/opcodes.rb +324 -0
  37. data/{lib/metasm → metasm/cpu}/arm/parse.rb +25 -13
  38. data/{lib/metasm → metasm/cpu}/arm/render.rb +2 -2
  39. data/metasm/cpu/arm64.rb +15 -0
  40. data/metasm/cpu/arm64/debug.rb +38 -0
  41. data/metasm/cpu/arm64/decode.rb +289 -0
  42. data/metasm/cpu/arm64/encode.rb +41 -0
  43. data/metasm/cpu/arm64/main.rb +105 -0
  44. data/metasm/cpu/arm64/opcodes.rb +232 -0
  45. data/metasm/cpu/arm64/parse.rb +20 -0
  46. data/metasm/cpu/arm64/render.rb +95 -0
  47. data/{lib/metasm/ppc.rb → metasm/cpu/bpf.rb} +2 -4
  48. data/metasm/cpu/bpf/decode.rb +142 -0
  49. data/metasm/cpu/bpf/main.rb +60 -0
  50. data/metasm/cpu/bpf/opcodes.rb +81 -0
  51. data/metasm/cpu/bpf/render.rb +41 -0
  52. data/metasm/cpu/cy16.rb +9 -0
  53. data/metasm/cpu/cy16/decode.rb +253 -0
  54. data/metasm/cpu/cy16/main.rb +63 -0
  55. data/metasm/cpu/cy16/opcodes.rb +78 -0
  56. data/metasm/cpu/cy16/render.rb +41 -0
  57. data/metasm/cpu/dalvik.rb +11 -0
  58. data/{lib/metasm → metasm/cpu}/dalvik/decode.rb +35 -13
  59. data/{lib/metasm → metasm/cpu}/dalvik/main.rb +51 -2
  60. data/{lib/metasm → metasm/cpu}/dalvik/opcodes.rb +19 -11
  61. data/metasm/cpu/ia32.rb +17 -0
  62. data/{lib/metasm → metasm/cpu}/ia32/compile_c.rb +5 -7
  63. data/{lib/metasm → metasm/cpu}/ia32/debug.rb +5 -5
  64. data/{lib/metasm → metasm/cpu}/ia32/decode.rb +246 -59
  65. data/{lib/metasm → metasm/cpu}/ia32/decompile.rb +7 -7
  66. data/{lib/metasm → metasm/cpu}/ia32/encode.rb +19 -13
  67. data/{lib/metasm → metasm/cpu}/ia32/main.rb +51 -8
  68. data/metasm/cpu/ia32/opcodes.rb +1424 -0
  69. data/{lib/metasm → metasm/cpu}/ia32/parse.rb +47 -16
  70. data/{lib/metasm → metasm/cpu}/ia32/render.rb +31 -4
  71. data/metasm/cpu/mips.rb +14 -0
  72. data/{lib/metasm → metasm/cpu}/mips/compile_c.rb +1 -1
  73. data/metasm/cpu/mips/debug.rb +42 -0
  74. data/{lib/metasm → metasm/cpu}/mips/decode.rb +46 -16
  75. data/{lib/metasm → metasm/cpu}/mips/encode.rb +4 -3
  76. data/{lib/metasm → metasm/cpu}/mips/main.rb +11 -4
  77. data/{lib/metasm → metasm/cpu}/mips/opcodes.rb +86 -17
  78. data/{lib/metasm → metasm/cpu}/mips/parse.rb +1 -1
  79. data/{lib/metasm → metasm/cpu}/mips/render.rb +1 -1
  80. data/{lib/metasm/dalvik.rb → metasm/cpu/msp430.rb} +1 -1
  81. data/metasm/cpu/msp430/decode.rb +247 -0
  82. data/metasm/cpu/msp430/main.rb +62 -0
  83. data/metasm/cpu/msp430/opcodes.rb +101 -0
  84. data/{lib/metasm → metasm/cpu}/pic16c/decode.rb +6 -7
  85. data/{lib/metasm → metasm/cpu}/pic16c/main.rb +0 -0
  86. data/{lib/metasm → metasm/cpu}/pic16c/opcodes.rb +1 -1
  87. data/{lib/metasm/mips.rb → metasm/cpu/ppc.rb} +4 -4
  88. data/{lib/metasm → metasm/cpu}/ppc/decode.rb +18 -12
  89. data/{lib/metasm → metasm/cpu}/ppc/decompile.rb +3 -3
  90. data/{lib/metasm → metasm/cpu}/ppc/encode.rb +2 -2
  91. data/{lib/metasm → metasm/cpu}/ppc/main.rb +17 -12
  92. data/{lib/metasm → metasm/cpu}/ppc/opcodes.rb +11 -5
  93. data/metasm/cpu/ppc/parse.rb +55 -0
  94. data/metasm/cpu/python.rb +8 -0
  95. data/metasm/cpu/python/decode.rb +136 -0
  96. data/metasm/cpu/python/main.rb +36 -0
  97. data/metasm/cpu/python/opcodes.rb +180 -0
  98. data/{lib/metasm → metasm/cpu}/sh4.rb +1 -1
  99. data/{lib/metasm → metasm/cpu}/sh4/decode.rb +48 -17
  100. data/{lib/metasm → metasm/cpu}/sh4/main.rb +13 -4
  101. data/{lib/metasm → metasm/cpu}/sh4/opcodes.rb +7 -8
  102. data/metasm/cpu/x86_64.rb +15 -0
  103. data/{lib/metasm → metasm/cpu}/x86_64/compile_c.rb +28 -17
  104. data/{lib/metasm → metasm/cpu}/x86_64/debug.rb +4 -4
  105. data/{lib/metasm → metasm/cpu}/x86_64/decode.rb +57 -15
  106. data/{lib/metasm → metasm/cpu}/x86_64/encode.rb +55 -26
  107. data/{lib/metasm → metasm/cpu}/x86_64/main.rb +14 -6
  108. data/metasm/cpu/x86_64/opcodes.rb +136 -0
  109. data/{lib/metasm → metasm/cpu}/x86_64/parse.rb +10 -2
  110. data/metasm/cpu/x86_64/render.rb +35 -0
  111. data/metasm/cpu/z80.rb +9 -0
  112. data/metasm/cpu/z80/decode.rb +313 -0
  113. data/metasm/cpu/z80/main.rb +67 -0
  114. data/metasm/cpu/z80/opcodes.rb +224 -0
  115. data/metasm/cpu/z80/render.rb +59 -0
  116. data/{lib/metasm/os/main.rb → metasm/debug.rb} +160 -401
  117. data/{lib/metasm → metasm}/decode.rb +35 -4
  118. data/{lib/metasm → metasm}/decompile.rb +15 -16
  119. data/{lib/metasm → metasm}/disassemble.rb +201 -45
  120. data/{lib/metasm → metasm}/disassemble_api.rb +651 -87
  121. data/{lib/metasm → metasm}/dynldr.rb +220 -133
  122. data/{lib/metasm → metasm}/encode.rb +10 -1
  123. data/{lib/metasm → metasm}/exe_format/a_out.rb +9 -6
  124. data/{lib/metasm → metasm}/exe_format/autoexe.rb +1 -0
  125. data/{lib/metasm → metasm}/exe_format/bflt.rb +57 -27
  126. data/{lib/metasm → metasm}/exe_format/coff.rb +11 -3
  127. data/{lib/metasm → metasm}/exe_format/coff_decode.rb +53 -20
  128. data/{lib/metasm → metasm}/exe_format/coff_encode.rb +11 -13
  129. data/{lib/metasm → metasm}/exe_format/dex.rb +13 -5
  130. data/{lib/metasm → metasm}/exe_format/dol.rb +1 -0
  131. data/{lib/metasm → metasm}/exe_format/elf.rb +93 -57
  132. data/{lib/metasm → metasm}/exe_format/elf_decode.rb +143 -34
  133. data/{lib/metasm → metasm}/exe_format/elf_encode.rb +122 -31
  134. data/metasm/exe_format/gb.rb +65 -0
  135. data/metasm/exe_format/javaclass.rb +424 -0
  136. data/{lib/metasm → metasm}/exe_format/macho.rb +204 -16
  137. data/{lib/metasm → metasm}/exe_format/main.rb +26 -3
  138. data/{lib/metasm → metasm}/exe_format/mz.rb +1 -0
  139. data/{lib/metasm → metasm}/exe_format/nds.rb +7 -4
  140. data/{lib/metasm → metasm}/exe_format/pe.rb +71 -8
  141. data/metasm/exe_format/pyc.rb +167 -0
  142. data/{lib/metasm → metasm}/exe_format/serialstruct.rb +67 -14
  143. data/{lib/metasm → metasm}/exe_format/shellcode.rb +7 -3
  144. data/metasm/exe_format/shellcode_rwx.rb +114 -0
  145. data/metasm/exe_format/swf.rb +205 -0
  146. data/{lib/metasm → metasm}/exe_format/xcoff.rb +7 -7
  147. data/metasm/exe_format/zip.rb +335 -0
  148. data/metasm/gui.rb +13 -0
  149. data/{lib/metasm → metasm}/gui/cstruct.rb +35 -41
  150. data/{lib/metasm → metasm}/gui/dasm_coverage.rb +11 -11
  151. data/{lib/metasm → metasm}/gui/dasm_decomp.rb +7 -20
  152. data/{lib/metasm → metasm}/gui/dasm_funcgraph.rb +0 -0
  153. data/metasm/gui/dasm_graph.rb +1695 -0
  154. data/{lib/metasm → metasm}/gui/dasm_hex.rb +12 -8
  155. data/{lib/metasm → metasm}/gui/dasm_listing.rb +43 -28
  156. data/{lib/metasm → metasm}/gui/dasm_main.rb +310 -53
  157. data/{lib/metasm → metasm}/gui/dasm_opcodes.rb +5 -19
  158. data/{lib/metasm → metasm}/gui/debug.rb +93 -27
  159. data/{lib/metasm → metasm}/gui/gtk.rb +162 -40
  160. data/{lib/metasm → metasm}/gui/qt.rb +12 -2
  161. data/{lib/metasm → metasm}/gui/win32.rb +179 -42
  162. data/{lib/metasm → metasm}/gui/x11.rb +59 -59
  163. data/{lib/metasm → metasm}/main.rb +389 -264
  164. data/{lib/metasm/os/remote.rb → metasm/os/gdbremote.rb} +146 -54
  165. data/{lib/metasm → metasm}/os/gnu_exports.rb +1 -1
  166. data/{lib/metasm → metasm}/os/linux.rb +628 -151
  167. data/metasm/os/main.rb +330 -0
  168. data/{lib/metasm → metasm}/os/windows.rb +132 -42
  169. data/{lib/metasm → metasm}/os/windows_exports.rb +141 -0
  170. data/{lib/metasm → metasm}/parse.rb +26 -24
  171. data/{lib/metasm → metasm}/parse_c.rb +221 -116
  172. data/{lib/metasm → metasm}/preprocessor.rb +55 -40
  173. data/{lib/metasm → metasm}/render.rb +14 -38
  174. data/misc/hexdump.rb +2 -1
  175. data/misc/lint.rb +58 -0
  176. data/misc/txt2html.rb +9 -7
  177. data/samples/bindiff.rb +3 -4
  178. data/samples/dasm-plugins/bindiff.rb +15 -0
  179. data/samples/dasm-plugins/bookmark.rb +133 -0
  180. data/samples/dasm-plugins/c_constants.rb +57 -0
  181. data/samples/dasm-plugins/colortheme_solarized.rb +125 -0
  182. data/samples/dasm-plugins/cppobj_funcall.rb +60 -0
  183. data/samples/dasm-plugins/dasm_all.rb +70 -0
  184. data/samples/dasm-plugins/demangle_cpp.rb +31 -0
  185. data/samples/dasm-plugins/deobfuscate.rb +251 -0
  186. data/samples/dasm-plugins/dump_text.rb +35 -0
  187. data/samples/dasm-plugins/export_graph_svg.rb +86 -0
  188. data/samples/dasm-plugins/findgadget.rb +75 -0
  189. data/samples/dasm-plugins/hl_opcode.rb +32 -0
  190. data/samples/dasm-plugins/hotfix_gtk_dbg.rb +19 -0
  191. data/samples/dasm-plugins/imm2off.rb +34 -0
  192. data/samples/dasm-plugins/match_libsigs.rb +93 -0
  193. data/samples/dasm-plugins/patch_file.rb +95 -0
  194. data/samples/dasm-plugins/scanfuncstart.rb +36 -0
  195. data/samples/dasm-plugins/scanxrefs.rb +26 -0
  196. data/samples/dasm-plugins/selfmodify.rb +197 -0
  197. data/samples/dasm-plugins/stringsxrefs.rb +28 -0
  198. data/samples/dasmnavig.rb +1 -1
  199. data/samples/dbg-apihook.rb +24 -9
  200. data/samples/dbg-plugins/heapscan.rb +283 -0
  201. data/samples/dbg-plugins/heapscan/compiled_heapscan_lin.c +155 -0
  202. data/samples/dbg-plugins/heapscan/compiled_heapscan_win.c +128 -0
  203. data/samples/dbg-plugins/heapscan/graphheap.rb +616 -0
  204. data/samples/dbg-plugins/heapscan/heapscan.rb +709 -0
  205. data/samples/dbg-plugins/heapscan/winheap.h +174 -0
  206. data/samples/dbg-plugins/heapscan/winheap7.h +307 -0
  207. data/samples/dbg-plugins/trace_func.rb +214 -0
  208. data/samples/disassemble-gui.rb +35 -5
  209. data/samples/disassemble.rb +31 -6
  210. data/samples/dump_upx.rb +24 -12
  211. data/samples/dynamic_ruby.rb +12 -3
  212. data/samples/exeencode.rb +6 -5
  213. data/samples/factorize-headers-peimports.rb +1 -1
  214. data/samples/lindebug.rb +175 -381
  215. data/samples/metasm-shell.rb +1 -2
  216. data/samples/peldr.rb +2 -2
  217. data/tests/all.rb +1 -1
  218. data/tests/arc.rb +26 -0
  219. data/tests/dynldr.rb +22 -4
  220. data/tests/expression.rb +55 -0
  221. data/tests/graph_layout.rb +285 -0
  222. data/tests/ia32.rb +79 -26
  223. data/tests/mips.rb +9 -2
  224. data/tests/x86_64.rb +66 -18
  225. metadata +330 -218
  226. data/lib/metasm/arm/opcodes.rb +0 -177
  227. data/lib/metasm/gui.rb +0 -23
  228. data/lib/metasm/gui/dasm_graph.rb +0 -1354
  229. data/lib/metasm/ia32.rb +0 -14
  230. data/lib/metasm/ia32/opcodes.rb +0 -873
  231. data/lib/metasm/ppc/parse.rb +0 -52
  232. data/lib/metasm/x86_64.rb +0 -12
  233. data/lib/metasm/x86_64/opcodes.rb +0 -118
  234. data/samples/gdbclient.rb +0 -583
  235. data/samples/rubstop.rb +0 -399
@@ -84,7 +84,7 @@ class Preprocessor
84
84
  # modifies the list, returns an array of list of tokens/nil
85
85
  # handles nesting
86
86
  def self.parse_arglist(lexer, list=nil)
87
- readtok = lambda { list ? list.shift : lexer.readtok(false) }
87
+ readtok = lambda { list ? list.shift : lexer.readtok_nopp }
88
88
  unreadtok = lambda { |t| list ? (list.unshift(t) if t) : lexer.unreadtok(t) }
89
89
  tok = nil
90
90
  unreadlist = []
@@ -378,6 +378,7 @@ class Preprocessor
378
378
  # hash filename => file content
379
379
  attr_accessor :hooked_include
380
380
  attr_accessor :warn_redefinition
381
+ attr_accessor :may_preprocess
381
382
 
382
383
  # global default search directory for #included <files>
383
384
  @@include_search_path = ['/usr/include']
@@ -385,18 +386,14 @@ class Preprocessor
385
386
  def self.include_search_path=(np) @@include_search_path=np end
386
387
 
387
388
  def initialize(text='')
388
- @queue = []
389
389
  @backtrace = []
390
390
  @definition = %w[__FILE__ __LINE__ __COUNTER__ __DATE__ __TIME__].inject({}) { |h, n| h.update n => SpecialMacro.new(n) }
391
391
  @include_search_path = @@include_search_path.dup
392
392
  # stack of :accept/:discard/:discard_all/:testing, represents the current nesting of #if..#endif
393
393
  @ifelse_nesting = []
394
- @text = text
395
- @pos = 0
396
- @filename = 'unknown'
397
- @lineno = 1
398
394
  @warn_redefinition = true
399
395
  @hooked_include = {}
396
+ @may_preprocess = false
400
397
  @pragma_once = {}
401
398
  @pragma_callback = lambda { |otok|
402
399
  tok = otok
@@ -405,6 +402,7 @@ class Preprocessor
405
402
  unreadtok tok
406
403
  puts otok.exception("unhandled pragma #{str.inspect}").message if $VERBOSE
407
404
  }
405
+ feed!(text)
408
406
  define '__METASM__', VERSION
409
407
  end
410
408
 
@@ -493,11 +491,16 @@ class Preprocessor
493
491
  def feed!(text, filename='unknown', lineno=1)
494
492
  raise ArgumentError, 'need something to parse!' if not text
495
493
  @text = text
494
+ if not @may_preprocess and (@text =~ /^\s*(#|\?\?=)/ or (not @definition.empty? and
495
+ @text =~ /#{@definition.keys.map { |k| Regexp.escape(k) }.join('|')}/))
496
+ @may_preprocess = true
497
+ end
496
498
  # @filename[-1] used in trace_macros to distinguish generic/specific files
497
499
  @filename = "\"#{filename}\""
498
500
  @lineno = lineno
499
501
  @pos = 0
500
502
  @queue = []
503
+ @backtrace = []
501
504
  self
502
505
  end
503
506
 
@@ -512,7 +515,7 @@ class Preprocessor
512
515
 
513
516
  # reads one character from self.text
514
517
  # updates self.lineno
515
- # handles trigraphs and \-continued lines
518
+ # handles \-continued lines
516
519
  def getchar
517
520
  @ungetcharpos = @pos
518
521
  @ungetcharlineno = @lineno
@@ -520,11 +523,11 @@ class Preprocessor
520
523
  @pos += 1
521
524
 
522
525
  # check trigraph
523
- if c == ?? and @text[@pos] == ?? and Trigraph[@text[@pos+1]]
524
- puts "can i has trigraf plox ??#{c.chr} (#@filename:#@lineno)" if $VERBOSE
525
- c = Trigraph[@text[@pos+1]]
526
- @pos += 2
527
- end
526
+ #if c == ?? and @text[@pos] == ?? and Trigraph[@text[@pos+1]]
527
+ # puts "can i has trigraf plox ??#{c.chr} (#@filename:#@lineno)" if $VERBOSE
528
+ # c = Trigraph[@text[@pos+1]]
529
+ # @pos += 2
530
+ #end
528
531
 
529
532
  # check line continuation
530
533
  # TODO portability
@@ -567,9 +570,9 @@ class Preprocessor
567
570
  end
568
571
 
569
572
  # calls readtok_nopp and handles preprocessor directives
570
- def readtok(expand_macros = true)
571
- lastpos = @pos
573
+ def readtok
572
574
  tok = readtok_nopp
575
+ return tok if not @may_preprocess # shortcut
573
576
 
574
577
  if not tok
575
578
  # end of file: resume parent
@@ -579,32 +582,41 @@ class Preprocessor
579
582
  tok = readtok
580
583
  end
581
584
 
582
- elsif (tok.type == :eol or lastpos == 0) and @ifelse_nesting.last != :testing
583
- unreadtok tok if lastpos == 0
584
- # detect preprocessor directive
585
- # state = 1 => seen :eol, 2 => seen #
585
+ elsif tok.type == :punct and tok.raw == '#' and not tok.expanded_from and @ifelse_nesting.last != :testing
586
+ # backward check for :eol (skip the '#' itself)
587
+ pos = @pos-2
588
+ while pos >= 0 # if reach start of file, proceed
589
+ case @text[pos, 1]
590
+ when "\n"
591
+ pos -= 1 if pos > 0 and @text[pos-1] == ?\r
592
+ return tok if pos > 0 and @text[pos-1] == ?\\ # check if the newline was a line-continuation
593
+ return tok if pos > 2 and @text[pos-3, 3] == '??/' # trigraph
594
+ break # proceed
595
+ when /\s/ # beware switch order, this matches "\n" too
596
+ else return tok # false alarm
597
+ end
598
+ pos -= 1
599
+ end
586
600
  pretok = []
587
601
  rewind = true
588
- state = 1
589
- loop do
590
- pretok << (ntok = readtok_nopp)
591
- break if not ntok
602
+ while ntok = readtok_nopp
603
+ pretok << ntok
592
604
  if ntok.type == :space # nothing
593
- elsif state == 1 and ntok.type == :punct and ntok.raw == '#' and not ntok.expanded_from
594
- state = 2
595
- elsif state == 2 and ntok.type == :string and not ntok.expanded_from
605
+ next
606
+ elsif ntok.type == :string and not ntok.expanded_from
596
607
  rewind = false if preprocessor_directive(ntok)
597
- break
598
- else break
599
608
  end
609
+ break
600
610
  end
601
611
  if rewind
602
612
  # false alarm: revert
603
613
  pretok.reverse_each { |t| unreadtok t }
614
+ else
615
+ # XXX return :eol ?
616
+ tok = readtok
604
617
  end
605
- tok = readtok if lastpos == 0 # else return the :eol
606
618
 
607
- elsif expand_macros and tok.type == :string and m = @definition[tok.raw] and not tok.expanded_from.to_a.find { |ef| ef.raw == m.name.raw } and
619
+ elsif tok.type == :string and m = @definition[tok.raw] and not tok.expanded_from.to_a.find { |ef| ef.raw == m.name.raw } and
608
620
  ((m.args and margs = Macro.parse_arglist(self)) or not m.args)
609
621
 
610
622
  if defined? @traced_macros and tok.backtrace[-2].to_s[0] == ?" and m.name and m.name.backtrace[-2].to_s[0] == ?<
@@ -637,21 +649,20 @@ class Preprocessor
637
649
  when ?a..?z, ?A..?Z, ?0..?9, ?$, ?_
638
650
  tok.type = :string
639
651
  raw = tok.raw << c
640
- loop do
641
- case c = getchar
642
- when nil; ungetchar; break # avoids 'no method "coerce" for nil' warning
652
+ while c = getchar
653
+ case c
643
654
  when ?a..?z, ?A..?Z, ?0..?9, ?$, ?_
644
- raw << c
645
- else ungetchar; break
655
+ else break
646
656
  end
657
+ raw << c
647
658
  end
659
+ ungetchar
648
660
 
649
661
  when ?\ , ?\t, ?\r, ?\n, ?\f
650
662
  tok.type = ((c == ?\ || c == ?\t) ? :space : :eol)
651
663
  raw = tok.raw << c
652
- loop do
653
- case c = getchar
654
- when nil; break
664
+ while c = getchar
665
+ case c
655
666
  when ?\ , ?\t
656
667
  when ?\n, ?\f, ?\r; tok.type = :eol
657
668
  else break
@@ -676,8 +687,7 @@ class Preprocessor
676
687
  tok.type = :space
677
688
  raw << c
678
689
  seenstar = false
679
- loop do
680
- raise tok, 'unterminated c++ comment' if not c = getchar
690
+ while c = getchar
681
691
  raw << c
682
692
  case c
683
693
  when ?*; seenstar = true
@@ -685,6 +695,7 @@ class Preprocessor
685
695
  else seenstar = false
686
696
  end
687
697
  end
698
+ raise tok, 'unterminated c++ comment' if not c
688
699
  else
689
700
  # just a slash
690
701
  ungetchar
@@ -705,6 +716,7 @@ class Preprocessor
705
716
  tok.type = :quoted
706
717
  tok.raw << delimiter
707
718
  tok.value = ''
719
+ tok.value.force_encoding('binary') if tok.value.respond_to?(:force_encoding)
708
720
  c = nil
709
721
  loop do
710
722
  raise tok, 'unterminated string' if not c = getchar
@@ -767,6 +779,9 @@ class Preprocessor
767
779
  def define(name, value=nil, from=caller.first)
768
780
  from =~ /^(.*?):(\d+)/
769
781
  btfile, btlineno = $1, $2.to_i
782
+ if not @may_preprocess and @text =~ /#{Regexp.escape name}/
783
+ @may_preprocess = true
784
+ end
770
785
  t = Token.new([btfile, btlineno])
771
786
  t.type = :string
772
787
  t.raw = name.dup
@@ -1095,7 +1110,7 @@ class Preprocessor
1095
1110
  nil while dir = readtok and dir.type == :space
1096
1111
  raise cmd, 'qstring expected' if not dir or dir.type != :quoted
1097
1112
  dir = ::File.expand_path dir.value
1098
- raise cmd, 'invalid path' if not ::File.directory? dir
1113
+ raise cmd, "invalid path #{dir.inspect}" if not ::File.directory? dir
1099
1114
  @include_search_path.unshift dir
1100
1115
 
1101
1116
  when 'push_macro', 'pop_macro'
@@ -19,8 +19,10 @@ module Renderable
19
19
  r = proc { |e|
20
20
  case e
21
21
  when Expression
22
- yield e
23
22
  r[e.lexpr] ; r[e.rexpr]
23
+ yield e
24
+ when ExpressionType
25
+ yield e
24
26
  when Renderable
25
27
  e.render.each { |re| r[re] }
26
28
  end
@@ -64,45 +66,13 @@ end
64
66
 
65
67
  class Expression
66
68
  include Renderable
67
- attr_accessor :render_info
68
-
69
- # this is an accessor to @@render_int, the lambda used to render integers > 10
70
- # usage: Expression.render_int = lambda { |e| '0x%x' % e }
71
- # or Expression.render_int { |e| '0x%x' % e }
72
- # XXX the returned string should be suitable for inclusion in a label name etc
73
- def self.render_int(&b)
74
- if b
75
- @@render_int = b
76
- else
77
- @@render_int
78
- end
79
- end
80
- def self.render_int=(p)
81
- @@render_int = p
82
- end
83
- @@render_int = nil
84
69
 
85
70
  def render_integer(e)
86
- if render_info and @render_info[:char]
87
- ee = e
88
- v = []
89
- while ee > 0
90
- v << (ee & 0xff)
91
- ee >>= 8
92
- end
93
- v.reverse! if @render_info[:char] == :big
94
- if not v.empty? and v.all? { |c| c < 0x7f }
95
- # XXX endianness
96
- return "'" + v.pack('C*').inspect.gsub("'") { '\\\'' }[1...-1] + "'"
97
- end
98
- end
99
71
  if e < 0
100
72
  neg = true
101
73
  e = -e
102
74
  end
103
75
  if e < 10; e = e.to_s
104
- elsif @@render_int
105
- e = @@render_int[e]
106
76
  else
107
77
  e = '%xh' % e
108
78
  e = '0' << e unless (?0..?9).include? e[0]
@@ -114,17 +84,23 @@ class Expression
114
84
  NOSQ1 = NOSQ2 = {:* => [:*], :+ => [:+, :-, :*], :- => [:+, :-, :*]}
115
85
  NOSQ2[:-] = [:*]
116
86
  def render
117
- l = @lexpr.kind_of?(Integer) ? render_integer(@lexpr) : @lexpr
118
- r = @rexpr.kind_of?(Integer) ? render_integer(@rexpr) : @rexpr
119
- l = ['(', l, ')'] if @lexpr.kind_of? Expression and (not oa = NOSQ1[@op] or not oa.include?(@lexpr.op))
120
- r = ['(', r, ')'] if @rexpr.kind_of? Expression and (not oa = NOSQ2[@op] or not oa.include?(@rexpr.op))
87
+ l = @lexpr.kind_of?(::Integer) ? render_integer(@lexpr) : @lexpr
88
+ r = @rexpr.kind_of?(::Integer) ? render_integer(@rexpr) : @rexpr
89
+ l = ['(', l, ')'] if @lexpr.kind_of?(Expression) and (not oa = NOSQ1[@op] or not oa.include?(@lexpr.op))
90
+ r = ['(', r, ')'] if @rexpr.kind_of?(Expression) and (not oa = NOSQ2[@op] or not oa.include?(@rexpr.op))
121
91
  op = @op if l or @op != :+
122
92
  if op == :+
123
93
  r0 = [r].flatten.first
124
94
  r0 = r0.render.flatten.first while r0.kind_of? Renderable
125
- op = nil if (r0.kind_of? Integer and r0 < 0) or (r0.kind_of? String and r0[0] == ?-) or r0 == :-
95
+ op = nil if (r0.kind_of?(::Integer) and r0 < 0) or (r0.kind_of?(::String) and r0[0] == ?-) or r0 == :-
126
96
  end
127
97
  [l, op, r].compact
128
98
  end
129
99
  end
100
+
101
+ class ExpressionString
102
+ include Renderable
103
+
104
+ def render; hide_str ? @expr.render : render_str ; end
105
+ end
130
106
  end
@@ -51,5 +51,6 @@ if $0 == __FILE__
51
51
  fmt << 'd' if ARGV.delete '-D'
52
52
  fmt << 'a' if ARGV.delete '-A'
53
53
  fmt = ['c', 'd', 'a'] if ARGV.delete '-a'
54
- File.open(ARGV.first, 'rb').hexdump(:fmt => fmt)
54
+ infd = ARGV.empty? ? $stdin : File.open(ARGV.first, 'rb')
55
+ infd.hexdump(:fmt => fmt)
55
56
  end
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/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 is a ruby code cleaner tool
9
+ # it passes its argument to ruby -v -c, which displays warnings (eg unused variable)
10
+ # it shows the incriminated line along the warning, to help identify false positives
11
+ # probably linux-only, and need ruby-1.9.1 or newer
12
+
13
+ def lint(tg)
14
+ if File.symlink?(tg)
15
+ # nothing
16
+ elsif File.directory?(tg)
17
+ Dir.entries(tg).each { |ent|
18
+ next if ent == '.' or ent == '..'
19
+ ent = File.join(tg, ent)
20
+ lint(ent) if File.directory?(ent) or ent =~ /\.rb$/
21
+ }
22
+ else
23
+ lint_file(tg)
24
+ end
25
+ end
26
+
27
+ def lint_file(tg)
28
+ flines = nil
29
+ compile_warn(tg).each_line { |line|
30
+ file, lineno, warn = line.split(/\s*:\s*/, 3)
31
+ if file == tg
32
+ if not flines
33
+ puts "#{tg}:"
34
+ flines = File.readlines(file) #File.open(file, 'rb') { |fd| fd.readlines }
35
+ end
36
+ puts " l.#{lineno}: #{warn.strip}: #{flines[lineno.to_i-1].strip.inspect}"
37
+ end
38
+ }
39
+ puts if flines
40
+ end
41
+
42
+ def compile_warn(tg)
43
+ r, w = IO.pipe('binary')
44
+ if !fork
45
+ r.close
46
+ $stderr.reopen w
47
+ $stdout.reopen '/dev/null'
48
+ exec 'ruby', '-v', '-c', tg
49
+ exit!
50
+ else
51
+ w.close
52
+ end
53
+ r
54
+ end
55
+
56
+ ARGV << '.' if ARGV.empty?
57
+ ARGV.each { |arg| lint arg }
58
+
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ # encoding: binary (rage)
2
3
  # This file is part of Metasm, the Ruby assembly manipulation suite
3
4
  # Copyright (C) 2006-2009 Yoann GUILLOT
4
5
  #
@@ -48,7 +49,7 @@ class Elem
48
49
  if e.class.ancestors.include? Elem
49
50
  @content << e
50
51
  else
51
- @content << e.to_s.gsub(Regexp.new("(#{@@quotechars.keys.join('|')})")) { |x| @@quotechars[x] }
52
+ @content << e.to_s.gsub(Regexp.new("(#{@@quotechars.keys.join('|')})", 'm')) { |x| @@quotechars[x] }
52
53
  end
53
54
  }
54
55
  self
@@ -273,7 +274,7 @@ class Txt2Html
273
274
  puts "compiling #{outf}..." if $VERBOSE
274
275
 
275
276
  @pathfix = outf.split('/')[0...-1].map { '../' }.join
276
- out = compile(File.read(f).gsub("\r", '') + "\n\n")
277
+ out = compile(File.open(f, 'rb') { |fd| fd.read }.gsub("\r", '') + "\n\n")
277
278
  File.open(outf, 'wb') { |fd| fd.write out.to_s.gsub("\r", '').gsub("\n", "\r\n") }
278
279
  end
279
280
 
@@ -368,13 +369,13 @@ class Txt2Html
368
369
  out
369
370
  end
370
371
 
371
- # handle **bold_words** *italic* `fixed` <links>
372
+ # handle **bold_words** *italic* `fixed` <links> **bold__word__with__underscore**
372
373
  def compile_string(str)
373
374
  o = [str]
374
375
  on = []
375
376
  o.each { |s|
376
377
  while s.kind_of? String and o1 = s.index('**') and o2 = s.index('**', o1+2) and not s[o1..o2].index(' ')
377
- on << s[0...o1] << Html::Elem.new('b').add(s[o1+2...o2].tr('_', ' '))
378
+ on << s[0...o1] << Html::Elem.new('b').add(s[o1+2...o2].tr('_', ' ').gsub(' ', '_'))
378
379
  s = s[o2+2..-1]
379
380
  end
380
381
  on << s
@@ -383,7 +384,7 @@ class Txt2Html
383
384
  on = []
384
385
  o.each { |s|
385
386
  while s.kind_of? String and o1 = s.index('*') and o2 = s.index('*', o1+1) and not s[o1..o2].index(' ')
386
- on << s[0...o1] << Html::Elem.new('i').add(s[o1+1...o2].tr('_', ' '))
387
+ on << s[0...o1] << Html::Elem.new('i').add(s[o1+1...o2].tr('_', ' ').gsub(' ', '_'))
387
388
  s = s[o2+1..-1]
388
389
  end
389
390
  on << s
@@ -409,19 +410,20 @@ class Txt2Html
409
410
  when 'txt'
410
411
  tg = outfilename(lnk)
411
412
  Txt2Html.new(lnk)
412
- on << Html::A.new(@pathfix + tg, File.basename(lnk, '.txt').tr('_', ' '))
413
+ on << Html::A.new(@pathfix + tg, File.basename(lnk, '.txt').tr('_', ' ').gsub(' ', '_'))
413
414
  when 'jpg', 'png'
414
415
  on << Html::Img.new(lnk)
415
416
  end
416
417
  else
418
+ on << Html::A.new(lnk, lnk)
417
419
  if lnk =~ /\.txt$/
418
420
  @@seen_nofile ||= []
419
421
  if not @@seen_nofile.include? lnk
420
422
  @@seen_nofile << lnk
421
423
  puts "reference to missing #{lnk.inspect}"
422
424
  end
425
+ on.last.hclass('brokenlink')
423
426
  end
424
- on << Html::A.new(lnk, lnk)
425
427
  end
426
428
  end
427
429
  on << s
@@ -294,7 +294,6 @@ class BinDiffWidget < Gui::DrawableWidget
294
294
  set_status('match funcs') {
295
295
  # refine the layout matching with actual function matching
296
296
  already_matched = []
297
- match_score = {}
298
297
  layout_match.each { |f1, list|
299
298
  puts "matching #{Expression[f1]}" if $VERBOSE
300
299
  begin
@@ -429,8 +428,8 @@ end
429
428
  # show in window 1 the match of the function found in win 2
430
429
  def sync1
431
430
  c2 = curfunc2
432
- if a1 = match_funcs.find { |k, (a2, s)| a2 == c2 }
433
- @dasm1.gui.focus_addr(a1[0])
431
+ if a1 = match_funcs.find_key { |k| match_funcs[k][0] == c2 }
432
+ @dasm1.gui.focus_addr(a1)
434
433
  end
435
434
  end
436
435
 
@@ -491,7 +490,7 @@ $VERBOSE = true
491
490
  # parse arguments
492
491
  opts = {}
493
492
  OptionParser.new { |opt|
494
- opt.banner = 'Usage: bindiff.rb [options] <executable> [<entrypoints>]'
493
+ opt.banner = 'Usage: bindiff.rb [options] <exe1> <exe2> [<entrypoints>]'
495
494
  opt.on('-P <plugin>', '--plugin <plugin>', 'load a metasm disassembler plugin') { |h| (opts[:plugin] ||= []) << h }
496
495
  opt.on('-e <code>', '--eval <code>', 'eval a ruby code') { |h| (opts[:hookstr] ||= []) << h }
497
496
  opt.on('--map1 <mapfile>', 'load a map file (addr <-> name association)') { |f| opts[:map1] = f }