pwntools 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,31 @@
1
+ # encoding: ASCII-8BIT
2
+
3
+ require 'test_helper'
4
+ require 'pwnlib/constants/constants'
5
+ require 'pwnlib/context'
6
+
7
+ class ConstantsTest < MiniTest::Test
8
+ include ::Pwnlib::Context
9
+ Constants = ::Pwnlib::Constants
10
+
11
+ def test_amd64
12
+ context.local(arch: 'amd64') do
13
+ assert_equal('Constant("SYS_read", 0x0)', Constants.SYS_read.inspect)
14
+ assert_equal('__NR_arch_prctl', Constants.__NR_arch_prctl.to_s)
15
+ assert_equal('Constant("(O_CREAT)", 0x40)', Constants.eval('O_CREAT').inspect)
16
+ # TODO(david942j): implement 'real' Constants.eval
17
+ # assert_equal('Constant("(O_CREAT | O_WRONLY)", 0x41)', Constants.eval('O_CREAT | O_WRONLY').inspect)
18
+ end
19
+ end
20
+
21
+ def test_i386
22
+ context.local(arch: 'i386') do
23
+ assert_equal('Constant("SYS_read", 0x3)', Constants.SYS_read.inspect)
24
+ assert_equal('__NR_prctl', Constants.__NR_prctl.to_s)
25
+ assert_equal('Constant("(O_CREAT)", 0x40)', Constants.eval('O_CREAT').inspect)
26
+ assert_equal(0x40, Constants.method(:O_CREAT).call.to_i)
27
+ # 2 < 3
28
+ assert_operator(2, :<, Constants.SYS_read)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,131 @@
1
+ # encoding: ASCII-8BIT
2
+
3
+ require 'test_helper'
4
+ require 'pwnlib/context'
5
+
6
+ class ContextTest < MiniTest::Test
7
+ include ::Pwnlib::Context
8
+
9
+ def test_update
10
+ context.update(arch: 'arm', os: 'windows')
11
+ assert_equal('arm', context.arch)
12
+ assert_equal('windows', context.os)
13
+ end
14
+
15
+ def test_local
16
+ context.timeout = 1
17
+ assert_equal(1, context.timeout)
18
+
19
+ context.local(timeout: 2) do
20
+ assert_equal(2, context.timeout)
21
+ context.timeout = 3
22
+ assert_equal(3, context.timeout)
23
+ end
24
+
25
+ assert_equal(1, context.timeout)
26
+
27
+ assert_raises(RuntimeError) do
28
+ context.local(timeout: 3) { raise 'QQ failed in block' }
29
+ end
30
+
31
+ assert_equal(1, context.timeout)
32
+ end
33
+
34
+ def test_clear
35
+ default_arch = context.arch
36
+ context.arch = 'arm'
37
+ context.clear
38
+ assert_equal(default_arch, context.arch)
39
+ end
40
+
41
+ def test_arch
42
+ context.arch = 'mips'
43
+ assert_equal('mips', context.arch)
44
+
45
+ err = assert_raises(ArgumentError) { context.arch = 'shik' }
46
+ assert_match(/arch must be one of/, err.message)
47
+ assert_equal('mips', context.arch)
48
+
49
+ context.clear
50
+ assert_equal(32, context.bits)
51
+ context.arch = 'powerpc64'
52
+ assert_equal(64, context.bits)
53
+ assert_equal('big', context.endian)
54
+ end
55
+
56
+ def test_bits
57
+ context.bits = 64
58
+ assert_equal(64, context.bits)
59
+
60
+ err = assert_raises(ArgumentError) { context.bits = 0 }
61
+ assert_match(/bits must be > 0/, err.message)
62
+ end
63
+
64
+ def test_bytes
65
+ context.bytes = 8
66
+ assert_equal(64, context.bits)
67
+ assert_equal(8, context.bytes)
68
+
69
+ context.bits = 32
70
+ assert_equal(4, context.bytes)
71
+ end
72
+
73
+ def test_endian
74
+ context.endian = 'le'
75
+ assert_equal('little', context.endian)
76
+
77
+ context.endian = 'big'
78
+ assert_equal('big', context.endian)
79
+
80
+ err = assert_raises(ArgumentError) { context.endian = 'SUPERBIG' }
81
+ assert_match(/endian must be one of/, err.message)
82
+ end
83
+
84
+ def test_log_level
85
+ context.log_level = 'error'
86
+ assert_equal(Logger::ERROR, context.log_level)
87
+
88
+ context.log_level = 514
89
+ assert_equal(514, context.log_level)
90
+
91
+ err = assert_raises(ArgumentError) { context.log_level = 'BOOM' }
92
+ assert_match(/log_level must be an integer or one of/, err.message)
93
+ end
94
+
95
+ def test_os
96
+ context.os = 'windows'
97
+ assert_equal('windows', context.os)
98
+
99
+ err = assert_raises(ArgumentError) { context.os = 'deepblue' }
100
+ assert_match(/os must be one of/, err.message)
101
+ end
102
+
103
+ def test_signed
104
+ context.signed = true
105
+ assert_equal(true, context.signed)
106
+
107
+ context.signed = 'unsigned'
108
+ assert_equal(false, context.signed)
109
+
110
+ err = assert_raises(ArgumentError) { context.signed = 'partial' }
111
+ assert_match(/signed must be boolean or one of/, err.message)
112
+ end
113
+
114
+ def test_timeout
115
+ context.timeout = 123
116
+ assert_equal(123, context.timeout)
117
+ end
118
+
119
+ def test_newline
120
+ context.newline = "\r\n"
121
+ assert_equal("\r\n", context.newline)
122
+ end
123
+
124
+ def test_to_s
125
+ assert_match(/\APwnlib::Context::ContextType\(.+\)\Z/, context.to_s)
126
+ end
127
+
128
+ def teardown
129
+ context.clear
130
+ end
131
+ end
@@ -0,0 +1,8 @@
1
+ #include <stdio.h>
2
+
3
+ int main() {
4
+ setvbuf(stdout, NULL, _IONBF, 0);
5
+ printf("%p\n", __builtin_return_address(0));
6
+ scanf("%c");
7
+ return 0;
8
+ }
Binary file
Binary file
@@ -0,0 +1,48 @@
1
+ # encoding: ASCII-8BIT
2
+
3
+ require 'open3'
4
+
5
+ require 'tty-platform'
6
+
7
+ require 'test_helper'
8
+ require 'pwnlib/dynelf'
9
+
10
+ class DynELFTest < MiniTest::Test
11
+ def test_lookup
12
+ skip 'Only tested on linux' unless TTY::Platform.new.linux?
13
+ [32, 64].each do |b|
14
+ # TODO(hh): Use process instead of popen2
15
+ Open3.popen2(File.expand_path("../data/victim#{b}", __FILE__)) do |i, o, t|
16
+ main_ra = Integer(o.readline)
17
+ libc_path = nil
18
+ IO.readlines("/proc/#{t.pid}/maps").map(&:split).each do |s|
19
+ st, ed = s[0].split('-').map { |x| x.to_i(16) }
20
+ next unless main_ra.between?(st, ed)
21
+ libc_path = s[-1]
22
+ break
23
+ end
24
+ refute_nil(libc_path)
25
+
26
+ # TODO(hh): Use ELF instead of objdump
27
+ # Methods in libc might have multi-versions, so we record and check if
28
+ # we can find one of them.
29
+ h = Hash.new { |hsh, key| hsh[key] = [] }
30
+ symbols = `objdump -T #{libc_path}`.lines.map(&:split).select { |a| a[2] == 'DF' }
31
+ symbols.map { |a| h[a[-1]] << a[0].to_i(16) }
32
+
33
+ mem = open("/proc/#{t.pid}/mem", 'rb')
34
+ d = ::Pwnlib::DynELF.new(main_ra) do |addr|
35
+ mem.seek(addr)
36
+ mem.getc
37
+ end
38
+
39
+ assert_nil(d.lookup('pipi_hao_wei!'))
40
+ h.each do |sym, off|
41
+ assert_includes(off, d.lookup(sym) - d.libbase)
42
+ end
43
+
44
+ i.write('bye')
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,26 @@
1
+ # encoding: ASCII-8BIT
2
+
3
+ require 'test_helper'
4
+ require 'pwnlib/ext/array'
5
+ require 'pwnlib/ext/integer'
6
+ require 'pwnlib/ext/string'
7
+
8
+ class ExtTest < MiniTest::Test
9
+ # Thought that test one method in each module for each type is enough, since it's quite
10
+ # stupid (and meaningless) to copy the list of proxied functions to here...
11
+ def test_ext_string
12
+ assert_equal(0x4142, 'AB'.u16(endian: 'be'))
13
+ assert_equal([1, 1, 0, 0, 0, 1, 0, 0], "\xC4".bits)
14
+ end
15
+
16
+ def test_ext_integer
17
+ assert_equal('AB', 0x4241.p16)
18
+ assert_equal([0, 0, 1, 1, 0, 1, 0, 0], 0x34.bits)
19
+ assert_equal(2**31, 1.bitswap)
20
+ end
21
+
22
+ def test_ext_array
23
+ assert_equal("\xfe", [1, 1, 1, 1, 1, 1, 1, 0].unbits)
24
+ assert_equal("XX\xef\xbe\xad\xdeXX", ['XX', 0xdeadbeef, 'XX'].flat)
25
+ end
26
+ end
@@ -0,0 +1,34 @@
1
+ # encoding: ASCII-8BIT
2
+
3
+ # Make sure we're using local copy for local testing.
4
+ $LOAD_PATH.unshift File.expand_path(File.join(__FILE__, '..', '..', '..', 'lib'))
5
+
6
+ require 'pwn'
7
+
8
+ context[arch: 'amd64']
9
+
10
+ raise 'pack fail' unless pack(1) == "\x01\0\0\0\0\0\0\0"
11
+ unless ::Pwnlib::Util::Fiddling.__send__(:context).object_id == context.object_id
12
+ raise 'not unique context'
13
+ end
14
+ unless ::Pwnlib::Context.context.object_id == context.object_id
15
+ raise 'not unique context'
16
+ end
17
+
18
+ # Make sure things aren't polluting Object
19
+ begin
20
+ 1.__send__(:context)
21
+ raise 'context polluting Object.'
22
+ rescue NoMethodError
23
+ puts 'good'
24
+ end
25
+
26
+ begin
27
+ '1'.__send__(:context)
28
+ raise 'context polluting Object.'
29
+ rescue NoMethodError
30
+ puts 'good'
31
+ end
32
+
33
+ # Make sure we can use Util::xxx::yyy directly
34
+ raise 'pack fail' unless Util::Packing.pack(1) == "\x01\0\0\0\0\0\0\0"
@@ -0,0 +1,19 @@
1
+ # encoding: ASCII-8BIT
2
+
3
+ # Make sure we're using local copy for local testing.
4
+ $LOAD_PATH.unshift File.expand_path(File.join(__FILE__, '..', '..', '..', 'lib'))
5
+
6
+ # TODO(Darkpi): Should we make sure ALL module works? (maybe we should).
7
+ require 'pwnlib/util/packing'
8
+
9
+ raise 'call from module fail' unless ::Pwnlib::Util::Packing.p8(0x61) == 'a'
10
+
11
+ include ::Pwnlib::Util::Packing::ClassMethods
12
+ raise 'include module and call fail' unless p8(0x61) == 'a'
13
+
14
+ begin
15
+ ::Pwnlib::Util::Packing.context
16
+ raise 'context public in Pwnlib module'
17
+ rescue NoMethodError
18
+ puts 'good'
19
+ end
@@ -0,0 +1,16 @@
1
+ # encoding: ASCII-8BIT
2
+
3
+ require 'open3'
4
+
5
+ require 'test_helper'
6
+
7
+ class FullFileTest < MiniTest::Test
8
+ parallelize_me!
9
+ Dir['test/files/*.rb'].each do |f|
10
+ fn = File.basename(f, '.rb')
11
+ define_method("test_#{fn}") do
12
+ _, stderr, status = Open3.capture3('ruby', f, binmode: true)
13
+ assert(status.success?, stderr)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,72 @@
1
+ # encoding: ASCII-8BIT
2
+
3
+ require 'open3'
4
+
5
+ require 'tty-platform'
6
+
7
+ require 'test_helper'
8
+ require 'pwnlib/memleak'
9
+
10
+ class MemLeakTest < MiniTest::Test
11
+ def setup
12
+ @victim = IO.binread(File.expand_path('../data/victim32', __FILE__))
13
+ @leak = ::Pwnlib::MemLeak.new { |addr| @victim[addr] }
14
+ end
15
+
16
+ def test_find_elf_base_basic
17
+ assert_equal(0, @leak.find_elf_base(@victim.length * 2 / 3))
18
+ end
19
+
20
+ def test_find_elf_base_running
21
+ skip 'Only tested on linux' unless TTY::Platform.new.linux?
22
+ [32, 64].each do |b|
23
+ # TODO(hh): Use process instead of popen2
24
+ Open3.popen2(File.expand_path("../data/victim#{b}", __FILE__)) do |i, o, t|
25
+ main_ra = o.readline[2...-1].to_i(16)
26
+ realbase = nil
27
+ IO.readlines("/proc/#{t.pid}/maps").map(&:split).each do |s|
28
+ st, ed = s[0].split('-').map { |x| x.to_i(16) }
29
+ next unless main_ra.between?(st, ed)
30
+ realbase = st
31
+ break
32
+ end
33
+ refute_nil(realbase)
34
+ mem = open("/proc/#{t.pid}/mem", 'rb')
35
+ l2 = ::Pwnlib::MemLeak.new do |addr|
36
+ mem.seek(addr)
37
+ mem.getc
38
+ end
39
+ assert_equal(realbase, l2.find_elf_base(main_ra))
40
+ mem.close
41
+ i.write('bye')
42
+ end
43
+ end
44
+ end
45
+
46
+ def test_n
47
+ assert_equal("\x7fELF", @leak.n(0, 4))
48
+ assert_equal(@victim[0xf0, 0x20], @leak.n(0xf0, 0x20))
49
+ assert_equal(@victim[514, 0x20], @leak.n(514, 0x20))
50
+ end
51
+
52
+ def test_b
53
+ assert_equal(@victim[0x100], @leak.b(0x100))
54
+ assert_equal(@victim[514], @leak.b(514))
55
+ end
56
+
57
+ def test_w
58
+ assert_equal(::Pwnlib::Util::Packing.u16(@victim[0x100, 2]), @leak.w(0x100))
59
+ assert_equal(::Pwnlib::Util::Packing.u16(@victim[514, 2]), @leak.w(514))
60
+ end
61
+
62
+ def test_d
63
+ assert_equal(::Pwnlib::Util::Packing.u32(@victim[0, 4]), @leak.d(0))
64
+ assert_equal(::Pwnlib::Util::Packing.u32(@victim[0x100, 4]), @leak.d(0x100))
65
+ assert_equal(::Pwnlib::Util::Packing.u32(@victim[514, 4]), @leak.d(514))
66
+ end
67
+
68
+ def test_q
69
+ assert_equal(::Pwnlib::Util::Packing.u64(@victim[0x100, 8]), @leak.q(0x100))
70
+ assert_equal(::Pwnlib::Util::Packing.u64(@victim[514, 8]), @leak.q(514))
71
+ end
72
+ end
@@ -0,0 +1,41 @@
1
+ # encoding: ASCII-8BIT
2
+ require 'test_helper'
3
+ require 'pwnlib/reg_sort'
4
+
5
+ class RegSortTest < MiniTest::Test
6
+ include ::Pwnlib::RegSort::ClassMethods
7
+
8
+ def setup
9
+ @regs = %w(a b c d x y z)
10
+ end
11
+
12
+ def test_normal
13
+ assert_equal([['mov', 'a', 1], ['mov', 'b', 2]], regsort({ a: 1, b: 2 }, @regs))
14
+ end
15
+
16
+ def test_post_mov
17
+ assert_equal([['mov', 'a', 1], %w(mov b a)], regsort({ a: 1, b: 1 }, @regs))
18
+ assert_equal([%w(mov c a), ['mov', 'a', 1], %w(mov b a)], regsort({ a: 1, b: 1, c: 'a' }, @regs))
19
+ end
20
+
21
+ def test_pseudoforest
22
+ # only one connected component
23
+ assert_equal([%w(mov b a), ['mov', 'a', 1]], regsort({ a: 1, b: 'a' }, @regs))
24
+ assert_equal([['mov', 'c', 3], %w(xchg a b)], regsort({ a: 'b', b: 'a', c: 3 }, @regs))
25
+ assert_equal([%w(mov c b), %w(xchg a b)], regsort({ a: 'b', b: 'a', c: 'b' }, @regs))
26
+ assert_equal([%w(mov x 1), %w(mov y z), %w(mov z c), %w(xchg a b), %w(xchg b c)],
27
+ regsort({ a: 'b', b: 'c', c: 'a', x: '1', y: 'z', z: 'c' }, @regs))
28
+
29
+ # more than one connected components
30
+ assert_equal([%w(xchg a b), %w(xchg c d)], regsort({ a: 'b', b: 'a', c: 'd', d: 'c' }, @regs))
31
+ assert_equal([%w(mov c b), %w(mov d b), %w(mov z x), %w(xchg a b), %w(xchg x y)],
32
+ regsort({ a: 'b', b: 'a', c: 'b', d: 'b', x: 'y', y: 'x', z: 'x' }, @regs))
33
+ end
34
+
35
+ def test_raise
36
+ err = assert_raises(ArgumentError) do
37
+ regsort({ a: 1 }, ['b'])
38
+ end
39
+ assert_match(/Unknown register!/, err.message)
40
+ end
41
+ end
@@ -0,0 +1,13 @@
1
+ require 'codeclimate-test-reporter'
2
+
3
+ require 'simplecov'
4
+ SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new(
5
+ [SimpleCov::Formatter::HTMLFormatter, CodeClimate::TestReporter::Formatter]
6
+ )
7
+ SimpleCov.start do
8
+ add_filter '/test/'
9
+ end
10
+
11
+ require 'minitest/autorun'
12
+ require 'minitest/unit'
13
+ require 'minitest/hell'