Class: Nxo::NsoFile

Inherits:
NxoFile show all
Defined in:
lib/nxo/nso.rb

Constant Summary collapse

NSO_MAGIC =
"NSO0"
NSO_VERSION =
0

Constants inherited from NxoFile

Nxo::NxoFile::MOD_MAGIC

Instance Attribute Summary collapse

Attributes inherited from NxoFile

#dynamic

Instance Method Summary collapse

Methods inherited from NxoFile

#[], #bss, #data, #fs_sdk_versions, #name_heuristic, #rodata, #text

Constructor Details

#initialize(f, options = {}) ⇒ NsoFile

Returns a new instance of NsoFile.



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# File 'lib/nxo/nso.rb', line 12

def initialize(f, options = {})
  @f = f

  @f.pos = 0
  magic, version, flags = @f.read(0x10).unpack("a4L<x4L<")

  if magic != NSO_MAGIC then
    raise Error::InvalidMagicError.new(magic, NSO_MAGIC)
  end

  if version != NSO_VERSION then
    raise Error::UnknownVersionError.new(version, NSO_VERSION)
  end

  segment_headers = 3.times.map do
    Hash[[:file_offset, :memory_offset, :decompressed_size, :misc].zip(@f.read(0x10).unpack("L<L<L<L<"))]
  end

  module_offset, module_file_size, bss_size = segment_headers.map do |sh| sh[:misc] end

  @build_id = @f.read(0x20)

  @f.read(3 * 0x4).unpack("L<L<L<").each_with_index do |size, i|
    segment_headers[i][:compressed_size] = size
  end

  @f.pos = 0x88
  @extents = Hash[[:api_info, :dynstr, :dynsym].zip(@f.read(0x18).unpack("Q<Q<Q<"))]
  
  @f.read(3 * 0x20).unpack("a32a32a32").each_with_index do |hash, i|
    segment_headers[i][:hash] = hash
  end

  location_counter = 0
  segments = [:text, :rodata, :data].each_with_index.map do |name, i|
    sh = segment_headers[i]
    @f.pos = sh[:file_offset]
    contents = @f.read(sh[:compressed_size])

    if flags[i] == 1 then # is compressed
      contents = LZ4::Raw.decompress(contents, sh[:decompressed_size])[0]
    end

    if flags[i+3] == 1 && !options[:disable_hash_check] then # check hash
      if Digest::SHA256.digest(contents) != sh[:hash] then
        raise Error::HashCheckError.new(name)
      end
    end

    if sh[:memory_offset] < location_counter then
      raise Error::AddressMismatchError.new(name, sh[:memory_offset], location_counter)
    end

    location_counter = sh[:memory_offset] + contents.bytesize
    
    Segment.new(name, sh[:memory_offset], contents)
  end + [Segment.new("bss", location_counter, 0.chr * bss_size)]

  super(segments)
end

Instance Attribute Details

#build_idObject (readonly)

Returns the value of attribute build_id.



73
74
75
# File 'lib/nxo/nso.rb', line 73

def build_id
  @build_id
end

#extentsObject (readonly)

Returns the value of attribute extents.



74
75
76
# File 'lib/nxo/nso.rb', line 74

def extents
  @extents
end

#segmentsObject (readonly)

Returns the value of attribute segments.



75
76
77
# File 'lib/nxo/nso.rb', line 75

def segments
  @segments
end