Class: PEdump::Comparer

Inherits:
Object show all
Defined in:
lib/pedump/comparer.rb

Overview

comparing 2 binaries

Constant Summary collapse

METHODS =
[:sections, :data_dirs, :imports, :resources, :pe_hdr]

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(ldr1, ldr2) ⇒ Comparer

Returns a new instance of Comparer.



14
15
16
17
18
# File 'lib/pedump/comparer.rb', line 14

def initialize ldr1, ldr2
  @ldr1,@ldr2 = ldr1,ldr2
  @ignored_data_dirs = []
  @ignored_sections  = []
end

Instance Attribute Details

#ignored_data_dirsObject

Returns the value of attribute ignored_data_dirs.



10
11
12
# File 'lib/pedump/comparer.rb', line 10

def ignored_data_dirs
  @ignored_data_dirs
end

#ignored_sectionsObject

Returns the value of attribute ignored_sections.



10
11
12
# File 'lib/pedump/comparer.rb', line 10

def ignored_sections
  @ignored_sections
end

#verboseObject

Returns the value of attribute verbose.



9
10
11
# File 'lib/pedump/comparer.rb', line 9

def verbose
  @verbose
end

Class Method Details

._cmp(ldr1, ldr2) ⇒ Object

each arg is a PEdump::Loader



126
127
128
# File 'lib/pedump/comparer.rb', line 126

def _cmp ldr1, ldr2
  new(ldr1, ldr2).equal?
end

.cmp(*args) ⇒ Object

arguments can be:

a) filenames
b) IO instances
c) PEdump::Loader instances


113
114
115
116
117
118
119
120
121
122
123
# File 'lib/pedump/comparer.rb', line 113

def cmp *args
  handles = []
  if args.all?{|x| x.is_a?(String)}
    handles = args.map{|x| File.open(x,"rb")}
    _cmp(*handles.map{|h| PEdump::Loader.new(h)})
  else
    _cmp(*args)
  end
ensure
  handles.each(&:close)
end

.cmp_ios(*ios) ⇒ Object



130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
# File 'lib/pedump/comparer.rb', line 130

def cmp_ios *ios
  ndiff = 0
  while !ios.any?(&:eof)
    bytes = ios.map(&:readbyte)
    if bytes.uniq.size > 1
      ndiff += 1
      printf ("\t%08x:"+" %02x"*ios.size).yellow+"\n", ios[0].pos-1, *bytes
      if ndiff >= 5
        puts "\t...".yellow
        break
      end
    end
  end
  puts if ndiff > 0
end

Instance Method Details

#cmp_data_dirsObject



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/pedump/comparer.rb', line 68

def cmp_data_dirs
  r = true
  @ldr1.pe.ioh.DataDirectory.each_with_index do |d1,idx|
    break if idx == 15
    d2 = @ldr2.pe.ioh.DataDirectory[idx]

    case idx
      when PEdump::IMAGE_DATA_DIRECTORY::BASERELOC
        # total 8-byte size relocs == no relocs at all
        next if [d1.va, d2.va].min == 0 && [d1.size, d2.size].max == 8
    end

    next if @ignored_data_dirs.include?(idx)

    if d1.va != d2.va && d1.size != d2.size
      r = false
      printf "[!] data_dir: %-12s:  SIZE & VA: %6x %6x  |  %6x %6x\n".red, d1.type,
        d1.va, d1.size, d2.va, d2.size
    elsif d1.va != d2.va
      r = false
      printf "[!] data_dir: %-12s:  VA       : %x != %x\n".red, d1.type, d1.va, d2.va
    elsif d1.size != d2.size
      r = false
      printf "[!] data_dir: %-12s:  SIZE     : %x != %x\n".red, d1.type, d1.size, d2.size
    end
  end
  r
end

#cmp_importsObject



97
98
99
100
101
102
103
104
105
106
# File 'lib/pedump/comparer.rb', line 97

def cmp_imports
  @ldr1.pedump.imports.each_with_index do |iid1,idx|
    iid2 = @ldr2.pedump.imports[idx]
    if iid1 != iid2
      puts "[!] diff imports".red
      return false
    end
  end
  true
end

#cmp_pe_hdrObject



28
29
30
31
# File 'lib/pedump/comparer.rb', line 28

def cmp_pe_hdr
  @ldr1.pe.ioh.AddressOfEntryPoint == @ldr2.pe.ioh.AddressOfEntryPoint &&
  @ldr1.pe.ioh.ImageBase           == @ldr2.pe.ioh.ImageBase
end

#cmp_resourcesObject



33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/pedump/comparer.rb', line 33

def cmp_resources
  PEdump.quiet do
    #@ldr1.pedump.resources == @ldr2.pedump.resources
    @ldr1.pedump.resources.each_with_index do |r1,idx|
     r2 = @ldr2.pedump.resources[idx]
     if (r1.to_a - [r1.file_offset]) != (r2.to_a - [r2.file_offset])
       p r1
       p r2
       return false
     end
    end
  end
  true
end

#cmp_sectionsObject



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/pedump/comparer.rb', line 48

def cmp_sections
  r = true
  @ldr1.sections.each_with_index do |s1,idx|
    next if @ignored_sections.include?(s1.name)
    s2 = @ldr2.sections[idx]

    if !s2
      r = false
      printf "[!] extra section %-12s in %s\n".red, s1.name.inspect, f1
    elsif s1.data == s2.data
      printf "[.] section: %s == %s\n".green, s1.name, s2.name if @verbose
    else
      r = false
      printf "[!] section: %s != %s\n".red, s1.name, s2.name
      self.class.cmp_ios *[s1,s2].map{ |section| StringIO.new(section.data) }
    end
  end
  r
end

#diffObject



24
25
26
# File 'lib/pedump/comparer.rb', line 24

def diff
  METHODS.map{ |m| send("cmp_#{m}") ? nil : m }.compact
end

#equal?Boolean

Returns:

  • (Boolean)


20
21
22
# File 'lib/pedump/comparer.rb', line 20

def equal?
  METHODS.map{ |m| send("cmp_#{m}") }.uniq == [true]
end