pwntools 1.1.0 → 1.2.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 +6 -3
- data/lib/pwn.rb +1 -0
- data/lib/pwnlib/abi.rb +1 -0
- data/lib/pwnlib/asm.rb +83 -42
- data/lib/pwnlib/constants/constant.rb +4 -1
- data/lib/pwnlib/constants/constants.rb +3 -0
- data/lib/pwnlib/constants/linux/amd64.rb +2 -0
- data/lib/pwnlib/constants/linux/i386.rb +2 -0
- data/lib/pwnlib/context.rb +10 -1
- data/lib/pwnlib/dynelf.rb +7 -2
- data/lib/pwnlib/elf/elf.rb +79 -6
- data/lib/pwnlib/errors.rb +3 -2
- data/lib/pwnlib/ext/array.rb +2 -1
- data/lib/pwnlib/ext/helper.rb +3 -2
- data/lib/pwnlib/ext/integer.rb +2 -1
- data/lib/pwnlib/ext/string.rb +3 -2
- data/lib/pwnlib/logger.rb +21 -1
- data/lib/pwnlib/memleak.rb +1 -0
- data/lib/pwnlib/pwn.rb +5 -1
- data/lib/pwnlib/reg_sort.rb +5 -0
- data/lib/pwnlib/runner.rb +53 -0
- data/lib/pwnlib/shellcraft/generators/amd64/common/common.rb +2 -0
- data/lib/pwnlib/shellcraft/generators/amd64/common/infloop.rb +1 -0
- data/lib/pwnlib/shellcraft/generators/amd64/common/memcpy.rb +5 -1
- data/lib/pwnlib/shellcraft/generators/amd64/common/mov.rb +4 -0
- data/lib/pwnlib/shellcraft/generators/amd64/common/nop.rb +2 -0
- data/lib/pwnlib/shellcraft/generators/amd64/common/popad.rb +1 -0
- data/lib/pwnlib/shellcraft/generators/amd64/common/pushstr.rb +3 -1
- data/lib/pwnlib/shellcraft/generators/amd64/common/pushstr_array.rb +1 -0
- data/lib/pwnlib/shellcraft/generators/amd64/common/ret.rb +1 -0
- data/lib/pwnlib/shellcraft/generators/amd64/common/setregs.rb +3 -2
- data/lib/pwnlib/shellcraft/generators/amd64/linux/cat.rb +3 -2
- data/lib/pwnlib/shellcraft/generators/amd64/linux/execve.rb +1 -0
- data/lib/pwnlib/shellcraft/generators/amd64/linux/exit.rb +1 -0
- data/lib/pwnlib/shellcraft/generators/amd64/linux/linux.rb +2 -0
- data/lib/pwnlib/shellcraft/generators/amd64/linux/ls.rb +1 -0
- data/lib/pwnlib/shellcraft/generators/amd64/linux/open.rb +1 -0
- data/lib/pwnlib/shellcraft/generators/amd64/linux/sh.rb +3 -2
- data/lib/pwnlib/shellcraft/generators/amd64/linux/sleep.rb +24 -0
- data/lib/pwnlib/shellcraft/generators/amd64/linux/syscall.rb +1 -0
- data/lib/pwnlib/shellcraft/generators/helper.rb +11 -2
- data/lib/pwnlib/shellcraft/generators/i386/common/common.rb +2 -0
- data/lib/pwnlib/shellcraft/generators/i386/common/infloop.rb +1 -0
- data/lib/pwnlib/shellcraft/generators/i386/common/memcpy.rb +34 -0
- data/lib/pwnlib/shellcraft/generators/i386/common/mov.rb +3 -0
- data/lib/pwnlib/shellcraft/generators/i386/common/nop.rb +2 -0
- data/lib/pwnlib/shellcraft/generators/i386/common/pushstr.rb +2 -0
- data/lib/pwnlib/shellcraft/generators/i386/common/pushstr_array.rb +1 -0
- data/lib/pwnlib/shellcraft/generators/i386/common/setregs.rb +3 -2
- data/lib/pwnlib/shellcraft/generators/i386/linux/cat.rb +3 -2
- data/lib/pwnlib/shellcraft/generators/i386/linux/execve.rb +1 -0
- data/lib/pwnlib/shellcraft/generators/i386/linux/exit.rb +1 -0
- data/lib/pwnlib/shellcraft/generators/i386/linux/linux.rb +2 -0
- data/lib/pwnlib/shellcraft/generators/i386/linux/ls.rb +1 -0
- data/lib/pwnlib/shellcraft/generators/i386/linux/open.rb +1 -0
- data/lib/pwnlib/shellcraft/generators/i386/linux/sh.rb +3 -2
- data/lib/pwnlib/shellcraft/generators/i386/linux/sleep.rb +24 -0
- data/lib/pwnlib/shellcraft/generators/i386/linux/syscall.rb +1 -0
- data/lib/pwnlib/shellcraft/generators/x86/common/common.rb +5 -3
- data/lib/pwnlib/shellcraft/generators/x86/common/infloop.rb +2 -0
- data/lib/pwnlib/shellcraft/generators/x86/common/memcpy.rb +17 -0
- data/lib/pwnlib/shellcraft/generators/x86/common/mov.rb +2 -0
- data/lib/pwnlib/shellcraft/generators/x86/common/pushstr.rb +2 -0
- data/lib/pwnlib/shellcraft/generators/x86/common/pushstr_array.rb +1 -0
- data/lib/pwnlib/shellcraft/generators/x86/common/setregs.rb +8 -6
- data/lib/pwnlib/shellcraft/generators/x86/linux/cat.rb +1 -0
- data/lib/pwnlib/shellcraft/generators/x86/linux/execve.rb +3 -0
- data/lib/pwnlib/shellcraft/generators/x86/linux/exit.rb +1 -0
- data/lib/pwnlib/shellcraft/generators/x86/linux/linux.rb +2 -0
- data/lib/pwnlib/shellcraft/generators/x86/linux/ls.rb +1 -0
- data/lib/pwnlib/shellcraft/generators/x86/linux/open.rb +1 -0
- data/lib/pwnlib/shellcraft/generators/x86/linux/sh.rb +1 -0
- data/lib/pwnlib/shellcraft/generators/x86/linux/sleep.rb +52 -0
- data/lib/pwnlib/shellcraft/generators/x86/linux/syscall.rb +10 -10
- data/lib/pwnlib/shellcraft/registers.rb +5 -1
- data/lib/pwnlib/shellcraft/shellcraft.rb +8 -3
- data/lib/pwnlib/timer.rb +6 -2
- data/lib/pwnlib/tubes/buffer.rb +4 -1
- data/lib/pwnlib/tubes/process.rb +2 -0
- data/lib/pwnlib/tubes/serialtube.rb +3 -1
- data/lib/pwnlib/tubes/sock.rb +7 -1
- data/lib/pwnlib/tubes/tube.rb +23 -3
- data/lib/pwnlib/ui.rb +21 -0
- data/lib/pwnlib/util/cyclic.rb +2 -0
- data/lib/pwnlib/util/fiddling.rb +37 -5
- data/lib/pwnlib/util/getdents.rb +1 -0
- data/lib/pwnlib/util/hexdump.rb +8 -5
- data/lib/pwnlib/util/lists.rb +3 -0
- data/lib/pwnlib/util/packing.rb +5 -2
- data/lib/pwnlib/util/ruby.rb +1 -0
- data/lib/pwnlib/version.rb +2 -1
- data/test/abi_test.rb +1 -0
- data/test/asm_test.rb +75 -85
- data/test/constants/constant_test.rb +1 -0
- data/test/constants/constants_test.rb +1 -0
- data/test/context_test.rb +1 -0
- data/test/data/assembly/aarch64.s +19 -0
- data/test/data/assembly/amd64.s +21 -0
- data/test/data/assembly/arm.s +9 -0
- data/test/data/assembly/i386.s +21 -0
- data/test/data/assembly/mips.s +16 -0
- data/test/data/assembly/mips64.s +6 -0
- data/test/data/assembly/powerpc.s +18 -0
- data/test/data/assembly/powerpc64.s +36 -0
- data/test/data/assembly/sparc.s +33 -0
- data/test/data/assembly/sparc64.s +5 -0
- data/test/data/assembly/thumb.s +37 -0
- data/test/data/echo.rb +1 -0
- data/test/dynelf_test.rb +3 -1
- data/test/elf/elf_test.rb +18 -0
- data/test/ext_test.rb +1 -0
- data/test/files/use_pwn.rb +1 -0
- data/test/files/use_pwnlib.rb +1 -0
- data/test/full_file_test.rb +6 -0
- data/test/logger_test.rb +24 -3
- data/test/memleak_test.rb +1 -0
- data/test/reg_sort_test.rb +1 -0
- data/test/runner_test.rb +32 -0
- data/test/shellcraft/infloop_test.rb +1 -0
- data/test/shellcraft/linux/cat_test.rb +1 -0
- data/test/shellcraft/linux/ls_test.rb +1 -0
- data/test/shellcraft/linux/sh_test.rb +1 -0
- data/test/shellcraft/linux/sleep_test.rb +68 -0
- data/test/shellcraft/linux/syscalls/execve_test.rb +1 -0
- data/test/shellcraft/linux/syscalls/exit_test.rb +1 -0
- data/test/shellcraft/linux/syscalls/open_test.rb +1 -0
- data/test/shellcraft/linux/syscalls/syscall_test.rb +1 -0
- data/test/shellcraft/memcpy_test.rb +20 -5
- data/test/shellcraft/mov_test.rb +1 -0
- data/test/shellcraft/nop_test.rb +1 -0
- data/test/shellcraft/popad_test.rb +1 -0
- data/test/shellcraft/pushstr_array_test.rb +1 -0
- data/test/shellcraft/pushstr_test.rb +1 -0
- data/test/shellcraft/registers_test.rb +1 -0
- data/test/shellcraft/ret_test.rb +1 -0
- data/test/shellcraft/setregs_test.rb +9 -8
- data/test/shellcraft/shellcraft_test.rb +1 -0
- data/test/test_helper.rb +28 -0
- data/test/timer_test.rb +2 -1
- data/test/tubes/buffer_test.rb +1 -0
- data/test/tubes/process_test.rb +8 -2
- data/test/tubes/serialtube_test.rb +1 -4
- data/test/tubes/sock_test.rb +1 -0
- data/test/tubes/tube_test.rb +10 -1
- data/test/ui_test.rb +18 -0
- data/test/util/cyclic_test.rb +1 -0
- data/test/util/fiddling_test.rb +8 -0
- data/test/util/getdents_test.rb +1 -0
- data/test/util/hexdump_test.rb +2 -1
- data/test/util/lists_test.rb +1 -0
- data/test/util/packing_test.rb +3 -2
- metadata +119 -59
data/lib/pwnlib/ui.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# encoding: ASCII-8BIT
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'pwnlib/logger'
|
5
|
+
|
6
|
+
module Pwnlib
|
7
|
+
# This module collects utilities that need user interactions.
|
8
|
+
module UI
|
9
|
+
module_function
|
10
|
+
|
11
|
+
# Waits for user input.
|
12
|
+
#
|
13
|
+
# @return [void]
|
14
|
+
def pause
|
15
|
+
log.info('Paused (press enter to continue)')
|
16
|
+
$stdin.gets
|
17
|
+
end
|
18
|
+
|
19
|
+
include ::Pwnlib::Logger
|
20
|
+
end
|
21
|
+
end
|
data/lib/pwnlib/util/cyclic.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# encoding: ASCII-8BIT
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
module Pwnlib
|
4
5
|
module Util
|
@@ -42,6 +43,7 @@ module Pwnlib
|
|
42
43
|
# The result sequence.
|
43
44
|
def de_bruijn(alphabet: ASCII_LOWERCASE, n: 4)
|
44
45
|
return to_enum(__method__, alphabet: alphabet, n: n) { alphabet.size**n } unless block_given?
|
46
|
+
|
45
47
|
k = alphabet.size
|
46
48
|
a = [0] * (k * n)
|
47
49
|
|
data/lib/pwnlib/util/fiddling.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# encoding: ASCII-8BIT
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
require 'pwnlib/context'
|
4
5
|
|
@@ -56,7 +57,7 @@ module Pwnlib
|
|
56
57
|
# hex(-10) #=> '-0xa'
|
57
58
|
# hex(0xfaceb00cdeadbeef) #=> '0xfaceb00cdeadbeef'
|
58
59
|
def hex(n)
|
59
|
-
(n
|
60
|
+
(n.negative? ? '-' : '') + format('0x%x', n.abs)
|
60
61
|
end
|
61
62
|
|
62
63
|
# URL-encodes a string.
|
@@ -92,7 +93,7 @@ module Pwnlib
|
|
92
93
|
# urldecode('%qw%er%ty') #=> raise ArgumentError
|
93
94
|
# urldecode('%qw%er%ty', true) #=> '%qw%er%ty'
|
94
95
|
def urldecode(s, ignore_invalid = false)
|
95
|
-
res = ''
|
96
|
+
res = +''
|
96
97
|
n = 0
|
97
98
|
while n < s.size
|
98
99
|
if s[n] != '%'
|
@@ -139,12 +140,13 @@ module Pwnlib
|
|
139
140
|
is_little = context.endian == 'little'
|
140
141
|
case s
|
141
142
|
when String
|
142
|
-
v = 'B*'
|
143
|
+
v = +'B*'
|
143
144
|
v.downcase! if is_little
|
144
145
|
s.unpack(v)[0].chars.map { |ch| ch == '1' ? one : zero }
|
145
146
|
when Integer
|
146
147
|
# TODO(Darkpi): What should we do to negative number?
|
147
148
|
raise ArgumentError, 's must be non-negative' unless s >= 0
|
149
|
+
|
148
150
|
r = s.to_s(2).chars.map { |ch| ch == '1' ? one : zero }
|
149
151
|
r.unshift(zero) until (r.size % 8).zero?
|
150
152
|
is_little ? r.reverse : r
|
@@ -265,6 +267,35 @@ module Pwnlib
|
|
265
267
|
s.unpack('m0')[0]
|
266
268
|
end
|
267
269
|
|
270
|
+
# Xor two strings.
|
271
|
+
# If two strings have different length, the shorter one will be repeated until has the same length as another
|
272
|
+
# one.
|
273
|
+
#
|
274
|
+
# @param [String] s1
|
275
|
+
# First string.
|
276
|
+
# @param [String] s2
|
277
|
+
# Second string.
|
278
|
+
#
|
279
|
+
# @return [String]
|
280
|
+
# The xor-ed result.
|
281
|
+
#
|
282
|
+
# @example
|
283
|
+
# xor("\xE8\xE1\xF0\xF0\xF9", "\x80")
|
284
|
+
# => 'happy'
|
285
|
+
#
|
286
|
+
# xor("\x80", "\xE8\xE1\xF0\xF0\xF9")
|
287
|
+
# => 'happy'
|
288
|
+
#
|
289
|
+
# xor('plaintext', 'thekey')
|
290
|
+
# => "\x04\x04\x04\x02\v\r\x11\x10\x11"
|
291
|
+
#
|
292
|
+
# xor('217', "\x00" * 10)
|
293
|
+
# => '2172172172'
|
294
|
+
def xor(s1, s2)
|
295
|
+
s1, s2 = s2, s1 if s1.size < s2.size
|
296
|
+
s1.bytes.zip(''.ljust(s1.size, s2).bytes).map { |a, b| a ^ b }.pack('C*')
|
297
|
+
end
|
298
|
+
|
268
299
|
# Find two strings that will xor into a given string, while only using a given alphabet.
|
269
300
|
#
|
270
301
|
# @param [String, Integer] data
|
@@ -280,12 +311,13 @@ module Pwnlib
|
|
280
311
|
def xor_pair(data, avoid: "\x00\n")
|
281
312
|
data = pack(data) if data.is_a?(Integer)
|
282
313
|
alphabet = 256.times.reject { |c| avoid.include?(c.chr) }
|
283
|
-
res1 = ''
|
284
|
-
res2 = ''
|
314
|
+
res1 = +''
|
315
|
+
res2 = +''
|
285
316
|
data.bytes.each do |c1|
|
286
317
|
# alphabet.shuffle! if context.randomize
|
287
318
|
c2 = alphabet.find { |c| alphabet.include?(c1 ^ c) }
|
288
319
|
return nil if c2.nil?
|
320
|
+
|
289
321
|
res1 << c2.chr
|
290
322
|
res2 << (c1 ^ c2).chr
|
291
323
|
end
|
data/lib/pwnlib/util/getdents.rb
CHANGED
data/lib/pwnlib/util/hexdump.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# encoding: ASCII-8BIT
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
require 'rainbow'
|
4
5
|
|
@@ -18,7 +19,7 @@ module Pwnlib
|
|
18
19
|
# hexdump('217')
|
19
20
|
# #=> "00000000 32 31 37 │217│\n00000003"
|
20
21
|
module HexDump
|
21
|
-
MARKER = "\u2502"
|
22
|
+
MARKER = "\u2502"
|
22
23
|
HIGHLIGHT_STYLE = ->(s) { Rainbow(s).bg(:red) }
|
23
24
|
DEFAULT_STYLE = {
|
24
25
|
0x00 => ->(s) { Rainbow(s).red },
|
@@ -67,7 +68,8 @@ module Pwnlib
|
|
67
68
|
style = DEFAULT_STYLE.merge(style)
|
68
69
|
highlight.bytes.each { |b| style[b] = HIGHLIGHT_STYLE }
|
69
70
|
(0..255).each do |b|
|
70
|
-
next if style.
|
71
|
+
next if style.key?(b)
|
72
|
+
|
71
73
|
style[b] = (b.chr =~ /[[:print:]]/ ? style[:printable] : style[:unprintable])
|
72
74
|
end
|
73
75
|
|
@@ -83,12 +85,13 @@ module Pwnlib
|
|
83
85
|
|
84
86
|
byte_index = offset
|
85
87
|
skipping = false
|
86
|
-
last_chunk = ''
|
88
|
+
last_chunk = +''
|
87
89
|
|
88
90
|
loop do
|
89
91
|
# We assume that chunk is in ASCII-8BIT encoding.
|
90
92
|
chunk = io.read(width)
|
91
93
|
break unless chunk
|
94
|
+
|
92
95
|
chunk_bytes = chunk.bytes
|
93
96
|
start_byte_index = byte_index
|
94
97
|
byte_index += chunk_bytes.size
|
@@ -102,8 +105,8 @@ module Pwnlib
|
|
102
105
|
skipping = false
|
103
106
|
last_chunk = chunk
|
104
107
|
|
105
|
-
hex_bytes = ''
|
106
|
-
printable = ''
|
108
|
+
hex_bytes = +''
|
109
|
+
printable = +''
|
107
110
|
chunk_bytes.each_with_index do |b, i|
|
108
111
|
left_hex, right_char = styled_bytes[b]
|
109
112
|
hex_bytes << left_hex
|
data/lib/pwnlib/util/lists.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# encoding: ASCII-8BIT
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
require 'pwnlib/context'
|
4
5
|
|
@@ -37,6 +38,7 @@ module Pwnlib
|
|
37
38
|
unless %i(ignore drop fill).include?(underfull_action)
|
38
39
|
raise ArgumentError, 'underfull_action expect to be one of :ignore, :drop, and :fill'
|
39
40
|
end
|
41
|
+
|
40
42
|
sliced = str.chars.each_slice(n).map(&:join)
|
41
43
|
case underfull_action
|
42
44
|
when :drop
|
@@ -45,6 +47,7 @@ module Pwnlib
|
|
45
47
|
remain = n - sliced.last.size
|
46
48
|
fill_value = fill_value.to_s
|
47
49
|
raise ArgumentError, 'fill_value must be a character' unless fill_value.size == 1
|
50
|
+
|
48
51
|
sliced.last.concat(fill_value * remain)
|
49
52
|
end
|
50
53
|
sliced
|
data/lib/pwnlib/util/packing.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# encoding: ASCII-8BIT
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
require 'pwnlib/context'
|
4
5
|
|
@@ -71,7 +72,8 @@ module Pwnlib
|
|
71
72
|
end
|
72
73
|
else
|
73
74
|
if is_all
|
74
|
-
raise ArgumentError, "Can't pack negative number with bits='all' and signed=false" if number
|
75
|
+
raise ArgumentError, "Can't pack negative number with bits='all' and signed=false" if number.negative?
|
76
|
+
|
75
77
|
bits = number.zero? ? 8 : ((number.bit_length - 1) | 7) + 1
|
76
78
|
end
|
77
79
|
|
@@ -197,6 +199,7 @@ module Pwnlib
|
|
197
199
|
bytes = bits / 8
|
198
200
|
|
199
201
|
raise ArgumentError, "data.size=#{data.size} must be a multiple of bytes=#{bytes}" if data.size % bytes != 0
|
202
|
+
|
200
203
|
ret = []
|
201
204
|
(data.size / bytes).times do |idx|
|
202
205
|
x1 = idx * bytes
|
@@ -259,7 +262,7 @@ module Pwnlib
|
|
259
262
|
v = case it
|
260
263
|
when Array then flat(*it, **kwargs, &preprocessor)
|
261
264
|
when Integer then p[it]
|
262
|
-
when String then it.force_encoding('ASCII-8BIT')
|
265
|
+
when String then it.dup.force_encoding('ASCII-8BIT') # dup in case 'it' is frozen
|
263
266
|
else
|
264
267
|
raise ArgumentError, "flat does not support values of type #{it.class}"
|
265
268
|
end
|
data/lib/pwnlib/util/ruby.rb
CHANGED
data/lib/pwnlib/version.rb
CHANGED
data/test/abi_test.rb
CHANGED
data/test/asm_test.rb
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
# encoding: ASCII-8BIT
|
2
|
+
# frozen_string_literal: true
|
2
3
|
|
3
4
|
require 'test_helper'
|
4
5
|
|
5
6
|
require 'pwnlib/asm'
|
6
7
|
require 'pwnlib/shellcraft/shellcraft'
|
8
|
+
require 'pwnlib/tubes/process'
|
7
9
|
|
8
10
|
class AsmTest < MiniTest::Test
|
9
11
|
include ::Pwnlib::Context
|
@@ -13,98 +15,88 @@ class AsmTest < MiniTest::Test
|
|
13
15
|
@shellcraft = ::Pwnlib::Shellcraft::Shellcraft.instance
|
14
16
|
end
|
15
17
|
|
16
|
-
def
|
17
|
-
|
18
|
-
|
18
|
+
def parse_sfile(filename)
|
19
|
+
File.read(filename).split("\n\n").each do |it|
|
20
|
+
lines = it.lines
|
21
|
+
metadata = {}
|
22
|
+
# First line of +lines+ might be the extra context setting
|
23
|
+
if lines.first.start_with?('# context: ')
|
24
|
+
# "# context: arch: a, endian: big"
|
25
|
+
# => { arch: 'a', endian: 'big' }
|
26
|
+
metadata = lines.shift.slice(11..-1)
|
27
|
+
.split(',').map { |c| c.split(':', 2).map(&:strip) }
|
28
|
+
.map { |k, v| [k.to_sym, v] }.to_h
|
29
|
+
end
|
30
|
+
comment, output = lines.partition { |l| l =~ /^\s*[;#]/ }.map(&:join)
|
31
|
+
next if output.empty?
|
32
|
+
|
33
|
+
output << "\n" unless output.end_with?("\n")
|
34
|
+
tests = output.lines.map do |l|
|
35
|
+
vma, hex_code, _dummy, inst = l.scan(/^\s*(\w+):\s{3}(([\da-f]{2}\s)+)\s+(.*)$/).first
|
36
|
+
[vma.to_i(16), hex_code.split.join, inst.strip]
|
37
|
+
end
|
19
38
|
|
20
|
-
|
21
|
-
|
39
|
+
vma = tests.first.first
|
40
|
+
bytes = [tests.map { |l| l[1] }.join].pack('H*')
|
41
|
+
insts = tests.map(&:last)
|
42
|
+
yield(bytes, vma, insts, output, comment, **metadata)
|
43
|
+
end
|
22
44
|
end
|
23
45
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
46
|
+
# All tests of asm can be found under test/data/assembly/<arch>.s.
|
47
|
+
%w[aarch64 amd64 arm i386 mips mips64 powerpc powerpc64 sparc sparc64 thumb].each do |arch|
|
48
|
+
file = File.join(__dir__, 'data', 'assembly', arch + '.s')
|
49
|
+
# Defining methods dynamically makes proper error message shown when tests failed.
|
50
|
+
__send__(:define_method, "test_asm_#{arch}") do
|
51
|
+
skip_windows
|
52
|
+
|
53
|
+
context.local(arch: arch) do
|
54
|
+
parse_sfile(file) do |bytes, vma, insts, _output, comment, **ctx|
|
55
|
+
next if comment.include?('!skip asm')
|
56
|
+
|
57
|
+
context.local(**ctx) do
|
58
|
+
assert_equal(bytes, Asm.asm(insts.join("\n"), vma: vma))
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
33
62
|
end
|
34
63
|
end
|
35
64
|
|
36
|
-
def
|
65
|
+
def test_asm_unsupported
|
37
66
|
skip_windows
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
assert_equal("jhH\xb8/bin///sPj;XH\x89\xe71\xf6\x99\x0f\x05", Asm.asm(@shellcraft.sh))
|
42
|
-
assert_equal("j\x01\xfe\x0c$H\xb8\x01\x01\x01\x01\x01\x01\x01\x01PH\xb8\xfe\xfe\xfe\xfe\xfe\xfe\x0b\xfeH1\x04$",
|
43
|
-
Asm.asm(@shellcraft.pushstr("\xff\xff\xff\xff\xff\xff\x0a\xff")))
|
67
|
+
|
68
|
+
err = context.local(arch: :vax) do
|
69
|
+
assert_raises(::Pwnlib::Errors::UnsupportedArchError) { Asm.asm('') }
|
44
70
|
end
|
71
|
+
assert_equal('Asm on architecture "vax" is not supported yet.', err.message)
|
45
72
|
end
|
46
73
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
19: 68 2f 2f 2f 73 push 0x732f2f2f
|
64
|
-
1e: 68 2f 62 69 6e push 0x6e69622f
|
65
|
-
23: 6a 0b push 0xb
|
66
|
-
25: 58 pop eax
|
67
|
-
26: 89 e3 mov ebx, esp
|
68
|
-
28: 89 d1 mov ecx, edx
|
69
|
-
2a: 99 cdq
|
70
|
-
2b: cd 80 int 0x80
|
71
|
-
EOS
|
72
|
-
assert_equal(<<-EOS, Asm.disasm("\xb8\x5d\x00\x00\x00"))
|
73
|
-
0: b8 5d 00 00 00 mov eax, 0x5d
|
74
|
-
EOS
|
74
|
+
# All tests of disasm can be found under test/data/assembly/<arch>.s.
|
75
|
+
%w[aarch64 amd64 arm i386 mips mips64 powerpc64 sparc sparc64 thumb].each do |arch|
|
76
|
+
file = File.join(__dir__, 'data', 'assembly', arch + '.s')
|
77
|
+
# Defining methods dynamically makes proper error message shown when tests failed.
|
78
|
+
__send__(:define_method, "test_disasm_#{arch}") do
|
79
|
+
skip_windows
|
80
|
+
|
81
|
+
context.local(arch: arch) do
|
82
|
+
parse_sfile(file) do |bytes, vma, _insts, output, comment, **ctx|
|
83
|
+
next if comment.include?('!skip disasm')
|
84
|
+
|
85
|
+
context.local(**ctx) do
|
86
|
+
assert_equal(output, Asm.disasm(bytes, vma: vma))
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
75
90
|
end
|
76
91
|
end
|
77
92
|
|
78
|
-
def
|
93
|
+
def test_disasm_unsupported
|
79
94
|
skip_windows
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
assert_equal(<<-EOS, str)
|
85
|
-
fff: 68 72 69 01 01 push 0x1016972
|
86
|
-
1004: 81 34 24 01 01 01 01 xor dword ptr [rsp], 0x1010101
|
87
|
-
100b: 31 d2 xor edx, edx
|
88
|
-
100d: 52 push rdx
|
89
|
-
100e: 6a 08 push 8
|
90
|
-
1010: 5a pop rdx
|
91
|
-
1011: 48 01 e2 add rdx, rsp
|
92
|
-
1014: 52 push rdx
|
93
|
-
1015: 48 89 e2 mov rdx, rsp
|
94
|
-
1018: 6a 68 push 0x68
|
95
|
-
101a: 48 b8 2f 62 69 6e 2f 2f 2f 73 movabs rax, 0x732f2f2f6e69622f
|
96
|
-
1024: 50 push rax
|
97
|
-
1025: 6a 3b push 0x3b
|
98
|
-
1027: 58 pop rax
|
99
|
-
1028: 48 89 e7 mov rdi, rsp
|
100
|
-
102b: 48 89 d6 mov rsi, rdx
|
101
|
-
102e: 99 cdq
|
102
|
-
102f: 0f 05 syscall
|
103
|
-
EOS
|
104
|
-
assert_equal(<<-EOS, Asm.disasm("\xb8\x17\x00\x00\x00"))
|
105
|
-
0: b8 17 00 00 00 mov eax, 0x17
|
106
|
-
EOS
|
95
|
+
|
96
|
+
err = context.local(arch: :vax) do
|
97
|
+
assert_raises(::Pwnlib::Errors::UnsupportedArchError) { Asm.disasm('') }
|
107
98
|
end
|
99
|
+
assert_equal('Disasm on architecture "vax" is not supported yet.', err.message)
|
108
100
|
end
|
109
101
|
|
110
102
|
# To ensure coverage
|
@@ -115,8 +107,8 @@ class AsmTest < MiniTest::Test
|
|
115
107
|
assert_match(/meow/, err.message)
|
116
108
|
end
|
117
109
|
|
118
|
-
def make_elf_file(
|
119
|
-
elf = Asm.make_elf(
|
110
|
+
def make_elf_file(data, **kwargs)
|
111
|
+
elf = Asm.make_elf(data, **kwargs)
|
120
112
|
stream = StringIO.new(elf)
|
121
113
|
[elf, ::ELFTools::ELFFile.new(stream)]
|
122
114
|
end
|
@@ -167,19 +159,17 @@ class AsmTest < MiniTest::Test
|
|
167
159
|
# this test can be removed after method +run_shellcode+ being implemented
|
168
160
|
def test_make_elf_and_run
|
169
161
|
# run the ELF we created to make sure it works.
|
170
|
-
linux_only
|
162
|
+
linux_only 'ELF can only be executed on Linux'
|
171
163
|
|
172
164
|
# test supported architecture
|
173
165
|
{
|
174
|
-
i386: /08048000-08049000
|
175
|
-
amd64: /00400000-00401000
|
166
|
+
i386: /08048000-08049000 rwxp/,
|
167
|
+
amd64: /00400000-00401000 rwxp/
|
176
168
|
}.each do |arch, regexp|
|
177
169
|
context.local(arch: arch) do
|
178
170
|
data = Asm.asm(@shellcraft.cat('/proc/self/maps') + @shellcraft.syscall('SYS_exit', 0))
|
179
171
|
Asm.make_elf(data) do |path|
|
180
|
-
|
181
|
-
assert_match(regexp, o.gets)
|
182
|
-
end
|
172
|
+
assert_match(regexp, ::Pwnlib::Tubes::Process.new(path).gets)
|
183
173
|
end
|
184
174
|
end
|
185
175
|
end
|