metasm 1.0.2 → 1.0.3

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 (58) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -0
  3. data/Gemfile +1 -0
  4. data/doc/code_organisation.txt +1 -1
  5. data/metasm.gemspec +1 -1
  6. data/metasm.rb +2 -1
  7. data/metasm/cpu/arc/decode.rb +3 -3
  8. data/metasm/cpu/arm/decode.rb +2 -2
  9. data/metasm/cpu/ia32/compile_c.rb +18 -2
  10. data/metasm/cpu/ia32/decode.rb +9 -4
  11. data/metasm/cpu/ia32/decompile.rb +22 -8
  12. data/metasm/cpu/ia32/opcodes.rb +5 -5
  13. data/metasm/cpu/mcs51.rb +8 -0
  14. data/metasm/cpu/mcs51/decode.rb +99 -0
  15. data/metasm/cpu/mcs51/main.rb +76 -0
  16. data/metasm/cpu/mcs51/opcodes.rb +120 -0
  17. data/metasm/cpu/mips/decode.rb +5 -4
  18. data/metasm/cpu/st20.rb +9 -0
  19. data/metasm/cpu/st20/decode.rb +180 -0
  20. data/metasm/cpu/st20/decompile.rb +283 -0
  21. data/metasm/cpu/st20/main.rb +37 -0
  22. data/metasm/cpu/st20/opcodes.rb +140 -0
  23. data/metasm/cpu/x86_64/encode.rb +4 -2
  24. data/metasm/cpu/x86_64/opcodes.rb +4 -2
  25. data/metasm/decode.rb +16 -15
  26. data/metasm/decompile.rb +1 -1
  27. data/metasm/disassemble.rb +3 -1
  28. data/metasm/disassemble_api.rb +3 -1
  29. data/metasm/dynldr.rb +9 -3
  30. data/metasm/encode.rb +2 -2
  31. data/metasm/exe_format/coff.rb +3 -1
  32. data/metasm/exe_format/coff_decode.rb +5 -3
  33. data/metasm/exe_format/elf.rb +4 -0
  34. data/metasm/exe_format/elf_decode.rb +1 -2
  35. data/metasm/exe_format/elf_encode.rb +4 -1
  36. data/metasm/exe_format/macho.rb +20 -6
  37. data/metasm/exe_format/pe.rb +1 -1
  38. data/metasm/exe_format/serialstruct.rb +1 -1
  39. data/metasm/gui.rb +1 -1
  40. data/metasm/gui/dasm_hex.rb +2 -2
  41. data/metasm/gui/dasm_main.rb +8 -8
  42. data/metasm/gui/debug.rb +4 -4
  43. data/metasm/gui/gtk.rb +1 -1
  44. data/metasm/gui/qt.rb +2 -2
  45. data/metasm/gui/win32.rb +1 -1
  46. data/metasm/main.rb +11 -6
  47. data/metasm/os/windows.rb +26 -23
  48. data/misc/hexdump.rb +2 -2
  49. data/misc/objdiff.rb +4 -1
  50. data/misc/objscan.rb +1 -1
  51. data/samples/dasm-plugins/bindiff.rb +1 -1
  52. data/samples/dasm-plugins/scanxrefs.rb +2 -1
  53. data/samples/dynamic_ruby.rb +24 -25
  54. data/samples/elfencode.rb +15 -0
  55. data/samples/exeencode.rb +2 -2
  56. data/samples/metasm-shell.rb +67 -55
  57. data/tests/mcs51.rb +27 -0
  58. metadata +13 -2
@@ -365,8 +365,7 @@ class ELF
365
365
  # marks a symbol as @encoded.export (from s.value, using segments or sections)
366
366
  def decode_symbol_export(s)
367
367
  if s.name and s.shndx != 'UNDEF' and %w[NOTYPE OBJECT FUNC].include?(s.type)
368
- if @header.type == 'REL'
369
- sec = @sections[s.shndx]
368
+ if @header.type == 'REL' and s.shndx.kind_of?(::Integer) and sec = @sections[s.shndx]
370
369
  o = sec.offset + s.value
371
370
  elsif not o = addr_to_off(s.value)
372
371
  # allow to point to end of segment
@@ -11,7 +11,7 @@ module Metasm
11
11
  class ELF
12
12
  class Header
13
13
  def set_default_values elf
14
- @magic ||= "\x7fELF"
14
+ @magic ||= ELF::MAGIC
15
15
  @e_class ||= elf.bitsize.to_s
16
16
  @data ||= (elf.endianness == :big ? 'MSB' : 'LSB')
17
17
  @version ||= 'CURRENT'
@@ -62,6 +62,7 @@ class ELF
62
62
  return if name_p and sne.data[@name_p, @name.length+1] == @name+0.chr
63
63
  return if @name_p = sne.data.index(@name+0.chr)
64
64
  @name_p = sne.virtsize
65
+ @name.force_encoding('BINARY') if name.respond_to?(:force_encoding)
65
66
  sne << @name << 0
66
67
  end
67
68
  end
@@ -92,6 +93,7 @@ class ELF
92
93
  return if name_p and s[@name_p, @name.length+1] == @name+0.chr
93
94
  return if @name_p = s.index(@name+0.chr)
94
95
  @name_p = strtab.length
96
+ @name.force_encoding('BINARY') if name.respond_to?(:force_encoding)
95
97
  strtab << @name << 0
96
98
  end
97
99
  end
@@ -519,6 +521,7 @@ class ELF
519
521
  add_str = lambda { |n|
520
522
  if n and n != '' and not ret = strtab.encoded.data.index(n + 0.chr)
521
523
  ret = strtab.encoded.virtsize
524
+ n.force_encoding('BINARY') if n.respond_to?(:force_encoding)
522
525
  strtab.encoded << n << 0
523
526
  end
524
527
  ret || 0
@@ -43,6 +43,8 @@ class MachO < ExeFormat
43
43
  9 => '8600', 10 => '8650', 11 => '8800', 12 => 'UVAXIII',
44
44
  },
45
45
  'ROMP' => { 0 => 'ALL', 1 => 'PC', 2 => 'APC', 3 => '135',
46
+ },
47
+ 'NS32032' => { # same for NS*
46
48
  0 => 'MMAX_ALL', 1 => 'MMAX_DPC', 2 => 'SQT',
47
49
  3 => 'MMAX_APC_FPU', 4 => 'MMAX_APC_FPA', 5 => 'MMAX_XPC',
48
50
  },
@@ -138,7 +140,11 @@ class MachO < ExeFormat
138
140
  SEC_TYPE = {
139
141
  0 => 'REGULAR', 1 => 'ZEROFILL', 2 => 'CSTRING_LITERALS', 3 => '4BYTE_LITERALS',
140
142
  4 => '8BYTE_LITERALS', 5 => 'LITERAL_POINTERS', 6 => 'NON_LAZY_SYMBOL_POINTERS',
141
- 7 => 'LAZY_SYMBOL_POINTERS', 8 => 'SYMBOL_STUBS', 9 => 'MOD_INIT_FUNC_POINTERS'
143
+ 7 => 'LAZY_SYMBOL_POINTERS', 8 => 'SYMBOL_STUBS', 9 => 'MOD_INIT_FUNC_POINTERS',
144
+ 10 => 'MOD_TERM_FUNC_POINTERS', 11 => 'COALESCED', 12 => 'GB_ZEROFILL', 13 => 'INTERPOSING',
145
+ 14 => '16BYTE_LITERALS', 15 => 'DTRACE_DOF', 16 => 'LAZY_DYLIB_SYMBOL_POINTERS',
146
+ 17 => 'THREAD_LOCAL_REGULAR', 18 => 'THREAD_LOCAL_ZEROFILL', 19 => 'THREAD_LOCAL_VARIABLES',
147
+ 20 => 'THREAD_LOCAL_VARIABLE_POINTERS', 21 => 'THREAD_LOCAL_INIT_FUNCTION_POINTERS'
142
148
  }
143
149
 
144
150
  class SerialStruct < Metasm::SerialStruct
@@ -628,22 +634,26 @@ class MachO < ExeFormat
628
634
  when 'NON_LAZY_SYMBOL_POINTERS', 'LAZY_SYMBOL_POINTERS'
629
635
  edata = seg.encoded
630
636
  off = sec.offset - seg.fileoff
631
- (sec.size / 4).times { |i|
637
+ (sec.size / sizeof_xword).times { |i|
632
638
  sidx = indsymtab[sec.res1+i]
639
+ if not sidx
640
+ puts "W: osx: invalid symbol pointer index #{i} ?" if $VERBOSE
641
+ next
642
+ end
633
643
  case IND_SYM_IDX[sidx]
634
644
  when 'INDIRECT_SYMBOL_LOCAL' # base reloc: add delta from prefered image base
635
645
  edata.ptr = off
636
- addr = decode_word(edata)
646
+ addr = decode_xword(edata)
637
647
  if s = segment_at(addr)
638
648
  label = label_at(s.encoded, s.encoded.ptr, "xref_#{Expression[addr]}")
639
- seg.encoded.reloc[off] = Metasm::Relocation.new(Expression[label], :u32, @endianness)
649
+ seg.encoded.reloc[off] = Metasm::Relocation.new(Expression[label], "u#@size".to_sym, @endianness)
640
650
  end
641
651
  when 'INDIRECT_SYMBOL_ABS' # nothing
642
652
  else
643
653
  sym = @symbols[sidx]
644
- seg.encoded.reloc[off] = Metasm::Relocation.new(Expression[sym.name], :u32, @endianness)
654
+ seg.encoded.reloc[off] = Metasm::Relocation.new(Expression[sym.name],"u#@size".to_sym, @endianness)
645
655
  end
646
- off += 4
656
+ off += sizeof_xword
647
657
  }
648
658
  when 'SYMBOL_STUBS'
649
659
  # TODO next unless arch == 386 and sec.attrs & SELF_MODIFYING_CODE and sec.res2 == 5
@@ -653,6 +663,10 @@ class MachO < ExeFormat
653
663
  off = sec.offset - seg.fileoff + 1
654
664
  (sec.size / 5).times { |i|
655
665
  sidx = indsymtab[sec.res1+i]
666
+ if not sidx
667
+ puts "W: osx: invalid symbol stub index #{i} ?" if $VERBOSE
668
+ next
669
+ end
656
670
  case IND_SYM_IDX[sidx]
657
671
  when 'INDIRECT_SYMBOL_LOCAL' # base reloc: add delta from prefered image base
658
672
  edata.ptr = off
@@ -330,7 +330,7 @@ EOS
330
330
  # compute Mandiant "importhash"
331
331
  def imphash
332
332
  lst = []
333
- @imports.each { |id|
333
+ @imports.to_a.each { |id|
334
334
  ln = id.libname.downcase.sub(/.(dll|sys|ocx)$/, '')
335
335
  id.imports.each { |i|
336
336
  if not i.name and ordtable = WindowsExports::IMPORT_HASH[ln]
@@ -56,7 +56,7 @@ class << self
56
56
 
57
57
  # a fixed-size memory chunk
58
58
  def mem(name, len, defval='')
59
- new_field(name, lambda { |exe, me| exe.curencoded.read(len) }, lambda { |exe, me, val| val[0, len].ljust(len, 0.chr) }, lambda { |exe, me| len }, defval)
59
+ new_field(name, lambda { |exe, me| exe.curencoded.read(len) }, lambda { |exe, me, val| d = val[0, len].ljust(len, 0.chr) ; d.force_encoding('BINARY') if d.respond_to?(:force_encoding) ; d }, lambda { |exe, me| len }, defval)
60
60
  end
61
61
  # a fixed-size string, 0-padded
62
62
  def str(name, len, defval='')
@@ -6,7 +6,7 @@ backend = ENV['METASM_GUI'] || (
6
6
  require 'gtk2'
7
7
  'gtk'
8
8
  rescue LoadError
9
- raise LoadError, 'No GUI ruby binding installed - please install libgtk2-ruby'
9
+ raise LoadError, 'No GUI ruby binding installed - please install ruby-gtk2'
10
10
  end
11
11
  end
12
12
  )
@@ -350,8 +350,8 @@ class HexWidget < DrawableWidget
350
350
  else
351
351
  case v = key
352
352
  when ?0..?9; v -= ?0
353
- when ?a..?f; v -= ?a-10
354
- when ?A..?F; v -= ?A-10
353
+ when ?a..?f; v -= ?a - 10
354
+ when ?A..?F; v -= ?A - 10
355
355
  else return false
356
356
  end
357
357
  end
@@ -946,11 +946,11 @@ class DasmWindow < Window
946
946
  exe
947
947
  end
948
948
 
949
- def promptopen(caption='chose target binary', &b)
949
+ def promptopen(caption='choose target binary', &b)
950
950
  openfile(caption) { |exename| loadfile(exename) ; b.call(self) if b }
951
951
  end
952
952
 
953
- def promptdebug(caption='chose target', &b)
953
+ def promptdebug(caption='choose target', &b)
954
954
  l = nil
955
955
  i = inputbox(caption) { |name|
956
956
  i = nil ; l.destroy if l and not l.destroyed?
@@ -996,7 +996,7 @@ class DasmWindow < Window
996
996
  @dasm_widget.dasm.save_file @savefile
997
997
  return
998
998
  end
999
- openfile('chose save file') { |file|
999
+ savefile('choose save file') { |file|
1000
1000
  @savefile = file
1001
1001
  @dasm_widget.dasm.save_file(file)
1002
1002
  }
@@ -1039,13 +1039,13 @@ class DasmWindow < Window
1039
1039
 
1040
1040
  importmenu = new_menu
1041
1041
  addsubmenu(importmenu, 'Load _map') {
1042
- openfile('chose map file') { |file|
1042
+ openfile('choose map file') { |file|
1043
1043
  @dasm_widget.dasm.load_map(File.read(file)) if @dasm_widget
1044
1044
  @dasm_widget.gui_update if @dasm_widget
1045
1045
  } if @dasm_widget
1046
1046
  }
1047
1047
  addsubmenu(importmenu, 'Load _C') {
1048
- openfile('chose C file') { |file|
1048
+ openfile('choose C file') { |file|
1049
1049
  @dasm_widget.dasm.parse_c(File.read(file)) if @dasm_widget
1050
1050
  } if @dasm_widget
1051
1051
  }
@@ -1053,21 +1053,21 @@ class DasmWindow < Window
1053
1053
 
1054
1054
  exportmenu = new_menu
1055
1055
  addsubmenu(exportmenu, 'Save _map') {
1056
- savefile('chose map file') { |file|
1056
+ savefile('choose map file') { |file|
1057
1057
  File.open(file, 'w') { |fd|
1058
1058
  fd.puts @dasm_widget.dasm.save_map
1059
1059
  } if @dasm_widget
1060
1060
  } if @dasm_widget
1061
1061
  }
1062
1062
  addsubmenu(exportmenu, 'Save _asm') {
1063
- savefile('chose asm file') { |file|
1063
+ savefile('choose asm file') { |file|
1064
1064
  File.open(file, 'w') { |fd|
1065
1065
  fd.puts @dasm_widget.dasm
1066
1066
  } if @dasm_widget
1067
1067
  } if @dasm_widget
1068
1068
  }
1069
1069
  addsubmenu(exportmenu, 'Save _C') {
1070
- savefile('chose C file') { |file|
1070
+ savefile('choose C file') { |file|
1071
1071
  File.open(file, 'w') { |fd|
1072
1072
  fd.puts @dasm_widget.dasm.c_parser
1073
1073
  } if @dasm_widget
@@ -154,7 +154,7 @@ class DbgWidget < ContainerVBoxWidget
154
154
  @children.each { |c| c.gui_update }
155
155
  end
156
156
 
157
- def prompt_attach(caption='chose target')
157
+ def prompt_attach(caption='choose target')
158
158
  l = nil
159
159
  i = inputbox(caption) { |name|
160
160
  i = nil ; l.destroy if l and not l.destroyed?
@@ -184,7 +184,7 @@ class DbgWidget < ContainerVBoxWidget
184
184
  } if not list_pr.empty?
185
185
  end
186
186
 
187
- def prompt_createprocess(caption='chose path')
187
+ def prompt_createprocess(caption='choose path')
188
188
  openfile(caption) { |path|
189
189
  path = '"' + path + '"' if @dbg.shortname == 'windbg' and path =~ /\s/
190
190
  inputbox('target args?', :text => path) { |pa|
@@ -410,8 +410,8 @@ class DbgRegWidget < DrawableWidget
410
410
  case v = key
411
411
  when ?\x20; v = nil
412
412
  when ?0..?9; v -= ?0
413
- when ?a..?f; v -= ?a-10
414
- when ?A..?F; v -= ?A-10
413
+ when ?a..?f; v -= ?a - 10
414
+ when ?A..?F; v -= ?A - 10
415
415
  else return false
416
416
  end
417
417
  end
@@ -45,7 +45,7 @@ module Msgbox
45
45
  InputBox.new(toplevel, *a) { |*ya| protect { yield(*ya) } }
46
46
  end
47
47
 
48
- # asks to chose a file to open, yields filename
48
+ # asks to choose a file to open, yields filename
49
49
  # args: title, :path => path
50
50
  def openfile(*a)
51
51
  OpenFile.new(toplevel, *a) { |*ya| protect { yield(*ya) } }
@@ -51,7 +51,7 @@ module Msgbox
51
51
 
52
52
  @@dialogfilefolder = nil
53
53
 
54
- # asks to chose a file to open, yields filename
54
+ # asks to choose a file to open, yields filename
55
55
  # args: title, :path => path
56
56
  def openfile(title, opts={})
57
57
  f = Qt::FileDialog.get_open_file_name(nil, title, @@dialogfilefolder)
@@ -180,7 +180,7 @@ Standby OpenUrl LaunchMail LaunchMedia Launch0 Launch1 Launch2 Launch3 Launch4 L
180
180
  LaunchC LaunchD LaunchE LaunchF MediaLast unknown Call Context1 Context2 Context3 Context4 Flip Hangup No Select Yes
181
181
  Execute Printer Play Sleep Zoom Cancel
182
182
  ].inject({}) { |h, cst|
183
- v = Qt.const_get("Key_#{cst}").to_i # AONETUHANOTEUHATNOHEU Qt::Enum != Fixnum
183
+ v = Qt.const_get("Key_#{cst}").to_i # AONETUHANOTEUHATNOHEU Qt::Enum != Integer
184
184
  key = cst.downcase.to_sym
185
185
  key = { :pageup => :pgup, :pagedown => :pgdown, :escape => :esc, :return => :enter }.fetch(key, key)
186
186
  h.update v => key
@@ -1401,7 +1401,7 @@ module Msgbox
1401
1401
  InputBox.new(toplevel, *a) { |*ya| protect { yield(*ya) } }
1402
1402
  end
1403
1403
 
1404
- # asks to chose a file to open, yields filename
1404
+ # asks to choose a file to open, yields filename
1405
1405
  # args: title, :path => path
1406
1406
  def openfile(*a)
1407
1407
  OpenFile.new(toplevel, *a) { |*ya| protect { yield(*ya) } }
@@ -307,7 +307,7 @@ class ExeFormat
307
307
  def new_label(base = '')
308
308
  base = base.dup.tr('^a-zA-Z0-9_', '_')
309
309
  # use %x instead of to_s(16) for negative values
310
- base = (base << '_uuid' << ('%08x' % base.object_id)).freeze if base.empty? or @unique_labels_cache[base]
310
+ base = (base << '_uuid' << ('%08x' % (base.object_id & 0xffff_ffff_ffff_ffff))).freeze if base.empty? or @unique_labels_cache[base]
311
311
  @unique_labels_cache[base] = true
312
312
  base
313
313
  end
@@ -892,7 +892,7 @@ class Expression < ExpressionType
892
892
  if targ and vars[targ]
893
893
  return false if exp != vars[targ]
894
894
  elsif targ and vars.has_key? targ
895
- return false if not vars[targ] = exp
895
+ vars[targ] = exp
896
896
  elsif targ.kind_of? ExpressionType
897
897
  return false if not exp.kind_of? ExpressionType or not exp.match_rec(targ, vars)
898
898
  else
@@ -1002,8 +1002,11 @@ class EncodedData
1002
1002
  attr_reader :ptr # custom writer
1003
1003
  def ptr=(p) @ptr = @export[p] || p end
1004
1004
 
1005
+ INITIAL_DATA = ''
1006
+ INITIAL_DATA.force_encoding('BINARY') if INITIAL_DATA.respond_to?(:force_encoding)
1007
+
1005
1008
  # opts' keys in :reloc, :export, :virtsize, defaults to empty/empty/data.length
1006
- def initialize(data='', opts={})
1009
+ def initialize(data=INITIAL_DATA.dup, opts={})
1007
1010
  if data.respond_to?(:force_encoding) and data.encoding.name != 'ASCII-8BIT' and data.length > 0
1008
1011
  puts "Forcing edata.data.encoding = BINARY at", caller if $DEBUG
1009
1012
  data = data.dup.force_encoding('binary')
@@ -1128,11 +1131,11 @@ class EncodedData
1128
1131
  ((val + len - 1) / len).to_i * len
1129
1132
  end
1130
1133
 
1131
- # concatenation of another +EncodedData+ (or nil/Fixnum/anything supporting String#<<)
1134
+ # concatenation of another +EncodedData+ (or nil/Integer/anything supporting String#<<)
1132
1135
  def <<(other)
1133
1136
  case other
1134
1137
  when nil
1135
- when ::Fixnum
1138
+ when ::Integer
1136
1139
  fill
1137
1140
  @data = @data.to_str if not @data.kind_of? String
1138
1141
  @data << other
@@ -1151,17 +1154,19 @@ class EncodedData
1151
1154
  other.inv_export.each { |k, v| @inv_export[@virtsize + k] = v }
1152
1155
  end
1153
1156
  if @data.empty?; @data = other.data.dup
1157
+ elsif other.empty?
1154
1158
  elsif not @data.kind_of?(String); @data = @data.to_str << other.data
1155
1159
  else @data << other.data
1156
1160
  end
1157
1161
  @virtsize += other.virtsize
1158
1162
  else
1159
1163
  fill
1160
- if other.respond_to?(:force_encoding) and other.encoding.name != 'ASCII-8BIT'
1164
+ if other.respond_to?(:force_encoding) and other.encoding.name != 'ASCII-8BIT' and other.length > 0
1161
1165
  puts "Forcing edata.data.encoding = BINARY at", caller if $DEBUG
1162
1166
  other = other.dup.force_encoding('binary')
1163
1167
  end
1164
1168
  if @data.empty?; @data = other.dup
1169
+ elsif other.empty?
1165
1170
  elsif not @data.kind_of?(String); @data = @data.to_str << other
1166
1171
  else @data << other
1167
1172
  end
@@ -1232,22 +1232,31 @@ class WinOS < OS
1232
1232
  end
1233
1233
  attr_writer :debugger
1234
1234
 
1235
- # returns the memory address size of the target process
1236
- def addrsz
1237
- @addrsz ||= if WinAPI.respond_to?(:iswow64process)
1235
+ # return 32 for 32bit process, 64 for 64bit process
1236
+ # populates iswow64
1237
+ def cpusz
1238
+ @cpusz ||= (
1238
1239
  byte = 0.chr*8
1239
- if WinAPI.iswow64process(handle, byte)
1240
+ if WinAPI.respond_to?(:iswow64process) and WinAPI.iswow64process(handle, byte)
1241
+ # os supports iswow64process, so target may be 64bits
1240
1242
  if byte != 0.chr*8
1241
- 32 # target = wow64
1242
- elsif WinAPI.iswow64process(WinAPI.getcurrentprocess, byte) and byte != 0.chr*8
1243
- 64 # us = wow64, target is not
1243
+ @iswow64 = true
1244
+ 32
1244
1245
  else
1246
+ @iswow64 = false
1245
1247
  WinAPI.host_cpu.size
1246
1248
  end
1247
1249
  else
1248
1250
  WinAPI.host_cpu.size
1249
1251
  end
1250
- end
1252
+ )
1253
+ end
1254
+ attr_accessor :iswow64
1255
+
1256
+ # returns the memory address size of the target process
1257
+ # if the target is a wow64 process (32bit process under a 64bit os), return 64
1258
+ def addrsz
1259
+ @addrsz ||= ((cpusz == 32 and iswow64) ? 64 : cpusz)
1251
1260
  end
1252
1261
 
1253
1262
  def modules
@@ -1363,7 +1372,7 @@ class WinOS < OS
1363
1372
 
1364
1373
  # increment the suspend count of the target thread - stop at >0
1365
1374
  def suspend
1366
- if WinAPI.host_cpu.size == 64 and process and process.addrsz == 32
1375
+ if WinAPI.host_cpu.size == 64 and process and process.iswow64
1367
1376
  WinAPI.wow64suspendthread(handle)
1368
1377
  else
1369
1378
  WinAPI.suspendthread(handle)
@@ -1400,26 +1409,20 @@ class WinOS < OS
1400
1409
  class Context
1401
1410
  def initialize(thread, kind=:all)
1402
1411
  @handle = thread.handle
1403
- tg = (thread.process ? thread.process.addrsz : 32)
1404
- hcpu = WinAPI.host_cpu.shortname
1405
- case hcpu
1406
- when 'ia32', 'x64'
1407
- else raise "unsupported architecture #{tg}"
1408
- end
1409
-
1412
+ tg = (thread.process ? thread.process.cpusz : 32)
1410
1413
  @getcontext = :getthreadcontext
1411
1414
  @setcontext = :setthreadcontext
1412
- case tg
1413
- when 32
1415
+ if tg == 32
1416
+ # XXX check CS under wow64 ?
1414
1417
  @context = WinAPI.alloc_c_struct('_CONTEXT_I386')
1415
- @context.contextflags = WinAPI::CONTEXT_I386_ALL
1416
- if hcpu == 'x64'
1418
+ @context.contextflags = WinAPI::CONTEXT_I386_ALL # XXX kind ?
1419
+ if WinAPI.host_cpu.shortname == 'x64' and thread.process and thread.process.iswow64
1417
1420
  @getcontext = :wow64getthreadcontext
1418
1421
  @setcontext = :wow64setthreadcontext
1419
1422
  end
1420
- when 64
1423
+ else
1421
1424
  @context = WinAPI.alloc_c_struct('_CONTEXT_AMD64')
1422
- @context.contextflags = WinAPI::CONTEXT_AMD64_ALL
1425
+ @context.contextflags = WinAPI::CONTEXT_AMD64_ALL # XXX kind ?
1423
1426
  end
1424
1427
  end
1425
1428
 
@@ -1805,7 +1808,7 @@ class WinDebugger < Debugger
1805
1808
  return if not @os_process
1806
1809
  case WinAPI.host_cpu.shortname
1807
1810
  when 'ia32', 'x64'
1808
- @cpu = Ia32.new(os_process.addrsz)
1811
+ @cpu = Ia32.new(os_process.cpusz)
1809
1812
  else
1810
1813
  raise 'unsupported architecture'
1811
1814
  end
@@ -29,7 +29,7 @@ def hexdump(ctx={})
29
29
  print s.unpack('C*').map { |b| '%02x' % b }.join(' ').ljust(3*16-1) + ' ' if fmt.include? 'c'
30
30
  print s.unpack('v*').map { |b| '%04x' % b }.join(' ').ljust(5*8-1) + ' ' if fmt.include? 'w'
31
31
  print s.unpack('L*').map { |b| '%08x' % b }.join(' ').ljust(9*4-1) + ' ' if fmt.include? 'd'
32
- print s.tr("\0-\x1f\x7f-\xff", '.') if fmt.include? 'a'
32
+ print s.tr("\0-\x1f\x7f-\xff".force_encoding('BINARY'), '.') if fmt.include? 'a'
33
33
  puts
34
34
  elsif not ctx[:lastdup]
35
35
  ctx[:lastdup] = true
@@ -50,7 +50,7 @@ if $0 == __FILE__
50
50
  fmt << 'w' if ARGV.delete '-W'
51
51
  fmt << 'd' if ARGV.delete '-D'
52
52
  fmt << 'a' if ARGV.delete '-A'
53
- fmt = ['c', 'd', 'a'] if ARGV.delete '-a'
53
+ fmt = ['c', 'd', 'a'] if ARGV.delete '-a' or fmt.empty?
54
54
  infd = ARGV.empty? ? $stdin : File.open(ARGV.first, 'rb')
55
55
  infd.hexdump(:fmt => fmt)
56
56
  end