elf-mithril 0.0.1 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -656,14 +656,14 @@ module Elf
656
656
  @file.symbols.each {|staticsym|
657
657
  @canonical_symbol[staticsym] = staticsym
658
658
  next if staticsym.name == ""
659
- next if staticsym.visibility == STB::STB_LOCAL
660
- dyn_by_name[staticsym.name].andand.each {|sym|
661
- next if sym.sectoffset != dynsym.sectoffset
662
- next if sym.section != dynsym.section
663
- @canonical_symbol[dynsym] = sym
659
+ next if staticsym.bind == STB::STB_LOCAL
660
+ dyn_by_name[staticsym.name].andand.each {|dynsym|
661
+ next if dynsym.sectoffset != staticsym.sectoffset
662
+ next if dynsym.section != staticsym.section
663
+ @canonical_symbol[dynsym] = staticsym
664
664
  staticsym.is_dynamic = true
665
- staticsym.gnu_version = sym.gnu_version
666
- expect_value "Dynamic #{sym.name} size", sym.size, staticsym.size
665
+ staticsym.gnu_version = dynsym.gnu_version
666
+ expect_value "Dynamic #{dynsym.name} size", dynsym.size, staticsym.size
667
667
  }
668
668
  }
669
669
  @dynsym.each {|sym|
@@ -1,335 +1,6 @@
1
1
  require 'bindata'
2
2
  #Nothing to see here. For background, see Dartmouth College CS
3
3
  #TR2013-727 (ELFbac)
4
- module Elf
5
- module Policy
6
- def self.section_symbol_name(file_name,section_name)
7
- "_elfp_#{file_name}_#{section_name}"
8
- end
9
- R = ElfFlags::Relocation
10
- ELFP = ElfFlags::ElfPData
11
- class Transition
12
- attr_accessor :from, :to
13
- end
14
- class Call < Transition
15
- attr_accessor :symbol
16
- attr_accessor :parambytes,:returnbytes
17
- def initialize(from,to, symbol, parambytes, returnbytes)
18
- @from, @to, @symbol, @parambytes, @returnbytes = from,to, symbol, parambytes, returnbytes
19
- end
20
- def allows_return?
21
- @returnbytes >= 0
22
- end
23
- end
24
- class Data < Transition
25
- attr_accessor :tag
26
- attr_accessor :read,:write, :exec
27
- def initialize(from,to,tag , read=false ,write=false,exec=false)
28
- @from, @to, @tag, @read,@write,@exec = from,to,tag,read,write,exec
29
- end
30
- end
31
- class MemoryRange
32
- attr_accessor :low, :high
33
- def initialize(from,to)
34
- @low,@high = from,to
35
- end
36
- end
37
- class Policy
38
- attr_accessor :data, :calls, :start, :tags
39
- attr_accessor :imported_symbols
40
- def states
41
- t = data.keys + data.values.map(&:keys).flatten + calls.map(&:from) +
42
- calls.map(&:to)
43
- t.uniq
44
- end
45
- def <<(*transitions)
46
- transitions.each do |t|
47
- if t.is_a? Data
48
- x= data
49
- x[t.from] ||= {}
50
- x[t.from][t.to] ||= {}
51
- x[t.from][t.to][t.tag] ||= t
52
- x[t.from][t.to][t.tag].read ||= t.read
53
- x[t.from][t.to][t.tag].write ||= t.write
54
- x[t.from][t.to][t.tag].exec ||= t.exec
55
- elsif t.is_a? Call
56
- calls << t
57
- else
58
- raise ArgumentError.new "#{t.class} is not a valid transition"
59
- end
60
- end
61
- end
62
- def initialize
63
- @data={}
64
- @calls=[]
65
- @states ={}
66
- @tags = {}
67
- @imported_symbols = {}
68
- end
69
- def resolve_reference(elffile, relocations,offset, ref)
70
- if(ref.is_a? Integer)
71
- ref.to_i
72
- elsif(ref == "_dl_runtime_resolve") #HACK:HACK:HACK: I couldn't hack ld.so to fix this, so
73
- #here comes a nasty hack
74
- #note that the address of _dl_runtime_resolve is 16 bytes into PLT.GOT
75
- if !elffile.symbols.include? "_elfp_hidden_trampolineaddr"
76
- pltgot = elffile.dynamic.pltgot or raise RuntimeError.new "No plt.got for _dl_runtime_resolve hack"
77
- elffile.symbols << Elf::Symbol.new("_elfp_hidden_trampolineaddr", pltgot,STT::STT_OBJECT,16, STB::STB_LOCAL,8)
78
- end
79
- symb = elffile.symbols["_elfp_hidden_trampolineaddr"]
80
- relocations << Elf::Relocation.new.tap{|x|
81
- x.type = R::R_X86_64_COPY
82
- x.offset = offset
83
- x.symbol = symb
84
- x.is_dynamic = true
85
- x.addend = 0
86
- }
87
- 0xDEADBEEF
88
- else
89
- raise RuntimeError.new "Symbol #{ref} not found" unless elffile.symbols.include? ref
90
- relocations << Elf::Relocation.new.tap{|x|
91
- x.type = R::R_X86_64_64
92
- x.offset = offset
93
- x.symbol = elffile.symbols[ref]
94
- x.is_dynamic = true
95
- x.addend = 0
96
- }
97
- 2**64-1
98
- end
99
- end
100
- def resolve_size(elffile,relocations, offset, ref)
101
- if(ref.is_a? Integer)
102
- ref.to_i
103
- else
104
- raise RuntimeError.new "Symbol #{ref} not found" unless elffile.symbols.include? ref
105
- relocations << Elf::Relocation.new.tap{|x|
106
- x.type = R::R_X86_64_SIZE64
107
- x.offset = offset
108
- x.symbol = elffile.symbols[ref]
109
- x.is_dynamic = true
110
- x.addend = 0
111
- }
112
- 2**64-1
113
- end
114
- end
115
- def write_amd64(elffile)
116
- factory = ElfStructFactory.instance(:little,64)
117
- @imported_symbols.each_key {|symbol|
118
- if elffile.symbols.include?(symbol)
119
- elffile.symbols[symbol].is_dynamic = true
120
- else
121
- elffile.symbols << Elf::Symbol.new(symbol,nil,Elf::STT::STT_OBJECT, 0, Elf::STB::STB_GLOBAL, 0).tap {|x|
122
- x.semantics = Elf::SHN::SHN_UNDEF
123
- }
124
- end
125
- }
126
- out = factory.elfp_header.new()
127
- state_ids = {}
128
- tag_ids = {}
129
- relocations = []
130
- states = states()
131
- @start = states.first unless states.include? @start
132
- #These have to be filled in the order in which they are written
133
- #FIXME: Make these aware of double transitions to the same range/ state
134
- states.each_with_index do |state,index|
135
- id = index + 2
136
- id = 1 if @start == state
137
- out.states << factory.elfp_state.new.tap {|x|
138
- x.id = id
139
- x.stackid = 0
140
- }
141
- state_ids[state] = id
142
- print "State #{state} #{id}\n"
143
- end
144
- tag_ids[:default] = 0
145
- @tags.each_with_index do |(name,ranges),index|
146
- tag_ids[name] = index+1
147
- ranges.each do |data|
148
- out.tags << factory.elfp_tag.new.tap {|x|
149
- x.tag = index + 1
150
- x.addr = 0
151
- x.siz = 0
152
- }
153
- out.tags.last.tap {|x|
154
- x.addr = resolve_reference(elffile,relocations,x.addr.offset,data.low)
155
- if data.high.nil?
156
- x.siz = resolve_size(elffile,relocations,x.siz.offset,data.low)
157
- else
158
- pp "Warning, emitting SIZE symbol with value #{ data.high.to_i rescue data.high.name}"
159
- x.siz = resolve_reference(elffile,relocations,x.siz.offset,data.high)
160
- end
161
- }
162
- end
163
- print "Tag #{name} #{index + 1} \n"
164
- end
165
- self.calls.each do |call|
166
- out.calls << factory.elfp_call.new.tap {|x|
167
- x.from = state_ids[call.from]
168
- x.to = state_ids[call.to]
169
- x.parambytes = call.parambytes
170
- x.returnbytes = call.parambytes
171
- }
172
- out.calls.last.off = resolve_reference(elffile,relocations,out.calls.last.off.offset, call.symbol)
173
- end
174
- self.data.values.map(&:values).flatten.map(&:values).flatten.each do |data|
175
- out.data << factory.elfp_data.new.tap {|x|
176
- x.from = state_ids[data.from]
177
- x.to = state_ids[data.to]
178
- x.type = 0
179
- x.type |= ELFP::ELFP_RW_READ if data.read
180
- x.type |= ELFP::ELFP_RW_WRITE if data.write
181
- x.type |= ELFP::ELFP_RW_EXEC if data.exec
182
- raise RuntimeError.new "Unknown tag #{data.tag}" unless tag_ids.include? data.tag
183
- x.tag = tag_ids[data.tag]
184
- }
185
- end
186
- out = Elf::ProgBits.new(".elfbac",nil,out.to_binary_s)
187
- out.align = 8
188
- out.flags = SHF::SHF_ALLOC | SHF::SHF_WRITE
189
- out.sect_type = SHT::SHT_PROGBITS
190
- out.phdr = ElfFlags::PhdrType::PT_ELFBAC
191
- out.phdr_flags = ElfFlags::PhdrFlags::PF_R
192
- relocations.each { |rel|
193
- rel.section = out
194
- elffile.relocations << rel
195
- }
196
- elffile.progbits << out
197
-
198
- end
199
- def inject(file)
200
- case file.machine
201
- when ElfFlags::Machine::EM_X86_64
202
- write_amd64(file)
203
- else
204
- raise RuntimeError.new "Wrong architecture for ARM64"
205
- end
206
- end
207
- end
208
- module BuilderHelper
209
- def section_start(name, file_name="")
210
- Elf::Policy.section_symbol_name(file_name,name).tap{|x| @policy.imported_symbols[x] = true}
211
- end
212
- end
213
- class TagBuilder
214
- include BuilderHelper
215
- attr_accessor :ranges
216
- def initialize(pol)
217
- @policy = pol
218
- @ranges = []
219
- end
220
- def section(name,file_name="")
221
- range(section_start(name,file_name))
222
- end
223
- def range(low,high=nil)
224
- @ranges << MemoryRange.new(low,high)
225
- end
226
- def symbol(sym)
227
- range(sym)
228
- end
229
- end
230
- class DataBuilder
231
- include BuilderHelper
232
- def initialize(transition)
233
- @transition = transition
234
- end
235
- def read(v=true) #TODO: Unify transitions? Intervaltree?
236
- @transition.read = v
237
- end
238
- def write(v=true)
239
- @transition.write = v
240
- @transition.read ||= v
241
- end
242
- def exec(v=true)
243
- @transition.exec = v
244
- @transition.read ||= v
245
- end
246
- end
247
- class StateBuilder
248
- include BuilderHelper
249
- def initialize(from,to,pol)
250
- @from = from
251
- @to = to
252
- @policy = pol
253
- end
254
-
255
- {
256
- text: ".text",
257
- data: ".data",
258
- bss:".bss"
259
- }.each{|function,name|
260
- define_method function, lambda{|library=''| section(name,library)}
261
- }
262
- def call(symbol, parambytes= 0, returnbytes=0)
263
- raise RuntimeError.new "Call has to have a destination" if @from == @to
264
- @policy << Call.new(@from,@to, symbol, parambytes, returnbytes)
265
- end
266
- def call_noreturn(symbol,parambytes=0)
267
- call(symbol, parambytes,-1)
268
- end
269
- def mem(tag, &block)
270
- d = Data.new(@from,@to,tag)
271
- DataBuilder.new(d).instance_eval(&block)
272
- @policy << d
273
- end
274
- def exec(tag)
275
- mem(tag){
276
- exec }
277
- end
278
- def read(tag)
279
- mem(tag){
280
- read
281
- }
282
- end
283
- def write(tag)
284
- mem(tag){
285
- write
286
- }
287
- end
288
- def readwrite(tag)
289
- mem(tag){
290
- read
291
- write
292
- }
293
- end
294
-
295
- def to(name,&block)
296
- raise RuntimeError.new "Cannot nest to{} blocks" if @from != @to# or name == @from
297
- StateBuilder.new(@from,name, @policy).instance_eval(&block)
298
- end
299
- def transition(trans)
300
- @policy << trans
301
- end
302
- end
303
- class PolicyBuilder
304
- include BuilderHelper
305
- attr_reader :policy
306
- def initialize()
307
- @policy = Policy.new()
308
- end
309
- def state(name, &block)
310
- StateBuilder.new(name,name,@policy).instance_eval(&block)
311
- end
312
- def tag(name, &block)
313
- policy.tags[name] ||= []
314
- x =TagBuilder.new(@policy)
315
- x.instance_eval(&block)
316
- policy.tags[name] += x.ranges
317
- end
318
- def call_noreturn(from,to,symbol, parambytes=0)
319
- @policy << Call.new(from,to, symbol, parambytes,-1)
320
- end
321
- def read
322
- @policy << Data.new(from,to,from,to )
323
- end
324
- def start(name)
325
- @policy.start = name
326
- end
327
- end
328
- def self.build(&block)
329
- x= PolicyBuilder.new()
330
- x.instance_eval(&block)
331
- x.policy
332
- end
333
- end
334
-
335
- end
4
+ require_relative 'policy/dsl'
5
+ require_relative 'policy/inject_policy'
6
+ require_relative 'policy/defaults'
@@ -0,0 +1,9 @@
1
+ module Elf::Policy::Hacks
2
+ def self.initializer_functions(filename)
3
+ lib = `objdump -D #{filename} | grep -B 3 'callq.*libc_start_main' `
4
+ init_addr = /\$0x([0-9a-f]*),\%r8/.match(lib)[1].to_i(16)
5
+ fini_addr = /\$0x([0-9a-f]*),\%rcx/.match(lib)[1].to_i(16)
6
+ main_addr = /\$0x([0-9a-f]*),\%rdi/.match(lib)[1].to_i(16)
7
+ [init_addr,fini_addr,main_addr]
8
+ end
9
+ end
@@ -0,0 +1,59 @@
1
+ module Elf::Policy::Generator
2
+ H= Elf::Policy::Hacks
3
+ TwoState = Proc.new {|file,filename|
4
+
5
+ tag('program') do
6
+ section('.init')
7
+ section('.fini')
8
+ section('.text')
9
+ section('.plt')
10
+ section('.data')
11
+ section('.bss')
12
+ section('.rodata')
13
+ section('.got')
14
+ end
15
+ tag('libraries') do
16
+ section('.plt')
17
+ # libs.each do |lib|
18
+ # section('.text',lib)
19
+ # section('.plt',lib)
20
+ # section('.data',lib)
21
+ # section('.bss',lib)
22
+ # section('.rodata',lib)
23
+ # section('.plt',lib)
24
+ # section('.got.plt',lib)
25
+ # end
26
+ end
27
+ state('main') do
28
+ exec 'program'
29
+ readwrite 'libraries'
30
+ readwrite 'program'
31
+ readwrite :default
32
+ to('libs') do
33
+ plt = file.progbits.select{|x|x.name==".plt"}.first
34
+ (plt.addr .. (plt.addr + plt.size)).step(8).each do |plt_addr| #FIXME: This is a
35
+ #hack
36
+ call plt_addr
37
+ end
38
+ end
39
+ to('libs') do
40
+ call '_dl_runtime_resolve'
41
+ end
42
+ end
43
+ state('libs') do
44
+ exec 'libraries'
45
+ readwrite 'libraries'
46
+ readwrite 'program'
47
+ readwrite :default
48
+ exec :default # Really, this sucks
49
+ to 'main' do
50
+ call file.entry.to_i
51
+ H::initializer_functions(filename).each {|initializer|
52
+ call initializer
53
+ }
54
+ call '_fini'
55
+ end
56
+ end
57
+ start 'libs'
58
+ }
59
+ end
@@ -0,0 +1,2 @@
1
+ require_relative 'default/hacks'
2
+ require_relative 'default/twostate'
@@ -0,0 +1,338 @@
1
+ module Elf
2
+
3
+ module Policy
4
+ def self.section_symbol_name(file_name,section_name)
5
+ "_elfp_#{file_name}_#{section_name}"
6
+ end
7
+ R = ElfFlags::Relocation
8
+ ELFP = ElfFlags::ElfPData
9
+ class Transition
10
+ attr_accessor :from, :to
11
+ end
12
+ class Call < Transition
13
+ attr_accessor :symbol
14
+ attr_accessor :parambytes,:returnbytes
15
+ def initialize(from,to, symbol, parambytes, returnbytes)
16
+ @from, @to, @symbol, @parambytes, @returnbytes = from,to, symbol, parambytes, returnbytes
17
+ end
18
+ def allows_return?
19
+ @returnbytes >= 0
20
+ end
21
+ end
22
+ class Data < Transition
23
+ attr_accessor :tag
24
+ attr_accessor :read,:write, :exec
25
+ def initialize(from,to,tag , read=false ,write=false,exec=false)
26
+ @from, @to, @tag, @read,@write,@exec = from,to,tag,read,write,exec
27
+ end
28
+ end
29
+ class MemoryRange
30
+ attr_accessor :low, :high
31
+ def initialize(from,to)
32
+ @low,@high = from,to
33
+ end
34
+ end
35
+ class Policy
36
+ attr_accessor :data, :calls, :start, :tags
37
+ attr_accessor :imported_symbols
38
+ def states
39
+ t = data.keys + data.values.map(&:keys).flatten + calls.map(&:from) +
40
+ calls.map(&:to)
41
+ t.uniq
42
+ end
43
+ def <<(*transitions)
44
+ transitions.each do |t|
45
+ if t.is_a? Data
46
+ x= data
47
+ x[t.from] ||= {}
48
+ x[t.from][t.to] ||= {}
49
+ x[t.from][t.to][t.tag] ||= t
50
+ x[t.from][t.to][t.tag].read ||= t.read
51
+ x[t.from][t.to][t.tag].write ||= t.write
52
+ x[t.from][t.to][t.tag].exec ||= t.exec
53
+ elsif t.is_a? Call
54
+ calls << t
55
+ else
56
+ raise ArgumentError.new "#{t.class} is not a valid transition"
57
+ end
58
+ end
59
+ end
60
+ def initialize
61
+ @data={}
62
+ @calls=[]
63
+ @states ={}
64
+ @tags = {}
65
+ @imported_symbols = {}
66
+ end
67
+ def resolve_reference(elffile, relocations,offset, ref)
68
+ if(ref.is_a? Integer)
69
+ ref.to_i
70
+ elsif(ref == "_dl_runtime_resolve") #HACK:HACK:HACK: I couldn't hack ld.so to fix this, so
71
+ #here comes a nasty hack
72
+ #note that the address of _dl_runtime_resolve is 16 bytes into PLT.GOT
73
+ if !elffile.symbols.include? "_elfp_hidden_trampolineaddr"
74
+ pltgot = elffile.dynamic.pltgot or raise RuntimeError.new "No plt.got for _dl_runtime_resolve hack"
75
+ elffile.symbols << Elf::Symbol.new("_elfp_hidden_trampolineaddr", pltgot,STT::STT_OBJECT,16, STB::STB_LOCAL,8)
76
+ end
77
+ symb = elffile.symbols["_elfp_hidden_trampolineaddr"]
78
+ relocations << Elf::Relocation.new.tap{|x|
79
+ x.type = R::R_X86_64_COPY
80
+ x.offset = offset
81
+ x.symbol = symb
82
+ x.is_dynamic = true
83
+ x.addend = 0
84
+ }
85
+ 0xDEADBEEF
86
+ else
87
+ raise RuntimeError.new "Symbol #{ref} not found" unless elffile.symbols.include? ref
88
+ relocations << Elf::Relocation.new.tap{|x|
89
+ x.type = R::R_X86_64_64
90
+ x.offset = offset
91
+ x.symbol = elffile.symbols[ref]
92
+ x.is_dynamic = true
93
+ x.addend = 0
94
+ }
95
+ 2**64-1
96
+ end
97
+ end
98
+ def resolve_size(elffile,relocations, offset, ref)
99
+ if(ref.is_a? Integer)
100
+ ref.to_i
101
+ else
102
+ raise RuntimeError.new "Symbol #{ref} not found" unless elffile.symbols.include? ref
103
+ relocations << Elf::Relocation.new.tap{|x|
104
+ x.type = R::R_X86_64_SIZE64
105
+ x.offset = offset
106
+ x.symbol = elffile.symbols[ref]
107
+ x.is_dynamic = true
108
+ x.addend = 0
109
+ }
110
+ 2**64-1
111
+ end
112
+ end
113
+ def write_amd64(elffile)
114
+ factory = ElfStructFactory.instance(:little,64)
115
+ @imported_symbols.each_key {|symbol|
116
+ if elffile.symbols.include?(symbol)
117
+ elffile.symbols[symbol].is_dynamic = true
118
+ else
119
+ elffile.symbols << Elf::Symbol.new(symbol,nil,Elf::STT::STT_OBJECT, 0, Elf::STB::STB_GLOBAL, 0).tap {|x|
120
+ x.semantics = Elf::SHN::SHN_UNDEF
121
+ }
122
+ end
123
+ }
124
+ out = factory.elfp_header.new()
125
+ state_ids = {}
126
+ tag_ids = {}
127
+ relocations = []
128
+ states = states()
129
+ @start = states.first unless states.include? @start
130
+ #These have to be filled in the order in which they are written
131
+ #FIXME: Make these aware of double transitions to the same range/ state
132
+ states.each_with_index do |state,index|
133
+ id = index + 2
134
+ id = 1 if @start == state
135
+ out.states << factory.elfp_state.new.tap {|x|
136
+ x.id = id
137
+ x.stackid = 0
138
+ }
139
+ state_ids[state] = id
140
+ print "State #{state} #{id}\n"
141
+ end
142
+ tag_ids[:default] = 0
143
+ @tags.each_with_index do |(name,ranges),index|
144
+ tag_ids[name] = index+1
145
+ ranges.each do |data|
146
+ out.tags << factory.elfp_tag.new.tap {|x|
147
+ x.tag = index + 1
148
+ x.addr = 0
149
+ x.siz = 0
150
+ }
151
+ out.tags.last.tap {|x|
152
+ x.addr = resolve_reference(elffile,relocations,x.addr.offset,data.low)
153
+ if data.high.nil?
154
+ x.siz = resolve_size(elffile,relocations,x.siz.offset,data.low)
155
+ else
156
+ pp "Warning, emitting SIZE symbol with value #{ data.high.to_i rescue data.high.name}"
157
+ x.siz = resolve_reference(elffile,relocations,x.siz.offset,data.high)
158
+ end
159
+ }
160
+ end
161
+ print "Tag #{name} #{index + 1} \n"
162
+ end
163
+ self.calls.each do |call|
164
+ out.calls << factory.elfp_call.new.tap {|x|
165
+ x.from = state_ids[call.from]
166
+ x.to = state_ids[call.to]
167
+ x.parambytes = call.parambytes
168
+ x.returnbytes = call.parambytes
169
+ }
170
+ out.calls.last.off = resolve_reference(elffile,relocations,out.calls.last.off.offset, call.symbol)
171
+ end
172
+ self.data.values.map(&:values).flatten.map(&:values).flatten.each do |data|
173
+ out.data << factory.elfp_data.new.tap {|x|
174
+ x.from = state_ids[data.from]
175
+ x.to = state_ids[data.to]
176
+ x.type = 0
177
+ x.type |= ELFP::ELFP_RW_READ if data.read
178
+ x.type |= ELFP::ELFP_RW_WRITE if data.write
179
+ x.type |= ELFP::ELFP_RW_EXEC if data.exec
180
+ raise RuntimeError.new "Unknown tag #{data.tag}" unless tag_ids.include? data.tag
181
+ x.tag = tag_ids[data.tag]
182
+ }
183
+ end
184
+ out = Elf::ProgBits.new(".elfbac",nil,out.to_binary_s)
185
+ out.align = 8
186
+ out.flags = SHF::SHF_ALLOC | SHF::SHF_WRITE
187
+ out.sect_type = SHT::SHT_PROGBITS
188
+ out.phdr = ElfFlags::PhdrType::PT_ELFBAC
189
+ out.phdr_flags = ElfFlags::PhdrFlags::PF_R
190
+ relocations.each { |rel|
191
+ rel.section = out
192
+ elffile.relocations << rel
193
+ }
194
+ elffile.progbits << out
195
+
196
+ end
197
+ def inject(file)
198
+ case file.machine
199
+ when ElfFlags::Machine::EM_X86_64
200
+ write_amd64(file)
201
+ else
202
+ raise RuntimeError.new "Wrong architecture for ARM64"
203
+ end
204
+ end
205
+ end
206
+ module BuilderHelper
207
+ def section_start(name, file_name="")
208
+ Elf::Policy.section_symbol_name(file_name,name).tap{|x| @policy.imported_symbols[x] = true}
209
+ end
210
+ end
211
+ class TagBuilder
212
+ include BuilderHelper
213
+ attr_accessor :ranges
214
+ def initialize(pol)
215
+ @policy = pol
216
+ @ranges = []
217
+ end
218
+ def section(name,file_name="")
219
+ range(section_start(name,file_name))
220
+ end
221
+ def range(low,high=nil)
222
+ @ranges << MemoryRange.new(low,high)
223
+ end
224
+ def symbol(sym)
225
+ range(sym)
226
+ end
227
+ end
228
+ class DataBuilder
229
+ include BuilderHelper
230
+ def initialize(transition)
231
+ @transition = transition
232
+ end
233
+ def read(v=true) #TODO: Unify transitions? Intervaltree?
234
+ @transition.read = v
235
+ end
236
+ def write(v=true)
237
+ @transition.write = v
238
+ @transition.read ||= v
239
+ end
240
+ def exec(v=true)
241
+ @transition.exec = v
242
+ @transition.read ||= v
243
+ end
244
+ end
245
+ class StateBuilder
246
+ include BuilderHelper
247
+ def initialize(from,to,pol)
248
+ @from = from
249
+ @to = to
250
+ @policy = pol
251
+ end
252
+
253
+ {
254
+ text: ".text",
255
+ data: ".data",
256
+ bss:".bss"
257
+ }.each{|function,name|
258
+ define_method function, lambda{|library=''| section(name,library)}
259
+ }
260
+ def call(symbol, parambytes= 0, returnbytes=0)
261
+ raise RuntimeError.new "Call has to have a destination" if @from == @to
262
+ @policy << Call.new(@from,@to, symbol, parambytes, returnbytes)
263
+ end
264
+ def call_noreturn(symbol,parambytes=0)
265
+ call(symbol, parambytes,-1)
266
+ end
267
+ def mem(tag, &block)
268
+ d = Data.new(@from,@to,tag)
269
+ DataBuilder.new(d).instance_eval(&block)
270
+ @policy << d
271
+ end
272
+ def exec(tag)
273
+ mem(tag){
274
+ exec }
275
+ end
276
+ def read(tag)
277
+ mem(tag){
278
+ read
279
+ }
280
+ end
281
+ def write(tag)
282
+ mem(tag){
283
+ write
284
+ }
285
+ end
286
+ def readwrite(tag)
287
+ mem(tag){
288
+ read
289
+ write
290
+ }
291
+ end
292
+
293
+ def to(name,&block)
294
+ raise RuntimeError.new "Cannot nest to{} blocks" if @from != @to# or name == @from
295
+ StateBuilder.new(@from,name, @policy).instance_eval(&block)
296
+ end
297
+ def transition(trans)
298
+ @policy << trans
299
+ end
300
+ end
301
+ class PolicyBuilder
302
+ include BuilderHelper
303
+ attr_reader :policy
304
+ def initialize()
305
+ @policy = Policy.new()
306
+ @every_state = []
307
+ end
308
+ def state(name, &block)
309
+ StateBuilder.new(name,name,@policy).tap {|x|
310
+ x.instance_eval(&block)
311
+ @every_state.each {|b|
312
+ x.instance_eval(b)
313
+ }
314
+ }
315
+ end
316
+ def tag(name, &block)
317
+ policy.tags[name] ||= []
318
+ x =TagBuilder.new(@policy)
319
+ x.instance_eval(&block)
320
+ policy.tags[name] += x.ranges
321
+ end
322
+ def every_state(&block)
323
+ @every_state << block
324
+ @policy.state
325
+ end
326
+ def start(name)
327
+ @policy.start = name
328
+ end
329
+
330
+ end
331
+ def self.build(&block)
332
+ x= PolicyBuilder.new()
333
+ x.instance_eval(&block)
334
+ x.policy
335
+ end
336
+ end
337
+
338
+ end
@@ -0,0 +1,18 @@
1
+ module Elf
2
+ class ElfFile
3
+ def build_policy(&builder)
4
+ #TODO: Allow special 'default_generator' synthax instead of instance_exec
5
+ Elf::Policy::inject_symbols(self)
6
+ p = Elf::Policy.build(&builder)
7
+ p.inject(self)
8
+ end
9
+ end
10
+ def self.policy(&block)
11
+ #TODO: optional arg?
12
+ Elf::rewrite(ARGV[0]) do |file|
13
+ file.build_policy do
14
+ instance_exec(file,&block)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -1,3 +1,3 @@
1
1
  module Mithril
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.4"
3
3
  end
@@ -85,6 +85,11 @@ module Elf
85
85
  def [](idx)
86
86
  @sections[idx]
87
87
  end
88
+ def to_s
89
+ out = "Layout\n"
90
+ @layout.each {|key,value| out << "#{key.to_s(16)} #{value.end.to_s(16)} #{value.name}\n"}
91
+ out
92
+ end
88
93
  def add(*sections) #Ordering as follows: Fixed
89
94
  #(non-nil vaddrs) go where they have to go
90
95
  # Flexible sections are added to lowest hole after section of
@@ -10,10 +10,10 @@ Gem::Specification.new do |spec|
10
10
  spec.email = ["jbangert@acm.org"]
11
11
  spec.description = %q{In Soviet Russia, Mithril forges Elf}
12
12
  spec.summary = %q{The Mithril toolkit for canonical elf manipulation}
13
- spec.homepage = ""
13
+ spec.homepage = "https://github.com/jbangert/mithril"
14
14
  spec.license = "MIT"
15
15
 
16
- spec.files = `git ls-files`.split($/)
16
+ spec.files = `git ls-files`.split($/).select{|i| !i[/\.pdf$/] }
17
17
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: elf-mithril
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-09-12 00:00:00.000000000 Z
12
+ date: 2013-11-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -149,6 +149,11 @@ files:
149
149
  - lib/mithril/inject_symbols.rb
150
150
  - lib/mithril/parser.rb
151
151
  - lib/mithril/policy.rb
152
+ - lib/mithril/policy/default/hacks.rb
153
+ - lib/mithril/policy/default/twostate.rb
154
+ - lib/mithril/policy/defaults.rb
155
+ - lib/mithril/policy/dsl.rb
156
+ - lib/mithril/policy/inject_policy.rb
152
157
  - lib/mithril/version.rb
153
158
  - lib/mithril/writer.rb
154
159
  - lib/mithril/writer2.rb
@@ -163,7 +168,7 @@ files:
163
168
  - tools/gnu_elf_hash_test.cxx
164
169
  - tools/hash_test
165
170
  - tools/hash_test.c
166
- homepage: ''
171
+ homepage: https://github.com/jbangert/mithril
167
172
  licenses:
168
173
  - MIT
169
174
  post_install_message: