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