elf-mithril 0.0.1 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: