heapinfo 0.0.2 → 0.0.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fd09327165de603d3fa3350e9022d8bf642a1f7c
4
- data.tar.gz: 5c1dd70e46c5fad709e187c25a8347be8262586e
3
+ metadata.gz: e90a4db825f5e6b53989edc82441a0800d13aaa7
4
+ data.tar.gz: f638662fb165a7c884c5427b378cfac091ebe83a
5
5
  SHA512:
6
- metadata.gz: 6827c2c7129162b716046200e71cdba7475de9edad4a1880b0aec374c3e9a5649c6a2ae934566097794671bc1c30d255e4fed9142e6a1de4b95a914f3c8c5ee1
7
- data.tar.gz: 82bfd1db1bca104fa62d54e7c14a63ad91d2a208dfa346d8a23464141d9767e1f9d18dda21dfd106a840d2799c92c3d4dad2a78893b4bcbc224aa9c415f38692
6
+ metadata.gz: f2356a124a5a9480e2e170f6abb2ee782f671734d4e7edbe2f15f47f690609a40580ac1d3d8f027342d03a82901c996b32d9dc21dccb4473105f027814149503
7
+ data.tar.gz: 3e3df55aca650bf6c8277185afdf56bb3f9c4e3ded9ec444af64f6159302aa9eb5d001da0f3f7dac82d174348c5e8af5b4340abfa1a5cca6f205a7936fa640b0
@@ -3,22 +3,25 @@ module HeapInfo
3
3
  class Arena
4
4
  # @return [Array<HeapInfo::Fastbin>] Fastbins in an array.
5
5
  attr_reader :fastbin
6
- # @return [Array<HeapInfo::UnsortedBin>] The unsorted bin (only one).
6
+ # @return [HeapInfo::Chunk] Current top chunk.
7
+ attr_reader :top_chunk
8
+ # @return [HeapInfo::Chunk] Current last remainder.
9
+ attr_reader :last_remainder
10
+ # @return [Array<HeapInfo::UnsortedBin>] The unsorted bin (array size will always be one).
7
11
  attr_reader :unsorted_bin
8
12
  # @return [Array<HeapInfo::Smallbin>] Smallbins in an array.
9
13
  attr_reader :smallbin
10
- # @return [HeapInfo::Chunk] Current top chunk.
11
- attr_reader :top_chunk
14
+ # @return [Integer] The <tt>system_mem</tt>
15
+ attr_reader :system_mem
12
16
  # attr_reader :largebin, :last_remainder
13
17
 
14
18
  # Instantiate a <tt>HeapInfo::Arena</tt> object.
15
19
  #
16
20
  # @param [Integer] base Base address of arena.
17
- # @param [Integer] bits Either 64 or 32
21
+ # @param [Integer] size_t Either 8 or 4
18
22
  # @param [Proc] dumper For dump more data
19
- def initialize(base, bits, dumper)
20
- @base, @dumper = base, dumper
21
- @size_t = bits / 8
23
+ def initialize(base, size_t, dumper)
24
+ @base, @size_t, @dumper = base, size_t, dumper
22
25
  reload!
23
26
  end
24
27
 
@@ -26,16 +29,19 @@ module HeapInfo
26
29
  # Retrive data using <tt>@dumper</tt>, load bins, top chunk etc.
27
30
  # @return [HeapInfo::Arena] self
28
31
  def reload!
29
- top_ptr = Helper.unpack(size_t, @dumper.call(@base + 8 + size_t * 10, size_t))
32
+ top_ptr_offset = @base + 8 + size_t * 10
33
+ top_ptr = Helper.unpack(size_t, @dumper.call(top_ptr_offset, size_t))
30
34
  @fastbin = []
31
35
  return self if top_ptr == 0 # arena not init yet
32
36
  @top_chunk = Chunk.new size_t, top_ptr, @dumper
37
+ @last_remainder = Chunk.new size_t, top_ptr_offset + 8, @dumper
38
+ @system_mem = Helper.unpack(size_t, @dumper.call(top_ptr_offset + 258 * size_t + 16, size_t))
33
39
  @fastbin = Array.new(7) do |idx|
34
40
  f = Fastbin.new(size_t, @base + 8 - size_t * 2 + size_t * idx, @dumper, head: true)
35
41
  f.index = idx
36
42
  f
37
43
  end
38
- @unsorted_bin = UnsortedBin.new(size_t, @base + 8 + size_t * 10, @dumper, head: true)
44
+ @unsorted_bin = UnsortedBin.new(size_t, top_ptr_offset, @dumper, head: true)
39
45
  @smallbin = Array.new(55) do |idx|
40
46
  s = Smallbin.new(size_t, @base + 8 + size_t * (26 + 2 * idx), @dumper, head: true)
41
47
  s.index = idx
@@ -61,6 +61,27 @@ module HeapInfo
61
61
  flag
62
62
  end
63
63
 
64
+ # Ask if chunk not belongs to main arena.
65
+ #
66
+ # @return [Boolean] <tt>true|false</tt> if chunk not belongs to main arena
67
+ def non_main_arena?
68
+ flags.include? :non_main_arena
69
+ end
70
+
71
+ # Ask if chunk is mmapped.
72
+ #
73
+ # @return [Boolean] <tt>true|false</tt> if chunk is mmapped
74
+ def mmapped?
75
+ flags.include? :mmapped
76
+ end
77
+
78
+ # Ask if chunk has set the prev-inuse bit.
79
+ #
80
+ # @return [Boolean] <tt>true|false</tt> if the <tt>prev_inuse</tt> bit has been set
81
+ def prev_inuse?
82
+ flags.include? :prev_inuse
83
+ end
84
+
64
85
  # Size of chunk
65
86
  # @return [Integer] The chunk size without flag masks
66
87
  def size
@@ -0,0 +1,11 @@
1
+ module HeapInfo
2
+ module Glibc
3
+ # @abstract Exceptions raised by HeapInfo inherit from Error
4
+ class Error < StandardError; end
5
+ # Exception raised in malloc.c(malloc, free, etc.) methods.
6
+ class MallocError < Error; end
7
+ def malloc_assert(condition)
8
+ raise MallocError.new(yield) unless condition
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,77 @@
1
+ # Implment glibc's free-related functions
2
+ # [Reference](https://code.woboq.org/userspace/glibc/malloc/malloc.c.html)
3
+ module HeapInfo
4
+ module Glibc
5
+ # Implmentation of <tt>void __libc_free(void *mem)</tt>.
6
+ # [Source](https://code.woboq.org/userspace/glibc/malloc/malloc.c.html#__libc_free)
7
+ # @param [Integer] mem Memory address to be free.
8
+ def libc_free(mem)
9
+ # TODO: free_hook
10
+ mem = ulong mem
11
+ return if mem == 0 # free(0) has no effect
12
+ ptr = mem2chunk(mem)
13
+ return munmap_chunk(ptr) if chunk_is_mmapped(ptr)
14
+ av = arena_for_chunk(ptr)
15
+ int_free(av, ptr)
16
+ end
17
+ alias :free :libc_free
18
+
19
+ private
20
+ # Implmentation of <tt>void _int_free (mstate av, mchunkptr p, [int have_lock])</tt>.
21
+ # [Source](https://code.woboq.org/userspace/glibc/malloc/malloc.c.html#_int_free)
22
+ #
23
+ # The original method in C is too long, split to multiple methods to match ruby convention.
24
+ # @param [HeapInfo::Arena] av
25
+ # @param [Integer] ptr Use <tt>ptr</tt> instead of <tt>p</tt> to prevent confusing with ruby native method.
26
+ def int_free(av, ptr) # is have_lock important?
27
+ chunk = dumper.call(ptr, size_t * 2).to_chunk
28
+ size = ulong chunk.size
29
+ invalid_pointer(ptr, size)
30
+ invalid_size(size)
31
+ # check_inuse_chunk # off
32
+ if size <= get_max_fast
33
+ int_free_fast(av, ptr, size)
34
+ elsif !chunk_is_mmapped(ptr) # Though this has been checked in #libc_free
35
+ int_free_small(av, ptr, size)
36
+ else
37
+ munmap_chunk(ptr)
38
+ end
39
+ end
40
+
41
+ def int_free_fast(av, ptr, size)
42
+ invalid_next_size(:fast, av, ptr, size)
43
+ true
44
+ end
45
+
46
+ def int_free_small(av, ptr, size)
47
+ true
48
+ end
49
+
50
+ def munmap_chunk(ptr)
51
+ # TODO: check page alignment and... page exists?
52
+ true
53
+ end
54
+
55
+ # Start of checkers
56
+
57
+ def invalid_pointer(ptr, size)
58
+ errmsg = "free(): invalid pointer\n"
59
+ # unsigned compare
60
+ malloc_assert(ptr <= ulong(-size)) { errmsg + "ptr(0x%x) > -size(0x%x)" % [ptr, ulong(-size)] }
61
+ malloc_assert(ptr % (size_t * 2) == 0) { errmsg + "ptr(0x%x) %% %d != 0" % [ptr, size_t * 2] }
62
+ end
63
+
64
+ def invalid_size(size)
65
+ errmsg = "free(): invalid size\n"
66
+ malloc_assert(size >= min_chunk_size) { errmsg + "size(0x%x) < min_chunk_size(0x%x)" % [size, min_chunk_size] }
67
+ malloc_assert(aligned_ok size) { errmsg + "alignment error: size(0x%x) %% 0x%x != 0" % [size, size_t * 2] }
68
+ end
69
+
70
+ def invalid_next_size(type, av, ptr, size)
71
+ errmsg = "free(): invalid next size (#{type})\n"
72
+ nxt_chk = dumper.call(ptr + size, size_t * 2).to_chunk(base: ptr + size)
73
+ malloc_assert(nxt_chk.size > 2 * size_t) { errmsg + "next chunk(0x%x) has size(#{nxt_chk.size}) <= 2 * #{size_t}" % nxt_chk.base }
74
+ malloc_assert(nxt_chk.size < av.system_mem) { errmsg + "next chunk(0x%x) has size(0x%x) >= av.system_mem(0x%x)" % [nxt_chk.base, nxt_chk.size, av.system_mem] }
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,11 @@
1
+ module HeapInfo
2
+ module Glibc
3
+ attr_accessor :size_t
4
+ private
5
+ attr_accessor :main_arena
6
+ attr_accessor :dumper
7
+ end
8
+ end
9
+ require 'heapinfo/glibc/error.rb'
10
+ require 'heapinfo/glibc/helper.rb'
11
+ require 'heapinfo/glibc/free.rb'
@@ -0,0 +1,44 @@
1
+ module HeapInfo
2
+ module Glibc
3
+ private
4
+ def mem2chunk(mem)
5
+ ulong(mem - 2 * size_t)
6
+ end
7
+
8
+ # @return [Boolean]
9
+ def chunk_is_mmapped(ptr)
10
+ # TODO: handle memory not accessible
11
+ dumper.call(ptr, size_t * 2).to_chunk.mmapped?
12
+ end
13
+
14
+ def get_max_fast
15
+ size_t * 16
16
+ end
17
+
18
+ # The minimal chunk size.
19
+ # Not the real implmentation, maybe wrong some day?
20
+ # @return [Integer] The size.
21
+ def min_chunk_size
22
+ size_t * 4
23
+ end
24
+
25
+ # Not the real implmentation, maybe wrong some day?
26
+ # @return [Boolean]
27
+ def aligned_ok(size)
28
+ size & (2 * size_t - 1) == 0
29
+ end
30
+
31
+ # @return [Integer]
32
+ def ulong(n)
33
+ n % 2 ** (size_t * 8)
34
+ end
35
+
36
+ # @return [HeapInfo::Arena]
37
+ def arena_for_chunk(ptr)
38
+ # not support arena other than initial main_arena
39
+ return if dumper.call(ptr, size_t * 2).to_chunk.non_main_arena?
40
+ main_arena
41
+ end
42
+
43
+ end
44
+ end
@@ -93,6 +93,16 @@ module HeapInfo
93
93
  data.unpack(size_t == 4 ? 'L*' : 'Q*')[0]
94
94
  end
95
95
 
96
+ # Convert number in hex format
97
+ #
98
+ # @param [Integer] num Non-negative integer.
99
+ # @return [String] number in hex format.
100
+ # @example
101
+ # HeapInfo::Helper.hex(1000) # => '0x3e8'
102
+ def self.hex(num)
103
+ '0x' + num.to_s(16)
104
+ end
105
+
96
106
  # Retrieve pure class name(without module) of an object
97
107
  # @param [Object] obj Any instance
98
108
  # @return [String] Class name of <tt>obj</tt>
data/lib/heapinfo/libc.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  module HeapInfo
2
2
  # Record libc's base, name, and offsets.
3
3
  class Libc < Segment
