rubypwn 0.0.9 → 0.0.10

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.
Files changed (5) hide show
  1. checksums.yaml +4 -4
  2. data/docs/source/elf.rst +30 -7
  3. data/lib/elf.rb +119 -97
  4. data/rubypwn.gemspec +1 -1
  5. metadata +1 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 664749222c6cda64b3f8b081695a1253a0cecd02
4
- data.tar.gz: 59e480b3859aee5e5a101dd59cff5a1526125c97
3
+ metadata.gz: 8c0d72fc09f9d7adca8c1e58494f061c2901d9cf
4
+ data.tar.gz: aadbaee90c0108328029d26591102a21f9933305
5
5
  SHA512:
6
- metadata.gz: 17ca9d90c0f7f3dadd28c4dff5758f25e65f49ec5968ba8f33b39f40c145b349656ead4150c70fdcf7bf7bc2622644f6cc47014dd2890a20db5d5cf12e9db58a
7
- data.tar.gz: a03a8798cea1f3ee0157a6bd39308a7c2e29a22f04d707879d959a54038ea0cd3a24eeb8c28e78d4e480c4fd595c1fa38044fa8d5891887590e41f8246005b65
6
+ metadata.gz: 93d38f069c3aeb10fe0fb5a0c8fc973c6b502259e666b7ac7852fa39aa551893a2c6f8c6376d2d3d8189f0b3c180a533611754212439dee124b4eba88f5b6bbf
7
+ data.tar.gz: f8ce8a3d75a3233bb100e68e679e475b468aafa518bef24ccebcdae7decd8a42936c32a5b409ef98f75ee86259a870893e5190c381edae0b5eb372a68ecef406
data/docs/source/elf.rst CHANGED
@@ -3,12 +3,35 @@ class Elf
3
3
 
4
4
  Used to get some constant value from the binary::
5
5
 
6
+ 2.2.0 :001 > require 'pp'
6
7
  2.2.0 :001 > require 'rubypwn'
7
8
  => true
8
- 2.2.0 :002 > e = Elf.new "/lib/i386-linux-gnu/libc.so.6"
9
- 2.2.0 :003 > e.gotplt.keys
10
- => ["_Unwind_Find_FDE", "realloc", "malloc", "memalign", "_dl_find_dso_for_object", "calloc", "___tls_get_addr", "free", ""]
11
- 2.2.0 :004 > e.gotplt["malloc"]
12
- => 1744916
13
- 2.2.0 :005 > puts "%08x" % e.gotplt["malloc"]
14
- 001aa014
9
+ 2.2.0 :002 > e = Elf.new "traveller"
10
+ 2.2.2 :005 > pp Elf.new "traveller"
11
+ #<Elf:0x007fdd23c3b510
12
+ @arch="x86",
13
+ @bits=32,
14
+ @dynamic=
15
+ {"strtab"=>134513496,
16
+ "symtab"=>134513160,
17
+ "rel_type"=>"REL",
18
+ "jmprel"=>134513844},
19
+ @global={"__gmon_start__"=>{"offset"=>134521192, "value"=>0}},
20
+ @got=
21
+ {"__errno_location"=>134521208,
22
+ "sigemptyset"=>134521212,
23
+ "getpid"=>134521216,
24
+ "__gmon_start__"=>134521220,
25
+ "__isoc99_sscanf"=>134521224,
26
+ "fgets"=>134521228,
27
+ "__libc_start_main"=>134521232,
28
+ "sigaltstack"=>134521236,
29
+ "siglongjmp"=>134521240,
30
+ "sigaction"=>134521244,
31
+ "strlen"=>134521248,
32
+ "printf"=>134521252,
33
+ "setvbuf"=>134521256,
34
+ "puts"=>134521260,
35
+ "kill"=>134521264,
36
+ "__sigsetjmp"=>134521268,
37
+ "exit"=>134521272}>
data/lib/elf.rb CHANGED
@@ -1,5 +1,17 @@
1
1
  require 'bindata'
2
2
 
3
+ class Dynamic32 < BinData::Record
4
+ endian :little
5
+ int32 :d_tag
6
+ uint32 :d_val
7
+ end
8
+
9
+ class Dynamic64 < BinData::Record
10
+ endian :little
11
+ int64 :d_tag
12
+ uint64 :d_val
13
+ end
14
+
3
15
  class Symtab32 < BinData::Record
4
16
  endian :little
5
17
  int32 :st_name #/* Symbol name (string tbl index) */
