metasm 1.0.2 → 1.0.3

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