pwntools 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/pwnlib/context.rb +92 -6
- data/lib/pwnlib/elf/elf.rb +4 -4
- data/lib/pwnlib/version.rb +1 -1
- data/test/context_test.rb +12 -3
- data/test/data/elfs/Makefile +2 -0
- data/test/data/elfs/amd64.static.elf +0 -0
- data/test/elf/elf_test.rb +14 -0
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d329dcead1dc5c93633effddf3c627f5071cce80
|
4
|
+
data.tar.gz: b5bf6ed6299056cbd1fd93ad6a37e04a992ce3e1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 71594da6ddc2572a11e2d41c641f04d494d1ea2d3e81ef1a6fd82d92edb3af3599e7099bbdc3393d56a5955fcfd983416dd8be787087fb06d3a586286eb13079
|
7
|
+
data.tar.gz: b7cfba8de4134ea156f58244dff5d1a4e7431b376d1a75d9713503552c11911fb103187249e063baef93cac1f1ce651864f64815e5e2105fc539a6d8ef491df8
|
data/lib/pwnlib/context.rb
CHANGED
@@ -80,11 +80,19 @@ module Pwnlib
|
|
80
80
|
# We use Logger#const_defined for pwnlib logger.
|
81
81
|
LOG_LEVELS = %w(DEBUG INFO WARN ERROR FATAL UNKNOWN).freeze
|
82
82
|
|
83
|
+
# Instantiate a {Pwnlib::Context::ContextType} object.
|
83
84
|
def initialize(**kwargs)
|
84
85
|
@attrs = DEFAULT.dup
|
85
86
|
update(**kwargs)
|
86
87
|
end
|
87
88
|
|
89
|
+
# Convenience function, which is shorthand for setting multiple variables at once.
|
90
|
+
#
|
91
|
+
# @param [Hash] kwargs
|
92
|
+
# Variables to be assigned in the environment.
|
93
|
+
#
|
94
|
+
# @example
|
95
|
+
# context.update(arch: 'amd64', os: :linux)
|
88
96
|
def update(**kwargs)
|
89
97
|
kwargs.each do |k, v|
|
90
98
|
next if v.nil?
|
@@ -96,12 +104,23 @@ module Pwnlib
|
|
96
104
|
alias [] update
|
97
105
|
alias call update
|
98
106
|
|
107
|
+
# Create a string representation of self.
|
99
108
|
def to_s
|
100
109
|
vals = @attrs.map { |k, v| "#{k} = #{v.inspect}" }
|
101
110
|
"#{self.class}(#{vals.join(', ')})"
|
102
111
|
end
|
103
112
|
|
104
|
-
#
|
113
|
+
# Create a context manager for a block.
|
114
|
+
#
|
115
|
+
# @param [Hash] kwargs
|
116
|
+
# Variables to be assigned in the environment.
|
117
|
+
#
|
118
|
+
# @return
|
119
|
+
# This would return what the block returned.
|
120
|
+
#
|
121
|
+
# @example
|
122
|
+
# context.local(arch: 'amd64') { puts context.endian }
|
123
|
+
# # little
|
105
124
|
def local(**kwargs)
|
106
125
|
raise ArgumentError, "Need a block for #{self.class}##{__callee__}" unless block_given?
|
107
126
|
# XXX(Darkpi):
|
@@ -116,6 +135,13 @@ module Pwnlib
|
|
116
135
|
end
|
117
136
|
end
|
118
137
|
|
138
|
+
# Clear the contents of the context, which will set all values to their defaults.
|
139
|
+
#
|
140
|
+
# @example
|
141
|
+
# context.arch = 'amd64'
|
142
|
+
# context.clear
|
143
|
+
# context.bits == 32
|
144
|
+
# #=> true
|
119
145
|
def clear
|
120
146
|
@attrs = DEFAULT.dup
|
121
147
|
end
|
@@ -125,42 +151,84 @@ module Pwnlib
|
|
125
151
|
define_method(k) { @attrs[k] }
|
126
152
|
end
|
127
153
|
|
154
|
+
# Set the newline.
|
155
|
+
#
|
156
|
+
# @param [String] newline
|
157
|
+
# The newline.
|
158
|
+
#
|
159
|
+
# @example
|
160
|
+
# context.newline = "\r\n"
|
128
161
|
def newline=(newline)
|
129
162
|
@attrs[:newline] = newline
|
130
163
|
end
|
131
164
|
|
165
|
+
# Set the default amount of time to wait for a blocking operation before it times out.
|
166
|
+
#
|
167
|
+
# @param [Float, :forever] timeout
|
168
|
+
# Any positive floating number, indicates timeout in seconds.
|
169
|
+
#
|
170
|
+
# @example
|
171
|
+
# context.timeout = 5.14
|
132
172
|
def timeout=(timeout)
|
133
173
|
@attrs[:timeout] = timeout
|
134
174
|
end
|
135
175
|
|
176
|
+
# Set the architecture of the target binary.
|
177
|
+
#
|
178
|
+
# @param [String, Symbol] arch
|
179
|
+
# The architecture. Only values in {Pwnlib::Context::ContextType::ARCHS} are available.
|
180
|
+
#
|
136
181
|
# @diff We always change +bits+ and +endian+ field whether user have already changed them.
|
137
182
|
def arch=(arch)
|
138
|
-
arch = arch.downcase.gsub(/[[:punct:]]/, '')
|
183
|
+
arch = arch.to_s.downcase.gsub(/[[:punct:]]/, '')
|
139
184
|
defaults = ARCHS[arch]
|
140
185
|
raise ArgumentError, "arch must be one of #{ARCHS.keys.sort.inspect}" unless defaults
|
141
186
|
defaults.each { |k, v| @attrs[k] = v }
|
142
187
|
@attrs[:arch] = arch
|
143
188
|
end
|
144
189
|
|
190
|
+
# Set the word size of the target machine in bits (i.e. the size of general purpose registers).
|
191
|
+
#
|
192
|
+
# @param [Integer] bits
|
193
|
+
# The word size.
|
145
194
|
def bits=(bits)
|
146
195
|
raise ArgumentError, "bits must be > 0 (#{bits} given)" unless bits > 0
|
147
196
|
@attrs[:bits] = bits
|
148
197
|
end
|
149
198
|
|
199
|
+
# The word size of the target machine.
|
150
200
|
def bytes
|
151
201
|
bits / 8
|
152
202
|
end
|
153
203
|
|
204
|
+
# Set the word size of the target machine in bytes (i.e. the size of general purpose registers).
|
205
|
+
#
|
206
|
+
# @param [Integer] bytes
|
207
|
+
# The word size.
|
154
208
|
def bytes=(bytes)
|
155
209
|
self.bits = bytes * 8
|
156
210
|
end
|
157
211
|
|
212
|
+
# The endianness of the target machine.
|
213
|
+
#
|
214
|
+
# @param [String, Symbol] endian
|
215
|
+
# The endianness. Only values in {Pwnlib::Context::ContextType::ENDIANNESSES} are available.
|
216
|
+
#
|
217
|
+
# @example
|
218
|
+
# context.endian = :big
|
158
219
|
def endian=(endian)
|
159
|
-
endian = ENDIANNESSES[endian.downcase]
|
220
|
+
endian = ENDIANNESSES[endian.to_s.downcase]
|
160
221
|
raise ArgumentError, "endian must be one of #{ENDIANNESSES.sort.inspect}" if endian.nil?
|
161
222
|
@attrs[:endian] = endian
|
162
223
|
end
|
163
224
|
|
225
|
+
# Set the verbosity of the logger in +Pwnlib+.
|
226
|
+
#
|
227
|
+
# @param [String, Symbol] value
|
228
|
+
# The verbosity. Only values in {Pwnlib::Context::ContextType::LOG_LEVELS} are available.
|
229
|
+
#
|
230
|
+
# @example
|
231
|
+
# context.log_level = :debug
|
164
232
|
def log_level=(value)
|
165
233
|
log_level = nil
|
166
234
|
case value
|
@@ -174,17 +242,35 @@ module Pwnlib
|
|
174
242
|
@attrs[:log_level] = log_level
|
175
243
|
end
|
176
244
|
|
245
|
+
# Set the operating system of the target machine.
|
246
|
+
#
|
247
|
+
# @param [String, Symbol] os
|
248
|
+
# The name of the os. Only values in {Pwnlib::Context::ContextType::OSES} are available.
|
249
|
+
#
|
250
|
+
# @example
|
251
|
+
# context.os = :windows
|
177
252
|
def os=(os)
|
178
|
-
os = os.downcase
|
253
|
+
os = os.to_s.downcase
|
179
254
|
raise ArgumentError, "os must be one of #{OSES.sort.inspect}" unless OSES.include?(os)
|
180
255
|
@attrs[:os] = os
|
181
256
|
end
|
182
257
|
|
258
|
+
# Set the signedness for packing opreation.
|
259
|
+
#
|
260
|
+
# @param [String, Symbol, true, false] value
|
261
|
+
# The signedness. Only values in {Pwnlib::Context::ContextType::SIGNEDNESSES} are available.
|
262
|
+
#
|
263
|
+
# @example
|
264
|
+
# context.signed == false
|
265
|
+
# #=> true
|
266
|
+
# context.signed = 'signed'
|
267
|
+
# context.signed == true
|
268
|
+
# #=> true
|
183
269
|
def signed=(value)
|
184
270
|
signed = nil
|
185
271
|
case value
|
186
|
-
when String
|
187
|
-
signed = SIGNEDNESSES[value.downcase]
|
272
|
+
when String, Symbol
|
273
|
+
signed = SIGNEDNESSES[value.to_s.downcase]
|
188
274
|
when true, false
|
189
275
|
signed = value
|
190
276
|
end
|
data/lib/pwnlib/elf/elf.rb
CHANGED
@@ -115,7 +115,7 @@ module Pwnlib
|
|
115
115
|
#
|
116
116
|
# @return [Boolean] Yes or not.
|
117
117
|
def canary?
|
118
|
-
@got.respond_to?('__stack_chk_fail')
|
118
|
+
@got.respond_to?('__stack_chk_fail') || @symbols.respond_to?('__stack_chk_fail')
|
119
119
|
end
|
120
120
|
|
121
121
|
# Is stack executable?
|
@@ -133,9 +133,9 @@ module Pwnlib
|
|
133
133
|
end
|
134
134
|
|
135
135
|
# There's too many objects inside, let pry not so verbose.
|
136
|
-
# @return [
|
136
|
+
# @return [String]
|
137
137
|
def inspect
|
138
|
-
|
138
|
+
"#<Pwnlib::ELF::ELF:#{::Pwnlib::Util::Fiddling.hex(__id__)}>"
|
139
139
|
end
|
140
140
|
|
141
141
|
# Yields the ELF's virtual address space for the specified string or regexp.
|
@@ -191,7 +191,7 @@ module Pwnlib
|
|
191
191
|
# Get the dynamic tag with +type+.
|
192
192
|
# @return [ELFTools::Dynamic::Tag, nil]
|
193
193
|
def dynamic_tag(type)
|
194
|
-
dynamic = @elf_file.segment_by_type(:dynamic) || @
|
194
|
+
dynamic = @elf_file.segment_by_type(:dynamic) || @elf_file.section_by_name('.dynamic')
|
195
195
|
return nil if dynamic.nil? # No dynamic present, might be static-linked.
|
196
196
|
dynamic.tag_by_type(type)
|
197
197
|
end
|
data/lib/pwnlib/version.rb
CHANGED
data/test/context_test.rb
CHANGED
@@ -8,7 +8,7 @@ class ContextTest < MiniTest::Test
|
|
8
8
|
include ::Pwnlib::Context
|
9
9
|
|
10
10
|
def test_update
|
11
|
-
context.update(arch:
|
11
|
+
context.update(arch: :arm, os: 'windows')
|
12
12
|
assert_equal('arm', context.arch)
|
13
13
|
assert_equal('windows', context.os)
|
14
14
|
end
|
@@ -49,7 +49,7 @@ class ContextTest < MiniTest::Test
|
|
49
49
|
|
50
50
|
context.clear
|
51
51
|
assert_equal(32, context.bits)
|
52
|
-
context.arch =
|
52
|
+
context.arch = :powerpc64
|
53
53
|
assert_equal(64, context.bits)
|
54
54
|
assert_equal('big', context.endian)
|
55
55
|
end
|
@@ -75,7 +75,7 @@ class ContextTest < MiniTest::Test
|
|
75
75
|
context.endian = 'le'
|
76
76
|
assert_equal('little', context.endian)
|
77
77
|
|
78
|
-
context.endian =
|
78
|
+
context.endian = :big
|
79
79
|
assert_equal('big', context.endian)
|
80
80
|
|
81
81
|
err = assert_raises(ArgumentError) { context.endian = 'SUPERBIG' }
|
@@ -86,6 +86,9 @@ class ContextTest < MiniTest::Test
|
|
86
86
|
context.log_level = 'error'
|
87
87
|
assert_equal(Logger::ERROR, context.log_level)
|
88
88
|
|
89
|
+
context.log_level = :fatal
|
90
|
+
assert_equal(Logger::FATAL, context.log_level)
|
91
|
+
|
89
92
|
context.log_level = 514
|
90
93
|
assert_equal(514, context.log_level)
|
91
94
|
|
@@ -97,6 +100,9 @@ class ContextTest < MiniTest::Test
|
|
97
100
|
context.os = 'windows'
|
98
101
|
assert_equal('windows', context.os)
|
99
102
|
|
103
|
+
context.os = :freebsd
|
104
|
+
assert_equal('freebsd', context.os)
|
105
|
+
|
100
106
|
err = assert_raises(ArgumentError) { context.os = 'deepblue' }
|
101
107
|
assert_match(/os must be one of/, err.message)
|
102
108
|
end
|
@@ -108,6 +114,9 @@ class ContextTest < MiniTest::Test
|
|
108
114
|
context.signed = 'unsigned'
|
109
115
|
assert_equal(false, context.signed)
|
110
116
|
|
117
|
+
context.signed = :yes
|
118
|
+
assert_equal(true, context.signed)
|
119
|
+
|
111
120
|
err = assert_raises(ArgumentError) { context.signed = 'partial' }
|
112
121
|
assert_match(/signed must be boolean or one of/, err.message)
|
113
122
|
end
|
data/test/data/elfs/Makefile
CHANGED
@@ -5,6 +5,7 @@ NOPIE_FLAGS=-no-pie
|
|
5
5
|
FULL_RELRO_FLAGS=-Wl,-z,relro,-z,now
|
6
6
|
PARTIAL_RELRO_FLAGS=-Wl,-z,relro
|
7
7
|
NO_RELRO_FLAGS=-Wl,-z,norelro
|
8
|
+
STATIC_FLAGS=-static
|
8
9
|
TARGETS=amd64 i386
|
9
10
|
.PHONY: clean
|
10
11
|
all: ${TARGETS}
|
@@ -14,6 +15,7 @@ amd64: ${source}
|
|
14
15
|
g++ -m64 ${source} -o amd64.frelro.pie.elf ${FLAGS} ${FULL_RELRO_FLAGS} ${PIE_FLAGS}
|
15
16
|
g++ -m64 ${source} -o amd64.prelro.elf ${FLAGS} ${PARTIAL_RELRO_FLAGS} ${NOPIE_FLAGS}
|
16
17
|
g++ -m64 ${source} -o amd64.nrelro.elf ${FLAGS} ${NO_RELRO_FLAGS} ${NOPIE_FLAGS}
|
18
|
+
g++ -m64 ${source} -o amd64.static.elf ${FLAGS} ${STATIC_FLAGS} ${NOPIE_FLAGS}
|
17
19
|
i386: ${source}
|
18
20
|
g++ -m32 ${source} -o i386.prelro.elf ${FLAGS} ${PARTIAL_RELRO_FLAGS} ${NOPIE_FLAGS}
|
19
21
|
g++ -m32 ${source} -o i386.frelro.pie.elf ${FLAGS} ${FULL_RELRO_FLAGS} ${PIE_FLAGS}
|
Binary file
|
data/test/elf/elf_test.rb
CHANGED
@@ -60,6 +60,10 @@ PIE: No PIE (0x400000)
|
|
60
60
|
EOS
|
61
61
|
end
|
62
62
|
|
63
|
+
def test_inspect
|
64
|
+
assert_match(/#<Pwnlib::ELF::ELF:0x[0-9a-f]+>/, @elf.inspect)
|
65
|
+
end
|
66
|
+
|
63
67
|
def test_got
|
64
68
|
assert_same(8, @elf.got.to_h.size)
|
65
69
|
assert_same(0x8049ff8, @elf.got['__gmon_start__'])
|
@@ -94,6 +98,16 @@ PIE: No PIE (0x400000)
|
|
94
98
|
assert_equal(0xdeadbeef06c2, elf.symbols.main)
|
95
99
|
end
|
96
100
|
|
101
|
+
def test_static
|
102
|
+
elf = ::Pwnlib::ELF::ELF.new(@path_of.call('amd64.static.elf'), checksec: false)
|
103
|
+
assert_equal(<<-EOS.strip, elf.checksec)
|
104
|
+
RELRO: Partial RELRO
|
105
|
+
Stack: Canary found
|
106
|
+
NX: NX enabled
|
107
|
+
PIE: No PIE (0x400000)
|
108
|
+
EOS
|
109
|
+
end
|
110
|
+
|
97
111
|
def test_search
|
98
112
|
elf = ::Pwnlib::ELF::ELF.new(File.join(__dir__, '..', 'data', 'lib32', 'libc.so.6'), checksec: false)
|
99
113
|
assert_equal([0x1, 0x15e613], elf.search('ELF').to_a)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pwntools
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- peter50216@gmail.com
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2017-
|
13
|
+
date: 2017-11-02 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: crabstone
|
@@ -291,6 +291,7 @@ files:
|
|
291
291
|
- test/data/elfs/amd64.frelro.pie.elf
|
292
292
|
- test/data/elfs/amd64.nrelro.elf
|
293
293
|
- test/data/elfs/amd64.prelro.elf
|
294
|
+
- test/data/elfs/amd64.static.elf
|
294
295
|
- test/data/elfs/i386.frelro.pie.elf
|
295
296
|
- test/data/elfs/i386.prelro.elf
|
296
297
|
- test/data/elfs/source.cpp
|
@@ -368,6 +369,7 @@ test_files:
|
|
368
369
|
- test/data/elfs/i386.frelro.pie.elf
|
369
370
|
- test/data/elfs/amd64.nrelro.elf
|
370
371
|
- test/data/elfs/i386.prelro.elf
|
372
|
+
- test/data/elfs/amd64.static.elf
|
371
373
|
- test/data/elfs/amd64.prelro.elf
|
372
374
|
- test/data/elfs/source.cpp
|
373
375
|
- test/data/victim32
|