pwntools 0.1.0 → 1.0.0

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.
Files changed (123) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +88 -11
  3. data/Rakefile +5 -1
  4. data/lib/pwn.rb +9 -7
  5. data/lib/pwnlib/abi.rb +60 -0
  6. data/lib/pwnlib/asm.rb +146 -0
  7. data/lib/pwnlib/constants/constant.rb +16 -2
  8. data/lib/pwnlib/constants/constants.rb +35 -19
  9. data/lib/pwnlib/constants/linux/amd64.rb +30 -1
  10. data/lib/pwnlib/context.rb +25 -17
  11. data/lib/pwnlib/dynelf.rb +117 -54
  12. data/lib/pwnlib/elf/elf.rb +267 -0
  13. data/lib/pwnlib/ext/helper.rb +4 -4
  14. data/lib/pwnlib/logger.rb +87 -0
  15. data/lib/pwnlib/memleak.rb +58 -29
  16. data/lib/pwnlib/pwn.rb +19 -8
  17. data/lib/pwnlib/reg_sort.rb +102 -108
  18. data/lib/pwnlib/shellcraft/generators/amd64/common/common.rb +14 -0
  19. data/lib/pwnlib/shellcraft/generators/amd64/common/infloop.rb +17 -0
  20. data/lib/pwnlib/shellcraft/generators/amd64/common/memcpy.rb +31 -0
  21. data/lib/pwnlib/shellcraft/generators/amd64/common/mov.rb +127 -0
  22. data/lib/pwnlib/shellcraft/generators/amd64/common/nop.rb +16 -0
  23. data/lib/pwnlib/shellcraft/generators/amd64/common/popad.rb +27 -0
  24. data/lib/pwnlib/shellcraft/generators/amd64/common/pushstr.rb +64 -0
  25. data/lib/pwnlib/shellcraft/generators/amd64/common/pushstr_array.rb +19 -0
  26. data/lib/pwnlib/shellcraft/generators/amd64/common/ret.rb +32 -0
  27. data/lib/pwnlib/shellcraft/generators/amd64/common/setregs.rb +19 -0
  28. data/lib/pwnlib/shellcraft/generators/amd64/linux/execve.rb +21 -0
  29. data/lib/pwnlib/shellcraft/generators/amd64/linux/linux.rb +14 -0
  30. data/lib/pwnlib/shellcraft/generators/amd64/linux/ls.rb +19 -0
  31. data/lib/pwnlib/shellcraft/generators/amd64/linux/sh.rb +19 -0
  32. data/lib/pwnlib/shellcraft/generators/amd64/linux/syscall.rb +21 -0
  33. data/lib/pwnlib/shellcraft/generators/helper.rb +106 -0
  34. data/lib/pwnlib/shellcraft/generators/i386/common/common.rb +14 -0
  35. data/lib/pwnlib/shellcraft/generators/i386/common/infloop.rb +17 -0
  36. data/lib/pwnlib/shellcraft/generators/i386/common/mov.rb +90 -0
  37. data/lib/pwnlib/shellcraft/generators/i386/common/nop.rb +16 -0
  38. data/lib/pwnlib/shellcraft/generators/i386/common/pushstr.rb +39 -0
  39. data/lib/pwnlib/shellcraft/generators/i386/common/pushstr_array.rb +19 -0
  40. data/lib/pwnlib/shellcraft/generators/i386/common/setregs.rb +19 -0
  41. data/lib/pwnlib/shellcraft/generators/i386/linux/execve.rb +19 -0
  42. data/lib/pwnlib/shellcraft/generators/i386/linux/linux.rb +14 -0
  43. data/lib/pwnlib/shellcraft/generators/i386/linux/ls.rb +19 -0
  44. data/lib/pwnlib/shellcraft/generators/i386/linux/sh.rb +19 -0
  45. data/lib/pwnlib/shellcraft/generators/i386/linux/syscall.rb +19 -0
  46. data/lib/pwnlib/shellcraft/generators/x86/common/common.rb +26 -0
  47. data/lib/pwnlib/shellcraft/generators/x86/common/infloop.rb +22 -0
  48. data/lib/pwnlib/shellcraft/generators/x86/common/mov.rb +15 -0
  49. data/lib/pwnlib/shellcraft/generators/x86/common/pushstr.rb +15 -0
  50. data/lib/pwnlib/shellcraft/generators/x86/common/pushstr_array.rb +85 -0
  51. data/lib/pwnlib/shellcraft/generators/x86/common/setregs.rb +82 -0
  52. data/lib/pwnlib/shellcraft/generators/x86/linux/execve.rb +69 -0
  53. data/lib/pwnlib/shellcraft/generators/x86/linux/linux.rb +14 -0
  54. data/lib/pwnlib/shellcraft/generators/x86/linux/ls.rb +66 -0
  55. data/lib/pwnlib/shellcraft/generators/x86/linux/sh.rb +52 -0
  56. data/lib/pwnlib/shellcraft/generators/x86/linux/syscall.rb +52 -0
  57. data/lib/pwnlib/shellcraft/registers.rb +145 -0
  58. data/lib/pwnlib/shellcraft/shellcraft.rb +67 -0
  59. data/lib/pwnlib/timer.rb +60 -0
  60. data/lib/pwnlib/tubes/buffer.rb +96 -0
  61. data/lib/pwnlib/tubes/sock.rb +95 -0
  62. data/lib/pwnlib/tubes/tube.rb +270 -0
  63. data/lib/pwnlib/util/cyclic.rb +95 -94
  64. data/lib/pwnlib/util/fiddling.rb +256 -220
  65. data/lib/pwnlib/util/getdents.rb +83 -0
  66. data/lib/pwnlib/util/hexdump.rb +109 -108
  67. data/lib/pwnlib/util/lists.rb +55 -0
  68. data/lib/pwnlib/util/packing.rb +226 -228
  69. data/lib/pwnlib/util/ruby.rb +18 -0
  70. data/lib/pwnlib/version.rb +2 -1
  71. data/test/abi_test.rb +21 -0
  72. data/test/asm_test.rb +104 -0
  73. data/test/constants/constant_test.rb +1 -0
  74. data/test/constants/constants_test.rb +4 -2
  75. data/test/context_test.rb +1 -0
  76. data/test/data/echo.rb +20 -0
  77. data/test/data/elfs/Makefile +22 -0
  78. data/test/data/elfs/amd64.frelro.elf +0 -0
  79. data/test/data/elfs/amd64.frelro.pie.elf +0 -0
  80. data/test/data/elfs/amd64.nrelro.elf +0 -0
  81. data/test/data/elfs/amd64.prelro.elf +0 -0
  82. data/test/data/elfs/i386.frelro.pie.elf +0 -0
  83. data/test/data/elfs/i386.prelro.elf +0 -0
  84. data/test/data/elfs/source.cpp +19 -0
  85. data/test/data/flag +1 -0
  86. data/test/data/lib32/ld.so.2 +0 -0
  87. data/test/data/lib32/libc.so.6 +0 -0
  88. data/test/data/lib64/ld.so.2 +0 -0
  89. data/test/data/lib64/libc.so.6 +0 -0
  90. data/test/dynelf_test.rb +59 -24
  91. data/test/elf/elf_test.rb +120 -0
  92. data/test/ext_test.rb +3 -2
  93. data/test/files/use_pwnlib.rb +1 -1
  94. data/test/logger_test.rb +61 -0
  95. data/test/memleak_test.rb +4 -33
  96. data/test/reg_sort_test.rb +3 -1
  97. data/test/shellcraft/infloop_test.rb +26 -0
  98. data/test/shellcraft/linux/ls_test.rb +108 -0
  99. data/test/shellcraft/linux/sh_test.rb +119 -0
  100. data/test/shellcraft/linux/syscalls/execve_test.rb +136 -0
  101. data/test/shellcraft/linux/syscalls/syscall_test.rb +83 -0
  102. data/test/shellcraft/memcpy_test.rb +35 -0
  103. data/test/shellcraft/mov_test.rb +98 -0
  104. data/test/shellcraft/nop_test.rb +26 -0
  105. data/test/shellcraft/popad_test.rb +29 -0
  106. data/test/shellcraft/pushstr_array_test.rb +91 -0
  107. data/test/shellcraft/pushstr_test.rb +108 -0
  108. data/test/shellcraft/registers_test.rb +32 -0
  109. data/test/shellcraft/ret_test.rb +30 -0
  110. data/test/shellcraft/setregs_test.rb +62 -0
  111. data/test/shellcraft/shellcraft_test.rb +28 -0
  112. data/test/test_helper.rb +12 -1
  113. data/test/timer_test.rb +23 -0
  114. data/test/tubes/buffer_test.rb +45 -0
  115. data/test/tubes/sock_test.rb +68 -0
  116. data/test/tubes/tube_test.rb +241 -0
  117. data/test/util/cyclic_test.rb +2 -1
  118. data/test/util/fiddling_test.rb +2 -1
  119. data/test/util/getdents_test.rb +32 -0
  120. data/test/util/hexdump_test.rb +7 -9
  121. data/test/util/lists_test.rb +21 -0
  122. data/test/util/packing_test.rb +4 -3
  123. metadata +215 -25