4
-
4
+ include HeapInfo::Glibc
5
5
  # Instantiate a <tt>HeapInfo::Libc</tt> object.
6
6
  #
7
7
  # @param [Mixed] args See <tt>#HeapInfo::Segment.initialize</tt> for more information.
@@ -24,21 +24,25 @@ module HeapInfo
24
24
  return @main_arena.reload! if @main_arena
25
25
  off = main_arena_offset
26
26
  return if off.nil?
27
- @main_arena = Arena.new(off + self.base, process.bits, process.method(:dump))
27
+ @main_arena = Arena.new(off + self.base, size_t, dumper)
28
28
  end
29
29
 
30
30
  # @param [Array] maps See <tt>#HeapInfo::Segment.find</tt> for more information.
31
31
  # @param [String] name See <tt>#HeapInfo::Segment.find</tt> for more information.
32
- # @param [HeapInfo::Process] process The process.
32
+ # @param [Integer] bits Either 64 or 32.
33
+ # @param [String] ld_name The loader's realpath, will be used for running subprocesses.
34
+ # @param [Proc] dumper The memory dumper for fetch more information.
33
35
  # @return [HeapInfo::Libc] libc segment found in maps.
34
- def self.find(maps, name, process)
36
+ def self.find(maps, name, bits, ld_name, dumper)
35
37
  obj = super(maps, name)
36
- obj.send(:process=, process)
38
+ obj.size_t = bits / 8
39
+ obj.send(:ld_name=, ld_name)
40
+ obj.send(:dumper=, dumper)
37
41
  obj
38
42
  end
39
43
 
40
44
  private
41
- attr_accessor :process
45
+ attr_accessor :ld_name
42
46
  # only for searching offset of main_arena now
43
47
  def exhaust_search(symbol)
44
48
  return false if symbol != :main_arena
@@ -58,9 +62,9 @@ module HeapInfo
58
62
  tmp_elf = HeapInfo::TMP_DIR + "/get_arena"
59
63
  libc_file = HeapInfo::TMP_DIR + "/libc.so.6"
60
64
  ld_file = HeapInfo::TMP_DIR + "/ld.so"
61
- flags = "-w #{@process.bits == 32 ? '-m32' : ''}"
65
+ flags = "-w #{size_t == 4 ? '-m32' : ''}"
62
66
  %x(cp #{self.name} #{libc_file} && \
63
- cp #{@process.ld.name} #{ld_file} && \
67
+ cp #{ld_name} #{ld_file} && \
64
68
  gcc #{flags} #{File.expand_path('../tools/get_arena.c', __FILE__)} -o #{tmp_elf} 2>&1 > /dev/null && \
65
69
  #{ld_file} --library-path #{HeapInfo::TMP_DIR} #{tmp_elf} && \
66
70
  rm #{tmp_elf} #{libc_file} #{ld_file}).to_i(16)
@@ -21,6 +21,17 @@ module HeapInfo
21
21
  return unless load?
22
22
  end
23
23
 
24
+ # Reload a new process with same program name
25
+ #
26
+ # @return [HeapInfo::Process] return <tt>self</tt> for chainable.
27
+ # @example
28
+ # puts h.reload!
29
+ def reload!
30
+ @pid = nil
31
+ load!
32
+ self
33
+ end
34
+
24
35
  # Use this method to wrapper all HeapInfo methods.
25
36
  #
26
37
  # Since <tt>::HeapInfo</tt> is a tool(debugger) for local usage,
@@ -164,7 +175,7 @@ module HeapInfo
164
175
  def load! # try to load
165
176
  return true if @pid
166
177
  @pid = fetch_pid
167
- return false if @pid.nil? # still can't load
178
+ return clear_process if @pid.nil? # still can't load
168
179
  load_info!
169
180
  true
170
181
  end
@@ -179,6 +190,13 @@ module HeapInfo
179
190
  pid
180
191
  end
181
192
 
193
+ def clear_process
194
+ ProcessInfo::EXPORT.each do |m|
195
+ self.class.send(:define_method, m) {Nil.new}
196
+ end
197
+ false
198
+ end
199
+
182
200
  def load_info!
183
201
  @info = ProcessInfo.new(self)
184
202
  ProcessInfo::EXPORT.each do |m|
@@ -32,8 +32,8 @@ module HeapInfo
32
32
  @stack = Segment.find(maps, '[stack]')
33
33
  # well.. stack is a strange case because it will grow in runtime..
34
34
  # should i detect stack base growing..?
35
- @libc = Libc.find(maps, match_maps(maps, options[:libc]), process)
36
35
  @ld = Segment.find(maps, match_maps(maps, options[:ld]))
36
+ @libc = Libc.find(maps, match_maps(maps, options[:libc]), @bits, @ld.name, ->(*args){ process.dump(*args) })
37
37
  end
38
38
 
39
39
  # Heap will not be mmapped if the process not use heap yet, so create a lazy loading method.
@@ -1,3 +1,3 @@
1
1
  module HeapInfo
2
- VERSION = '0.0.2'.freeze
2
+ VERSION = '0.0.3'.freeze
3
3
  end
data/lib/heapinfo.rb CHANGED
@@ -63,6 +63,7 @@ require 'heapinfo/cache'
63
63
  require 'heapinfo/process_info'
64
64
  require 'heapinfo/process'
65
65
  require 'heapinfo/segment'
66
+ require 'heapinfo/glibc/glibc'
66
67
  require 'heapinfo/libc'
67
68
  require 'heapinfo/chunk'
68
69
  require 'heapinfo/chunks'
data/spec/libc_spec.rb ADDED
@@ -0,0 +1,54 @@
1
+ # encoding: ascii-8bit
2
+ require 'heapinfo'
3
+ describe HeapInfo::Libc do
4
+ describe 'free' do
5
+ before(:all) do
6
+ HeapInfo::Cache.send :clear_all # force cache miss, to make sure coverage
7
+ @victim = HeapInfo::TMP_DIR + '/victim'
8
+ %x(g++ #{File.expand_path('../files/victim.cpp', __FILE__)} -o #{@victim} 2>&1 > /dev/null)
9
+ pid = fork
10
+ # run without ASLR
11
+ exec "setarch `uname -m` -R /bin/sh -c #{@victim}" if pid.nil?
12
+ loop until `pidof #{@victim}` != ''
13
+ @h = HeapInfo::Process.new(@victim, ld: '/ld')
14
+ @fake_mem = 0x13371000
15
+ @set_memory = ->(str) do
16
+ @h.libc.send(:dumper=, ->(ptr, len){
17
+ if ptr.between?(@fake_mem, @fake_mem + 0x1000)
18
+ str[ptr - @fake_mem, len]
19
+ else
20
+ @h.dump(ptr, len)
21
+ end
22
+ })
23
+ end
24
+ end
25
+ after(:all) do
26
+ `killall #{@victim}`
27
+ FileUtils.rm(@victim)
28
+ end
29
+
30
+ describe 'invalid' do
31
+ it 'invalid pointer' do
32
+ @set_memory.call [0, 0x21, 0x21, 0x0, 0x0].pack("Q*")
33
+ expect {@h.libc.free(@fake_mem + 24)}.to raise_error "free(): invalid pointer\nptr(#{HeapInfo::Helper.hex(@fake_mem + 8)}) % 16 != 0"
34
+ expect {@h.libc.free(@fake_mem + 32)}.to raise_error "free(): invalid pointer\nptr(#{HeapInfo::Helper.hex(@fake_mem + 16)}) > -size(0x0)"
35
+ end
36
+
37
+ it 'invalid size' do
38
+ @set_memory.call [0, 0x11].pack("Q*")
39
+ expect {@h.libc.free(@fake_mem + 16)}.to raise_error "free(): invalid size\nsize(0x10) < min_chunk_size(0x20)"
40
+ @set_memory.call [0, 0x38].pack("Q*")
41
+ expect {@h.libc.free(@fake_mem + 16)}.to raise_error "free(): invalid size\nalignment error: size(0x38) % 0x10 != 0"
42
+ end
43
+ end
44
+
45
+ describe 'fast' do
46
+ it 'invalid next size' do
47
+ @set_memory.call [0, 0x21, 0, 0, 0, 0xf].pack("Q*")
48
+ expect {@h.libc.free(@fake_mem + 16)}.to raise_error "free(): invalid next size (fast)\nnext chunk(#{HeapInfo::Helper.hex(@fake_mem + 32)}) has size(8) <= 2 * 8"
49
+ @set_memory.call [0, 0x21, 0, 0, 0, 0x21000].pack("Q*")
50
+ expect {@h.libc.free(@fake_mem + 16)}.to raise_error "free(): invalid next size (fast)\nnext chunk(#{HeapInfo::Helper.hex(@fake_mem + 32)}) has size(0x21000) >= av.system_mem(0x21000)"
51
+ end
52
+ end
53
+ end
54
+ end
data/spec/process_spec.rb CHANGED
@@ -38,7 +38,7 @@ describe HeapInfo::Process do
38
38
  @io = Cio.new
39
39
  end
40
40
  after(:all) do
41
- %x(killall #{@victim})
41
+ `killall #{@victim}`
42
42
  FileUtils.rm(@victim)
43
43
  end
44
44
 
@@ -84,6 +84,19 @@ describe HeapInfo::Process do
84
84
  end
85
85
  end
86
86
 
87
+ describe 'reload' do
88
+ it 'monkey' do
89
+ prog = File.readlink('/proc/self/exe')
90
+ @h = HeapInfo::Process.new(prog)
91
+ expect(@h.pid.is_a? Integer).to be true
92
+ pid = @h.pid
93
+ @h.instance_variable_set(:@prog, 'NO_THIS')
94
+ expect(@h.reload!.pid).to be nil
95
+ @h.instance_variable_set(:@prog, prog)
96
+ expect(@h.reload!.pid).to be pid
97
+ end
98
+ end
99
+
87
100
  describe 'fastbin' do
88
101
  it 'normal' do
89
102
  expect(@h.libc.main_arena.fastbin[0].list).to eq [0x602020, 0x602000, nil]
@@ -154,5 +167,9 @@ describe HeapInfo::Process do
154
167
  it 'nil chain' do
155
168
  expect(@h.dump(:heap).no_such_method.xdd.nil?).to be true
156
169
  end
170
+
171
+ it 'info methods' do
172
+ expect(@h.libc.base.nil?).to be true
173
+ end
157
174
  end
158
175
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: heapinfo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - david942j
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-05-21 00:00:00.000000000 Z
11
+ date: 2016-12-20 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: create an interactive memory info interface while pwn / exploiting
14
14
  email:
@@ -25,6 +25,10 @@ files:
25
25
  - lib/heapinfo/chunks.rb
26
26
  - lib/heapinfo/dumper.rb
27
27
  - lib/heapinfo/ext/string.rb
28
+ - lib/heapinfo/glibc/error.rb
29
+ - lib/heapinfo/glibc/free.rb
30
+ - lib/heapinfo/glibc/glibc.rb
31
+ - lib/heapinfo/glibc/helper.rb
28
32
  - lib/heapinfo/helper.rb
29
33
  - lib/heapinfo/libc.rb
30
34
  - lib/heapinfo/nil.rb
@@ -41,6 +45,7 @@ files:
41
45
  - spec/files/64bit_maps
42
46
  - spec/files/victim.cpp
43
47
  - spec/helper_spec.rb
48
+ - spec/libc_spec.rb
44
49
  - spec/nil_spec.rb
45
50
  - spec/process_spec.rb
46
51
  - spec/spec_helper.rb
@@ -65,20 +70,21 @@ required_rubygems_version: !ruby/object:Gem::Requirement
65
70
  version: '0'
66
71
  requirements: []
67
72
  rubyforge_project:
68
- rubygems_version: 2.4.8
73
+ rubygems_version: 2.5.2
69
74
  signing_key:
70
75
  specification_version: 4
71
76
  summary: HeapInfo - interactive heap exploitation helper
72
77
  test_files:
73
- - spec/chunk_spec.rb
74
78
  - spec/files/32bit_maps
75
- - spec/files/64bit_maps
76
79
  - spec/files/victim.cpp
77
- - spec/helper_spec.rb
80
+ - spec/files/64bit_maps
78
81
  - spec/cache_spec.rb
82
+ - spec/dumper_spec.rb
83
+ - spec/process_spec.rb
84
+ - spec/chunk_spec.rb
85
+ - spec/chunks_spec.rb
79
86
  - spec/string_spec.rb
80
87
  - spec/spec_helper.rb
88
+ - spec/helper_spec.rb
81
89
  - spec/nil_spec.rb
82
- - spec/chunks_spec.rb
83
- - spec/dumper_spec.rb
84
- - spec/process_spec.rb
90
+ - spec/libc_spec.rb