Class: PEdump::Packer

Inherits:
Struct
  • Object
show all
Defined in:
lib/pedump/packer.rb

Defined Under Namespace

Classes: Guess, Match

Constant Summary collapse

DATA_ROOT =
File.dirname(File.dirname(File.dirname(__FILE__)))
BIN_SIGS_FILE =
File.join(DATA_ROOT, "data", "sig.bin")
BLOCK_SIZE =
0x10000
@@deep =

default deep-scan flag

false

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Attribute Details

#ep_onlyObject

Returns the value of attribute ep_only

Returns:

  • (Object)

    the current value of ep_only



4
5
6
# File 'lib/pedump/packer.rb', line 4

def ep_only
  @ep_only
end

#nameObject

Returns the value of attribute name

Returns:

  • (Object)

    the current value of name



4
5
6
# File 'lib/pedump/packer.rb', line 4

def name
  @name
end

#reObject

Returns the value of attribute re

Returns:

  • (Object)

    the current value of re



4
5
6
# File 'lib/pedump/packer.rb', line 4

def re
  @re
end

#sizeObject

Returns the value of attribute size

Returns:

  • (Object)

    the current value of size



4
5
6
# File 'lib/pedump/packer.rb', line 4

def size
  @size
end

Class Method Details

.allObject Also known as: load



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/pedump/packer.rb', line 23

def all
  @@all ||=
    begin
      r = unmarshal
      unless r
        msg = "[?] #{self}: unmarshal failed, using slow text parsing instead"
        if PEdump.respond_to?(:logger) && PEdump.logger
          PEdump.logger.warn msg
        else
          STDERR.puts msg
        end
        r = SigParser.parse
      end
      r
    end
end

.default_deepObject



44
45
46
# File 'lib/pedump/packer.rb', line 44

def default_deep
  @@deep
end

.default_deep=(value) ⇒ Object



48
49
50
# File 'lib/pedump/packer.rb', line 48

def default_deep= value
  @@deep = value
end

.max_sizeObject



52
53
54
# File 'lib/pedump/packer.rb', line 52

def max_size
  @@max_size ||= all.map(&:size).max
end

.method_missing(*args, &block) ⇒ Object



151
152
153
# File 'lib/pedump/packer.rb', line 151

def method_missing *args, &block
  all.respond_to?(args.first) ? all.send(*args,&block) : super
end

.of(data, h = {}) ⇒ Object



56
57
58
59
60
61
62
63
64
# File 'lib/pedump/packer.rb', line 56

def of data, h = {}
  if data.respond_to?(:read) && data.respond_to?(:seek) && h[:pedump]
    of_pedump data, h
  elsif data.respond_to?(:read) && data.respond_to?(:seek) && h[:ep_offset]
    of_pe_file data, h
  else
    of_data data
  end
end

.of_data(data) ⇒ Object



140
141
142
143
144
145
146
147
148
149
# File 'lib/pedump/packer.rb', line 140

def of_data data
  r = []
  return r unless data
  each do |packer|
    if (idx=data.index(packer.re)) == 0
      r << Match.new(idx, packer)
    end
  end
  r.any? ? r.sort_by{ |x| -x.packer.size } : nil
end

.of_pe_file(f, h) ⇒ Object

try to determine packer of FILE f, ep_offset - offset to entrypoint from start of file



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

def of_pe_file f, h
  h[:deep] = @@deep unless h.key?(:deep)
  h[:deep] = 1 if h[:deep] == true
  h[:deep] = 0 if h[:deep] == false

  f.seek(h[:ep_offset])             # offset of PE EntryPoint from start of file
  r = Array(of_data(f.read(max_size)))
  return r if r && r.any? && h[:deep] < 2
  r += scan_whole_file(f,
                       :limit => (h[:deep] > 0 ? nil : 1048576),
                       :deep  => h[:deep]
                      ) # scan only 1st mb unless :deep
end

.of_pedump(f, h) ⇒ Object

try to determine packer of FILE f, h is a PEdump instance



67
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
# File 'lib/pedump/packer.rb', line 67

def of_pedump f, h
  pedump = h[:pedump]
  pe = pedump.pe
  if !(va=pe.ioh.AddressOfEntryPoint)
    pedump.logger.error "[?] can't find EntryPoint RVA"
    nil
  elsif va == 0 && pe.dll?
    pedump.logger.debug "[.] it's a DLL with no EntryPoint"
    nil
  elsif !(ofs = pedump.va2file(va))
    pedump.logger.error "[?] can't find EntryPoint RVA (0x#{va.to_s(16)}) file offset"
    nil
  else
    r = of_pe_file(f, h.merge({:ep_offset => ofs}))
    return r if r && r.any?

    # nothing found, try to guess by pe section names
    if pedump.sections
      if pedump.sections.any?{ |s| s.Name.to_s =~ /upx/i }
        return [Guess.new('UPX?')]
      end
      if pedump.sections.any?{ |s| s.Name.to_s =~ /aspack/i }
        return [Guess.new('ASPack?')]
      end
    end
    nil
  end
end

.scan_whole_file(f, h = {}) ⇒ Object



113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/pedump/packer.rb', line 113

def scan_whole_file f, h = {}
  h[:limit] ||= f.size
  f.seek( pos = 0 )
  buf = ''.force_encoding('binary')
  sigs =
    if h[:deep].is_a?(Numeric) && h[:deep] > 1
      self.all
    else
      self.find_all{ |sig| !sig.ep_only }
    end
  r = []
  while true
    f.read BLOCK_SIZE, buf
    pos += buf.size
    sigs.each do |sig|
      if idx = buf.index(sig.re)
        r << Match.new(f.tell-buf.size+idx, sig)
      end
    end
    break if f.eof? || pos >= h[:limit]
    # overlap the read for the case when read buffer boundary breaks signature
    f.seek -max_size-2, IO::SEEK_CUR
    pos -= (max_size+2)
  end
  r
end

.unmarshalObject



155
156
157
158
159
160
161
# File 'lib/pedump/packer.rb', line 155

def unmarshal
  File.open(BIN_SIGS_FILE,"rb") do |f|
    Marshal.load(f)
  end
rescue
  nil
end