@@ -0,0 +1,18 @@
1
+ # encoding: ASCII-8BIT
2
+
3
+ module Pwnlib
4
+ module Util
5
+ # module for some utilities for Ruby metaprogramming.
6
+ module Ruby
7
+ def self.private_class_method_block
8
+ define_singleton_method(:singleton_method_added) do |m|
9
+ private_class_method m
10
+ end
11
+ yield
12
+ class << self
13
+ remove_method(:singleton_method_added)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -1,5 +1,6 @@
1
1
  # encoding: ASCII-8BIT
2
2
 
3
3
  module Pwnlib
4
- VERSION = '0.1.0'.freeze
4
+ # version of pwntools-ruby
5
+ VERSION = '1.0.0'.freeze
5
6
  end
@@ -0,0 +1,21 @@
1
+ # encoding: ASCII-8BIT
2
+
3
+ require 'test_helper'
4
+
5
+ require 'pwnlib/abi'
6
+ require 'pwnlib/context'
7
+
8
+ class AbiTest < MiniTest::Test
9
+ include ::Pwnlib::Context
10
+ ABI = ::Pwnlib::ABI
11
+
12
+ def test_default
13
+ context.local(arch: 'i386', os: 'linux') { assert_same ABI::DEFAULT[[32, 'i386', 'linux']], ABI::ABI.default }
14
+ context.local(arch: 'amd64', os: 'linux') { assert_same ABI::DEFAULT[[64, 'amd64', 'linux']], ABI::ABI.default }
15
+ end
16
+
17
+ def test_syscall
18
+ context.local(arch: 'i386', os: 'linux') { assert_same ABI::SYSCALL[[32, 'i386', 'linux']], ABI::ABI.syscall }
19
+ context.local(arch: 'amd64', os: 'linux') { assert_same ABI::SYSCALL[[64, 'amd64', 'linux']], ABI::ABI.syscall }
20
+ end
21
+ end
@@ -0,0 +1,104 @@
1
+ # encoding: ASCII-8BIT
2
+
3
+ require 'test_helper'
4
+
5
+ require 'pwnlib/asm'
6
+ require 'pwnlib/shellcraft/shellcraft'
7
+
8
+ class AsmTest < MiniTest::Test
9
+ include ::Pwnlib::Context
10
+ Asm = ::Pwnlib::Asm
11
+
12
+ def setup
13
+ skip 'Not test asm/disasm on Windows' if TTY::Platform.new.windows?
14
+ @shellcraft = ::Pwnlib::Shellcraft::Shellcraft.instance
15
+ end
16
+
17
+ def test_i386_asm
18
+ context.local(arch: 'i386') do
19
+ assert_equal("\x90", Asm.asm('nop'))
20
+ assert_equal("\xeb\xfe", Asm.asm(@shellcraft.infloop))
21
+ assert_equal("jhh///sh/binj\x0bX\x89\xe31\xc9\x99\xcd\x80", Asm.asm(@shellcraft.sh))
22
+ # issue #51
23
+ assert_equal("j\x01\xfe\x0c$h\x01\x01\x01\x01\x814$\xf2\xf3\x0b\xfe",
24
+ Asm.asm(@shellcraft.pushstr("\xf3\xf2\x0a\xff")))
25
+ end
26
+ end
27
+
28
+ def test_amd64_asm
29
+ context.local(arch: 'amd64') do
30
+ assert_equal("\x90", Asm.asm('nop'))
31
+ assert_equal("\xeb\xfe", Asm.asm(@shellcraft.infloop))
32
+ assert_equal("jhH\xb8/bin///sPj;XH\x89\xe71\xf6\x99\x0f\x05", Asm.asm(@shellcraft.sh))
33
+ 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$",
34
+ Asm.asm(@shellcraft.pushstr("\xff\xff\xff\xff\xff\xff\x0a\xff")))
35
+ end
36
+ end
37
+
38
+ def test_i386_disasm
39
+ context.local(arch: 'i386') do
40
+ str = Asm.disasm("h\x01\x01\x01\x01\x814$ri\x01\x011\xd2"\
41
+ "Rj\x04Z\x01\xe2R\x89\xe2jhh///sh/binj\x0bX\x89\xe3\x89\xd1\x99\xcd\x80")
42
+ assert_equal(<<-EOS, str)
43
+ 0: 68 01 01 01 01 push 0x1010101
44
+ 5: 81 34 24 72 69 01 01 xor dword ptr [esp], 0x1016972
45
+ c: 31 d2 xor edx, edx
46
+ e: 52 push edx
47
+ f: 6a 04 push 4
48
+ 11: 5a pop edx
49
+ 12: 01 e2 add edx, esp
50
+ 14: 52 push edx
51
+ 15: 89 e2 mov edx, esp
52
+ 17: 6a 68 push 0x68
53
+ 19: 68 2f 2f 2f 73 push 0x732f2f2f
54
+ 1e: 68 2f 62 69 6e push 0x6e69622f
55
+ 23: 6a 0b push 0xb
56
+ 25: 58 pop eax
57
+ 26: 89 e3 mov ebx, esp
58
+ 28: 89 d1 mov ecx, edx
59
+ 2a: 99 cdq
60
+ 2b: cd 80 int 0x80
61
+ EOS
62
+ assert_equal(<<-EOS, Asm.disasm("\xb8\x5d\x00\x00\x00"))
63
+ 0: b8 5d 00 00 00 mov eax, 0x5d
64
+ EOS
65
+ end
66
+ end
67
+
68
+ def test_amd64_disasm
69
+ context.local(arch: 'amd64') do
70
+ str = Asm.disasm("hri\x01\x01\x814$\x01\x01\x01\x011\xd2" \
71
+ "Rj\x08ZH\x01\xe2RH\x89\xe2jhH\xb8/bin///sPj;XH\x89\xe7H\x89\xd6\x99\x0f\x05", vma: 0xfff)
72
+
73
+ assert_equal(<<-EOS, str)
74
+ fff: 68 72 69 01 01 push 0x1016972
75
+ 1004: 81 34 24 01 01 01 01 xor dword ptr [rsp], 0x1010101
76
+ 100b: 31 d2 xor edx, edx
77
+ 100d: 52 push rdx
78
+ 100e: 6a 08 push 8
79
+ 1010: 5a pop rdx
80
+ 1011: 48 01 e2 add rdx, rsp
81
+ 1014: 52 push rdx
82
+ 1015: 48 89 e2 mov rdx, rsp
83
+ 1018: 6a 68 push 0x68
84
+ 101a: 48 b8 2f 62 69 6e 2f 2f 2f 73 movabs rax, 0x732f2f2f6e69622f
85
+ 1024: 50 push rax
86
+ 1025: 6a 3b push 0x3b
87
+ 1027: 58 pop rax
88
+ 1028: 48 89 e7 mov rdi, rsp
89
+ 102b: 48 89 d6 mov rsi, rdx
90
+ 102e: 99 cdq
91
+ 102f: 0f 05 syscall
92
+ EOS
93
+ assert_equal(<<-EOS, Asm.disasm("\xb8\x17\x00\x00\x00"))
94
+ 0: b8 17 00 00 00 mov eax, 0x17
95
+ EOS
96
+ end
97
+ end
98
+
99
+ # To ensure coverage
100
+ def test_require
101
+ err = assert_raises(LoadError) { Asm.__send__(:require_message, 'no_such_lib', 'meow') }
102
+ assert_match(/meow/, err.message)
103
+ end
104
+ end
@@ -1,6 +1,7 @@
1
1
  # encoding: ASCII-8BIT