@@ -87,6 +99,7 @@ class Relaplt64 < BinData::Record
87
99
  r_info & 0xffffffff
88
100
  end
89
101
  end
102
+
90
103
  class ElfParser < BinData::Record
91
104
  endian :little
92
105
  # magic number
@@ -126,26 +139,7 @@ class ElfParser < BinData::Record
126
139
  # Section header string table index
127
140
  int16 :e_shstrndx
128
141
  skip :length => lambda{e_shoff - e_ehsize}
129
- # Program header table
130
- #array :ph, :initial_length => :e_phnum do
131
- #int32 :p_type
132
- ## Segment bit mask (RWX)
133
- #int32 :p_flags
134
- ## Segment file offset
135
- #choice :p_offset, :selection => lambda{e_ident.ei_class}, :choices => {1 => :int32le, 2 => :int64le}
136
- ## Segment virtual address
137
- #choice :p_vaddr, :selection => lambda{e_ident.ei_class}, :choices => {1 => :int32le, 2 => :int64le}
138
- ## Segment physical address
139
- #choice :p_paddr, :selection => lambda{e_ident.ei_class}, :choices => {1 => :int32le, 2 => :int64le}
140
- ## Segment size in file
141
- #choice :p_filesz, :selection => lambda{e_ident.ei_class}, :choices => {1 => :int32le, 2 => :int64le}
142
- ## Segment size in memory
143
- #choice :p_memsz, :selection => lambda{e_ident.ei_class}, :choices => {1 => :int32le, 2 => :int64le}
144
- ## Segment alignment
145
- #choice :p_align, :selection => lambda{e_ident.ei_class}, :choices => {1 => :int32le, 2 => :int64le}
146
- ##string :p_segment, :read_length => lambda{p_filesz - e_phentsize}
147
- #end
148
- # Contains index of the section header tab entry that contains the section names.
142
+
149
143
  array :sh, :initial_length => lambda{e_shnum} do
150
144
  # Section name (string tbl index)
151
145
  int32 :sh_name
@@ -179,22 +173,6 @@ class ElfParser < BinData::Record
179
173
  array 1, :type => :symtab32, :initial_length => 0
180
174
  array 2, :type => :symtab64, :initial_length => 0
181
175
  end
182
- choice :relplt, :selection => lambda{e_ident.ei_class} do
183
- array 1, :type => :relplt32, :initial_length => 0
184
- array 2, :type => :relplt64, :initial_length => 0
185
- end
186
- choice :relaplt, :selection => lambda{e_ident.ei_class} do
187
- array 1, :type => :relaplt32, :initial_length => 0
188
- array 2, :type => :relaplt64, :initial_length => 0
189
- end
190
- choice :reldyn, :selection => lambda{e_ident.ei_class} do
191
- array 1, :type => :relplt32, :initial_length => 0
192
- array 2, :type => :relplt64, :initial_length => 0
193
- end
194
- choice :reladyn, :selection => lambda{e_ident.ei_class} do
195
- array 1, :type => :relaplt32, :initial_length => 0
196
- array 2, :type => :relaplt64, :initial_length => 0
197
- end
198
176
 
199
177
  def parse_bits(ei_class)
200
178
  ei_class == 1 ? 32 : 64
@@ -292,24 +270,34 @@ class ElfParser < BinData::Record
292
270
  end
293
271
 
294
272
  class Elf
295
- attr_accessor :gotplt
273
+ #attr_accessor :gotplt
274
+ attr_accessor :arch, :bits, :dynamic, :got, :global
296
275
 
297
276
  def initialize(file)
298
277
  # To avoid unicode
299
278
  binary = File.read(file).force_encoding('binary')
300
279
  # To fix bugs leading eof, that's why here is a newline ...
301
- @elf = ElfParser.read binary + "\n"
302
- # Section name assignment
303
- assign_section_name binary, @elf
304
- # parse symbol table
305
- parse_symtab binary, @elf
306
- # parse rel.plt
307
- parse_relplt binary, @elf
308
- @gotplt = gen_gotplt @elf
280
+ elf = ElfParser.read binary + "\n"
281
+ # parse information we need
282
+ extract_info binary, elf
309
283
  end
310
284
 
311
285
  private
