heapinfo 0.0.0
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 +7 -0
- data/README.md +130 -0
- data/lib/heapinfo.rb +75 -0
- data/lib/heapinfo/arena.rb +193 -0
- data/lib/heapinfo/chunk.rb +96 -0
- data/lib/heapinfo/chunks.rb +20 -0
- data/lib/heapinfo/dumper.rb +204 -0
- data/lib/heapinfo/ext/string.rb +29 -0
- data/lib/heapinfo/helper.rb +123 -0
- data/lib/heapinfo/libc.rb +46 -0
- data/lib/heapinfo/nil.rb +27 -0
- data/lib/heapinfo/process.rb +205 -0
- data/lib/heapinfo/segment.rb +34 -0
- data/lib/heapinfo/tools/get_arena.c +29 -0
- data/lib/heapinfo/version.rb +3 -0
- data/spec/chunk_spec.rb +40 -0
- data/spec/chunks_spec.rb +25 -0
- data/spec/dumper_spec.rb +79 -0
- data/spec/files/32bit_maps +23 -0
- data/spec/files/64bit_maps +29 -0
- data/spec/files/victim.cpp +32 -0
- data/spec/helper_spec.rb +73 -0
- data/spec/nil_spec.rb +15 -0
- data/spec/process_spec.rb +157 -0
- data/spec/spec_helper.rb +98 -0
- data/spec/string_spec.rb +18 -0
- metadata +81 -0
@@ -0,0 +1,205 @@
|
|
1
|
+
#encoding: ascii-8bit
|
2
|
+
module HeapInfo
|
3
|
+
# Main class of heapinfo.
|
4
|
+
class Process
|
5
|
+
# The dafault options of libaries,
|
6
|
+
# use for matching glibc and ld segments in <tt>/proc/[pid]/maps</tt>
|
7
|
+
DEFAULT_LIB = {
|
8
|
+
libc: /libc[^\w]/,
|
9
|
+
ld: /\/ld-.+\.so/,
|
10
|
+
}
|
11
|
+
# @return [Fixnum, NilClass] return the pid of process, <tt>nil</tt> if no such process found
|
12
|
+
attr_reader :pid
|
13
|
+
attr_reader :status
|
14
|
+
|
15
|
+
# Instantiate a <tt>HeapInfo::Process</tt> object
|
16
|
+
# @param [String, Fixnum] prog Process name or pid, see <tt>HeapInfo::heapinfo</tt> for more information
|
17
|
+
# @param [Hash] options libraries' filename, see <tt>HeapInfo::heapinfo</tt> for more information
|
18
|
+
def initialize(prog, options = {})
|
19
|
+
@prog = prog
|
20
|
+
@options = DEFAULT_LIB.merge options
|
21
|
+
load!
|
22
|
+
return unless load?
|
23
|
+
@dumper = Dumper.new(@status, mem_filename)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Use this method to wrapper all HeapInfo methods.
|
27
|
+
#
|
28
|
+
# Since <tt>::HeapInfo</tt> is a tool(debugger) for local usage,
|
29
|
+
# while exploiting remote service, all methods will not work properly.
|
30
|
+
# So I suggest to wrapper all methods inside <tt>#debug</tt>,
|
31
|
+
# which will ignore the block while the victim process is not found.
|
32
|
+
#
|
33
|
+
# @example
|
34
|
+
# h = heapinfo('./victim') # such process doesn't exist
|
35
|
+
# libc_base = leak_libc_base_of_victim # normal exploit
|
36
|
+
# h.debug {
|
37
|
+
# # for local to check if exploit correct
|
38
|
+
# fail('libc_base') unless libc_base == h.libc.base
|
39
|
+
# }
|
40
|
+
# # block of #debug will not execute if can't found process
|
41
|
+
def debug
|
42
|
+
return unless load!
|
43
|
+
yield if block_given?
|
44
|
+
end
|
45
|
+
|
46
|
+
# Dump the content of specific memory address.
|
47
|
+
#
|
48
|
+
# Note: This method require you have permission of attaching another process. If not, a warning message will present.
|
49
|
+
#
|
50
|
+
# @param [Mixed] args Will be parsed into <tt>[base, offset, length]</tt>, see Examples for more information.
|
51
|
+
# @return [String, HeapInfo::Nil] The content needed. When the request address is not readable or the process not exists, <tt>HeapInfo::Nil.new</tt> is returned.
|
52
|
+
#
|
53
|
+
# @example
|
54
|
+
# h = heapinfo('victim')
|
55
|
+
# h.dump(:heap) # &heap[0, 8]
|
56
|
+
# h.dump(:heap, 64) # &heap[0, 64]
|
57
|
+
# h.dump(:heap, 256, 64) # &heap[256, 64]
|
58
|
+
# h.dump('heap+256, 64' # &heap[256, 64]
|
59
|
+
# h.dump('heap+0x100', 64) # &heap[256, 64]
|
60
|
+
# h.dump(<segment>, 8) # semgent can be [heap, stack, (program|elf), libc, ld]
|
61
|
+
# h.dump(addr, 64) # addr[0, 64]
|
62
|
+
#
|
63
|
+
# # Invalid usage
|
64
|
+
# dump(:meow) # no such segment
|
65
|
+
# dump('heap-1, 64') # not support '-'
|
66
|
+
def dump(*args)
|
67
|
+
return Nil.new unless load?
|
68
|
+
@dumper.dump(*args)
|
69
|
+
end
|
70
|
+
|
71
|
+
# Return the dump result as chunks.
|
72
|
+
# see <tt>HeapInfo::Dumper#dump_chunks</tt> for more information.
|
73
|
+
#
|
74
|
+
# @return [HeapInfo::Chunks, HeapInfo::Nil] An array of chunk(s).
|
75
|
+
# @param [Mixed] args Same as arguments of <tt>#dump</tt>
|
76
|
+
def dump_chunks(*args)
|
77
|
+
return Nil.new unless load?
|
78
|
+
@dumper.dump_chunks(*args)
|
79
|
+
end
|
80
|
+
|
81
|
+
# Gdb-like command
|
82
|
+
#
|
83
|
+
# Show dump results like in gdb's command <tt>x</tt>,
|
84
|
+
# while will auto detect the current elf class to decide using <tt>gx</tt> or <tt>wx</tt>.
|
85
|
+
#
|
86
|
+
# The dump results wrapper with color codes and nice typesetting will output to <tt>stdout</tt> by default.
|
87
|
+
# @param [Integer] count The number of result need to dump, see examples for more information
|
88
|
+
# @param [Mixed] commands Same format as <tt>#dump(*args)</tt>, see <tt>#dump</tt> for more information
|
89
|
+
# @param [IO] io <tt>IO</tt> that use for printing, default is <tt>$stdout</tt>
|
90
|
+
# @return [NilClass] The return value of <tt>io.puts</tt>.
|
91
|
+
# @example
|
92
|
+
# h.x 8, :heap
|
93
|
+
# # 0x1f0d000: 0x0000000000000000 0x0000000000002011
|
94
|
+
# # 0x1f0d010: 0x00007f892a9f87b8 0x00007f892a9f87b8
|
95
|
+
# # 0x1f0d020: 0x0000000000000000 0x0000000000000000
|
96
|
+
# # 0x1f0d030: 0x0000000000000000 0x0000000000000000
|
97
|
+
# @example
|
98
|
+
# h.x 3, 0x400000
|
99
|
+
# # 0x400000: 0x00010102464c457f 0x0000000000000000
|
100
|
+
# # 0x400010: 0x00000001003e0002
|
101
|
+
def x(count, *commands, io: $stdout)
|
102
|
+
return unless load? and io.respond_to? :puts
|
103
|
+
@dumper.x(count, *commands, io: io)
|
104
|
+
end
|
105
|
+
|
106
|
+
# Gdb-like command.
|
107
|
+
#
|
108
|
+
# Search a specific value/string/regexp in memory.
|
109
|
+
# <tt>#find</tt> only return the first matched address, if want to find all adress, use <tt>#find_all</tt> instead.
|
110
|
+
# @param [Integer, String, Regexp] pattern The desired search pattern, can be value(<tt>Integer</tt>), string, or regular expression.
|
111
|
+
# @param [Integer, String, Symbol] from Start address for searching, can be segment(<tt>Symbol</tt>) or segments with offset. See examples for more information.
|
112
|
+
# @param [Integer] length The search length limit, default is unlimited, which will search until pattern found or reach unreadable memory.
|
113
|
+
# @return [Integer, NilClass] The first matched address, <tt>nil</tt> is returned when no such pattern found.
|
114
|
+
# @example
|
115
|
+
# h.find(0xdeadbeef, :heap)
|
116
|
+
# h.find(0xdeadbeef, 'heap+0x10', 0x1000)
|
117
|
+
def find(pattern, from, length = :unlimited)
|
118
|
+
return Nil.new unless load?
|
119
|
+
length = 1 << 40 if length.is_a? Symbol
|
120
|
+
@dumper.find(pattern, from, length)
|
121
|
+
end
|
122
|
+
|
123
|
+
# <tt>search</tt> is more intutive to me
|
124
|
+
alias :search :find
|
125
|
+
|
126
|
+
# Pretty dump of bins layouts.
|
127
|
+
#
|
128
|
+
# The request layouts will output to <tt>stdout</tt> by default.
|
129
|
+
# @param [Array<Symbol>] args Bin type(s) you want to see.
|
130
|
+
# @param [IO] io <tt>IO</tt> that use for printing, default is <tt>$stdout</tt>
|
131
|
+
# @return [NilClass] The return value of <tt>io.puts</tt>.
|
132
|
+
# @example
|
133
|
+
# h.layouts :fastbin, :unsorted_bin, :smallbin
|
134
|
+
def layouts(*args, io: $stdout)
|
135
|
+
return unless load? and io.respond_to? :puts
|
136
|
+
io.puts self.libc.main_arena.layouts(*args)
|
137
|
+
end
|
138
|
+
|
139
|
+
# Show simple information of target process.
|
140
|
+
# Contains program names, pid, and segments' info.
|
141
|
+
#
|
142
|
+
# @return [String]
|
143
|
+
# @example
|
144
|
+
# puts h
|
145
|
+
def to_s
|
146
|
+
return "Process not found" unless load?
|
147
|
+
"Program: #{Helper.color program.name} PID: #{Helper.color pid}\n" +
|
148
|
+
program.to_s +
|
149
|
+
heap.to_s +
|
150
|
+
stack.to_s +
|
151
|
+
libc.to_s +
|
152
|
+
ld.to_s
|
153
|
+
end
|
154
|
+
|
155
|
+
private
|
156
|
+
attr_reader :dumper
|
157
|
+
def load?
|
158
|
+
@pid != nil
|
159
|
+
end
|
160
|
+
|
161
|
+
def load! # force load is not efficient
|
162
|
+
@pid = fetch_pid
|
163
|
+
return false if @pid.nil? # still can't load
|
164
|
+
load_status @options
|
165
|
+
true
|
166
|
+
end
|
167
|
+
|
168
|
+
def fetch_pid
|
169
|
+
pid = nil
|
170
|
+
if @prog.is_a? String
|
171
|
+
pid = Helper.pidof @prog
|
172
|
+
elsif @prog.is_a? Integer
|
173
|
+
pid = @prog
|
174
|
+
end
|
175
|
+
pid
|
176
|
+
end
|
177
|
+
|
178
|
+
def load_status(options)
|
179
|
+
elf = Helper.exe_of pid
|
180
|
+
maps = Helper.parse_maps Helper.maps_of pid
|
181
|
+
@status = {
|
182
|
+
program: Segment.find(maps, File.readlink("/proc/#{pid}/exe")),
|
183
|
+
libc: Libc.find(maps, match_maps(maps, options[:libc]), self),
|
184
|
+
heap: Segment.find(maps, '[heap]'),
|
185
|
+
stack: Segment.find(maps, '[stack]'),
|
186
|
+
ld: Segment.find(maps, match_maps(maps, options[:ld])),
|
187
|
+
bits: bits_of(elf),
|
188
|
+
}
|
189
|
+
@status[:elf] = @status[:program] #alias
|
190
|
+
@status.keys.each do |m|
|
191
|
+
self.class.send(:define_method, m) {@status[m]}
|
192
|
+
end
|
193
|
+
@dumper = Dumper.new(@status, mem_filename)
|
194
|
+
end
|
195
|
+
def match_maps(maps, pattern)
|
196
|
+
maps.map{|s| s[3]}.find{|seg| pattern.is_a?(Regexp) ? seg =~ pattern : seg.include?(pattern)}
|
197
|
+
end
|
198
|
+
def bits_of(elf)
|
199
|
+
elf[4] == "\x01" ? 32 : 64
|
200
|
+
end
|
201
|
+
def mem_filename
|
202
|
+
"/proc/#{pid}/mem"
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module HeapInfo
|
2
|
+
class Segment
|
3
|
+
|
4
|
+
# Base address of segment
|
5
|
+
attr_reader :base
|
6
|
+
# Name of segment
|
7
|
+
attr_reader :name
|
8
|
+
# Instantiate a <tt>HeapInfo::Segment</tt> object
|
9
|
+
# @param [Integer] base Base address
|
10
|
+
# @param [String] name Name of segment
|
11
|
+
def initialize(base, name)
|
12
|
+
@base = base
|
13
|
+
@name = name
|
14
|
+
end
|
15
|
+
|
16
|
+
# Hook <tt>#to_s</tt> for pretty printing
|
17
|
+
# @return [String] Information of name and base address wrapper with color codes.
|
18
|
+
def to_s
|
19
|
+
"%-28s\tbase @ #{Helper.color("%#x" % base)}\n" % Helper.color(name.split('/')[-1])
|
20
|
+
end
|
21
|
+
|
22
|
+
# Helper for create an <tt>Segment</tt>
|
23
|
+
#
|
24
|
+
# Search the specific <tt>pattern</tt> in <tt>maps</tt> and return a <tt>HeapInfo::Segment</tt> object.
|
25
|
+
#
|
26
|
+
# @param [Array] maps <tt>maps</tt> is in the form of the return value of <tt>HeapInfo::Helper.parse_maps</tt>
|
27
|
+
# @param [Regexp, String] pattern The segment name want to match in maps. If <tt>String</tt> is given, the pattern is matched as a substring.
|
28
|
+
# @return [HeapInfo::Segment, NilClass] The request <tt>Segment</tt> object. If the pattern is not matched, <tt>nil</tt> will be returned.
|
29
|
+
def self.find(maps, pattern)
|
30
|
+
needs = maps.select{|m| pattern.is_a?(Regexp) ? m[3] =~ pattern : m[3].include?(pattern)}
|
31
|
+
self.new needs.map{|m| m[0]}.min, needs[0][3] unless needs.empty?
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
/*
|
2
|
+
@author: david942j
|
3
|
+
use for get libc's main_arena offset
|
4
|
+
Sample Usage
|
5
|
+
> ./get_arena
|
6
|
+
> LD_LIBRARY_PATH=. ./get_arena
|
7
|
+
> ./ld-linux.so.2 --library-path . ./get_arena
|
8
|
+
*/
|
9
|
+
#include <stdlib.h>
|
10
|
+
#include <stdio.h>
|
11
|
+
#include <stddef.h>
|
12
|
+
#define SZ sizeof(size_t)
|
13
|
+
#define PAGE_SIZE 0x1000
|
14
|
+
void *search_head(size_t e) {
|
15
|
+
e = (e >> 12) << 12;
|
16
|
+
while(strncmp((void*)e, "\177ELF", 4)) e -= PAGE_SIZE;
|
17
|
+
return (void*) e;
|
18
|
+
}
|
19
|
+
int main() {
|
20
|
+
void **p = (void**)malloc(SZ*16); // small bin with chunk size SZ*18
|
21
|
+
void *z = malloc(SZ); // prevent p merge with top chunk
|
22
|
+
*p = z; // prevent compiler optimize
|
23
|
+
free(p); // now *p must be the pointer of the (chunk_ptr) unsorted bin
|
24
|
+
//TODO: check if this offset change in different version glibc
|
25
|
+
z = (void*)((*p) - (4 + 4 + SZ * 10 )); // mutex+flags+fastbin[]
|
26
|
+
void* a = search_head((size_t)__builtin_return_address(0));
|
27
|
+
printf("%p\n", z-a);
|
28
|
+
return 0;
|
29
|
+
}
|
data/spec/chunk_spec.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
require 'heapinfo'
|
3
|
+
describe HeapInfo::Chunk do
|
4
|
+
describe '32bit' do
|
5
|
+
before(:all) do
|
6
|
+
@fast = [0, 0x47, 0x1337].pack("L*").to_chunk(bits: 32)
|
7
|
+
@small = [0, 0x48, 0xabcdef].pack("L*").to_chunk(bits: 32)
|
8
|
+
end
|
9
|
+
it 'basic' do
|
10
|
+
expect(@fast.size_t).to be 4
|
11
|
+
expect(@fast.size).to be 0x40
|
12
|
+
expect(@fast.flags).to eq [:non_main_arena, :mmapped, :prev_inuse]
|
13
|
+
expect(@fast.bintype).to eq :fast
|
14
|
+
expect(@fast.data).to eq [0x1337].pack("L*")
|
15
|
+
expect(@small.bintype).to eq :small
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'to_s' do
|
19
|
+
expect(@small.to_s).to eq "\e[38;5;155m#<HeapInfo::Chunk:0>\n\e[0mflags = []\nsize = \e[38;5;12m0x48\e[0m (small)\nprev_size = \e[38;5;12m0\e[0m\ndata = \e[38;5;1m\"\\xEF\\xCD\\xAB\\x00\"\e[0m...\n"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '64bit' do
|
24
|
+
before(:all) do
|
25
|
+
@fast = [0, 0x87, 0x1337].pack("Q*").to_chunk # default 64bits
|
26
|
+
@small = [0, 0x90, 0xdead].pack("Q*").to_chunk
|
27
|
+
end
|
28
|
+
it 'basic' do
|
29
|
+
expect(@fast.size_t).to be 8
|
30
|
+
expect(@fast.size).to be 0x80
|
31
|
+
expect(@fast.flags).to eq [:non_main_arena, :mmapped, :prev_inuse]
|
32
|
+
expect(@fast.bintype).to eq :fast
|
33
|
+
expect(@fast.data).to eq [0x1337].pack("Q*")
|
34
|
+
expect(@small.bintype).to eq :small
|
35
|
+
end
|
36
|
+
it 'to_s' do
|
37
|
+
expect(@small.to_s).to eq "\e[38;5;155m#<HeapInfo::Chunk:0>\n\e[0mflags = []\nsize = \e[38;5;12m0x90\e[0m (small)\nprev_size = \e[38;5;12m0\e[0m\ndata = \e[38;5;1m\"\\xAD\\xDE\\x00\\x00\\x00\\x00\\x00\\x00\"\e[0m...\n"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/spec/chunks_spec.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
require 'heapinfo'
|
3
|
+
describe HeapInfo::Chunks do
|
4
|
+
before(:each) do
|
5
|
+
@chunks = HeapInfo::Chunks.new
|
6
|
+
@chunks << 0; @chunks << 1; @chunks << 2
|
7
|
+
end
|
8
|
+
it '<<' do
|
9
|
+
expect(@chunks.size).to be 3
|
10
|
+
@chunks << ("\x00"*16).to_chunk
|
11
|
+
expect(@chunks.size).to be 4
|
12
|
+
end
|
13
|
+
it 'each' do
|
14
|
+
@chunks.each_with_index{|c, idx|
|
15
|
+
expect(c).to be idx
|
16
|
+
}
|
17
|
+
end
|
18
|
+
it 'to_s' do
|
19
|
+
expect(@chunks.to_s).to eq @chunks.instance_variable_get(:@chunks).map(&:to_s).join("\n")
|
20
|
+
end
|
21
|
+
it 'size' do
|
22
|
+
expect(@chunks.size).to eq @chunks.instance_variable_get(:@chunks).size
|
23
|
+
expect(@chunks.length).to eq @chunks.instance_variable_get(:@chunks).length
|
24
|
+
end
|
25
|
+
end
|
data/spec/dumper_spec.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
# encoding: ascii-8bit
|
2
|
+
require 'heapinfo'
|
3
|
+
describe HeapInfo::Dumper do
|
4
|
+
describe 'dump' do
|
5
|
+
before(:each) do
|
6
|
+
@mem_filename = '/proc/self/mem'
|
7
|
+
end
|
8
|
+
it 'simple' do
|
9
|
+
dumper = HeapInfo::Dumper.new(nil, @mem_filename)
|
10
|
+
expect(dumper.dump(0x400000, 4)).to eq "\x7fELF"
|
11
|
+
end
|
12
|
+
it 'segment' do
|
13
|
+
segments = {elf: HeapInfo::Segment.new(0x400000, 'elf')}
|
14
|
+
dumper = HeapInfo::Dumper.new(segments, @mem_filename)
|
15
|
+
expect(dumper.dump(:elf, 4)).to eq "\x7fELF"
|
16
|
+
end
|
17
|
+
it 'invalid' do
|
18
|
+
dumper = HeapInfo::Dumper.new({}, @mem_filename)
|
19
|
+
expect(dumper.dump(:zzz, 1)).to be nil
|
20
|
+
expect(dumper.dump(0x12345, 1)).to be nil
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'dumpable?' do
|
25
|
+
dumper = HeapInfo::Dumper.new({}, '/proc/self/mem')
|
26
|
+
expect(dumper.send(:dumpable?)).to be true
|
27
|
+
# a little hack
|
28
|
+
dumper.instance_variable_set(:@filename, '/proc/1/mem')
|
29
|
+
expect(dumper.send(:dumpable?)).to be false
|
30
|
+
expect(dumper.dump).to be nil # show need permission
|
31
|
+
dumper.instance_variable_set(:@filename, '/proc/-1/mem')
|
32
|
+
expect {dumper.send(:dumpable?)}.to raise_error ArgumentError
|
33
|
+
end
|
34
|
+
|
35
|
+
describe 'find' do
|
36
|
+
before(:all) do
|
37
|
+
@dumper = HeapInfo::Dumper.new({elf: HeapInfo::Segment.new(0x400000, ''), bits: 64}, '/proc/self/mem')
|
38
|
+
end
|
39
|
+
it 'simple' do
|
40
|
+
expect(@dumper.find("ELF", :elf, 4)).to eq 0x400001
|
41
|
+
expect(@dumper.find("ELF", :elf, 3)).to be nil
|
42
|
+
end
|
43
|
+
it 'regexp' do
|
44
|
+
addr = @dumper.find(/ru.y/, :elf, 0x1000)
|
45
|
+
expect(@dumper.dump(addr, 4) =~ /ru.y/).to eq 0
|
46
|
+
end
|
47
|
+
it 'invalid' do
|
48
|
+
expect(@dumper.find(nil, :elf, 1)).to be nil
|
49
|
+
end
|
50
|
+
it 'parser' do
|
51
|
+
expect(@dumper.find("ELF", ':elf + 1', 3)).to eq 0x400001
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe 'parse_cmd' do
|
56
|
+
it 'normal' do
|
57
|
+
expect(HeapInfo::Dumper.parse_cmd [0x30]).to eq [0x30, 0, 8]
|
58
|
+
expect(HeapInfo::Dumper.parse_cmd [0x30, 3]).to eq [0x30, 0, 3]
|
59
|
+
expect(HeapInfo::Dumper.parse_cmd [0x30, 2, 3]).to eq [0x30, 2, 3]
|
60
|
+
end
|
61
|
+
it 'symbol' do
|
62
|
+
expect(HeapInfo::Dumper.parse_cmd [:heap]).to eq [:heap,0 , 8]
|
63
|
+
expect(HeapInfo::Dumper.parse_cmd [:heap, 10]).to eq [:heap,0 , 10]
|
64
|
+
expect(HeapInfo::Dumper.parse_cmd [:heap, 3, 10]).to eq [:heap,3 , 10]
|
65
|
+
end
|
66
|
+
it 'string' do
|
67
|
+
expect(HeapInfo::Dumper.parse_cmd ['heap']).to eq [:heap, 0, 8]
|
68
|
+
expect(HeapInfo::Dumper.parse_cmd ['heap, 10']).to eq [:heap, 0, 10]
|
69
|
+
expect(HeapInfo::Dumper.parse_cmd ['heap, 0x33, 10']).to eq [:heap, 51, 10]
|
70
|
+
expect(HeapInfo::Dumper.parse_cmd ['heap+0x15, 10']).to eq [:heap, 0x15, 10]
|
71
|
+
expect(HeapInfo::Dumper.parse_cmd ['heap + 0x15, 10']).to eq [:heap, 0x15, 10]
|
72
|
+
expect(HeapInfo::Dumper.parse_cmd ['heap + 0x15']).to eq [:heap, 0x15, 8]
|
73
|
+
end
|
74
|
+
it 'mixed' do
|
75
|
+
expect(HeapInfo::Dumper.parse_cmd ['heap+ 0x10', 10]).to eq [:heap, 0x10, 10]
|
76
|
+
expect(HeapInfo::Dumper.parse_cmd ['heap', 10]).to eq [:heap, 0, 10]
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
08048000-08049000 r-xp 00000000 ca:01 464143 /home/heapinfo/examples/uaf/uaf
|
2
|
+
08049000-0804a000 r--p 00000000 ca:01 464143 /home/heapinfo/examples/uaf/uaf
|
3
|
+
0804a000-0804b000 rw-p 00001000 ca:01 464143 /home/heapinfo/examples/uaf/uaf
|
4
|
+
f73d4000-f73d7000 rw-p 00000000 00:00 0
|
5
|
+
f73d7000-f73f3000 r-xp 00000000 ca:01 160460 /usr/lib32/libgcc_s.so.1
|
6
|
+
f73f3000-f73f4000 rw-p 0001b000 ca:01 160460 /usr/lib32/libgcc_s.so.1
|
7
|
+
f73f4000-f7438000 r-xp 00000000 ca:01 402366 /lib32/libm-2.19.so
|
8
|
+
f7438000-f7439000 r--p 00043000 ca:01 402366 /lib32/libm-2.19.so
|
9
|
+
f7439000-f743a000 rw-p 00044000 ca:01 402366 /lib32/libm-2.19.so
|
10
|
+
f743a000-f75df000 r-xp 00000000 ca:01 463662 /lib32/libc-2.19.so
|
11
|
+
f75df000-f75e1000 r--p 001a5000 ca:01 463662 /lib32/libc-2.19.so
|
12
|
+
f75e1000-f75e2000 rw-p 001a7000 ca:01 463662 /lib32/libc-2.19.so
|
13
|
+
f75e2000-f75e5000 rw-p 00000000 00:00 0
|
14
|
+
f75e5000-f76c1000 r-xp 00000000 ca:01 137147 /usr/lib32/libstdc++.so.6.0.19
|
15
|
+
f76c1000-f76c5000 r--p 000dc000 ca:01 137147 /usr/lib32/libstdc++.so.6.0.19
|
16
|
+
f76c5000-f76c6000 rw-p 000e0000 ca:01 137147 /usr/lib32/libstdc++.so.6.0.19
|
17
|
+
f76c6000-f76ce000 rw-p 00000000 00:00 0
|
18
|
+
f76db000-f76dd000 rw-p 00000000 00:00 0
|
19
|
+
f76dd000-f76de000 r-xp 00000000 00:00 0 [vdso]
|
20
|
+
f76de000-f76fe000 r-xp 00000000 ca:01 463655 /lib32/ld-2.19.so
|
21
|
+
f76fe000-f76ff000 r--p 0001f000 ca:01 463655 /lib32/ld-2.19.so
|
22
|
+
f76ff000-f7700000 rw-p 00020000 ca:01 463655 /lib32/ld-2.19.so
|
23
|
+
ffdd7000-ffdf8000 rw-p 00000000 00:00 0 [stack]
|