2
2
 
3
3
  require 'test_helper'
4
+
4
5
  require 'pwnlib/constants/constant'
5
6
 
6
7
  class ConstantTest < MiniTest::Test
@@ -1,6 +1,7 @@
1
1
  # encoding: ASCII-8BIT
2
2
 
3
3
  require 'test_helper'
4
+
4
5
  require 'pwnlib/constants/constants'
5
6
  require 'pwnlib/context'
6
7
 
@@ -13,8 +14,9 @@ class ConstantsTest < MiniTest::Test
13
14
  assert_equal('Constant("SYS_read", 0x0)', Constants.SYS_read.inspect)
14
15
  assert_equal('__NR_arch_prctl', Constants.__NR_arch_prctl.to_s)
15
16
  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)
17
+ assert_equal('Constant("(O_CREAT | O_WRONLY)", 0x41)', Constants.eval('O_CREAT | O_WRONLY').inspect)
18
+ err = assert_raises(NameError) { Constants.eval('rax') }
19
+ assert_equal('no value provided for variables: rax', err.message)
18
20
  end
19
21
  end
20
22
 
@@ -1,6 +1,7 @@
1
1
  # encoding: ASCII-8BIT
2
2
 
3
3
  require 'test_helper'
4
+
4
5
  require 'pwnlib/context'
