elftools 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +139 -0
- data/lib/elftools/constants.rb +182 -0
- data/lib/elftools/dynamic.rb +106 -0
- data/lib/elftools/elf_file.rb +277 -0
- data/lib/elftools/exceptions.rb +3 -0
- data/lib/elftools/lazy_array.rb +43 -0
- data/lib/elftools/note.rb +112 -0
- data/lib/elftools/sections/dynamic_section.rb +20 -0
- data/lib/elftools/sections/note_section.rb +25 -0
- data/lib/elftools/sections/null_section.rb +16 -0
- data/lib/elftools/sections/section.rb +44 -0
- data/lib/elftools/sections/sections.rb +34 -0
- data/lib/elftools/sections/str_tab_section.rb +27 -0
- data/lib/elftools/sections/sym_tab_section.rb +123 -0
- data/lib/elftools/segments/dynamic_segment.rb +18 -0
- data/lib/elftools/segments/interp_segment.rb +18 -0
- data/lib/elftools/segments/note_segment.rb +24 -0
- data/lib/elftools/segments/segment.rb +44 -0
- data/lib/elftools/segments/segments.rb +30 -0
- data/lib/elftools/structures.rb +133 -0
- data/lib/elftools/util.rb +51 -0
- data/lib/elftools/version.rb +3 -0
- data/lib/elftools.rb +9 -0
- metadata +153 -0
@@ -0,0 +1,277 @@
|
|
1
|
+
require 'elftools/constants'
|
2
|
+
require 'elftools/exceptions'
|
3
|
+
require 'elftools/lazy_array'
|
4
|
+
require 'elftools/sections/sections'
|
5
|
+
require 'elftools/segments/segments'
|
6
|
+
require 'elftools/structures'
|
7
|
+
|
8
|
+
module ELFTools
|
9
|
+
# The main class for using elftools.
|
10
|
+
class ELFFile
|
11
|
+
attr_reader :stream # @return [File] The +File+ object.
|
12
|
+
attr_reader :elf_class # @return [Integer] 32 or 64.
|
13
|
+
attr_reader :endian # @return [Symbol] +:little+ or +:big+.
|
14
|
+
|
15
|
+
# Instantiate an {ELFFile} object.
|
16
|
+
#
|
17
|
+
# @param [File] stream
|
18
|
+
# The +File+ object to be fetch information from.
|
19
|
+
# @example
|
20
|
+
# ELFFile.new(File.open('/bin/cat'))
|
21
|
+
# #=> #<ELFTools::ELFFile:0x00564b106c32a0 @elf_class=64, @endian=:little, @stream=#<File:/bin/cat>>
|
22
|
+
def initialize(stream)
|
23
|
+
@stream = stream
|
24
|
+
identify # fetch the most basic information
|
25
|
+
end
|
26
|
+
|
27
|
+
# Return the file header.
|
28
|
+
#
|
29
|
+
# Lazy loading.
|
30
|
+
# @retrn [ELFTools::ELF_Ehdr] The header.
|
31
|
+
def header
|
32
|
+
return @header if @header
|
33
|
+
stream.pos = 0
|
34
|
+
@header = ELF_Ehdr.new(endian: endian)
|
35
|
+
@header.elf_class = elf_class
|
36
|
+
@header.read(stream)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Return the BuildID of ELF.
|
40
|
+
# @return [String, NilClass]
|
41
|
+
# BuildID in hex form will be returned.
|
42
|
+
# +nil+ is returned if the .note.gnu.build-id section
|
43
|
+
# is not found.
|
44
|
+
# @example
|
45
|
+
# elf.build_id
|
46
|
+
# #=> '73ab62cb7bc9959ce053c2b711322158708cdc07'
|
47
|
+
def build_id
|
48
|
+
section = section_by_name('.note.gnu.build-id')
|
49
|
+
return nil if section.nil?
|
50
|
+
note = section.notes.first
|
51
|
+
return nil if note.nil?
|
52
|
+
note.desc.unpack('H*').first
|
53
|
+
end
|
54
|
+
|
55
|
+
# Get Machine architecture.
|
56
|
+
#
|
57
|
+
# Mappings of architecture can be found
|
58
|
+
# in {ELFTools::Constants::EM.mapping}.
|
59
|
+
# @return [String]
|
60
|
+
# Name of architecture.
|
61
|
+
# @example
|
62
|
+
# elf.machine
|
63
|
+
# #=> 'Advanced Micro Devices X86-64'
|
64
|
+
def machine
|
65
|
+
ELFTools::Constants::EM.mapping(header.e_machine)
|
66
|
+
end
|
67
|
+
|
68
|
+
#========= method about sections
|
69
|
+
|
70
|
+
# Number of sections in this file.
|
71
|
+
# @return [Integer] The desired number.
|
72
|
+
# @example
|
73
|
+
# elf.num_sections
|
74
|
+
# #=> 29
|
75
|
+
def num_sections
|
76
|
+
header.e_shnum
|
77
|
+
end
|
78
|
+
|
79
|
+
# Acquire the section named as +name+.
|
80
|
+
# @param [String] name The desired section name.
|
81
|
+
# @return [ELFTools::Sections::Section, NilClass] The target section.
|
82
|
+
# @example
|
83
|
+
# elf.section_by_name('.note.gnu.build-id')
|
84
|
+
# #=> #<ELFTools::Sections::Section:0x005647b1282428>
|
85
|
+
# elf.section_by_name('')
|
86
|
+
# #=> #<ELFTools::Sections::NullSection:0x005647b11da110>
|
87
|
+
# elf.section_by_name('no such section')
|
88
|
+
# #=> nil
|
89
|
+
def section_by_name(name)
|
90
|
+
@section_name_map ||= {}
|
91
|
+
return @section_name_map[name] if @section_name_map[name]
|
92
|
+
each_sections do |section|
|
93
|
+
@section_name_map[section.name] = section
|
94
|
+
return section if section.name == name
|
95
|
+
end
|
96
|
+
nil
|
97
|
+
end
|
98
|
+
|
99
|
+
# Iterate all sections.
|
100
|
+
#
|
101
|
+
# All sections are lazy loading, the section
|
102
|
+
# only be created whenever accessing it.
|
103
|
+
# This method is useful for {#section_by_name}
|
104
|
+
# since not all sections need to be created.
|
105
|
+
# @param [Block] block
|
106
|
+
# Just like +Array#each+, you can give a block.
|
107
|
+
# @return [ Array<ELFTools::Sections::Section>]
|
108
|
+
# The whole sections will be returned.
|
109
|
+
def each_sections
|
110
|
+
Array.new(num_sections) do |i|
|
111
|
+
sec = section_at(i)
|
112
|
+
block_given? ? yield(sec) : sec
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# Simply use {#sections} without giving block to get all sections.
|
117
|
+
alias sections each_sections
|
118
|
+
|
119
|
+
# Acquire the +n+-th section, 0-based.
|
120
|
+
#
|
121
|
+
# Sections are lazy loaded.
|
122
|
+
# @param [Integer] n The index.
|
123
|
+
# @return [ELFTools::Sections::Section, NilClass]
|
124
|
+
# The target section.
|
125
|
+
# If +n+ is out of bound, +nil+ is returned.
|
126
|
+
def section_at(n)
|
127
|
+
@sections ||= LazyArray.new(num_sections, &method(:create_section))
|
128
|
+
@sections[n]
|
129
|
+
end
|
130
|
+
|
131
|
+
# Get the string table section.
|
132
|
+
#
|
133
|
+
# This section is acquired by using the +e_shstrndx+
|
134
|
+
# in ELF header.
|
135
|
+
# @return [ELFTools::Sections::StrTabSection] The desired section.
|
136
|
+
def strtab_section
|
137
|
+
section_at(header.e_shstrndx)
|
138
|
+
end
|
139
|
+
|
140
|
+
#========= method about segments
|
141
|
+
|
142
|
+
# Number of segments in this file.
|
143
|
+
# @return [Integer] The desited number.
|
144
|
+
def num_segments
|
145
|
+
header.e_phnum
|
146
|
+
end
|
147
|
+
|
148
|
+
# Iterate all segments.
|
149
|
+
#
|
150
|
+
# All segments are lazy loading, the segment
|
151
|
+
# only be created whenever accessing it.
|
152
|
+
# This method is useful for {#segment_by_type}
|
153
|
+
# since not all segments need to be created.
|
154
|
+
# @param [Block] block
|
155
|
+
# Just like +Array#each+, you can give a block.
|
156
|
+
# @return [Array<ELFTools::Segments::Segment>]
|
157
|
+
# Whole segments will be returned.
|
158
|
+
def each_segments
|
159
|
+
Array.new(num_segments) do |i|
|
160
|
+
seg = segment_at(i)
|
161
|
+
block_given? ? yield(seg) : seg
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
# Simply use {#segments} without giving block to get all segments.
|
166
|
+
alias segments each_segments
|
167
|
+
|
168
|
+
# Get the first segment with +p_type=type+.
|
169
|
+
# The available types are listed in {ELFTools::Constants},
|
170
|
+
# starts with +PT_+.
|
171
|
+
#
|
172
|
+
# Notice: this method will return the first segment found,
|
173
|
+
# to found all segments with specific type you can use {#segments_by_type}.
|
174
|
+
# @param [Integer, Symbol, String] type
|
175
|
+
# See examples for clear usage.
|
176
|
+
# @return [ELFTools::Segments::Segment] The target segment.
|
177
|
+
# @example
|
178
|
+
# # type as an integer
|
179
|
+
# elf.segment_by_type(ELFTools::Constants::PT_NOTE)
|
180
|
+
# #=> #<ELFTools::Segments::NoteSegment:0x005629dda1e4f8>
|
181
|
+
#
|
182
|
+
# elf.segment_by_type(4) # PT_NOTE
|
183
|
+
# #=> #<ELFTools::Segments::NoteSegment:0x005629dda1e4f8>
|
184
|
+
#
|
185
|
+
# # type as a symbol
|
186
|
+
# elf.segment_by_type(:PT_NOTE)
|
187
|
+
# #=> #<ELFTools::Segments::NoteSegment:0x005629dda1e4f8>
|
188
|
+
#
|
189
|
+
# # you can do this
|
190
|
+
# elf.segment_by_type(:note) # will be transformed into `PT_NOTE`
|
191
|
+
# #=> #<ELFTools::Segments::NoteSegment:0x005629dda1e4f8>
|
192
|
+
#
|
193
|
+
# # type as a string
|
194
|
+
# elf.segment_by_type('PT_NOTE')
|
195
|
+
# #=> #<ELFTools::Segments::NoteSegment:0x005629dda1e4f8>
|
196
|
+
#
|
197
|
+
# # this is ok
|
198
|
+
# elf.segment_by_type('note') # will be tranformed into `PT_NOTE`
|
199
|
+
# #=> #<ELFTools::Segments::NoteSegment:0x005629dda1e4f8>
|
200
|
+
# @example
|
201
|
+
# elf.segment_by_type(1337)
|
202
|
+
# # ArgumentError: No constants in Constants::PT is 1337
|
203
|
+
#
|
204
|
+
# elf.segment_by_type('oao')
|
205
|
+
# # ArgumentError: No constants in Constants::PT named "PT_OAO"
|
206
|
+
# @example
|
207
|
+
# elf.segment_by_type(0)
|
208
|
+
# #=> nil # no such segment exists
|
209
|
+
def segment_by_type(type)
|
210
|
+
type = Util.to_constant(Constants::PT, type)
|
211
|
+
each_segments do |seg|
|
212
|
+
return seg if seg.header.p_type == type
|
213
|
+
end
|
214
|
+
nil
|
215
|
+
end
|
216
|
+
|
217
|
+
# Fetch all segments with specific type.
|
218
|
+
# If you want to find only one segment,
|
219
|
+
# use {#segment_by_type} instead.
|
220
|
+
# @param [Integer, Symbol, String] type
|
221
|
+
# The type needed, same format as {#segment_by_type}.
|
222
|
+
# @return [Array<ELFTools::Segments::Segment>] The target segments.
|
223
|
+
def segments_by_type(type)
|
224
|
+
type = Util.to_constant(Constants::PT, type)
|
225
|
+
segments.select { |segment| segment.header.p_type == type }
|
226
|
+
end
|
227
|
+
|
228
|
+
# Acquire the +n+-th segment, 0-based.
|
229
|
+
#
|
230
|
+
# Segments are lazy loaded.
|
231
|
+
# @param [Integer] n The index.
|
232
|
+
# @return [ELFTools::Segments::Segment, NilClass]
|
233
|
+
# The target segment.
|
234
|
+
# If +n+ is out of bound, +nil+ is returned.
|
235
|
+
def segment_at(n)
|
236
|
+
@segments ||= LazyArray.new(num_segments, &method(:create_segment))
|
237
|
+
@segments[n]
|
238
|
+
end
|
239
|
+
|
240
|
+
private
|
241
|
+
|
242
|
+
def identify
|
243
|
+
stream.pos = 0
|
244
|
+
magic = stream.read(4)
|
245
|
+
raise ELFError, "Invalid magic number #{magic.inspect}" unless magic == Constants::ELFMAG
|
246
|
+
ei_class = stream.read(1).ord
|
247
|
+
@elf_class = {
|
248
|
+
1 => 32,
|
249
|
+
2 => 64
|
250
|
+
}[ei_class]
|
251
|
+
raise ELFError, format('Invalid EI_CLASS "\x%02x"', ei_class) if elf_class.nil?
|
252
|
+
ei_data = stream.read(1).ord
|
253
|
+
@endian = {
|
254
|
+
1 => :little,
|
255
|
+
2 => :big
|
256
|
+
}[ei_data]
|
257
|
+
raise ELFError, format('Invalid EI_DATA "\x%02x"', ei_data) if endian.nil?
|
258
|
+
end
|
259
|
+
|
260
|
+
def create_section(n)
|
261
|
+
stream.pos = header.e_shoff + n * header.e_shentsize
|
262
|
+
shdr = ELF_Shdr.new(endian: endian)
|
263
|
+
shdr.elf_class = elf_class
|
264
|
+
shdr.read(stream)
|
265
|
+
Sections::Section.create(shdr, stream,
|
266
|
+
strtab: method(:strtab_section),
|
267
|
+
section_at: method(:section_at))
|
268
|
+
end
|
269
|
+
|
270
|
+
def create_segment(n)
|
271
|
+
stream.pos = header.e_phoff + n * header.e_phentsize
|
272
|
+
phdr = ELF_Phdr[elf_class].new(endian: endian)
|
273
|
+
phdr.elf_class = elf_class
|
274
|
+
Segments::Segment.create(phdr.read(stream), stream)
|
275
|
+
end
|
276
|
+
end
|
277
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module ELFTools
|
2
|
+
# A helper class for {ELFTools} easy to implement
|
3
|
+
# 'lazy loading' objects.
|
4
|
+
# Mainly used when loading sections, segments, and
|
5
|
+
# symbols.
|
6
|
+
class LazyArray
|
7
|
+
# Instantiate a {LazyArray} object.
|
8
|
+
# @param [Integer] size
|
9
|
+
# The size of array.
|
10
|
+
# @param [Block] block
|
11
|
+
# At first time accessing +i+-th element,
|
12
|
+
# block will be called as +block.call(i)+.
|
13
|
+
# @example
|
14
|
+
# arr = LazyArray.new(10) { |i| p i; i * i }
|
15
|
+
# p arr[2]
|
16
|
+
# # 2
|
17
|
+
# # 4
|
18
|
+
#
|
19
|
+
# p arr[3]
|
20
|
+
# # 3
|
21
|
+
# # 9
|
22
|
+
#
|
23
|
+
# p arr[3]
|
24
|
+
# # 9
|
25
|
+
def initialize(size, &block)
|
26
|
+
@internal = Array.new(size)
|
27
|
+
@block = block
|
28
|
+
end
|
29
|
+
|
30
|
+
# To access elements like a normal array.
|
31
|
+
#
|
32
|
+
# Elements are lazy loaded at the first time
|
33
|
+
# access it.
|
34
|
+
# @return [Object]
|
35
|
+
# The element, returned type is the
|
36
|
+
# return type of block given in {#initialize}.
|
37
|
+
def [](i)
|
38
|
+
# XXX: support negative index?
|
39
|
+
return nil if i < 0 || i >= @internal.size
|
40
|
+
@internal[i] ||= @block.call(i)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
require 'elftools/structures'
|
2
|
+
require 'elftools/util'
|
3
|
+
|
4
|
+
module ELFTools
|
5
|
+
# Since both note sections and note segments
|
6
|
+
# refer to notes, this module defines common
|
7
|
+
# methods for {ELFTools::Sections::NoteSection} and {ELFTools::Segments::NoteSegment}.
|
8
|
+
#
|
9
|
+
# Notice: this module can only be included in {ELFTools::Sections::NoteSection} and
|
10
|
+
# {ELFTools::Segments::NoteSegment} since some methods assume some attributes already
|
11
|
+
# exist.
|
12
|
+
module Note
|
13
|
+
# Since size of {ELFTools::ELF_Nhdr} will not change no
|
14
|
+
# matter what endian and what arch, we can do this here.
|
15
|
+
# This value should equal to 12.
|
16
|
+
SIZE_OF_NHDR = ELF_Nhdr.new(endian: :little).num_bytes
|
17
|
+
|
18
|
+
# Iterate all notes in a note section or segment.
|
19
|
+
#
|
20
|
+
# Structure of notes are:
|
21
|
+
# +---------------+
|
22
|
+
# | Note 1 header |
|
23
|
+
# +---------------+
|
24
|
+
# | Note 1 name |
|
25
|
+
# +---------------+
|
26
|
+
# | Note 1 desc |
|
27
|
+
# +---------------+
|
28
|
+
# | Note 2 header |
|
29
|
+
# +---------------+
|
30
|
+
# | ... |
|
31
|
+
# +---------------+
|
32
|
+
#
|
33
|
+
# Notice: This method assume following methods exist:
|
34
|
+
# stream
|
35
|
+
# note_start
|
36
|
+
# note_total_size
|
37
|
+
# @return [Array<ELFTools::Note::Note>]
|
38
|
+
# The array of notes will be returned.
|
39
|
+
def each_notes
|
40
|
+
@notes_offset_map ||= {}
|
41
|
+
cur = note_start
|
42
|
+
notes = []
|
43
|
+
while cur < note_start + note_total_size
|
44
|
+
stream.pos = cur
|
45
|
+
@notes_offset_map[cur] ||= create_note(cur)
|
46
|
+
note = @notes_offset_map[cur]
|
47
|
+
# name and desc size needs to be 4-bytes align
|
48
|
+
name_size = Util.align(note.header.n_namesz, 2)
|
49
|
+
desc_size = Util.align(note.header.n_descsz, 2)
|
50
|
+
cur += SIZE_OF_NHDR + name_size + desc_size
|
51
|
+
notes << note
|
52
|
+
yield note if block_given?
|
53
|
+
end
|
54
|
+
notes
|
55
|
+
end
|
56
|
+
|
57
|
+
# Simply +#notes+ to get all notes.
|
58
|
+
alias notes each_notes
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
# Get the endian.
|
63
|
+
#
|
64
|
+
# Notice: This method assume method +header+ exists.
|
65
|
+
# @return [Symbol] +:little+ or +:big+.
|
66
|
+
def endian
|
67
|
+
header.class.self_endian
|
68
|
+
end
|
69
|
+
|
70
|
+
def create_note(cur)
|
71
|
+
nhdr = ELF_Nhdr.new(endian: endian).read(stream)
|
72
|
+
ELFTools::Note::Note.new(nhdr, stream, cur)
|
73
|
+
end
|
74
|
+
|
75
|
+
# Class of a note.
|
76
|
+
class Note
|
77
|
+
attr_reader :header # @return [ELFTools::ELF_Nhdr] Note header.
|
78
|
+
attr_reader :stream # @return [File] Streaming object.
|
79
|
+
attr_reader :offset # @return [Integer] Address of this note start, includes note header.
|
80
|
+
|
81
|
+
# Instantiate a {ELFTools::Note::Note} object.
|
82
|
+
# @param [ELF_Nhdr] header The note header.
|
83
|
+
# @param [File] stream Streaming object.
|
84
|
+
# @param [Integer] offset
|
85
|
+
# Start address of this note, includes the header.
|
86
|
+
def initialize(header, stream, offset)
|
87
|
+
@header = header
|
88
|
+
@stream = stream
|
89
|
+
@offset = offset
|
90
|
+
end
|
91
|
+
|
92
|
+
# Name of this note.
|
93
|
+
# @return [String] The name.
|
94
|
+
def name
|
95
|
+
return @name if @name
|
96
|
+
stream.pos = @offset + SIZE_OF_NHDR
|
97
|
+
@name = stream.read(header.n_namesz)[0..-2]
|
98
|
+
end
|
99
|
+
|
100
|
+
# Description of this note.
|
101
|
+
# @return [String] The description.
|
102
|
+
def desc
|
103
|
+
return @desc if @desc
|
104
|
+
stream.pos = @offset + SIZE_OF_NHDR + Util.align(header.n_namesz, 2)
|
105
|
+
@desc = stream.read(header.n_descsz)
|
106
|
+
end
|
107
|
+
|
108
|
+
# If someone likes to use full name.
|
109
|
+
alias description desc
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'elftools/dynamic'
|
2
|
+
require 'elftools/sections/section'
|
3
|
+
|
4
|
+
module ELFTools
|
5
|
+
module Sections
|
6
|
+
# Class for dynamic table section.
|
7
|
+
#
|
8
|
+
# This section should always be named .dynamic.
|
9
|
+
# This class knows how to get the list of dynamic tags.
|
10
|
+
class DynamicSection < Section
|
11
|
+
include ELFTools::Dynamic
|
12
|
+
|
13
|
+
# Get the start address of tags.
|
14
|
+
# @return [Integer] Start address of tags.
|
15
|
+
def tag_start
|
16
|
+
header.sh_offset
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'elftools/note'
|
2
|
+
require 'elftools/sections/section'
|
3
|
+
|
4
|
+
module ELFTools
|
5
|
+
module Sections
|
6
|
+
# Class of note section.
|
7
|
+
# Note section records notes
|
8
|
+
class NoteSection < Section
|
9
|
+
# Load note related methods.
|
10
|
+
include ELFTools::Note
|
11
|
+
|
12
|
+
# Address offset of notes start.
|
13
|
+
# @return [Integer] The offset.
|
14
|
+
def note_start
|
15
|
+
header.sh_offset
|
16
|
+
end
|
17
|
+
|
18
|
+
# The total size of notes in this section.
|
19
|
+
# @return [Integer] The size.
|
20
|
+
def note_total_size
|
21
|
+
header.sh_size
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'elftools/sections/section'
|
2
|
+
|
3
|
+
module ELFTools
|
4
|
+
module Sections
|
5
|
+
# Class of null section.
|
6
|
+
# Null section is for specific the end
|
7
|
+
# of linked list (+sh_link+) between sections.
|
8
|
+
class NullSection < Section
|
9
|
+
# Is this a null section?
|
10
|
+
# @return [Boolean] Yes it is.
|
11
|
+
def null?
|
12
|
+
true
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'elftools/constants'
|
2
|
+
module ELFTools
|
3
|
+
module Sections
|
4
|
+
# Base class of sections.
|
5
|
+
class Section
|
6
|
+
attr_reader :header # @return [ELFTools::ELF_Shdr] Section header.
|
7
|
+
attr_reader :stream # @return [File] Streaming object.
|
8
|
+
|
9
|
+
# Instantiate a {Section} object.
|
10
|
+
# @param [ELFTools::ELF_Shdr] header
|
11
|
+
# The section header object.
|
12
|
+
# @param [File] stream
|
13
|
+
# The streaming object for further dump.
|
14
|
+
# @param [ELFTools::Sections::StrTabSection, Proc] strtab
|
15
|
+
# The string table object. For fetching section names.
|
16
|
+
# If +Proc+ if given, it will call at the first
|
17
|
+
# time access +#name+.
|
18
|
+
def initialize(header, stream, strtab: nil, **_kwagrs)
|
19
|
+
@header = header
|
20
|
+
@stream = stream
|
21
|
+
@strtab = strtab
|
22
|
+
end
|
23
|
+
|
24
|
+
# Get name of this section.
|
25
|
+
# @return [String] The name.
|
26
|
+
def name
|
27
|
+
@name ||= @strtab.call.name_at(header.sh_name)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Fetch data of this section.
|
31
|
+
# @return [String] Data.
|
32
|
+
def data
|
33
|
+
stream.pos = header.sh_offset
|
34
|
+
stream.read(header.sh_size)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Is this a null section?
|
38
|
+
# @return [Boolean] No it's not.
|
39
|
+
def null?
|
40
|
+
false
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# Require this file to load all sections classes.
|
2
|
+
|
3
|
+
require 'elftools/sections/section'
|
4
|
+
|
5
|
+
require 'elftools/sections/dynamic_section'
|
6
|
+
require 'elftools/sections/note_section'
|
7
|
+
require 'elftools/sections/null_section'
|
8
|
+
require 'elftools/sections/str_tab_section'
|
9
|
+
require 'elftools/sections/sym_tab_section'
|
10
|
+
|
11
|
+
module ELFTools
|
12
|
+
# Defines different types of sections in this module.
|
13
|
+
module Sections
|
14
|
+
# Class methods of {Sections::Section}.
|
15
|
+
class << Section
|
16
|
+
# Use different class according to +header.sh_type+.
|
17
|
+
# @param [ELFTools::ELF_Shdr] header Section header.
|
18
|
+
# @param [File] stream Streaming object.
|
19
|
+
# @return [ELFTools::Sections::Section]
|
20
|
+
# Return object dependes on +header.sh_type+.
|
21
|
+
def create(header, stream, *args)
|
22
|
+
klass = case header.sh_type
|
23
|
+
when Constants::SHT_DYNAMIC then DynamicSection
|
24
|
+
when Constants::SHT_NULL then NullSection
|
25
|
+
when Constants::SHT_NOTE then NoteSection
|
26
|
+
when Constants::SHT_STRTAB then StrTabSection
|
27
|
+
when Constants::SHT_SYMTAB, Constants::SHT_DYNSYM then SymTabSection
|
28
|
+
else Section
|
29
|
+
end
|
30
|
+
klass.new(header, stream, *args)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'elftools/sections/section'
|
2
|
+
|
3
|
+
module ELFTools
|
4
|
+
module Sections
|
5
|
+
# Class of string table section.
|
6
|
+
# Usually for section .strtab and .dynstr,
|
7
|
+
# which record names.
|
8
|
+
class StrTabSection < Section
|
9
|
+
# Return the section or symbol name.
|
10
|
+
# @param [Integer] offset
|
11
|
+
# Usually from +shdr.sh_name+ or +sym.st_name+.
|
12
|
+
# @return [String] The name without null bytes.
|
13
|
+
def name_at(offset)
|
14
|
+
stream.pos = header.sh_offset + offset
|
15
|
+
# read until "\x00"
|
16
|
+
ret = ''
|
17
|
+
loop do
|
18
|
+
c = stream.read(1)
|
19
|
+
return nil if c.nil? # reach EOF
|
20
|
+
break if c == "\x00"
|
21
|
+
ret += c
|
22
|
+
end
|
23
|
+
ret
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|