Class: PEdump::NE

Inherits:
Object show all
Defined in:
lib/pedump/ne.rb,
lib/pedump/ne/version_info.rb

Overview

from wine’s winnt.h

Defined Under Namespace

Classes: Bundle, Reloc, Resource, ResourceGroup, ResourceInfo, Segment, StringFileInfo, StringTable, VS_FIXEDFILEINFO, VS_VERSIONINFO, Var, VarFileInfo, VersionString

Constant Summary collapse

DEFAULT_CP =
1252

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#ioObject

Returns the value of attribute io.



35
36
37
# File 'lib/pedump/ne.rb', line 35

def io
  @io
end

#offsetObject

Returns the value of attribute offset.



35
36
37
# File 'lib/pedump/ne.rb', line 35

def offset
  @offset
end

Class Method Details

.cpObject



39
40
41
# File 'lib/pedump/ne.rb', line 39

def self.cp
  @@cp || DEFAULT_CP
end

.cp=(cp) ⇒ Object



43
44
45
# File 'lib/pedump/ne.rb', line 43

def self.cp= cp
  @@cp = cp
end

.read(io, *args) ⇒ Object



47
48
49
50
51
52
53
# File 'lib/pedump/ne.rb', line 47

def self.read io, *args
  self.cp = DEFAULT_CP
  offset = io.tell
  super.tap do |x|
    x.io, x.offset = io, offset
  end
end

Instance Method Details

#_detect_codepage(a, io = @io) ⇒ Object



228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
# File 'lib/pedump/ne.rb', line 228

def _detect_codepage a, io=@io
  a.find_all{ |res| res.type == 'VERSION' }.each do |res|
    res.parse(io)
    res.data.each do |vi|
      if vi.respond_to?(:Children) && vi.Children.respond_to?(:each)
        # vi is PEdump::NE::VS_VERSIONINFO
        vi.Children.each do |vfi|
          if vfi.is_a?(PEdump::NE::VarFileInfo) && vfi.Children.is_a?(PEdump::NE::Var)
            var = vfi.Children
            # var is PEdump::NE::Var
            if var.respond_to?(:Value) && var.Value.is_a?(Array) && var.Value.size == 2
              return var.Value.last
            end
          end
        end
      end
    end
  end
  nil
end

#_id2string(id, io, res_base) ⇒ Object



186
187
188
189
190
191
192
193
194
195
196
# File 'lib/pedump/ne.rb', line 186

def _id2string id, io, res_base
  if id & 0x8000 == 0
    # offset to name
    io.seek id + res_base
    namesize = (io.getc || 0.chr).ord
    io.read(namesize)
  else
    # numerical id
    "##{id & 0x7fff}"
  end
end

#bundles(io = @io) ⇒ Object



369
370
371
372
373
374
375
376
# File 'lib/pedump/ne.rb', line 369

def bundles io=@io
  io.seek @offset+ne_enttab
  bundles = []
  while bundle = Bundle.read(io)
    bundles << bundle
  end
  bundles
end

#entrypoints(io = @io) ⇒ Object



378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
# File 'lib/pedump/ne.rb', line 378

def entrypoints io=@io
  @entrypoints ||=
    begin
      r = [0] # entrypoint indexes are 1-based
      bundles(io).each do |b|
        if b.entries.empty?
          b.num_entries.times{ r<<0 }
        else
          b.entries.each do |e|
            if e.is_a?(Bundle::MovableEntry)
              r << (e.seg_idx<<16) + e.offset
            elsif e.is_a?(Bundle::FixedEntry)
              r << (b.seg_idx<<16) + e.offset
            else
              raise "invalid ep #{e.inspect}"
            end
          end
        end
      end
      r
    end
end

#exports(io = @io) ⇒ Object

first string with ordinal 0 is a module name



309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
# File 'lib/pedump/ne.rb', line 309

