pwntools 1.1.0 → 1.2.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.
- 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
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3385a46a409e98ef0ffac19fb93c5ec19d7fde592abbb99ccdc462e186d2b922
|
|
4
|
+
data.tar.gz: d865773d92a7b3068005bfaa9c9d5ba5f1a8bce0e62e05eb55b340c80d2fe3dd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1d529315d4e222cc89d3783f4454e804d8ce9d4c8a23a2657b29f23be14dd63e7b5f8f668aa95db944b7ec887d7fc2563f00067a93ec2b841448408e3aee141c
|
|
7
|
+
data.tar.gz: 1f95b2194ac3fea17ea87d030bbba0f52e638978797a7f9068e9af92c2c2d98f39d25cb90be6b73d2e7008e41fd2f913684395a68fbbb6d22115b341533fc8fd
|
data/README.md
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
[](https://github.com/peter50216/pwntools-ruby/stargazers)
|
|
2
|
-
[](https://github.com/peter50216/pwntools-ruby/issues)
|
|
3
3
|
[](https://travis-ci.org/peter50216/pwntools-ruby)
|
|
4
|
-
[](https://codeclimate.com/github/peter50216/pwntools-ruby/coverage)
|
|
5
|
+
[](https://codeclimate.com/github/peter50216/pwntools-ruby)
|
|
6
6
|
[](https://inch-ci.org/github/peter50216/pwntools-ruby)
|
|
7
7
|
[](http://choosealicense.com/licenses/mit/)
|
|
8
|
+
[](https://dependabot.com)
|
|
9
|
+
[](https://inventory.rawsec.ml/)
|
|
10
|
+
<!-- [](https://gemnasium.com/peter50216/pwntools-ruby) -->
|
|
8
11
|
|
|
9
12
|
# pwntools-ruby
|
|
10
13
|
|
data/lib/pwn.rb
CHANGED
data/lib/pwnlib/abi.rb
CHANGED
data/lib/pwnlib/asm.rb
CHANGED
|
@@ -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
|
|
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
|
|
51
|
-
# # 1002: 48 b8 2f 62 69 6e 2f 2f 2f 73
|
|
52
|
-
# # 100c: 50
|
|
53
|
-
# # 100d: 48 89 e7
|
|
54
|
-
# # 1010: 31 d2
|
|
55
|
-
# # 1012: 31 f6
|
|
56
|
-
# # 1014: 6a 3b
|
|
57
|
-
# # 1016: 58
|
|
58
|
-
# # 1017: 0f 05
|
|
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(
|
|
64
|
+
cs = Crabstone::Disassembler.new(cs_arch, cs_mode)
|
|
62
65
|
insts = cs.disasm(data, vma).map do |ins|
|
|
63
|
-
[ins.address, ins.bytes
|
|
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].
|
|
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(
|
|
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
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
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
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
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
|
-
|
|
193
|
-
|
|
194
|
-
|
|
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
|
-
|
|
200
|
-
|
|
201
|
-
|
|
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
|
|
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
|
|
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 #
|
|
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
|
-
|
|
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
|
-
|
|
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
|
data/lib/pwnlib/context.rb
CHANGED
|
@@ -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
|
|
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
|
|
data/lib/pwnlib/dynelf.rb
CHANGED
|
@@ -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:
|
|
161
|
-
thumb:
|
|
165
|
+
arm: [0x174],
|
|
166
|
+
thumb: [0x174],
|
|
162
167
|
aarch64: [0x238],
|
|
163
168
|
amd64: [0x270, 0x174],
|
|
164
169
|
powerpc: [0x174],
|
data/lib/pwnlib/elf/elf.rb
CHANGED
|
@@ -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
|
-
|
|
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 =>
|
|
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
|
|
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
|
-
|
|
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 }
|