pwntools 1.1.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +6 -3
- data/lib/pwn.rb +1 -0
- data/lib/pwnlib/abi.rb +1 -0
- data/lib/pwnlib/asm.rb +83 -42
- data/lib/pwnlib/constants/constant.rb +4 -1
- data/lib/pwnlib/constants/constants.rb +3 -0
- data/lib/pwnlib/constants/linux/amd64.rb +2 -0
- data/lib/pwnlib/constants/linux/i386.rb +2 -0
- data/lib/pwnlib/context.rb +10 -1
- data/lib/pwnlib/dynelf.rb +7 -2
- data/lib/pwnlib/elf/elf.rb +79 -6
- data/lib/pwnlib/errors.rb +3 -2
- data/lib/pwnlib/ext/array.rb +2 -1
- data/lib/pwnlib/ext/helper.rb +3 -2
- data/lib/pwnlib/ext/integer.rb +2 -1
- data/lib/pwnlib/ext/string.rb +3 -2
- data/lib/pwnlib/logger.rb +21 -1
- data/lib/pwnlib/memleak.rb +1 -0
- data/lib/pwnlib/pwn.rb +5 -1
- data/lib/pwnlib/reg_sort.rb +5 -0
- data/lib/pwnlib/runner.rb +53 -0
- data/lib/pwnlib/shellcraft/generators/amd64/common/common.rb +2 -0
- data/lib/pwnlib/shellcraft/generators/amd64/common/infloop.rb +1 -0
- data/lib/pwnlib/shellcraft/generators/amd64/common/memcpy.rb +5 -1
- data/lib/pwnlib/shellcraft/generators/amd64/common/mov.rb +4 -0
- data/lib/pwnlib/shellcraft/generators/amd64/common/nop.rb +2 -0
- data/lib/pwnlib/shellcraft/generators/amd64/common/popad.rb +1 -0
- data/lib/pwnlib/shellcraft/generators/amd64/common/pushstr.rb +3 -1
- data/lib/pwnlib/shellcraft/generators/amd64/common/pushstr_array.rb +1 -0
- data/lib/pwnlib/shellcraft/generators/amd64/common/ret.rb +1 -0
- data/lib/pwnlib/shellcraft/generators/amd64/common/setregs.rb +3 -2
- data/lib/pwnlib/shellcraft/generators/amd64/linux/cat.rb +3 -2
- data/lib/pwnlib/shellcraft/generators/amd64/linux/execve.rb +1 -0
- data/lib/pwnlib/shellcraft/generators/amd64/linux/exit.rb +1 -0
- data/lib/pwnlib/shellcraft/generators/amd64/linux/linux.rb +2 -0
- data/lib/pwnlib/shellcraft/generators/amd64/linux/ls.rb +1 -0
- data/lib/pwnlib/shellcraft/generators/amd64/linux/open.rb +1 -0
- data/lib/pwnlib/shellcraft/generators/amd64/linux/sh.rb +3 -2
- data/lib/pwnlib/shellcraft/generators/amd64/linux/sleep.rb +24 -0
- data/lib/pwnlib/shellcraft/generators/amd64/linux/syscall.rb +1 -0
- data/lib/pwnlib/shellcraft/generators/helper.rb +11 -2
- data/lib/pwnlib/shellcraft/generators/i386/common/common.rb +2 -0
- data/lib/pwnlib/shellcraft/generators/i386/common/infloop.rb +1 -0
- data/lib/pwnlib/shellcraft/generators/i386/common/memcpy.rb +34 -0
- data/lib/pwnlib/shellcraft/generators/i386/common/mov.rb +3 -0
- data/lib/pwnlib/shellcraft/generators/i386/common/nop.rb +2 -0
- data/lib/pwnlib/shellcraft/generators/i386/common/pushstr.rb +2 -0
- data/lib/pwnlib/shellcraft/generators/i386/common/pushstr_array.rb +1 -0
- data/lib/pwnlib/shellcraft/generators/i386/common/setregs.rb +3 -2
- data/lib/pwnlib/shellcraft/generators/i386/linux/cat.rb +3 -2
- data/lib/pwnlib/shellcraft/generators/i386/linux/execve.rb +1 -0
- data/lib/pwnlib/shellcraft/generators/i386/linux/exit.rb +1 -0
- data/lib/pwnlib/shellcraft/generators/i386/linux/linux.rb +2 -0
- data/lib/pwnlib/shellcraft/generators/i386/linux/ls.rb +1 -0
- data/lib/pwnlib/shellcraft/generators/i386/linux/open.rb +1 -0
- data/lib/pwnlib/shellcraft/generators/i386/linux/sh.rb +3 -2
- data/lib/pwnlib/shellcraft/generators/i386/linux/sleep.rb +24 -0
- data/lib/pwnlib/shellcraft/generators/i386/linux/syscall.rb +1 -0
- data/lib/pwnlib/shellcraft/generators/x86/common/common.rb +5 -3
- data/lib/pwnlib/shellcraft/generators/x86/common/infloop.rb +2 -0
- data/lib/pwnlib/shellcraft/generators/x86/common/memcpy.rb +17 -0
- data/lib/pwnlib/shellcraft/generators/x86/common/mov.rb +2 -0
- data/lib/pwnlib/shellcraft/generators/x86/common/pushstr.rb +2 -0
- data/lib/pwnlib/shellcraft/generators/x86/common/pushstr_array.rb +1 -0
- data/lib/pwnlib/shellcraft/generators/x86/common/setregs.rb +8 -6
- data/lib/pwnlib/shellcraft/generators/x86/linux/cat.rb +1 -0
- data/lib/pwnlib/shellcraft/generators/x86/linux/execve.rb +3 -0
- data/lib/pwnlib/shellcraft/generators/x86/linux/exit.rb +1 -0
- data/lib/pwnlib/shellcraft/generators/x86/linux/linux.rb +2 -0
- data/lib/pwnlib/shellcraft/generators/x86/linux/ls.rb +1 -0
- data/lib/pwnlib/shellcraft/generators/x86/linux/open.rb +1 -0
- data/lib/pwnlib/shellcraft/generators/x86/linux/sh.rb +1 -0
- data/lib/pwnlib/shellcraft/generators/x86/linux/sleep.rb +52 -0
- data/lib/pwnlib/shellcraft/generators/x86/linux/syscall.rb +10 -10
- data/lib/pwnlib/shellcraft/registers.rb +5 -1
- data/lib/pwnlib/shellcraft/shellcraft.rb +8 -3
- data/lib/pwnlib/timer.rb +6 -2
- data/lib/pwnlib/tubes/buffer.rb +4 -1
- data/lib/pwnlib/tubes/process.rb +2 -0
- data/lib/pwnlib/tubes/serialtube.rb +3 -1
- data/lib/pwnlib/tubes/sock.rb +7 -1
- data/lib/pwnlib/tubes/tube.rb +23 -3
- data/lib/pwnlib/ui.rb +21 -0
- data/lib/pwnlib/util/cyclic.rb +2 -0
- data/lib/pwnlib/util/fiddling.rb +37 -5
- data/lib/pwnlib/util/getdents.rb +1 -0
- data/lib/pwnlib/util/hexdump.rb +8 -5
- data/lib/pwnlib/util/lists.rb +3 -0
- data/lib/pwnlib/util/packing.rb +5 -2
- data/lib/pwnlib/util/ruby.rb +1 -0
- data/lib/pwnlib/version.rb +2 -1
- data/test/abi_test.rb +1 -0
- data/test/asm_test.rb +75 -85
- data/test/constants/constant_test.rb +1 -0
- data/test/constants/constants_test.rb +1 -0
- data/test/context_test.rb +1 -0
- data/test/data/assembly/aarch64.s +19 -0
- data/test/data/assembly/amd64.s +21 -0
- data/test/data/assembly/arm.s +9 -0
- data/test/data/assembly/i386.s +21 -0
- data/test/data/assembly/mips.s +16 -0
- data/test/data/assembly/mips64.s +6 -0
- data/test/data/assembly/powerpc.s +18 -0
- data/test/data/assembly/powerpc64.s +36 -0
- data/test/data/assembly/sparc.s +33 -0
- data/test/data/assembly/sparc64.s +5 -0
- data/test/data/assembly/thumb.s +37 -0
- data/test/data/echo.rb +1 -0
- data/test/dynelf_test.rb +3 -1
- data/test/elf/elf_test.rb +18 -0
- data/test/ext_test.rb +1 -0
- data/test/files/use_pwn.rb +1 -0
- data/test/files/use_pwnlib.rb +1 -0
- data/test/full_file_test.rb +6 -0
- data/test/logger_test.rb +24 -3
- data/test/memleak_test.rb +1 -0
- data/test/reg_sort_test.rb +1 -0
- data/test/runner_test.rb +32 -0
- data/test/shellcraft/infloop_test.rb +1 -0
- data/test/shellcraft/linux/cat_test.rb +1 -0
- data/test/shellcraft/linux/ls_test.rb +1 -0
- data/test/shellcraft/linux/sh_test.rb +1 -0
- data/test/shellcraft/linux/sleep_test.rb +68 -0
- data/test/shellcraft/linux/syscalls/execve_test.rb +1 -0
- data/test/shellcraft/linux/syscalls/exit_test.rb +1 -0
- data/test/shellcraft/linux/syscalls/open_test.rb +1 -0
- data/test/shellcraft/linux/syscalls/syscall_test.rb +1 -0
- data/test/shellcraft/memcpy_test.rb +20 -5
- data/test/shellcraft/mov_test.rb +1 -0
- data/test/shellcraft/nop_test.rb +1 -0
- data/test/shellcraft/popad_test.rb +1 -0
- data/test/shellcraft/pushstr_array_test.rb +1 -0
- data/test/shellcraft/pushstr_test.rb +1 -0
- data/test/shellcraft/registers_test.rb +1 -0
- data/test/shellcraft/ret_test.rb +1 -0
- data/test/shellcraft/setregs_test.rb +9 -8
- data/test/shellcraft/shellcraft_test.rb +1 -0
- data/test/test_helper.rb +28 -0
- data/test/timer_test.rb +2 -1
- data/test/tubes/buffer_test.rb +1 -0
- data/test/tubes/process_test.rb +8 -2
- data/test/tubes/serialtube_test.rb +1 -4
- data/test/tubes/sock_test.rb +1 -0
- data/test/tubes/tube_test.rb +10 -1
- data/test/ui_test.rb +18 -0
- data/test/util/cyclic_test.rb +1 -0
- data/test/util/fiddling_test.rb +8 -0
- data/test/util/getdents_test.rb +1 -0
- data/test/util/hexdump_test.rb +2 -1
- data/test/util/lists_test.rb +1 -0
- data/test/util/packing_test.rb +3 -2
- metadata +119 -59
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
|
[![GitHub stars](https://img.shields.io/github/stars/peter50216/pwntools-ruby.svg)](https://github.com/peter50216/pwntools-ruby/stargazers)
|
2
|
-
[![
|
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/
|
5
|
-
[![Code Climate](https://img.shields.io/codeclimate/
|
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
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 }
|