def exports io=@io
  exp_dir = IMAGE_EXPORT_DIRECTORY.new
  exp_dir.functions = []

  io.seek @offset+ne_restab
  while !io.eof && (namelen = io.getc.ord) > 0
    exp_dir.functions << ExportedFunction.new( io.read(namelen), io.read(2).unpack('v').first, 0 )
  end
  exp_dir.name = exp_dir.functions.shift.name if exp_dir.functions.any?

  a = []
  io.seek ne_nrestab
  while !io.eof && (namelen = io.getc.ord) > 0
    a << ExportedFunction.new( io.read(namelen), io.read(2).unpack('v').first, 0 )
  end
  exp_dir.description = a.shift.name if a.any?
  exp_dir.functions += a

  exp_dir.functions.each do |f|
    f.va = entrypoints[f.ord]
  end

  exp_dir
end

#imports(io = @io) ⇒ Object



277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
# File 'lib/pedump/ne.rb', line 277

def imports io=@io
  @imports ||=
    begin
      io.seek @offset+ne_modtab
      modules = io.read(2*ne_cmod).unpack('v*')
      modules.map! do |ofs|
        io.seek @offset+ne_imptab+ofs
        namelen = io.getc.ord
        io.read(namelen)
      end

      r = []
      segments(io).each do |seg|
        seg.relocs.each do |rel|
          if rel.type == Reloc::TYPE_IMPORTORDINAL
            r << (f = PEdump::ImportedFunction.new)
            f.module_name = modules[rel.module_idx-1]
            f.ordinal = rel.func_idx
          elsif rel.type == Reloc::TYPE_IMPORTNAME
            r << (f = PEdump::ImportedFunction.new)
            f.module_name = modules[rel.module_idx-1]
            io.seek @offset+ne_imptab+rel.func_idx
            namelen = io.getc.ord
            f.name = io.read(namelen)
          end
        end
      end
      r
    end
end

#resource_directory(io = @io) ⇒ Object



198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
# File 'lib/pedump/ne.rb', line 198

def resource_directory io=@io
  @resource_directory ||=
    begin
      res_base = ne_rsrctab+@offset
      io.seek res_base
      res_shift = io.read(2).unpack('v').first
      unless (0..16).include?(res_shift)
        PEdump.logger.error "[!] invalid res_shift = %d" % res_shift
        return []
      end
      PEdump.logger.info "[.] res_shift = %d" % res_shift
      r = []
      while !io.eof? && (g = ResourceGroup.read(io))
        r << g
      end
      r.each do |g|
        g.type = (g.type_id & 0x8000 != 0) && PEdump::ROOT_RES_NAMES[g.type_id & 0x7fff]
        g.type ||= _id2string( g.type_id, io, res_base)
        g.children.each do |res|
          res.name = _id2string(res.name_offset, io, res_base)
          res.offset ||= 0
          res.offset <<= res_shift
          res.size   ||= 0
          res.size   <<= res_shift
        end
      end
      r
    end
end

#resources(io = @io) ⇒ Object



249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
# File 'lib/pedump/ne.rb', line 249

def resources io=@io
  a = []
  resource_directory(io).each do |grp|
    grp.children.each do |res|
      a << (r = Resource.new)
      r.id   = (res.name_offset & 0x7fff) if (res.name_offset & 0x8000) != 0
      r.type = grp.type
      r.size = res.size
      r.name = res.name
      r.file_offset = res.offset
      r.reserved = res.reserved
    end
  end

  # try to detect codepage
  cp = _detect_codepage(a, io)
  if cp
    PEdump::NE.cp = cp # XXX HACK
    PEdump.logger.info "[.] detect_codepage: #{cp.inspect}"
  else
    cp = DEFAULT_CP
    PEdump.logger.info "[.] detect_codepage failed, using default #{cp}"
  end

  a.each{ |r| r.parse(io, :cp => cp) }
  a
end

#segments(io = @io) ⇒ Object



108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/pedump/ne.rb', line 108

def segments io=@io
  @segments ||= io &&
    begin
      io.seek ne_segtab+@offset
      ne_cseg.times.map{ Segment.read(io) }.each do |seg|
        seg.file_offset = seg.offset << ne_align
        seg.relocs = []
        if (seg.flags & Segment::FLAG_RELOCINFO) != 0
          io.seek seg.file_offset + seg.size
          nRelocs = io.read(2).unpack('v').first
          seg.relocs = nRelocs.times.map{ Reloc.read(io) }
        end
      end
    end
end