pwntools 1.0.0 → 1.0.1
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 +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
|