312
- def assign_section_name(binary, elf)
286
+
287
+ def extract_info(binary, elf)
288
+ @arch = elf.arch.to_s
289
+ @bits = elf.bits.to_i
290
+ # parse section name
291
+ parse_section_name binary, elf
292
+ # parse symbol table
293
+ parse_symtab binary, elf
294
+ # Parse dynamic section
295
+ parse_dynamic_constant binary, elf
296
+ ## parse rel.plt
297
+ parse_relplt binary, elf
298
+ end
299
+
300
+ def parse_section_name(binary, elf)
313
301
  strtab_offset = elf.sh[elf.e_shstrndx].sh_offset.to_i
314
302
  strtab = binary[(strtab_offset)..-1]
315
303
  elf.e_shnum.times do |i|
@@ -318,6 +306,42 @@ class Elf
318
306
  end
319
307
  end
320
308
 
309
+ def parse_dynamic_constant(binary, elf)
310
+ dynamic = nil
311
+ elf.e_shnum.times do |i|
312
+ content = binary[elf.sh[i].sh_offset, elf.sh[i].sh_size]
313
+ if elf.sh[i].sh_type == 6 # DYNAMIC
314
+ size = elf.sh[i].sh_size / elf.sh[i].sh_entsize
315
+ if @bits == 32
316
+ dynamic = BinData::Array.new(:type => :dynamic32, :initial_length => size)
317
+ else
318
+ dynamic = BinData::Array.new(:type => :dynamic64, :initial_length => size)
319
+ end
320
+ dynamic.read content
321
+ end
322
+ end
323
+ @dynamic = {}
324
+ dynamic.each do |d|
325
+ # PLTREL
326
+ if d.d_tag == 20
327
+ if d.d_val == 7
328
+ @dynamic["rel_type"]= "RELA"
329
+ elsif d.d_val == 17
330
+ @dynamic["rel_type"]= "REL"
331
+ end
332
+ # STRTAB
333
+ elsif d.d_tag == 5
334
+ @dynamic["strtab"]= d.d_val.to_i
335
+ # SYMTAB
336
+ elsif d.d_tag == 6
337
+ @dynamic["symtab"]= d.d_val.to_i
338
+ # JMPREL
339
+ elsif d.d_tag == 0x17
340
+ @dynamic["jmprel"]= d.d_val.to_i
341
+ end
342
+ end
343
+ end
344
+
321
345
  def parse_symtab(binary, elf)
322
346
  # find dynamic symtab
323
347
  symtab = nil
@@ -350,67 +374,65 @@ class Elf
350
374
  end
351
375
 
352
376
  def parse_relplt(binary, elf)
353
- plt = nil
377
+ rel = nil
378
+ reldyn = nil
354
379
  elf.e_shnum.times do |i|
355
- if elf.sh[i].name_str.to_s == ".rel.plt"
356
- size = elf.sh[i].sh_size/elf.sh[i].sh_entsize
357
- if elf.e_ident[:ei_class] == 1
358
- plt = BinData::Array.new(:type => :relplt32, :initial_length => size)
359
- else
360
- plt = BinData::Array.new(:type => :relplt64, :initial_length => size)
361
- end
362
- elf.relplt.assign plt.read binary[elf.sh[i].sh_offset, elf.sh[i].sh_size]
363
- elsif elf.sh[i].name_str.to_s == ".rel.dyn"
364
- size = elf.sh[i].sh_size/elf.sh[i].sh_entsize
365
- if elf.e_ident[:ei_class] == 1
366
- plt = BinData::Array.new(:type => :relplt32, :initial_length => size)
367
- else
368
- plt = BinData::Array.new(:type => :relplt64, :initial_length => size)
369
- end
370
- elf.reldyn.assign plt.read binary[elf.sh[i].sh_offset, elf.sh[i].sh_size]
371
- elsif elf.sh[i].name_str.to_s == ".rela.plt"
372
- size = elf.sh[i].sh_size/elf.sh[i].sh_entsize
373
- if elf.e_ident[:ei_class] == 1
374
- plt = BinData::Array.new(:type => :relaplt32, :initial_length => size)
375
- else
376
- plt = BinData::Array.new(:type => :relaplt64, :initial_length => size)
380
+ if @dynamic["rel_type"] == "REL"
381
+ if elf.sh[i].name_str == ".rel.plt"
382
+ size = elf.sh[i].sh_size/elf.sh[i].sh_entsize
383
+ if elf.e_ident[:ei_class] == 1
384
+ rel = BinData::Array.new(:type => :relplt32, :initial_length => size)
385
+ else
386
+ rel = BinData::Array.new(:type => :relplt64, :initial_length => size)
387
+ end
388
+ rel.read binary[elf.sh[i].sh_offset, elf.sh[i].sh_size]
389
+ elsif elf.sh[i].name_str == ".rel.dyn"
390
+ size = elf.sh[i].sh_size/elf.sh[i].sh_entsize
391
+ if @bits == 32
392
+ reldyn = BinData::Array.new(:type => :relplt32, :initial_length => size)
393
+ else
394
+ reldyn = BinData::Array.new(:type => :relplt64, :initial_length => size)
395
+ end
396
+ reldyn.read binary[elf.sh[i].sh_offset, elf.sh[i].sh_size]
377
397
  end