5
6
 
6
7
  class ContextTest < MiniTest::Test
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'socket'
4
+
5
+ if ARGV.empty?
6
+ puts "Usage #{__FILE__} port"
7
+ exit 1
8
+ end
9
+
10
+ server = TCPServer.open('127.0.0.1', ARGV[0].to_i)
11
+
12
+ STDOUT.puts 'Start!'
13
+ STDOUT.flush
14
+
15
+ client = server.accept
16
+ s = client.gets
17
+ client.puts(s)
18
+ client.close
19
+
20
+ STDOUT.puts 'Bye!'
@@ -0,0 +1,22 @@
1
+ source=source.cpp
2
+ FLAGS=
3
+ PIE_FLAGS=-pie
4
+ NOPIE_FLAGS=-no-pie
5
+ FULL_RELRO_FLAGS=-Wl,-z,relro,-z,now
6
+ PARTIAL_RELRO_FLAGS=-Wl,-z,relro
7
+ NO_RELRO_FLAGS=-Wl,-z,norelro
8
+ TARGETS=amd64 i386
9
+ .PHONY: clean
10
+ all: ${TARGETS}
11
+
12
+ amd64: ${source}
13
+ g++ -m64 ${source} -o amd64.frelro.elf ${FLAGS} ${FULL_RELRO_FLAGS} ${NOPIE_FLAGS}
14
+ g++ -m64 ${source} -o amd64.frelro.pie.elf ${FLAGS} ${FULL_RELRO_FLAGS} ${PIE_FLAGS}
15
+ g++ -m64 ${source} -o amd64.prelro.elf ${FLAGS} ${PARTIAL_RELRO_FLAGS} ${NOPIE_FLAGS}
16
+ g++ -m64 ${source} -o amd64.nrelro.elf ${FLAGS} ${NO_RELRO_FLAGS} ${NOPIE_FLAGS}
17
+ i386: ${source}
18
+ g++ -m32 ${source} -o i386.prelro.elf ${FLAGS} ${PARTIAL_RELRO_FLAGS} ${NOPIE_FLAGS}
19
+ g++ -m32 ${source} -o i386.frelro.pie.elf ${FLAGS} ${FULL_RELRO_FLAGS} ${PIE_FLAGS}
20
+
21
+ clean:
22
+ rm -f *.elf
@@ -0,0 +1,19 @@
1
+ #include <stdio.h>
2
+ #include <stdlib.h>
3
+ char s[101];
4
+ void func() {
5
+ static int test = 0;
6
+ test++;
7
+ puts("In func:");
8
+ printf("test = %d\n", test);
9
+ }
10
+ int main() {
11
+ fgets(s, 100, stdin);
12
+ printf("%s", s);
13
+ int n;
14
+ scanf("%d", &n);
15
+ while(n--) {
16
+ func();
17
+ }
18
+ return 0;
19
+ }
@@ -0,0 +1 @@
1
+ flag{pwntools_ruby}
Binary file
Binary file
Binary file
Binary file
@@ -5,43 +5,78 @@ require 'open3'
5
5
  require 'tty-platform'
