pwntools 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (153) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +6 -3
  3. data/lib/pwn.rb +1 -0
  4. data/lib/pwnlib/abi.rb +1 -0
  5. data/lib/pwnlib/asm.rb +83 -42
  6. data/lib/pwnlib/constants/constant.rb +4 -1
  7. data/lib/pwnlib/constants/constants.rb +3 -0
  8. data/lib/pwnlib/constants/linux/amd64.rb +2 -0
  9. data/lib/pwnlib/constants/linux/i386.rb +2 -0
  10. data/lib/pwnlib/context.rb +10 -1
  11. data/lib/pwnlib/dynelf.rb +7 -2
  12. data/lib/pwnlib/elf/elf.rb +79 -6
  13. data/lib/pwnlib/errors.rb +3 -2
  14. data/lib/pwnlib/ext/array.rb +2 -1
  15. data/lib/pwnlib/ext/helper.rb +3 -2
  16. data/lib/pwnlib/ext/integer.rb +2 -1
  17. data/lib/pwnlib/ext/string.rb +3 -2
  18. data/lib/pwnlib/logger.rb +21 -1
  19. data/lib/pwnlib/memleak.rb +1 -0
  20. data/lib/pwnlib/pwn.rb +5 -1
  21. data/lib/pwnlib/reg_sort.rb +5 -0
  22. data/lib/pwnlib/runner.rb +53 -0
  23. data/lib/pwnlib/shellcraft/generators/amd64/common/common.rb +2 -0
  24. data/lib/pwnlib/shellcraft/generators/amd64/common/infloop.rb +1 -0
  25. data/lib/pwnlib/shellcraft/generators/amd64/common/memcpy.rb +5 -1
  26. data/lib/pwnlib/shellcraft/generators/amd64/common/mov.rb +4 -0
  27. data/lib/pwnlib/shellcraft/generators/amd64/common/nop.rb +2 -0
  28. data/lib/pwnlib/shellcraft/generators/amd64/common/popad.rb +1 -0
  29. data/lib/pwnlib/shellcraft/generators/amd64/common/pushstr.rb +3 -1
  30. data/lib/pwnlib/shellcraft/generators/amd64/common/pushstr_array.rb +1 -0
  31. data/lib/pwnlib/shellcraft/generators/amd64/common/ret.rb +1 -0
  32. data/lib/pwnlib/shellcraft/generators/amd64/common/setregs.rb +3 -2
  33. data/lib/pwnlib/shellcraft/generators/amd64/linux/cat.rb +3 -2
  34. data/lib/pwnlib/shellcraft/generators/amd64/linux/execve.rb +1 -0
  35. data/lib/pwnlib/shellcraft/generators/amd64/linux/exit.rb +1 -0
  36. data/lib/pwnlib/shellcraft/generators/amd64/linux/linux.rb +2 -0
  37. data/lib/pwnlib/shellcraft/generators/amd64/linux/ls.rb +1 -0
  38. data/lib/pwnlib/shellcraft/generators/amd64/linux/open.rb +1 -0
  39. data/lib/pwnlib/shellcraft/generators/amd64/linux/sh.rb +3 -2
  40. data/lib/pwnlib/shellcraft/generators/amd64/linux/sleep.rb +24 -0
  41. data/lib/pwnlib/shellcraft/generators/amd64/linux/syscall.rb +1 -0
  42. data/lib/pwnlib/shellcraft/generators/helper.rb +11 -2
  43. data/lib/pwnlib/shellcraft/generators/i386/common/common.rb +2 -0
  44. data/lib/pwnlib/shellcraft/generators/i386/common/infloop.rb +1 -0
  45. data/lib/pwnlib/shellcraft/generators/i386/common/memcpy.rb +34 -0
  46. data/lib/pwnlib/shellcraft/generators/i386/common/mov.rb +3 -0
  47. data/lib/pwnlib/shellcraft/generators/i386/common/nop.rb +2 -0
  48. data/lib/pwnlib/shellcraft/generators/i386/common/pushstr.rb +2 -0
  49. data/lib/pwnlib/shellcraft/generators/i386/common/pushstr_array.rb +1 -0
  50. data/lib/pwnlib/shellcraft/generators/i386/common/setregs.rb +3 -2
  51. data/lib/pwnlib/shellcraft/generators/i386/linux/cat.rb +3 -2
  52. data/lib/pwnlib/shellcraft/generators/i386/linux/execve.rb +1 -0
  53. data/lib/pwnlib/shellcraft/generators/i386/linux/exit.rb +1 -0
  54. data/lib/pwnlib/shellcraft/generators/i386/linux/linux.rb +2 -0
  55. data/lib/pwnlib/shellcraft/generators/i386/linux/ls.rb +1 -0
  56. data/lib/pwnlib/shellcraft/generators/i386/linux/open.rb +1 -0
  57. data/lib/pwnlib/shellcraft/generators/i386/linux/sh.rb +3 -2
  58. data/lib/pwnlib/shellcraft/generators/i386/linux/sleep.rb +24 -0
  59. data/lib/pwnlib/shellcraft/generators/i386/linux/syscall.rb +1 -0
  60. data/lib/pwnlib/shellcraft/generators/x86/common/common.rb +5 -3
  61. data/lib/pwnlib/shellcraft/generators/x86/common/infloop.rb +2 -0
  62. data/lib/pwnlib/shellcraft/generators/x86/common/memcpy.rb +17 -0
  63. data/lib/pwnlib/shellcraft/generators/x86/common/mov.rb +2 -0
  64. data/lib/pwnlib/shellcraft/generators/x86/common/pushstr.rb +2 -0
  65. data/lib/pwnlib/shellcraft/generators/x86/common/pushstr_array.rb +1 -0
  66. data/lib/pwnlib/shellcraft/generators/x86/common/setregs.rb +8 -6
  67. data/lib/pwnlib/shellcraft/generators/x86/linux/cat.rb +1 -0
  68. data/lib/pwnlib/shellcraft/generators/x86/linux/execve.rb +3 -0
  69. data/lib/pwnlib/shellcraft/generators/x86/linux/exit.rb +1 -0
  70. data/lib/pwnlib/shellcraft/generators/x86/linux/linux.rb +2 -0
  71. data/lib/pwnlib/shellcraft/generators/x86/linux/ls.rb +1 -0
  72. data/lib/pwnlib/shellcraft/generators/x86/linux/open.rb +1 -0
  73. data/lib/pwnlib/shellcraft/generators/x86/linux/sh.rb +1 -0
  74. data/lib/pwnlib/shellcraft/generators/x86/linux/sleep.rb +52 -0
  75. data/lib/pwnlib/shellcraft/generators/x86/linux/syscall.rb +10 -10
  76. data/lib/pwnlib/shellcraft/registers.rb +5 -1
  77. data/lib/pwnlib/shellcraft/shellcraft.rb +8 -3
  78. data/lib/pwnlib/timer.rb +6 -2
  79. data/lib/pwnlib/tubes/buffer.rb +4 -1
  80. data/lib/pwnlib/tubes/process.rb +2 -0
  81. data/lib/pwnlib/tubes/serialtube.rb +3 -1
  82. data/lib/pwnlib/tubes/sock.rb +7 -1
  83. data/lib/pwnlib/tubes/tube.rb +23 -3
  84. data/lib/pwnlib/ui.rb +21 -0
  85. data/lib/pwnlib/util/cyclic.rb +2 -0
  86. data/lib/pwnlib/util/fiddling.rb +37 -5
  87. data/lib/pwnlib/util/getdents.rb +1 -0
  88. data/lib/pwnlib/util/hexdump.rb +8 -5
  89. data/lib/pwnlib/util/lists.rb +3 -0
  90. data/lib/pwnlib/util/packing.rb +5 -2
  91. data/lib/pwnlib/util/ruby.rb +1 -0
  92. data/lib/pwnlib/version.rb +2 -1
  93. data/test/abi_test.rb +1 -0
  94. data/test/asm_test.rb +75 -85
  95. data/test/constants/constant_test.rb +1 -0
  96. data/test/constants/constants_test.rb +1 -0
  97. data/test/context_test.rb +1 -0
  98. data/test/data/assembly/aarch64.s +19 -0
  99. data/test/data/assembly/amd64.s +21 -0
  100. data/test/data/assembly/arm.s +9 -0
  101. data/test/data/assembly/i386.s +21 -0
  102. data/test/data/assembly/mips.s +16 -0
  103. data/test/data/assembly/mips64.s +6 -0
  104. data/test/data/assembly/powerpc.s +18 -0
  105. data/test/data/assembly/powerpc64.s +36 -0
  106. data/test/data/assembly/sparc.s +33 -0
  107. data/test/data/assembly/sparc64.s +5 -0
  108. data/test/data/assembly/thumb.s +37 -0
  109. data/test/data/echo.rb +1 -0
  110. data/test/dynelf_test.rb +3 -1
  111. data/test/elf/elf_test.rb +18 -0
  112. data/test/ext_test.rb +1 -0
  113. data/test/files/use_pwn.rb +1 -0
  114. data/test/files/use_pwnlib.rb +1 -0
  115. data/test/full_file_test.rb +6 -0
  116. data/test/logger_test.rb +24 -3
  117. data/test/memleak_test.rb +1 -0
  118. data/test/reg_sort_test.rb +1 -0
  119. data/test/runner_test.rb +32 -0
  120. data/test/shellcraft/infloop_test.rb +1 -0
  121. data/test/shellcraft/linux/cat_test.rb +1 -0
  122. data/test/shellcraft/linux/ls_test.rb +1 -0
  123. data/test/shellcraft/linux/sh_test.rb +1 -0
  124. data/test/shellcraft/linux/sleep_test.rb +68 -0
  125. data/test/shellcraft/linux/syscalls/execve_test.rb +1 -0
  126. data/test/shellcraft/linux/syscalls/exit_test.rb +1 -0
  127. data/test/shellcraft/linux/syscalls/open_test.rb +1 -0
  128. data/test/shellcraft/linux/syscalls/syscall_test.rb +1 -0
  129. data/test/shellcraft/memcpy_test.rb +20 -5
  130. data/test/shellcraft/mov_test.rb +1 -0
  131. data/test/shellcraft/nop_test.rb +1 -0
  132. data/test/shellcraft/popad_test.rb +1 -0
  133. data/test/shellcraft/pushstr_array_test.rb +1 -0
  134. data/test/shellcraft/pushstr_test.rb +1 -0
  135. data/test/shellcraft/registers_test.rb +1 -0
  136. data/test/shellcraft/ret_test.rb +1 -0
  137. data/test/shellcraft/setregs_test.rb +9 -8
  138. data/test/shellcraft/shellcraft_test.rb +1 -0
  139. data/test/test_helper.rb +28 -0
  140. data/test/timer_test.rb +2 -1
  141. data/test/tubes/buffer_test.rb +1 -0
  142. data/test/tubes/process_test.rb +8 -2
  143. data/test/tubes/serialtube_test.rb +1 -4
  144. data/test/tubes/sock_test.rb +1 -0
  145. data/test/tubes/tube_test.rb +10 -1
  146. data/test/ui_test.rb +18 -0
  147. data/test/util/cyclic_test.rb +1 -0
  148. data/test/util/fiddling_test.rb +8 -0
  149. data/test/util/getdents_test.rb +1 -0
  150. data/test/util/hexdump_test.rb +2 -1
  151. data/test/util/lists_test.rb +1 -0
  152. data/test/util/packing_test.rb +3 -2
  153. metadata +119 -59
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7c323ddeb8d8f4ea3d4d087fc69eb53ee7594f64c2ee01dfb57ada9e2a9eb111
4
- data.tar.gz: b9177cb71feb8ecc038680cf850f0b654eea567c7f6774d8ad35cdb1b8949e93
3
+ metadata.gz: 3385a46a409e98ef0ffac19fb93c5ec19d7fde592abbb99ccdc462e186d2b922
4
+ data.tar.gz: d865773d92a7b3068005bfaa9c9d5ba5f1a8bce0e62e05eb55b340c80d2fe3dd
5
5
  SHA512:
6
- metadata.gz: 76cbcd91657ecaee5b8bfae49bfe378539937718a1eb46fbe517c8559919877a153cffb0e5beeb06dde68fe64cd7ab9e1fb30af507547771f49331e7bb90c93b
7
- data.tar.gz: 1aedd2cb397654aa4bc4e13761a1587431f7a67ecec2150c5e6393f1275dfd14801089e0de7234ddd887b2fb99c9635c9bc438ba183c6fcf8d021331269d99b5
6
+ metadata.gz: 1d529315d4e222cc89d3783f4454e804d8ce9d4c8a23a2657b29f23be14dd63e7b5f8f668aa95db944b7ec887d7fc2563f00067a93ec2b841448408e3aee141c
7
+ data.tar.gz: 1f95b2194ac3fea17ea87d030bbba0f52e638978797a7f9068e9af92c2c2d98f39d25cb90be6b73d2e7008e41fd2f913684395a68fbbb6d22115b341533fc8fd
data/README.md CHANGED
@@ -1,10 +1,13 @@
1
1
  [![GitHub stars](https://img.shields.io/github/stars/peter50216/pwntools-ruby.svg)](https://github.com/peter50216/pwntools-ruby/stargazers)
2
- [![Dependency Status](https://img.shields.io/gemnasium/peter50216/pwntools-ruby.svg)](https://gemnasium.com/peter50216/pwntools-ruby)
2
+ [![GitHub issues](https://img.shields.io/github/issues/peter50216/pwntools-ruby.svg)](https://github.com/peter50216/pwntools-ruby/issues)
3
3
  [![Build Status](https://img.shields.io/travis/peter50216/pwntools-ruby.svg)](https://travis-ci.org/peter50216/pwntools-ruby)
4
- [![Test Coverage](https://img.shields.io/codeclimate/coverage/github/peter50216/pwntools-ruby.svg)](https://codeclimate.com/github/peter50216/pwntools-ruby/coverage)
5
- [![Code Climate](https://img.shields.io/codeclimate/github/peter50216/pwntools-ruby.svg)](https://codeclimate.com/github/peter50216/pwntools-ruby)
4
+ [![Test Coverage](https://img.shields.io/codeclimate/coverage/peter50216/pwntools-ruby.svg)](https://codeclimate.com/github/peter50216/pwntools-ruby/coverage)
5
+ [![Code Climate](https://img.shields.io/codeclimate/maintainability/peter50216/pwntools-ruby.svg)](https://codeclimate.com/github/peter50216/pwntools-ruby)
6
6
  [![Inline docs](https://inch-ci.org/github/peter50216/pwntools-ruby.svg)](https://inch-ci.org/github/peter50216/pwntools-ruby)
7
7
  [![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](http://choosealicense.com/licenses/mit/)
8
+ [![Dependabot Status](https://api.dependabot.com/badges/status?host=github&repo=peter50216/pwntools-ruby)](https://dependabot.com)
9
+ [![Rawsec's CyberSecurity Inventory](https://inventory.rawsec.ml/img/badges/Rawsec-inventoried-FF5050_flat.svg)](https://inventory.rawsec.ml/)
10
+ <!-- [![Dependency Status](https://img.shields.io/gemnasium/peter50216/pwntools-ruby.svg)](https://gemnasium.com/peter50216/pwntools-ruby) -->
8
11
 
9
12
  # pwntools-ruby
10
13
 
data/lib/pwn.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  # encoding: ASCII-8BIT
2
+ # frozen_string_literal: true
2
3
 
3
4
  # require this file for easy exploit development, but would pollute main Object and some built-in objects. (String,
4
5
  # Integer, ...)
@@ -1,4 +1,5 @@
1
1
  # encoding: ASCII-8BIT
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'pwnlib/context'
4
5
 
@@ -1,4 +1,5 @@
1
1
  # encoding: ASCII-8BIT
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'tempfile'
4
5
 
@@ -37,41 +38,44 @@ module Pwnlib
37
38
  #
38
39
  # @raise [Pwnlib::Errors::DependencyError]
39
40
  # If libcapstone is not installed.
41
+ # @raise [Pwnlib::Errors::UnsupportedArchError]
42
+ # If disassembling of +context.arch+ is not supported.
40
43
  #
41
44
  # @example
42
45
  # context.arch = 'i386'
43
46
  # print disasm("\xb8\x5d\x00\x00\x00")
44
- # # 0: b8 5d 00 00 00 mov eax, 0x5d
47
+ # # 0: b8 5d 00 00 00 mov eax, 0x5d
45
48
  #
46
49
  # context.arch = 'amd64'
47
50
  # print disasm("\xb8\x17\x00\x00\x00")
48
51
  # # 0: b8 17 00 00 00 mov eax, 0x17
49
52
  # print disasm("jhH\xb8/bin///sPH\x89\xe71\xd21\xf6j;X\x0f\x05", vma: 0x1000)
50
- # # 1000: 6a 68 push 0x68
51
- # # 1002: 48 b8 2f 62 69 6e 2f 2f 2f 73 movabs rax, 0x732f2f2f6e69622f
52
- # # 100c: 50 push rax
53
- # # 100d: 48 89 e7 mov rdi, rsp
54
- # # 1010: 31 d2 xor edx, edx
55
- # # 1012: 31 f6 xor esi, esi
56
- # # 1014: 6a 3b push 0x3b
57
- # # 1016: 58 pop rax
58
- # # 1017: 0f 05 syscall
53
+ # # 1000: 6a 68 push 0x68
54
+ # # 1002: 48 b8 2f 62 69 6e 2f 2f 2f 73 movabs rax, 0x732f2f2f6e69622f
55
+ # # 100c: 50 push rax
56
+ # # 100d: 48 89 e7 mov rdi, rsp
57
+ # # 1010: 31 d2 xor edx, edx
58
+ # # 1012: 31 f6 xor esi, esi
59
+ # # 1014: 6a 3b push 0x3b
60
+ # # 1016: 58 pop rax
61
+ # # 1017: 0f 05 syscall
59
62
  def disasm(data, vma: 0)
60
63
  require_message('crabstone', install_crabstone_guide) # will raise error if require fail.
61
- cs = Crabstone::Disassembler.new(cap_arch, cap_mode)
64
+ cs = Crabstone::Disassembler.new(cs_arch, cs_mode)
62
65
  insts = cs.disasm(data, vma).map do |ins|
63
- [ins.address, ins.bytes.pack('C*'), ins.mnemonic, ins.op_str.to_s]
66
+ [ins.address, ins.bytes, ins.mnemonic.to_s, ins.op_str.to_s]
64
67
  end
65
68
  max_dlen = format('%x', insts.last.first).size + 2
66
69
  max_hlen = insts.map { |ins| ins[1].size }.max * 3
70
+ max_ilen = insts.map { |ins| ins[2].size }.max
67
71
  insts.reduce('') do |s, ins|
68
- hex_code = ins[1].bytes.map { |c| format('%02x', c) }.join(' ')
72
+ hex_code = ins[1].map { |c| format('%02x', c) }.join(' ')
69
73
  inst = if ins[3].empty?
70
74
  ins[2]
71
75
  else
72
- format('%-7s %s', ins[2], ins[3])
76
+ format("%-#{max_ilen}s %s", ins[2], ins[3])
73
77
  end
74
- s + format("%#{max_dlen}x: %-#{max_hlen}s%s\n", ins[0], hex_code, inst)
78
+ s + format("%#{max_dlen}x: %-#{max_hlen}s %s\n", ins[0], hex_code, inst)
75
79
  end
76
80
  end
77
81
 
@@ -79,10 +83,17 @@ module Pwnlib
79
83
  #
80
84
  # @param [String] code
81
85
  # The assembly code to be converted.
86
+ # @param [Integer] vma
87
+ # Virtual memory address.
82
88
  #
83
89
  # @return [String]
84
90
  # The result.
85
91
  #
92
+ # @raise [Pwnlib::Errors::DependencyError]
93
+ # If libkeystone is not installed.
94
+ # @raise [Pwnlib::Errors::UnsupportedArchError]
95
+ # If assembling of +context.arch+ is not supported.
96
+ #
86
97
  # @example
87
98
  # assembly = shellcraft.amd64.linux.sh
88
99
  # context.local(arch: 'amd64') { asm(assembly) }
@@ -93,9 +104,9 @@ module Pwnlib
93
104
  #
94
105
  # @diff
95
106
  # Not support +asm('mov eax, SYS_execve')+.
96
- def asm(code)
107
+ def asm(code, vma: 0)
97
108
  require_message('keystone_engine', install_keystone_guide)
98
- KeystoneEngine::Ks.new(ks_arch, ks_mode).asm(code)[0]
109
+ KeystoneEngine::Ks.new(ks_arch, ks_mode).asm(code, vma)[0]
99
110
  end
100
111
 
101
112
  # Builds an ELF file from executable code.
@@ -166,6 +177,7 @@ module Pwnlib
166
177
  phdr.p_filesz = phdr.p_memsz = entry + data.size
167
178
  elf = ehdr.to_binary_s + phdr.to_binary_s + data
168
179
  return elf unless to_file
180
+
169
181
  path = Dir::Tmpname.create(['pwn', '.elf']) do |temp|
170
182
  File.open(temp, 'wb', 0o750) { |f| f.write(elf) }
171
183
  end
@@ -173,32 +185,59 @@ module Pwnlib
173
185
  end
174
186
 
175
187
  ::Pwnlib::Util::Ruby.private_class_method_block do
176
- def cap_arch
177
- {
178
- 'i386' => Crabstone::ARCH_X86,
179
- 'amd64' => Crabstone::ARCH_X86
180
- }[context.arch]
188
+ def cs_arch
189
+ case context.arch
190
+ when 'aarch64' then Crabstone::ARCH_ARM64
191
+ when 'amd64', 'i386' then Crabstone::ARCH_X86
192
+ when 'arm', 'thumb' then Crabstone::ARCH_ARM
193
+ when 'mips', 'mips64' then Crabstone::ARCH_MIPS
194
+ when 'powerpc64' then Crabstone::ARCH_PPC
195
+ when 'sparc', 'sparc64' then Crabstone::ARCH_SPARC
196
+ else unsupported!("Disasm on architecture #{context.arch.inspect} is not supported yet.")
197
+ end
181
198
  end
182
199
 
183
- def cap_mode
184
- {
185
- 32 => Crabstone::MODE_32,
186
- 64 => Crabstone::MODE_64
187
- }[context.bits]
200
+ def cs_mode
201
+ case context.arch
202
+ when 'aarch64' then Crabstone::MODE_ARM
203
+ when 'amd64' then Crabstone::MODE_64
204
+ when 'arm' then Crabstone::MODE_ARM
205
+ when 'i386' then Crabstone::MODE_32
206
+ when 'mips' then Crabstone::MODE_MIPS32
207
+ when 'mips64' then Crabstone::MODE_MIPS64
208
+ when 'powerpc64' then Crabstone::MODE_64
209
+ when 'sparc' then 0 # default mode
210
+ when 'sparc64' then Crabstone::MODE_V9
211
+ when 'thumb' then Crabstone::MODE_THUMB
212
+ end | (context.endian == 'big' ? Crabstone::MODE_BIG_ENDIAN : Crabstone::MODE_LITTLE_ENDIAN)
188
213
  end
189
214
 
190
215
  def ks_arch
191
- {
192
- 'i386' => KeystoneEngine::KS_ARCH_X86,
193
- 'amd64' => KeystoneEngine::KS_ARCH_X86
194
- }[context.arch]
216
+ case context.arch
217
+ when 'aarch64' then KeystoneEngine::KS_ARCH_ARM64
218
+ when 'amd64', 'i386' then KeystoneEngine::KS_ARCH_X86
219
+ when 'arm', 'thumb' then KeystoneEngine::KS_ARCH_ARM
220
+ when 'mips', 'mips64' then KeystoneEngine::KS_ARCH_MIPS
221
+ when 'powerpc', 'powerpc64' then KeystoneEngine::KS_ARCH_PPC
222
+ when 'sparc', 'sparc64' then KeystoneEngine::KS_ARCH_SPARC
223
+ else unsupported!("Asm on architecture #{context.arch.inspect} is not supported yet.")
224
+ end
195
225
  end
196
226
 
197
227
  def ks_mode
198
- {
199
- 32 => KeystoneEngine::KS_MODE_32,
200
- 64 => KeystoneEngine::KS_MODE_64
201
- }[context.bits]
228
+ case context.arch
229
+ when 'aarch64' then 0 # default mode
230
+ when 'amd64' then KeystoneEngine::KS_MODE_64
231
+ when 'arm' then KeystoneEngine::KS_MODE_ARM
232
+ when 'i386' then KeystoneEngine::KS_MODE_32
233
+ when 'mips' then KeystoneEngine::KS_MODE_MIPS32
234
+ when 'mips64' then KeystoneEngine::KS_MODE_MIPS64
235
+ when 'powerpc' then KeystoneEngine::KS_MODE_PPC32
236
+ when 'powerpc64' then KeystoneEngine::KS_MODE_PPC64
237
+ when 'sparc' then KeystoneEngine::KS_MODE_SPARC32
238
+ when 'sparc64' then KeystoneEngine::KS_MODE_SPARC64
239
+ when 'thumb' then KeystoneEngine::KS_MODE_THUMB
240
+ end | (context.endian == 'big' ? KeystoneEngine::KS_MODE_BIG_ENDIAN : KeystoneEngine::KS_MODE_LITTLE_ENDIAN)
202
241
  end
203
242
 
204
243
  # FFI is used in keystone and capstone binding gems, this method handles when libraries not installed yet.
@@ -210,7 +249,7 @@ module Pwnlib
210
249
 
211
250
  def install_crabstone_guide
212
251
  <<-EOS
213
- #disasm dependes on capstone, which is detected not installed yet.
252
+ #disasm depends on capstone, which is detected not installed yet.
214
253
  Checkout the following link for installation guide:
215
254
 
216
255
  http://www.capstone-engine.org/documentation.html
@@ -220,7 +259,7 @@ http://www.capstone-engine.org/documentation.html
220
259
 
221
260
  def install_keystone_guide
222
261
  <<-EOS
223
- #asm dependes on keystone, which is detected not installed yet.
262
+ #asm depends on keystone, which is detected not installed yet.
224
263
  Checkout the following link for installation guide:
225
264
 
226
265
  https://github.com/keystone-engine/keystone/tree/master/docs
@@ -264,7 +303,7 @@ https://github.com/keystone-engine/keystone/tree/master/docs
264
303
  header.p_offset = 0
265
304
  header.p_vaddr = vma
266
305
  header.p_paddr = vma
267
- header.p_flags = 4 | 1 # r-x
306
+ header.p_flags = 4 | 2 | 1 # rwx
268
307
  header.p_align = arch_align
269
308
  header
270
309
  end
@@ -299,10 +338,8 @@ https://github.com/keystone-engine/keystone/tree/master/docs
299
338
 
300
339
  def e_machine
301
340
  const = ARCH_EM[context.arch.to_sym]
302
- if const.nil?
303
- raise ::Pwnlib::Errors::UnsupportedArchError,
304
- "Unknown machine type of architecture #{context.arch.inspect}."
305
- end
341
+ unsupported!("Unknown machine type of architecture #{context.arch.inspect}.") if const.nil?
342
+
306
343
  ::ELFTools::Constants::EM.const_get("EM_#{const}")
307
344
  end
308
345
 
@@ -310,6 +347,10 @@ https://github.com/keystone-engine/keystone/tree/master/docs
310
347
  context.endian.to_sym
311
348
  end
312
349
 
350
+ def unsupported!(msg)
351
+ raise ::Pwnlib::Errors::UnsupportedArchError, msg
352
+ end
353
+
313
354
  include ::Pwnlib::Context
314
355
  end
315
356
  end
@@ -1,4 +1,5 @@
1
1
  # encoding: ASCII-8BIT
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'pwnlib/util/fiddling'
4
5
 
@@ -27,9 +28,11 @@ module Pwnlib
27
28
  end
28
29
 
29
30
  # We don't need to fall back to super for this, so just disable the lint.
30
- def method_missing(method, *args, &block) # rubocop:disable Style/MethodMissing
31
+ # rubocop:disable Style/MethodMissingSuper
32
+ def method_missing(method, *args, &block)
31
33
  @val.__send__(method, *args, &block)
32
34
  end
35
+ # rubocop:enable Style/MethodMissingSuper
33
36
 
34
37
  def respond_to_missing?(method, include_all)
35
38
  @val.respond_to?(method, include_all)
@@ -1,4 +1,5 @@
1
1
  # encoding: ASCII-8BIT
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'dentaku'
4
5
 
@@ -50,6 +51,7 @@ module Pwnlib
50
51
  # # Pwnlib::Errors::ConstantNotFoundError: Undefined constant(s): meow
51
52
  def eval(str)
52
53
  return str unless str.instance_of?(String)
54
+
53
55
  begin
54
56
  val = calculator.evaluate!(str.strip).to_i
55
57
  rescue Dentaku::UnboundVariableError => e
@@ -94,6 +96,7 @@ module Pwnlib
94
96
  def load_constants((os, arch))
95
97
  filename = File.join(__dir__, os, "#{arch}.rb")
96
98
  return {} unless File.exist?(filename)
99
+
97
100
  builder = ConstantBuilder.new
98
101
  builder.instance_eval(IO.read(filename))
99
102
  builder.tbl
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  const :__NR_read, 0
2
4
  const :__NR_write, 1
3
5
  const :__NR_open, 2
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  const :__NR_exit, 1
2
4
  const :__NR_fork, 2
3
5
  const :__NR_read, 3
@@ -1,4 +1,5 @@
1
1
  # encoding: ASCII-8BIT
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'logger'
4
5
 
@@ -96,6 +97,7 @@ module Pwnlib
96
97
  def update(**kwargs)
97
98
  kwargs.each do |k, v|
98
99
  next if v.nil?
100
+
99
101
  public_send("#{k}=", v)
100
102
  end
101
103
  self
@@ -123,6 +125,7 @@ module Pwnlib
123
125
  # # little
124
126
  def local(**kwargs)
125
127
  raise ArgumentError, "Need a block for #{self.class}##{__callee__}" unless block_given?
128
+
126
129
  # XXX(Darkpi):
127
130
  # improve performance for this if this is too slow, since we use this in many places that has argument
128
131
  # endian / signed / ...
@@ -183,6 +186,7 @@ module Pwnlib
183
186
  arch = arch.to_s.downcase.gsub(/[[:punct:]]/, '')
184
187
  defaults = ARCHS[arch]
185
188
  raise ArgumentError, "arch must be one of #{ARCHS.keys.sort.inspect}" unless defaults
189
+
186
190
  defaults.each { |k, v| @attrs[k] = v }
187
191
  @attrs[:arch] = arch
188
192
  end
@@ -192,7 +196,8 @@ module Pwnlib
192
196
  # @param [Integer] bits
193
197
  # The word size.
194
198
  def bits=(bits)
195
- raise ArgumentError, "bits must be > 0 (#{bits} given)" unless bits > 0
199
+ raise ArgumentError, "bits must be > 0 (#{bits} given)" unless bits.positive?
200
+
196
201
  @attrs[:bits] = bits
197
202
  end
198
203
 
@@ -219,6 +224,7 @@ module Pwnlib
219
224
  def endian=(endian)
220
225
  endian = ENDIANNESSES[endian.to_s.downcase]
221
226
  raise ArgumentError, "endian must be one of #{ENDIANNESSES.sort.inspect}" if endian.nil?
227
+
222
228
  @attrs[:endian] = endian
223
229
  end
224
230
 
@@ -239,6 +245,7 @@ module Pwnlib
239
245
  log_level = value
240
246
  end
241
247
  raise ArgumentError, "log_level must be an integer or one of #{LOG_LEVELS.inspect}" unless log_level
248
+
242
249
  @attrs[:log_level] = log_level
243
250
  end
244
251
 
@@ -252,6 +259,7 @@ module Pwnlib
252
259
  def os=(os)
253
260
  os = os.to_s.downcase
254
261
  raise ArgumentError, "os must be one of #{OSES.sort.inspect}" unless OSES.include?(os)
262
+
255
263
  @attrs[:os] = os
256
264
  end
257
265
 
@@ -275,6 +283,7 @@ module Pwnlib
275
283
  signed = value
276
284
  end
277
285
  raise ArgumentError, "signed must be boolean or one of #{SIGNEDNESSES.keys.sort.inspect}" if signed.nil?
286
+
278
287
  @attrs[:signed] = signed
279
288
  end
280
289
 
@@ -1,4 +1,5 @@
1
1
  # encoding: ASCII-8BIT
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'elftools'
4
5
 
@@ -80,6 +81,7 @@ module Pwnlib
80
81
  def build_id
81
82
  build_id_offsets.each do |offset|
82
83
  next unless @leak.n(@libbase + offset + 12, 4) == "GNU\x00"
84
+
83
85
  return @leak.n(@libbase + offset + 16, 20).unpack('H*').first
84
86
  end
85
87
  nil
@@ -105,6 +107,7 @@ module Pwnlib
105
107
  ptr &= PAGE_MASK
106
108
  loop do
107
109
  return @base = ptr if @leak.n(ptr, 4) == "\x7fELF"
110
+
108
111
  ptr -= PAGE_SIZE
109
112
  end
110
113
  end
@@ -116,6 +119,7 @@ module Pwnlib
116
119
  loop do
117
120
  ptype = @leak.d(e_phoff)
118
121
  break if ptype == ELFTools::Constants::PT::PT_DYNAMIC
122
+
119
123
  e_phoff += phdr_size
120
124
  end
121
125
  offset = { 32 => 8, 64 => 16 }[@elfclass]
@@ -134,6 +138,7 @@ module Pwnlib
134
138
  d_addr = unpack(tmp[@elfword, @elfword])
135
139
  break if d_tag.zero?
136
140
  return d_addr if tag == d_tag
141
+
137
142
  ptr += dyn_size
138
143
  end
139
144
  nil
@@ -157,8 +162,8 @@ module Pwnlib
157
162
  def build_id_offsets
158
163
  {
159
164
  i386: [0x174],
160
- arm: [0x174],
161
- thumb: [0x174],
165
+ arm: [0x174],
166
+ thumb: [0x174],
162
167
  aarch64: [0x238],
163
168
  amd64: [0x270, 0x174],
164
169
  powerpc: [0x174],
@@ -1,6 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'ostruct'
2
4
 
3
5
  require 'elftools'
6
+ require 'one_gadget/one_gadget'
4
7
  require 'rainbow'
5
8
 
6
9
  require 'pwnlib/logger'
@@ -40,14 +43,15 @@ module Pwnlib
40
43
  # # PIE: PIE enabled
41
44
  # #=> #<Pwnlib::ELF::ELF:0x00559bd670dcb8>
42
45
  def initialize(path, checksec: true)
43
- path = File.realpath(path)
46
+ @path = File.realpath(path)
44
47
  @elf_file = ELFTools::ELFFile.new(File.open(path, 'rb'))
45
48
  load_got
46
49
  load_plt
47
50
  load_symbols
48
51
  @address = base_address
49
52
  @load_addr = @address
50
- show_info(path) if checksec
53
+ @one_gadgets = nil
54
+ show_info(@path) if checksec
51
55
  end
52
56
 
53
57
  # Set the base address.
@@ -56,6 +60,7 @@ module Pwnlib
56
60
  # got
57
61
  # plt
58
62
  # symbols
63
+ # one_gadgets
59
64
  #
60
65
  # @param [Integer] val
61
66
  # Address to be changed to.
@@ -68,6 +73,7 @@ module Pwnlib
68
73
  [@got, @plt, @symbols].compact.each do |tbl|
69
74
  tbl.each_pair { |k, _| tbl[k] += val - old }
70
75
  end
76
+ @one_gadgets&.map! { |off| off + val - old }
71
77
  end
72
78
 
73
79
  # Return the protection information, wrapper with color codes.
@@ -82,7 +88,7 @@ module Pwnlib
82
88
  none: Rainbow('No RELRO').red
83
89
  }[relro],
84
90
  'Stack:'.ljust(10) + {
85
- true => Rainbow('Canary found').green,
91
+ true => Rainbow('Canary found').green,
86
92
  false => Rainbow('No canary found').red
87
93
  }[canary?],
88
94
  'NX:'.ljust(10) + {
@@ -102,10 +108,13 @@ module Pwnlib
102
108
  def relro
103
109
  return :none unless @elf_file.segment_by_type(:gnu_relro)
104
110
  return :full if dynamic_tag(:bind_now)
111
+
105
112
  flags = dynamic_tag(:flags)
106
113
  return :full if flags && (flags.value & ::ELFTools::Constants::DF_BIND_NOW) != 0
114
+
107
115
  flags1 = dynamic_tag(:flags_1)
108
116
  return :full if flags1 && (flags1.value & ::ELFTools::Constants::DF_1_NOW) != 0
117
+
109
118
  :partial
110
119
  end
111
120
 
@@ -159,6 +168,7 @@ module Pwnlib
159
168
  # #=> true
160
169
  def search(needle)
161
170
  return enum_for(:search, needle) unless block_given?
171
+
162
172
  load_address_fixup = @address - @load_addr
163
173
  stream = @elf_file.stream
164
174
  @elf_file.each_segments do |seg|
@@ -173,6 +183,7 @@ module Pwnlib
173
183
  loop do
174
184
  offset = data.index(needle, offset)
175
185
  break if offset.nil?
186
+
176
187
  yield (addr + offset + load_address_fixup)
177
188
  offset += 1
178
189
  end
@@ -181,6 +192,58 @@ module Pwnlib
181
192
  end
182
193
  alias find search
183
194
 
195
+ # Returns one-gadgets of glibc.
196
+ #
197
+ # @return [Array<Integer>]
198
+ # Returns array of one-gadgets, see examples.
199
+ #
200
+ # @example
201
+ # ELF::ELF.new('/lib/x86_64-linux-gnu/libc.so.6').one_gadgets[0]
202
+ # #=> 324293 # 0x4f2c5
203
+ #
204
+ # @example
205
+ # libc = ELF::ELF.new('/lib/x86_64-linux-gnu/libc.so.6')
206
+ # libc.one_gadgets[1]
207
+ # #=> 324386 # 0x4f322
208
+ #
209
+ # libc.address = 0x7fff7fff0000
210
+ # libc.one_gadgets[1]
211
+ # #=> 140735341130530 # 0x7fff8003f322
212
+ #
213
+ # @example
214
+ # libc = ELF::ELF.new('/lib/x86_64-linux-gnu/libc.so.6')
215
+ # context.log_level = :debug
216
+ # libc.one_gadgets[0]
217
+ # # [DEBUG] 0x4f2c5 execve("/bin/sh", rsp+0x40, environ)
218
+ # # constraints:
219
+ # # rcx == NULL
220
+ # #=> 324293
221
+ def one_gadgets
222
+ return @one_gadgets if @one_gadgets
223
+
224
+ gadgets = OneGadget.gadgets(file: @path, details: true, level: 1)
225
+ @one_gadgets = gadgets.map { |g| g.offset + address }
226
+ @one_gadgets.instance_variable_set(:@gadgets, gadgets)
227
+
228
+ class << @one_gadgets
229
+ def [](idx)
230
+ super.tap { log.debug(@gadgets[idx].inspect) }
231
+ end
232
+
233
+ def first
234
+ self[0]
235
+ end
236
+
237
+ def last
238
+ self[-1]
239
+ end
240
+
241
+ include ::Pwnlib::Logger
242
+ end
243
+
244
+ @one_gadgets
245
+ end
246
+
184
247
  private
185
248
 
186
249
  def show_info(path)
@@ -192,7 +255,8 @@ module Pwnlib
192
255
  # @return [ELFTools::Dynamic::Tag, nil]
193
256
  def dynamic_tag(type)
194
257
  dynamic = @elf_file.segment_by_type(:dynamic) || @elf_file.section_by_name('.dynamic')
195
- return nil if dynamic.nil? # No dynamic present, might be static-linked.
258
+ return nil if dynamic.nil? # No dynamic table presents, might be statically linked.
259
+
196
260
  dynamic.tag_by_type(type)
197
261
  end
198
262
 
@@ -202,9 +266,11 @@ module Pwnlib
202
266
  sections_by_types(%i(rel rela)).each do |rel_sec|
203
267
  symtab = @elf_file.section_at(rel_sec.header.sh_link)
204
268
  next unless symtab.respond_to?(:symbol_at)
269
+
205
270
  rel_sec.relocations.each do |rel|
206
271
  symbol = symtab.symbol_at(rel.symbol_index)
207
272
  next if symbol.nil? # Unusual case.
273
+
208
274
  @got[symbol.name] = rel.header.r_offset.to_i
209
275
  end
210
276
  end
@@ -220,15 +286,19 @@ module Pwnlib
220
286
  @plt = nil
221
287
  plt_sec = @elf_file.section_by_name('.plt')
222
288
  return log.warn('No PLT section found, PLT not loaded') if plt_sec.nil?
289
+
223
290
  rel_sec = @elf_file.section_by_name('.rel.plt') || @elf_file.section_by_name('.rela.plt')
224
291
  return log.warn('No REL.PLT section found, PLT not loaded') if rel_sec.nil?
292
+
225
293
  symtab = @elf_file.section_at(rel_sec.header.sh_link)
226
294
  return unless symtab.respond_to?(:symbol_at) # unusual case
295
+
227
296
  @plt = OpenStruct.new
228
297
  address = plt_sec.header.sh_addr.to_i + PLT_OFFSET
229
298
  rel_sec.relocations.each do |rel|
230
299
  symbol = symtab.symbol_at(rel.symbol_index)
231
300
  next if symbol.nil? # unusual case
301
+
232
302
  @plt[symbol.name] = address
233
303
  address += PLT_OFFSET
234
304
  end
@@ -239,11 +309,13 @@ module Pwnlib
239
309
  @symbols = OpenStruct.new
240
310
  @elf_file.each_sections do |section|
241
311
  next unless section.respond_to?(:symbols)
312
+
242
313
  section.each_symbols do |symbol|
243
- # Don't care symbols without name.
314
+ # Don't care symbols without a name.
244
315
  next if symbol.name.empty?
245
316
  next if symbol.header.st_value.zero?
246
- # TODO(david942j): handle symbols with same name.
317
+
318
+ # TODO(david942j): handle symbols with the same name.
247
319
  @symbols[symbol.name] = symbol.header.st_value.to_i
248
320
  end
249
321
  end
@@ -255,6 +327,7 @@ module Pwnlib
255
327
 
256
328
  def base_address
257
329
  return 0 if pie?
330
+
258
331
  # Find the min of PT_LOAD's p_vaddr
259
332
  @elf_file.segments_by_type(:load)
260
333
  .map { |seg| seg.header.p_vaddr }