heapinfo 1.0.2 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +7 -4
- data/lib/heapinfo/arena.rb +5 -3
- data/lib/heapinfo/cache.rb +3 -3
- data/lib/heapinfo/chunk.rb +4 -1
- data/lib/heapinfo/dumper.rb +18 -17
- data/lib/heapinfo/glibc/free.rb +1 -1
- data/lib/heapinfo/helper.rb +3 -2
- data/lib/heapinfo/nil.rb +1 -1
- data/lib/heapinfo/process.rb +21 -11
- data/lib/heapinfo/process_info.rb +6 -3
- data/lib/heapinfo/segment.rb +11 -0
- data/lib/heapinfo/version.rb +1 -1
- metadata +18 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b734871451b91231d5c1c159633f1de9ad3255bb
|
4
|
+
data.tar.gz: 2742c1043b6466cad49415191c9753819e499e2d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 93861f6cd8f05a68666e2e67caff87d810f784f42aac009a4db4ca7b90031dc792a6643f780f316e7e5b43211e34c18eb5bd4a9dab3634dfad44a17d43c9de24
|
7
|
+
data.tar.gz: e6349ece2cba17b12af3daafb2a62dad995e4a03b0ca83e33a35661ed6985db16cc26e4d50810dedc411ceef497537c964a2804c84a081887cddd3cb1159f4f1
|
data/README.md
CHANGED
@@ -9,7 +9,7 @@
|
|
9
9
|
## HeapInfo
|
10
10
|
As pwn lovers, while playing CTF with heap exploitation, we always need a debugger (e.g. gdb) for tracking memory layout. But we don't really need gdb if we want to see whether the heap layout same as our imagine or not. Hope this small tool helps us exploit easier ;).
|
11
11
|
|
12
|
-
|
12
|
+
### Why
|
13
13
|
**HeapInfo** is very helpful when binary has somehow anti-debugger limitations, e.g being ptraced.
|
14
14
|
**HeapInfo** still works because it doesn't use ptrace.
|
15
15
|
|
@@ -17,9 +17,7 @@ Implement with ruby because I love ruby :P. But might also implement with Python
|
|
17
17
|
|
18
18
|
If you prefer [pwntools](https://github.com/Gallopsled/pwntools) for exploiting, you can still use **HeapInfo** in irb/pry as a small debugger.
|
19
19
|
|
20
|
-
Any suggestion of features or bug issues
|
21
|
-
|
22
|
-
Related works are [pwntools-ruby](https://github.com/peter50216/pwntools-ruby) and [gdbpwn](https://github.com/scwuaptx/Pwngdb).
|
20
|
+
Any suggestion of features or bug issues are welcome.
|
23
21
|
|
24
22
|
## Install
|
25
23
|
**HeapInfo** is still under developing for more features, so the version might change frequently :p
|
@@ -156,12 +154,17 @@ h.find(/E.F/, 0x400000, 4)
|
|
156
154
|
#=> 4194305 # 0x400001
|
157
155
|
h.find(/E.F/, 0x400000, 3)
|
158
156
|
#=> nil
|
157
|
+
|
158
|
+
# Get relative offset of searching result
|
159
|
+
h.find('/bin/sh', :libc, rel: true)
|
160
|
+
#=> 1622391 # 0x18c177
|
159
161
|
h.offset(h.find('/bin/sh', :libc))
|
160
162
|
# 0x18c177 after libc
|
161
163
|
```
|
162
164
|
|
163
165
|
## Tests
|
164
166
|
**HeapInfo** currently only run tests on ubuntu, followings are tested glibc versions:
|
167
|
+
|
165
168
|
* libc-2.19
|
166
169
|
* libc-2.23
|
167
170
|
* libc-2.24
|
data/lib/heapinfo/arena.rb
CHANGED
@@ -47,8 +47,8 @@ module HeapInfo
|
|
47
47
|
f
|
48
48
|
end
|
49
49
|
@unsorted_bin = UnsortedBin.new(size_t, top_ptr_offset, @dumper, head: true)
|
50
|
-
@smallbin = Array.new(
|
51
|
-
s = Smallbin.new(size_t, @base + 8 + size_t * (
|
50
|
+
@smallbin = Array.new(62) do |idx|
|
51
|
+
s = Smallbin.new(size_t, @base + 8 + size_t * (12 + 2 * idx), @dumper, head: true)
|
52
52
|
s.index = idx
|
53
53
|
s
|
54
54
|
end
|
@@ -61,7 +61,9 @@ module HeapInfo
|
|
61
61
|
# @return [String] Bin layouts that wrapper with color codes.
|
62
62
|
# @example
|
63
63
|
# puts h.libc.main_arena.layouts(:fast, :unsorted, :small)
|
64
|
+
# puts h.libc.main_arena.layouts(:all)
|
64
65
|
def layouts(*args)
|
66
|
+
args.concat(%i[fast unsort small large]) if args.map(&:to_s).include?('all')
|
65
67
|
args = args.map(&:to_s).join('|')
|
66
68
|
res = ''
|
67
69
|
res += fastbin.map(&:inspect).join if args.include?('fast')
|
@@ -227,7 +229,7 @@ module HeapInfo
|
|
227
229
|
# Mapping index of smallbin to chunk size.
|
228
230
|
# @return [Integer] size
|
229
231
|
def idx_to_size
|
230
|
-
index * size_t * 2 + size_t *
|
232
|
+
index * size_t * 2 + size_t * 4
|
231
233
|
end
|
232
234
|
end
|
233
235
|
|
data/lib/heapinfo/cache.rb
CHANGED
@@ -38,8 +38,8 @@ module HeapInfo
|
|
38
38
|
filepath = realpath(key)
|
39
39
|
return unless File.file?(filepath)
|
40
40
|
Marshal.load(IO.binread(filepath))
|
41
|
-
rescue
|
42
|
-
nil # handle if file content invalid
|
41
|
+
rescue TypeError, ArgumentError
|
42
|
+
nil # handle if file content is invalid
|
43
43
|
end
|
44
44
|
|
45
45
|
# Clear the cache directory.
|
@@ -53,7 +53,7 @@ module HeapInfo
|
|
53
53
|
# @return [void]
|
54
54
|
def init
|
55
55
|
FileUtils.mkdir_p(CACHE_DIR)
|
56
|
-
rescue
|
56
|
+
rescue Errno::EACCES
|
57
57
|
# To prevent ~/ is not writable.
|
58
58
|
send(:remove_const, :CACHE_DIR)
|
59
59
|
const_set(:CACHE_DIR, File.join(HeapInfo::TMP_DIR, '.cache/heapinfo'))
|
data/lib/heapinfo/chunk.rb
CHANGED
@@ -27,7 +27,10 @@ module HeapInfo
|
|
27
27
|
@size_t = size_t
|
28
28
|
@base = base
|
29
29
|
sz = dump(@base, size_t * 2)
|
30
|
-
|
30
|
+
if head # no need to read size if is bin
|
31
|
+
@data = dump(@base + size_t * 2, size_t * 4)
|
32
|
+
return
|
33
|
+
end
|
31
34
|
@prev_size = Helper.unpack(size_t, sz[0, size_t])
|
32
35
|
@size = Helper.unpack(size_t, sz[size_t..-1])
|
33
36
|
r_size = [size - size_t * 2, size_t * 4].min # don't read too much data
|
data/lib/heapinfo/dumper.rb
CHANGED
@@ -30,7 +30,7 @@ module HeapInfo
|
|
30
30
|
mem = file.readpartial len
|
31
31
|
file.close
|
32
32
|
mem
|
33
|
-
rescue => e
|
33
|
+
rescue => e # rubocop:disable Style/RescueStandardError
|
34
34
|
raise e if e.is_a? ArgumentError
|
35
35
|
nil
|
36
36
|
end
|
@@ -67,6 +67,8 @@ module HeapInfo
|
|
67
67
|
puts str
|
68
68
|
end
|
69
69
|
|
70
|
+
# @api private
|
71
|
+
#
|
70
72
|
# Search a specific value/string/regexp in memory.
|
71
73
|
# +#find+ only return the first matched address.
|
72
74
|
# @param [Integer, String, Regexp] pattern
|
@@ -75,22 +77,25 @@ module HeapInfo
|
|
75
77
|
# Start address for searching, can be segment(+Symbol+)
|
76
78
|
# or segments with offset. See examples for more information.
|
77
79
|
# @param [Integer] length The length limit for searching.
|
80
|
+
# @param [Boolean] rel Return relative or absolute.
|
78
81
|
# @return [Integer, nil] The first matched address, +nil+ is returned when no such pattern found.
|
79
82
|
# @example
|
80
|
-
# find(/E.F/, :elf)
|
83
|
+
# find(/E.F/, :elf, false)
|
81
84
|
# #=> 4194305
|
82
|
-
# find(0x4141414141414141, 'heap+0x10', 0x1000)
|
85
|
+
# find(0x4141414141414141, 'heap+0x10', 0x1000, false)
|
83
86
|
# #=> 6291472
|
84
|
-
# find('/bin/sh', :libc)
|
85
|
-
# #=>
|
86
|
-
def find(pattern, from, length)
|
87
|
+
# find('/bin/sh', :libc, true)
|
88
|
+
# #=> 1622391 # 0x18c177
|
89
|
+
def find(pattern, from, length, rel)
|
87
90
|
from = base_of(from)
|
88
91
|
length = 1 << 40 if length.is_a? Symbol
|
89
|
-
case pattern
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
92
|
+
ret = case pattern
|
93
|
+
when Integer then find_integer(pattern, from, length)
|
94
|
+
when String then find_string(pattern, from, length)
|
95
|
+
when Regexp then find_regexp(pattern, from, length)
|
96
|
+
end
|
97
|
+
ret -= from if ret && rel
|
98
|
+
ret
|
94
99
|
end
|
95
100
|
|
96
101
|
private
|
@@ -107,12 +112,8 @@ module HeapInfo
|
|
107
112
|
def dumpable?
|
108
113
|
mem_f.close
|
109
114
|
true
|
110
|
-
rescue
|
111
|
-
|
112
|
-
false
|
113
|
-
else
|
114
|
-
throw e
|
115
|
-
end
|
115
|
+
rescue Errno::EACCES, Errno::ENOENT
|
116
|
+
false
|
116
117
|
end
|
117
118
|
|
118
119
|
def mem_f
|
data/lib/heapinfo/glibc/free.rb
CHANGED
@@ -25,7 +25,7 @@ module HeapInfo
|
|
25
25
|
# The original method in C is too long, split to multiple methods to match ruby convention.
|
26
26
|
# @param [HeapInfo::Arena] av
|
27
27
|
# @param [Integer] ptr Use <tt>ptr</tt> instead of <tt>p</tt> to prevent confusing with ruby native method.
|
28
|
-
def int_free(av, ptr)
|
28
|
+
def int_free(av, ptr)
|
29
29
|
chunk = dumper.call(ptr, size_t * 2).to_chunk
|
30
30
|
size = ulong chunk.size
|
31
31
|
invalid_pointer(ptr, size)
|
data/lib/heapinfo/helper.rb
CHANGED
@@ -1,15 +1,16 @@
|
|
1
1
|
require 'dentaku'
|
2
2
|
require 'shellwords'
|
3
|
+
require 'time'
|
3
4
|
|
4
5
|
module HeapInfo
|
5
6
|
# Some helper functions.
|
6
7
|
module Helper
|
7
8
|
# Create read +/proc/[pid]/*+ methods.
|
8
|
-
%w
|
9
|
+
%w[exe maps auxv].each do |method|
|
9
10
|
define_singleton_method("#{method}_of".to_sym) do |pid|
|
10
11
|
begin
|
11
12
|
IO.binread("/proc/#{pid}/#{method}")
|
12
|
-
rescue
|
13
|
+
rescue Errno::ENOENT
|
13
14
|
throw "reading /proc/#{pid}/#{method} error"
|
14
15
|
end
|
15
16
|
end
|
data/lib/heapinfo/nil.rb
CHANGED
@@ -4,7 +4,7 @@ module HeapInfo
|
|
4
4
|
# Can be the return value of {HeapInfo::Process#dump} and {HeapInfo::Process#dump_chunks},
|
5
5
|
# to prevent use the return value for calculating accidentally while exploiting remote.
|
6
6
|
class Nil
|
7
|
-
%i
|
7
|
+
%i[nil? inspect to_s].each do |method_sym|
|
8
8
|
define_method(method_sym) { |*args, &block| nil.send(method_sym, *args, &block) }
|
9
9
|
end
|
10
10
|
|
data/lib/heapinfo/process.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# encoding: ascii-8bit
|
2
|
+
|
2
3
|
module HeapInfo
|
3
4
|
# Main class of heapinfo.
|
4
5
|
class Process
|
@@ -20,9 +21,9 @@ module HeapInfo
|
|
20
21
|
load!
|
21
22
|
end
|
22
23
|
|
23
|
-
# Reload a new process with same program name
|
24
|
+
# Reload a new process with same program name.
|
24
25
|
#
|
25
|
-
# @return [HeapInfo::Process] return +self+
|
26
|
+
# @return [HeapInfo::Process] return +self+ so that this method is chainable.
|
26
27
|
# @example
|
27
28
|
# puts h.reload!
|
28
29
|
def reload!
|
@@ -30,6 +31,7 @@ module HeapInfo
|
|
30
31
|
load!
|
31
32
|
self
|
32
33
|
end
|
34
|
+
alias reload reload!
|
33
35
|
|
34
36
|
# Use this method to wrapper all HeapInfo methods.
|
35
37
|
#
|
@@ -111,11 +113,14 @@ module HeapInfo
|
|
111
113
|
segment = @info.send(sym) if HeapInfo::ProcessInfo::EXPORT.include?(sym)
|
112
114
|
segment = nil unless segment.is_a?(HeapInfo::Segment)
|
113
115
|
if segment.nil?
|
114
|
-
sym, segment = @info.segments
|
116
|
+
sym, segment = @info.segments
|
117
|
+
.select { |_, seg| seg.base <= addr }
|
118
|
+
.min_by { |_, seg| addr - seg }
|
115
119
|
end
|
116
120
|
return puts "Invalid address #{Helper.hex(addr)}" if segment.nil?
|
117
|
-
puts Helper.color(Helper.hex(addr - segment
|
121
|
+
puts Helper.color(Helper.hex(addr - segment)) + ' after ' + Helper.color(sym, sev: :sym)
|
118
122
|
end
|
123
|
+
alias off offset
|
119
124
|
|
120
125
|
# Gdb-like command
|
121
126
|
#
|
@@ -153,6 +158,8 @@ module HeapInfo
|
|
153
158
|
# @param [Integer] length
|
154
159
|
# The search length limit, default is unlimited,
|
155
160
|
# which will search until pattern found or reach unreadable memory.
|
161
|
+
# @param [Boolean] rel
|
162
|
+
# To show relative offset of +from+ or absolute address.
|
156
163
|
# @return [Integer, nil] The first matched address, +nil+ is returned when no such pattern found.
|
157
164
|
# @example
|
158
165
|
# h.find(0xdeadbeef, 'heap+0x10', 0x1000)
|
@@ -161,12 +168,13 @@ module HeapInfo
|
|
161
168
|
# #=> 4194305 # 0x400001
|
162
169
|
# h.find(/E.F/, 0x400000, 3)
|
163
170
|
# #=> nil
|
164
|
-
# sh_offset = h.find('/bin/sh', :libc) - h.libc
|
171
|
+
# sh_offset = h.find('/bin/sh', :libc) - h.libc
|
165
172
|
# #=> 1559771 # 0x17ccdb
|
166
|
-
|
173
|
+
# h.find('/bin/sh', :libc, rel: true) == h.find('/bin/sh', :libc) - h.libc
|
174
|
+
# #=> true
|
175
|
+
def find(pattern, from, length = :unlimited, rel: false)
|
167
176
|
return Nil.new unless load?
|
168
|
-
|
169
|
-
dumper.find(pattern, from, length)
|
177
|
+
dumper.find(pattern, from, length, rel)
|
170
178
|
end
|
171
179
|
|
172
180
|
# +search+ is more intutive to me
|
@@ -215,19 +223,21 @@ module HeapInfo
|
|
215
223
|
|
216
224
|
# Make pry not so verbose.
|
217
225
|
#
|
218
|
-
# @return [
|
226
|
+
# @return [String]
|
219
227
|
def inspect
|
220
|
-
|
228
|
+
format('#<HeapInfo::Process:0x%016x>', __id__)
|
221
229
|
end
|
222
230
|
|
223
231
|
private
|
224
232
|
|
225
233
|
attr_accessor :dumper
|
234
|
+
|
226
235
|
def load?
|
227
236
|
@pid != nil
|
228
237
|
end
|
229
238
|
|
230
|
-
|
239
|
+
# try to load
|
240
|
+
def load!
|
231
241
|
return true if @pid
|
232
242
|
@pid = fetch_pid
|
233
243
|
return clear_process if @pid.nil? # still can't load
|
@@ -1,4 +1,5 @@
|
|
1
1
|
# encoding: ascii-8bit
|
2
|
+
|
2
3
|
module HeapInfo
|
3
4
|
# For {Process} to record basic process information.
|
4
5
|
#
|
@@ -7,7 +8,7 @@ module HeapInfo
|
|
7
8
|
class ProcessInfo
|
8
9
|
# Methods to be transparent to +process+.
|
9
10
|
# e.g. +process.libc+ alias to +process.info.libc+.
|
10
|
-
EXPORT = %i
|
11
|
+
EXPORT = %i[libc ld heap program elf stack bits auxv].freeze
|
11
12
|
|
12
13
|
# @return [Integer] 32 or 64.
|
13
14
|
attr_reader :bits
|
@@ -47,8 +48,10 @@ module HeapInfo
|
|
47
48
|
# Heap will not be mmapped if the process not use heap yet, so create a lazy loading method.
|
48
49
|
# Will re-read maps when heap segment not found yet.
|
49
50
|
#
|
51
|
+
# Special handling here because heap might not be initialized in the beginning.
|
52
|
+
#
|
50
53
|
# @return [HeapInfo::Segment] The {Segment} of heap.
|
51
|
-
def heap
|
54
|
+
def heap
|
52
55
|
@heap ||= Segment.find(load_maps, '[heap]')
|
53
56
|
end
|
54
57
|
|
@@ -70,7 +73,7 @@ module HeapInfo
|
|
70
73
|
def parse_auxv(str)
|
71
74
|
auxv = {}
|
72
75
|
sio = StringIO.new(str)
|
73
|
-
fetch = ->
|
76
|
+
fetch = -> { Helper.unpack(@bits / 8, sio.read(@bits / 8)) }
|
74
77
|
loop do
|
75
78
|
type = fetch.call
|
76
79
|
val = fetch.call
|
data/lib/heapinfo/segment.rb
CHANGED
@@ -19,6 +19,17 @@ module HeapInfo
|
|
19
19
|
format("%-28s\tbase @ #{Helper.color(format('%#x', base))}\n", Helper.color(name.split('/')[-1]))
|
20
20
|
end
|
21
21
|
|
22
|
+
# To support +addr - h.libc+.
|
23
|
+
# Treat all operations are manipulating on +base+.
|
24
|
+
#
|
25
|
+
# @param [Object] other
|
26
|
+
# Any object.
|
27
|
+
#
|
28
|
+
# @return [(Object, Integer)]
|
29
|
+
def coerce(other)
|
30
|
+
[other, base]
|
31
|
+
end
|
32
|
+
|
22
33
|
# Helper for creating a {HeapInfo::Segment}.
|
23
34
|
#
|
24
35
|
# Search the specific <tt>pattern</tt> in <tt>maps</tt> and return a {HeapInfo::Segment} object.
|
data/lib/heapinfo/version.rb
CHANGED
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: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- david942j
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-01-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dentaku
|
@@ -25,75 +25,75 @@ dependencies:
|
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '2'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: codeclimate-test-reporter
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '0.6'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '0.6'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
42
|
+
name: rake
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
47
|
+
version: '12.3'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
54
|
+
version: '12.3'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: rspec
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
61
|
+
version: '3.7'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
68
|
+
version: '3.7'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
70
|
+
name: rubocop
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: 0.
|
75
|
+
version: '0.52'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: 0.
|
82
|
+
version: '0.52'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
84
|
+
name: simplecov
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
87
|
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version:
|
89
|
+
version: 0.13.0
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version:
|
96
|
+
version: 0.13.0
|
97
97
|
description: |
|
98
98
|
Create an interactive memory info interface while pwn / exploiting.
|
99
99
|
Useful for rubiers writing exploit scripts.
|
@@ -145,7 +145,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
145
145
|
version: '0'
|
146
146
|
requirements: []
|
147
147
|
rubyforge_project:
|
148
|
-
rubygems_version: 2.6.
|
148
|
+
rubygems_version: 2.6.14
|
149
149
|
signing_key:
|
150
150
|
specification_version: 4
|
151
151
|
summary: HeapInfo - interactive heap exploitation helper
|