378
- elf.relaplt.assign plt.read binary[elf.sh[i].sh_offset, elf.sh[i].sh_size]
379
- elsif elf.sh[i].name_str.to_s == ".rela.dyn"
380
- size = elf.sh[i].sh_size/elf.sh[i].sh_entsize
381
- if elf.e_ident[:ei_class] == 1
382
- plt = BinData::Array.new(:type => :relaplt32, :initial_length => size)
383
- else
384
- plt = BinData::Array.new(:type => :relaplt64, :initial_length => size)
398
+ elsif @dynamic["rel_type"] == "RELA"
399
+ if elf.sh[i].name_str == ".rela.plt"
400
+ size = elf.sh[i].sh_size/elf.sh[i].sh_entsize
401
+ if @bits == 32
402
+ rel = BinData::Array.new(:type => :relaplt32, :initial_length => size)
403
+ else
404
+ rel = BinData::Array.new(:type => :relaplt64, :initial_length => size)
405
+ end
406
+ rel.read binary[elf.sh[i].sh_offset, elf.sh[i].sh_size]
407
+ elsif elf.sh[i].name_str == ".rela.dyn"
408
+ size = elf.sh[i].sh_size/elf.sh[i].sh_entsize
409
+ if @bits == 32
410
+ reldyn = BinData::Array.new(:type => :relaplt32, :initial_length => size)
411
+ else
412
+ reldyn = BinData::Array.new(:type => :relaplt64, :initial_length => size)
413
+ end
414
+ reldyn.read binary[elf.sh[i].sh_offset, elf.sh[i].sh_size]
385
415
  end
386
- elf.reladyn.assign plt.read binary[elf.sh[i].sh_offset, elf.sh[i].sh_size]
387
416
  end
388
417
  end
389
- end
390
-
391
- def gen_gotplt(elf)
392
- result = {}
393
- rel = nil
394
418
 
395
- elf.relplt.each do |r|
396
- result[elf.symtab[r.sym_index.to_i].name_str.to_s] = r.r_offset.to_i
397
- end
398
-
399
- elf.relaplt.each do |r|
400
- result[elf.symtab[r.sym_index.to_i].name_str.to_s] = r.r_offset.to_i
401
- end
402
-
403
- elf.reldyn.each do |r|
404
- result[elf.symtab[r.sym_index.to_i].name_str.to_s] = elf.symtab[r.sym_index.to_i].st_value.to_i
419
+ # extract information
420
+ @got = {}
421
+ rel.each do |r|
422
+ if r.type.to_i == 7 # JMP_SLOT
423
+ @got[elf.symtab[r.sym_index.to_i].name_str.to_s] = r.r_offset.to_i
424
+ end
405
425
  end
406
-
407
- elf.reladyn.each do |r|
408
- result[elf.symtab[r.sym_index.to_i].name_str.to_s] = elf.symtab[r.sym_index.to_i].st_value.to_i
426
+ @global = Hash.new {|h, k| h[k] = Hash.new}
427
+ reldyn.each do |r|
428
+ if r.type.to_i == 6 # GLOB_DAT
429
+ @global[elf.symtab[r.sym_index.to_i].name_str.to_s]["offset"] = r.r_offset.to_i
430
+ @global[elf.symtab[r.sym_index.to_i].name_str.to_s]["value"] = elf.symtab[r.sym_index.to_i].st_value.to_i
431
+ end
409
432
  end
410
- result
411
433
  end
412
434
  end
413
435
 
414
436
  #require 'pp'
415
437
  #e = Elf.new ARGV[0]
416
- #pp e.gotplt["__free_hook"]
438
+ #pp e
data/rubypwn.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'rubypwn'
3
- s.version = '0.0.9'
3
+ s.version = '0.0.10'
4
4
  s.date = '2015-09-06'
5
5
  s.summary = "ruby pwn tools"
6
6
  s.description = <<-DESCRIPTION.strip.gsub(/\s+/, " ")
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubypwn
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.9
4
+ version: 0.0.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - atdog