6
6
 
7
7
  require 'test_helper'
8
+
9
+ require 'pwnlib/context'
8
10
  require 'pwnlib/dynelf'
11
+ require 'pwnlib/elf/elf'
9
12
 
10
13
  class DynELFTest < MiniTest::Test
11
- def test_lookup
14
+ include ::Pwnlib
15
+ include ::Pwnlib::Context
16
+ include ::Pwnlib::ELF
17
+
18
+ def setup
12
19
  skip 'Only tested on linux' unless TTY::Platform.new.linux?
20
+ end
21
+
22
+ # popen victim with specific libc.so.6
23
+ def popen_victim(b)
24
+ lib_path = File.expand_path("data/lib#{b}/", __dir__)
25
+ libc_path = File.expand_path('libc.so.6', lib_path)
26
+ ld_path = File.expand_path('ld.so.2', lib_path)
27
+ victim_path = File.expand_path("data/victim#{b}", __dir__)
28
+
29
+ Open3.popen2("#{ld_path} --library-path #{lib_path} #{victim_path}") do |i, o, t|
30
+ main_ra = Integer(o.readline)
31
+ mem = open("/proc/#{t.pid}/mem", 'rb')
32
+ d = DynELF.new(main_ra) do |addr|
33
+ mem.seek(addr)
34
+ mem.getc
35
+ end
36
+
37
+ yield d, { libc: libc_path, main_ra: main_ra, pid: t.pid }
38
+
39
+ mem.close
40
+ i.write('bye')
41
+ end
42
+ end
43
+
44
+ def test_find_base
13
45
  [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|
46
+ popen_victim(b) do |d, options|
47
+ main_ra = options[:main_ra]
48
+ realbase = nil
49
+ IO.readlines("/proc/#{options[:pid]}/maps").map(&:split).each do |s|
19
50
  st, ed = s[0].split('-').map { |x| x.to_i(16) }
20
51
  next unless main_ra.between?(st, ed)
21
- libc_path = s[-1]
52
+ realbase = st
22
53
  break
23
54
  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
55
+ refute_nil(realbase)
56
+ assert_equal(realbase, d.libbase)
57
+ end
58
+ end
59
+ end
38
60
 
61
+ def test_lookup
62
+ [32, 64].each do |b|
63
+ popen_victim(b) do |d, options|
39
64
  assert_nil(d.lookup('pipi_hao_wei!'))
40
- h.each do |sym, off|
41
- assert_includes(off, d.lookup(sym) - d.libbase)
65
+ elf = ELF.new(options[:libc], checksec: false)
66
+ %i(system open read write execve printf puts sprintf mmap mprotect).each do |sym|
67
+ assert_equal(d.libbase + elf.symbols[sym], d.lookup(sym))
42
68
  end
69
+ end
70
+ end
71
+ end
43
72
 
44
- i.write('bye')
73
+ def test_build_id
74
+ [
75
+ [32, 'ac333186c6b532511a68d16aca4c61422eb772da', 'i386'],
76
+ [64, '088a6e00a1814622219f346b41e775b8dd46c518', 'amd64']
77
+ ].each do |b, answer, arch|
78
+ context.local(arch: arch) do
79
+ popen_victim(b) { |d| assert_equal(answer, d.build_id) }
45
80
  end
46
81
  end
47
82
  end
@@ -0,0 +1,120 @@
1
+ # encoding: ASCII-8BIT
2
+
3
+ require 'test_helper'
4
+
5
+ require 'pwnlib/elf/elf'
6
+ require 'pwnlib/logger'
7
+
8
+ class ELFTest < MiniTest::Test
9
+ include ::Pwnlib::Logger
10
+
11
+ def setup
12
+ @path_of = ->(file) { File.join(__dir__, '..', 'data', 'elfs', file) }
13
+ @elf = ::Pwnlib::ELF::ELF.new(@path_of.call('i386.prelro.elf'), checksec: false)
14
+ end
15
+
16
+ # check stdout when loaded
17
+ def test_load
18
+ file = @path_of.call('amd64.prelro.elf')
19
+ assert_output(<<-EOS) { log_stdout { ::Pwnlib::ELF::ELF.new(file) } }
20
+ [INFO] #{File.realpath(file).inspect}
21
+ RELRO: Partial RELRO
22
+ Stack: Canary found
23
+ NX: NX enabled
24
+ PIE: No PIE (0x400000)
25
+ EOS
26
+
27
+ file = @path_of.call('amd64.frelro.elf')
28
+ assert_output(<<-EOS) { log_stdout { ::Pwnlib::ELF::ELF.new(file) } }
29
+ [WARN] No REL.PLT section found, PLT not loaded
30
+ [INFO] #{File.realpath(file).inspect}
31
+ RELRO: Full RELRO
32
+ Stack: Canary found
33
+ NX: NX enabled
34
+ PIE: No PIE (0x400000)
35
+ EOS
36
+ end
37
+
38
+ def test_checksec
39
+ assert_equal(<<-EOS.strip, @elf.checksec)
40
+ RELRO: Partial RELRO
41
+ Stack: Canary found
42
+ NX: NX enabled
43
+ PIE: No PIE (0x8048000)
44
+ EOS
45
+
46
+ nrelro_elf = ::Pwnlib::ELF::ELF.new(@path_of.call('amd64.nrelro.elf'), checksec: false)
47
+ assert_equal(<<-EOS.strip, nrelro_elf.checksec)
48
+ RELRO: No RELRO
49
+ Stack: Canary found
50
+ NX: NX enabled
51
+ PIE: No PIE (0x400000)
52
+ EOS
53
+
54
+ frelro_elf = ::Pwnlib::ELF::ELF.new(@path_of.call('amd64.frelro.elf'), checksec: false)
55
+ assert_equal(<<-EOS.strip, frelro_elf.checksec)
56
+ RELRO: Full RELRO
57
+ Stack: Canary found
58
+ NX: NX enabled
59
+ PIE: No PIE (0x400000)
60
+ EOS
61
+ end
62
+
63
+ def test_got
64
+ assert_same(8, @elf.got.to_h.size)
65
+ assert_same(0x8049ff8, @elf.got['__gmon_start__'])
66
+ assert_same(0x8049ff8, @elf.got[:__gmon_start__])
67
+ assert_same(0x804a000, @elf.symbols['_GLOBAL_OFFSET_TABLE_'])
68
+ assert_same(0x804856d, @elf.symbols['main'])
69
+ assert_same(@elf.symbols.main, @elf.symbols[:main])
70
+ end
71
+
72
+ def test_plt
73
+ assert_same(6, @elf.plt.to_h.size)
74
+ assert_same(0x80483b0, @elf.plt.printf)
75
+ assert_same(0x80483f0, @elf.plt[:scanf])
76
+
77
+ elf = ::Pwnlib::ELF::ELF.new(@path_of.call('amd64.frelro.pie.elf'), checksec: false)
78
+ assert_nil(elf.plt)
79
+ end
80
+
81
+ def test_address
82
+ old_address = @elf.address
83
+ assert_equal(0x8048000, @elf.address)
84
+ old_main = @elf.symbols.main
85
+ new_address = 0x12340000
86
+ @elf.address = new_address
87
+ assert_equal(old_main - old_address + new_address, @elf.symbols.main)
88
+
89
+ elf = ::Pwnlib::ELF::ELF.new(@path_of.call('i386.frelro.pie.elf'), checksec: false)
90
+ assert_equal(0, elf.address)
91
+ assert_same(0x6c2, elf.symbols.main)
92
+ elf.address = 0xdeadbeef0000
93
+ # use 'equal' instead of 'same' because their +object_id+ are different on Windows.
94
+ assert_equal(0xdeadbeef06c2, elf.symbols.main)
95
+ end
96
+
97
+ def test_search
98
+ elf = ::Pwnlib::ELF::ELF.new(File.join(__dir__, '..', 'data', 'lib32', 'libc.so.6'), checksec: false)
99
+ assert_equal([0x1, 0x15e613], elf.search('ELF').to_a)
100
+ assert_equal(0x15900b, elf.find('/bin/sh').next)
101
+
102
+ result = elf.find(/E.F/)
103
+ assert_equal(0x1, result.next)
104
+ assert_equal(0xc8efa, result.next)
105
+ assert_equal(0xc9118, result.next)
106
+ assert_equal(0x158284, result.next)
107
+ assert_equal(0x158285, result.next)
108
+
109
+ elf.address = 0x1234000
110
+ assert_equal([0x1234001, 0x1392613], elf.search('ELF').to_a)
111
+ assert_equal(0x138d00b, elf.find('/bin/sh').next)
112
+ end
113
+
114
+ def log_stdout
115
+ old = log.instance_variable_get(:@logdev)
116
+ log.instance_variable_set(:@logdev, $stdout)
117
+ yield
118
+ log.instance_variable_set(:@logdev, old)
119
+ end
120
+ end