pwntools 0.1.0 → 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (168) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +96 -15
  3. data/Rakefile +8 -2
  4. data/lib/pwn.rb +10 -7
  5. data/lib/pwnlib/abi.rb +61 -0
  6. data/lib/pwnlib/asm.rb +357 -0
  7. data/lib/pwnlib/constants/constant.rb +19 -3
  8. data/lib/pwnlib/constants/constants.rb +46 -20
  9. data/lib/pwnlib/constants/linux/amd64.rb +32 -1
  10. data/lib/pwnlib/constants/linux/i386.rb +2 -0
  11. data/lib/pwnlib/context.rb +128 -27
  12. data/lib/pwnlib/dynelf.rb +122 -54
  13. data/lib/pwnlib/elf/elf.rb +340 -0
  14. data/lib/pwnlib/errors.rb +31 -0
  15. data/lib/pwnlib/ext/array.rb +2 -1
  16. data/lib/pwnlib/ext/helper.rb +6 -5
  17. data/lib/pwnlib/ext/integer.rb +2 -1
  18. data/lib/pwnlib/ext/string.rb +3 -2
  19. data/lib/pwnlib/logger.rb +245 -0
  20. data/lib/pwnlib/memleak.rb +59 -29
  21. data/lib/pwnlib/pwn.rb +27 -9
  22. data/lib/pwnlib/reg_sort.rb +109 -110
  23. data/lib/pwnlib/runner.rb +53 -0
  24. data/lib/pwnlib/shellcraft/generators/amd64/common/common.rb +16 -0
  25. data/lib/pwnlib/shellcraft/generators/amd64/common/infloop.rb +24 -0
  26. data/lib/pwnlib/shellcraft/generators/amd64/common/memcpy.rb +35 -0
  27. data/lib/pwnlib/shellcraft/generators/amd64/common/mov.rb +131 -0
  28. data/lib/pwnlib/shellcraft/generators/amd64/common/nop.rb +18 -0
  29. data/lib/pwnlib/shellcraft/generators/amd64/common/popad.rb +28 -0
  30. data/lib/pwnlib/shellcraft/generators/amd64/common/pushstr.rb +66 -0
  31. data/lib/pwnlib/shellcraft/generators/amd64/common/pushstr_array.rb +24 -0
  32. data/lib/pwnlib/shellcraft/generators/amd64/common/ret.rb +33 -0
  33. data/lib/pwnlib/shellcraft/generators/amd64/common/setregs.rb +24 -0
  34. data/lib/pwnlib/shellcraft/generators/amd64/linux/cat.rb +24 -0
  35. data/lib/pwnlib/shellcraft/generators/amd64/linux/execve.rb +24 -0
  36. data/lib/pwnlib/shellcraft/generators/amd64/linux/exit.rb +24 -0
  37. data/lib/pwnlib/shellcraft/generators/amd64/linux/linux.rb +16 -0
  38. data/lib/pwnlib/shellcraft/generators/amd64/linux/ls.rb +24 -0
  39. data/lib/pwnlib/shellcraft/generators/amd64/linux/open.rb +24 -0
  40. data/lib/pwnlib/shellcraft/generators/amd64/linux/sh.rb +24 -0
  41. data/lib/pwnlib/shellcraft/generators/amd64/linux/sleep.rb +24 -0
  42. data/lib/pwnlib/shellcraft/generators/amd64/linux/syscall.rb +24 -0
  43. data/lib/pwnlib/shellcraft/generators/helper.rb +115 -0
  44. data/lib/pwnlib/shellcraft/generators/i386/common/common.rb +16 -0
  45. data/lib/pwnlib/shellcraft/generators/i386/common/infloop.rb +24 -0
  46. data/lib/pwnlib/shellcraft/generators/i386/common/memcpy.rb +34 -0
  47. data/lib/pwnlib/shellcraft/generators/i386/common/mov.rb +93 -0
  48. data/lib/pwnlib/shellcraft/generators/i386/common/nop.rb +18 -0
  49. data/lib/pwnlib/shellcraft/generators/i386/common/pushstr.rb +41 -0
  50. data/lib/pwnlib/shellcraft/generators/i386/common/pushstr_array.rb +24 -0
  51. data/lib/pwnlib/shellcraft/generators/i386/common/setregs.rb +24 -0
  52. data/lib/pwnlib/shellcraft/generators/i386/linux/cat.rb +24 -0
  53. data/lib/pwnlib/shellcraft/generators/i386/linux/execve.rb +24 -0
  54. data/lib/pwnlib/shellcraft/generators/i386/linux/exit.rb +24 -0
  55. data/lib/pwnlib/shellcraft/generators/i386/linux/linux.rb +16 -0
  56. data/lib/pwnlib/shellcraft/generators/i386/linux/ls.rb +24 -0
  57. data/lib/pwnlib/shellcraft/generators/i386/linux/open.rb +24 -0
  58. data/lib/pwnlib/shellcraft/generators/i386/linux/sh.rb +24 -0
  59. data/lib/pwnlib/shellcraft/generators/i386/linux/sleep.rb +24 -0
  60. data/lib/pwnlib/shellcraft/generators/i386/linux/syscall.rb +24 -0
  61. data/lib/pwnlib/shellcraft/generators/x86/common/common.rb +29 -0
  62. data/lib/pwnlib/shellcraft/generators/x86/common/infloop.rb +24 -0
  63. data/lib/pwnlib/shellcraft/generators/x86/common/memcpy.rb +17 -0
  64. data/lib/pwnlib/shellcraft/generators/x86/common/mov.rb +17 -0
  65. data/lib/pwnlib/shellcraft/generators/x86/common/pushstr.rb +17 -0
  66. data/lib/pwnlib/shellcraft/generators/x86/common/pushstr_array.rb +86 -0
  67. data/lib/pwnlib/shellcraft/generators/x86/common/setregs.rb +84 -0
  68. data/lib/pwnlib/shellcraft/generators/x86/linux/cat.rb +54 -0
  69. data/lib/pwnlib/shellcraft/generators/x86/linux/execve.rb +72 -0
  70. data/lib/pwnlib/shellcraft/generators/x86/linux/exit.rb +34 -0
  71. data/lib/pwnlib/shellcraft/generators/x86/linux/linux.rb +16 -0
  72. data/lib/pwnlib/shellcraft/generators/x86/linux/ls.rb +67 -0
  73. data/lib/pwnlib/shellcraft/generators/x86/linux/open.rb +47 -0
  74. data/lib/pwnlib/shellcraft/generators/x86/linux/sh.rb +53 -0
  75. data/lib/pwnlib/shellcraft/generators/x86/linux/sleep.rb +52 -0
  76. data/lib/pwnlib/shellcraft/generators/x86/linux/syscall.rb +52 -0
  77. data/lib/pwnlib/shellcraft/registers.rb +148 -0
  78. data/lib/pwnlib/shellcraft/shellcraft.rb +73 -0
  79. data/lib/pwnlib/timer.rb +67 -0
  80. data/lib/pwnlib/tubes/buffer.rb +99 -0
  81. data/lib/pwnlib/tubes/process.rb +155 -0
  82. data/lib/pwnlib/tubes/serialtube.rb +114 -0
  83. data/lib/pwnlib/tubes/sock.rb +101 -0
  84. data/lib/pwnlib/tubes/tube.rb +442 -0
  85. data/lib/pwnlib/ui.rb +21 -0
  86. data/lib/pwnlib/util/cyclic.rb +97 -94
  87. data/lib/pwnlib/util/fiddling.rb +288 -220
  88. data/lib/pwnlib/util/getdents.rb +85 -0
  89. data/lib/pwnlib/util/hexdump.rb +116 -112
  90. data/lib/pwnlib/util/lists.rb +58 -0
  91. data/lib/pwnlib/util/packing.rb +223 -228
  92. data/lib/pwnlib/util/ruby.rb +19 -0
  93. data/lib/pwnlib/version.rb +3 -1
  94. data/test/abi_test.rb +22 -0
  95. data/test/asm_test.rb +177 -0
  96. data/test/constants/constant_test.rb +2 -0
  97. data/test/constants/constants_test.rb +5 -2
  98. data/test/context_test.rb +14 -3
  99. data/test/data/assembly/aarch64.s +19 -0
  100. data/test/data/assembly/amd64.s +21 -0
  101. data/test/data/assembly/arm.s +9 -0
  102. data/test/data/assembly/i386.s +21 -0
  103. data/test/data/assembly/mips.s +16 -0
  104. data/test/data/assembly/mips64.s +6 -0
  105. data/test/data/assembly/powerpc.s +18 -0
  106. data/test/data/assembly/powerpc64.s +36 -0
  107. data/test/data/assembly/sparc.s +33 -0
  108. data/test/data/assembly/sparc64.s +5 -0
  109. data/test/data/assembly/thumb.s +37 -0
  110. data/test/data/echo.rb +16 -0
  111. data/test/data/elfs/Makefile +24 -0
  112. data/test/data/elfs/amd64.frelro.elf +0 -0
  113. data/test/data/elfs/amd64.frelro.pie.elf +0 -0
  114. data/test/data/elfs/amd64.nrelro.elf +0 -0
  115. data/test/data/elfs/amd64.prelro.elf +0 -0
  116. data/test/data/elfs/amd64.static.elf +0 -0
  117. data/test/data/elfs/i386.frelro.pie.elf +0 -0
  118. data/test/data/elfs/i386.prelro.elf +0 -0
  119. data/test/data/elfs/source.cpp +19 -0
  120. data/test/data/flag +1 -0
  121. data/test/data/lib32/ld.so.2 +0 -0
  122. data/test/data/lib32/libc.so.6 +0 -0
  123. data/test/data/lib64/ld.so.2 +0 -0
  124. data/test/data/lib64/libc.so.6 +0 -0
  125. data/test/dynelf_test.rb +62 -25
  126. data/test/elf/elf_test.rb +147 -0
  127. data/test/ext_test.rb +4 -2
  128. data/test/files/use_pwn.rb +3 -6
  129. data/test/files/use_pwnlib.rb +2 -1
  130. data/test/full_file_test.rb +6 -0
  131. data/test/logger_test.rb +120 -0
  132. data/test/memleak_test.rb +5 -33
  133. data/test/reg_sort_test.rb +4 -1
  134. data/test/runner_test.rb +32 -0
  135. data/test/shellcraft/infloop_test.rb +27 -0
  136. data/test/shellcraft/linux/cat_test.rb +87 -0
  137. data/test/shellcraft/linux/ls_test.rb +109 -0
  138. data/test/shellcraft/linux/sh_test.rb +120 -0
  139. data/test/shellcraft/linux/sleep_test.rb +68 -0
  140. data/test/shellcraft/linux/syscalls/execve_test.rb +137 -0
  141. data/test/shellcraft/linux/syscalls/exit_test.rb +57 -0
  142. data/test/shellcraft/linux/syscalls/open_test.rb +87 -0
  143. data/test/shellcraft/linux/syscalls/syscall_test.rb +84 -0
  144. data/test/shellcraft/memcpy_test.rb +50 -0
  145. data/test/shellcraft/mov_test.rb +99 -0
  146. data/test/shellcraft/nop_test.rb +27 -0
  147. data/test/shellcraft/popad_test.rb +30 -0
  148. data/test/shellcraft/pushstr_array_test.rb +92 -0
  149. data/test/shellcraft/pushstr_test.rb +109 -0
  150. data/test/shellcraft/registers_test.rb +33 -0
  151. data/test/shellcraft/ret_test.rb +31 -0
  152. data/test/shellcraft/setregs_test.rb +63 -0
  153. data/test/shellcraft/shellcraft_test.rb +30 -0
  154. data/test/test_helper.rb +61 -2
  155. data/test/timer_test.rb +42 -0
  156. data/test/tubes/buffer_test.rb +46 -0
  157. data/test/tubes/process_test.rb +105 -0
  158. data/test/tubes/serialtube_test.rb +162 -0
  159. data/test/tubes/sock_test.rb +68 -0
  160. data/test/tubes/tube_test.rb +320 -0
  161. data/test/ui_test.rb +18 -0
  162. data/test/util/cyclic_test.rb +3 -1
  163. data/test/util/fiddling_test.rb +12 -3
  164. data/test/util/getdents_test.rb +33 -0
  165. data/test/util/hexdump_test.rb +9 -10
  166. data/test/util/lists_test.rb +22 -0
  167. data/test/util/packing_test.rb +5 -3
  168. metadata +357 -37
@@ -0,0 +1,34 @@
1
+ # encoding: ASCII-8BIT
2
+ # frozen_string_literal: true
3
+
4
+ require 'pwnlib/shellcraft/generators/x86/linux/linux'
5
+
6
+ module Pwnlib
7
+ module Shellcraft
8
+ module Generators
9
+ module X86
10
+ module Linux
11
+ # Exit syscall.
12
+ #
13
+ # @param [Integer] status
14
+ # Status code.
15
+ #
16
+ # @return [String]
17
+ # Assembly for invoking exit syscall.
18
+ #
19
+ # @example
20
+ # puts shellcraft.exit(1)
21
+ # # /* call exit(1) */
22
+ # # push 1 /* (SYS_exit) */
23
+ # # pop eax
24
+ # # push 1
25
+ # # pop ebx
26
+ # # int 0x80
27
+ def exit(status = 0)
28
+ cat Linux.syscall('SYS_exit', status)
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'pwnlib/shellcraft/generators/helper'
4
+
5
+ module Pwnlib
6
+ module Shellcraft
7
+ module Generators
8
+ module X86
9
+ # For os-related methods.
10
+ module Linux
11
+ extend ::Pwnlib::Shellcraft::Generators::Helper
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,67 @@
1
+ # encoding: ASCII-8BIT
2
+ # frozen_string_literal: true
3
+
4
+ require 'pwnlib/shellcraft/generators/x86/common/pushstr'
5
+ require 'pwnlib/shellcraft/generators/x86/linux/linux'
6
+ require 'pwnlib/shellcraft/generators/x86/linux/syscall'
7
+
8
+ module Pwnlib
9
+ module Shellcraft
10
+ module Generators
11
+ module X86
12
+ module Linux
13
+ # List files.
14
+ #
15
+ # @param [String] dir
16
+ # The relative path to be listed.
17
+ #
18
+ # @example
19
+ # context.arch = 'amd64'
20
+ # puts shellcraft.ls
21
+ # # /* push ".\x00" */
22
+ # # push 0x2e
23
+ # # /* call open("rsp", 0, 0) */
24
+ # # push 2 /* (SYS_open) */
25
+ # # pop rax
26
+ # # mov rdi, rsp
27
+ # # xor esi, esi /* 0 */
28
+ # # cdq /* rdx=0 */
29
+ # # syscall
30
+ # # /* call getdents("rax", "rsp", 4096) */
31
+ # # mov rdi, rax
32
+ # # push 0x4e /* (SYS_getdents) */
33
+ # # pop rax
34
+ # # mov rsi, rsp
35
+ # # xor edx, edx
36
+ # # mov dh, 0x1000 >> 8
37
+ # # syscall
38
+ # # /* call write(1, "rsp", "rax") */
39
+ # # push 1
40
+ # # pop rdi
41
+ # # mov rsi, rsp
42
+ # # mov rdx, rax
43
+ # # push 1 /* (SYS_write) */
44
+ # # pop rax
45
+ # # syscall
46
+ # #=> nil
47
+ #
48
+ # @note
49
+ # This shellcode will output the binary data returned by syscall +getdents+.
50
+ # Use {Pwnlib::Util::Getdents.parse} to parse the output.
51
+ def ls(dir = '.')
52
+ abi = ::Pwnlib::ABI::ABI.syscall
53
+ cat Common.pushstr(dir)
54
+ cat Linux.syscall('SYS_open', abi.stack_pointer, 0, 0)
55
+ # In x86, return value register is same as sysnr register.
56
+ ret = abi.register_arguments.first
57
+ # XXX(david942j): Will fixed size 0x1000 be an issue?
58
+ cat Linux.syscall('SYS_getdents', ret, abi.stack_pointer, 0x1000) # getdents(fd, buf, sz)
59
+
60
+ # Just write all the shits out
61
+ cat Linux.syscall('SYS_write', 1, abi.stack_pointer, ret)
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,47 @@
1
+ # encoding: ASCII-8BIT
2
+ # frozen_string_literal: true
3
+
4
+ require 'pwnlib/shellcraft/generators/x86/linux/linux'
5
+
6
+ module Pwnlib
7
+ module Shellcraft
8
+ module Generators
9
+ module X86
10
+ module Linux
11
+ # Push filename onto stack and perform open syscall.
12
+ #
13
+ # @param [String] filename
14
+ # The file to be opened.
15
+ # @param [String, Integer] flags
16
+ # Flags for opening a file.
17
+ # @param [Integer] mode
18
+ # If +filename+ doesn't exist and 'O_CREAT' is specified in +flags+,
19
+ # +mode+ will be used as the file permission for creating the file.
20
+ #
21
+ # @return [String]
22
+ # Assembly for syscall open.
23
+ #
24
+ # @example
25
+ # puts shellcraft.open('/etc/passwd', 'O_RDONLY')
26
+ # # /* push "/etc/passwd\x00" */
27
+ # # push 0x1010101
28
+ # # xor dword ptr [esp], 0x1657672 /* 0x1010101 ^ 0x647773 */
29
+ # # push 0x7361702f
30
+ # # push 0x6374652f
31
+ # # /* call open("esp", "O_RDONLY", 0) */
32
+ # # push 5 /* (SYS_open) */
33
+ # # pop eax
34
+ # # mov ebx, esp
35
+ # # xor ecx, ecx /* (O_RDONLY) */
36
+ # # cdq /* edx=0 */
37
+ # # int 0x80
38
+ def open(filename, flags = 'O_RDONLY', mode = 0)
39
+ abi = ::Pwnlib::ABI::ABI.syscall
40
+ cat Common.pushstr(filename)
41
+ cat Linux.syscall('SYS_open', abi.stack_pointer, flags, mode)
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,53 @@
1
+ # encoding: ASCII-8BIT
2
+ # frozen_string_literal: true
3
+
4
+ require 'pwnlib/shellcraft/generators/x86/linux/execve'
5
+ require 'pwnlib/shellcraft/generators/x86/linux/linux'
6
+
7
+ module Pwnlib
8
+ module Shellcraft
9
+ module Generators
10
+ module X86
11
+ module Linux
12
+ # Get shell!
13
+ #
14
+ # @param [Boolean, Array<String>] argv
15
+ # Arguments of +argv+ when calling +execve+.
16
+ # If +true+ is given, use +['sh']+.
17
+ # If +Array<String>+ is given, use it as arguments array.
18
+ #
19
+ # @example
20
+ # context.arch = 'i386'
21
+ # puts shellcraft.sh
22
+ # # /* push "/bin///sh\x00" */
23
+ # # push 0x68
24
+ # # push 0x732f2f2f
25
+ # # push 0x6e69622f
26
+ # #
27
+ # # /* call execve("esp", 0, 0) */
28
+ # # push 0xb /* (SYS_execve) */
29
+ # # pop eax
30
+ # # mov ebx, esp
31
+ # # xor ecx, ecx /* 0 */
32
+ # # cdq /* edx=0 */
33
+ # # int 0x80
34
+ # #=> nil
35
+ #
36
+ # @note Null pointer is always used as +envp+.
37
+ #
38
+ # @diff
39
+ # By default, this method calls +execve('/bin///sh', 0, 0)+, which is different from pwntools-python:
40
+ # +execve('/bin///sh', ['sh'], 0)+.
41
+ def sh(argv: false)
42
+ argv = case argv
43
+ when true then ['sh']
44
+ when false then 0
45
+ else argv
46
+ end
47
+ cat Linux.execve('/bin///sh', argv, 0)
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,52 @@
1
+ # encoding: ASCII-8BIT
2
+ # frozen_string_literal: true
3
+
4
+ require 'pwnlib/shellcraft/generators/x86/common/pushstr'
5
+ require 'pwnlib/shellcraft/generators/x86/linux/linux'
6
+ require 'pwnlib/shellcraft/generators/x86/linux/syscall'
7
+ require 'pwnlib/util/packing'
8
+
9
+ module Pwnlib
10
+ module Shellcraft
11
+ module Generators
12
+ module X86
13
+ module Linux
14
+ # Sleep for a specified number of seconds.
15
+ #
16
+ # @param [Float] seconds
17
+ # The seconds to sleep.
18
+ #
19
+ # @example
20
+ # context.arch = :amd64
21
+ # puts shellcraft.sleep(1)
22
+ # # /* push "\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" */
23
+ # # push 1
24
+ # # dec byte ptr [rsp]
25
+ # # push 1
26
+ # # /* call nanosleep("rsp", 0) */
27
+ # # push 0x23 /* (SYS_nanosleep) */
28
+ # # pop rax
29
+ # # mov rdi, rsp
30
+ # # xor esi, esi /* 0 */
31
+ # # syscall
32
+ # # add rsp, 16 /* recover rsp */
33
+ # #=> nil
34
+ #
35
+ # @note
36
+ # Syscall +nanosleep+ accepts a data pointer as argument, the stack will be used for putting the data
37
+ # needed. The generated assembly will use sizeof(struct timespec) = 16 bytes for putting data.
38
+ def sleep(seconds)
39
+ # pushes the data onto stack
40
+ tv_sec = seconds.to_i
41
+ tv_nsec = ((seconds - tv_sec) * 1e9).to_i
42
+ data = ::Pwnlib::Util::Packing.p64(tv_sec) + ::Pwnlib::Util::Packing.p64(tv_nsec)
43
+ cat Common.pushstr(data, append_null: false)
44
+ sp = ::Pwnlib::ABI::ABI.default.stack_pointer
45
+ cat Linux.syscall('SYS_nanosleep', sp, 0)
46
+ cat "add #{sp}, #{data.size} /* recover #{sp} */"
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,52 @@
1
+ # encoding: ASCII-8BIT
2
+ # frozen_string_literal: true
3
+
4
+ require 'pwnlib/shellcraft/generators/x86/common/setregs'
5
+ require 'pwnlib/shellcraft/generators/x86/linux/linux'
6
+ require 'pwnlib/util/ruby'
7
+
8
+ module Pwnlib
9
+ module Shellcraft
10
+ module Generators
11
+ module X86
12
+ module Linux
13
+ # Assembly of +syscall+.
14
+ #
15
+ # @example
16
+ # context.arch = 'i386'
17
+ # puts shellcraft.syscall('SYS_open', 'esp', 0, 0)
18
+ # # /* call open("esp", 0, 0) */
19
+ # # push 5 /* (SYS_open) */
20
+ # # pop eax
21
+ # # mov ebx, esp
22
+ # # xor ecx, ecx /* 0 */
23
+ # # cdq /* edx=0 */
24
+ # # int 0x80
25
+ # #=> nil
26
+ def syscall(*arguments)
27
+ abi = ::Pwnlib::ABI::ABI.syscall
28
+ registers = abi.register_arguments
29
+ reg_ctx = registers.zip(arguments).to_h
30
+ syscall = arguments.first
31
+ if syscall.to_s.start_with?('SYS_')
32
+ fmt = "#{syscall.to_s[4..-1]}(%s)"
33
+ args = []
34
+ else
35
+ fmt = 'syscall(%s)'
36
+ args = [syscall ? syscall.inspect : '?']
37
+ end
38
+ # arg0 to arg5
39
+ 1.upto(6) do |i|
40
+ args.push(arguments[i] ? arguments[i].inspect : '?')
41
+ end
42
+ args.pop while args.last == '?'
43
+
44
+ cat "/* call #{format(fmt, args.join(', '))} */"
45
+ cat Common.setregs(reg_ctx) if arguments.any? { |v| !v.nil? }
46
+ cat abi.syscall_str
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,148 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'pwnlib/context'
4
+
5
+ module Pwnlib
6
+ module Shellcraft
7
+ # Define register names and methods for shellcode generators.
8
+ module Registers
9
+ X86_BASEREGS = %w(ax cx dx bx sp bp si di ip).freeze
10
+
11
+ I386 = (X86_BASEREGS.map { |r| "e#{r}" } +
12
+ X86_BASEREGS +
13
+ %w(eflags cs ss ds es fs gs)).freeze
14
+
15
+ AMD64 = (X86_BASEREGS.map { |r| "r#{r}" } +
16
+ (8..15).map { |r| "r#{r}" } +
17
+ (8..15).map { |r| "r#{r}d" } +
18
+ I386).freeze
19
+
20
+ # x86 registers in decreasing size
21
+ X86_ORDERED = ([
22
+ %w(rax eax ax al),
23
+ %w(rbx ebx bx bl),
24
+ %w(rcx ecx cx cl),
25
+ %w(rdx edx dx dl),
26
+ %w(rdi edi di),
27
+ %w(rsi esi si),
28
+ %w(rbp ebp bp),
29
+ %w(rsp esp sp)
30
+ ] + (8..15).map { |r| ['', 'd', 'w', 'b'].map { |t| "r#{r}#{t}" } }).freeze
31
+
32
+ # class Register, currently only supports i386 and amd64.
33
+ class Register
34
+ # @return [String]
35
+ # Register's name.
36
+ attr_reader :name
37
+ attr_reader :bigger, :smaller, :ff00, :is64bit, :native64, :native32, :xor, :size, :sizes
38
+
39
+ # Instantiate a {Register} object.
40
+ #
41
+ # Create a register by its name and size (in bits) for fetching other information. For example, for register
42
+ # 'ax', +#bigger+ contains 'rax' and 'eax'.
43
+ #
44
+ # Normally you don't need to create any {Register} object, use {.get_register} to get register by name.
45
+ #
46
+ # @param [String] name
47
+ # Register's name.
48
+ # @param [Integer] size
49
+ # Register size in bits.
50
+ #
51
+ # @example
52
+ # Register.new('rax', 64)
53
+ # Register.new('bx', 16)
54
+ def initialize(name, size)
55
+ @name = name
56
+ @size = size
57
+ X86_ORDERED.each do |row|
58
+ next unless row.include?(name)
59
+
60
+ @bigger = row[0, row.index(name)]
61
+ @smaller = row[(row.index(name) + 1)..-1]
62
+ @native64 = row[0]
63
+ @native32 = row[1]
64
+ @sizes = row.each_with_object({}).with_index { |(r, h), i| h[64 >> i] = r }
65
+ @xor = @sizes[[size, 32].min]
66
+ break
67
+ end
68
+ @ff00 = "#{name[1]}h" if @size >= 32 && @name.end_with?('x')
69
+ @is64bit = true if @name.start_with?('r')
70
+ end
71
+
72
+ def bits
73
+ size
74
+ end
75
+
76
+ def bytes
77
+ bits / 8
78
+ end
79
+
80
+ def fits(value)
81
+ size >= Registers.bits_required(value)
82
+ end
83
+
84
+ def to_s
85
+ name
86
+ end
87
+
88
+ def inspect
89
+ format('Register(%s)', name)
90
+ end
91
+ end
92
+
93
+ module_function
94
+
95
+ def registers
96
+ {
97
+ [32, 'i386', 'linux'] => ::Pwnlib::Shellcraft::Registers::I386,
98
+ [64, 'amd64', 'linux'] => ::Pwnlib::Shellcraft::Registers::AMD64
99
+ }[[context.bits, context.arch, context.os]]
100
+ end
101
+
102
+ INTEL = (X86_ORDERED.each_with_object({}) do |row, obj|
103
+ row.each_with_index do |reg, i|
104
+ obj[reg] = Register.new(reg, 64 >> i)
105
+ end
106
+ end).freeze
107
+
108
+ # Get a {Register} object by name.
109
+ #
110
+ # @param [String, Symbol, Register] name
111
+ # The name of register.
112
+ # If +name+ is already a {Register} object, +name+ itself will be returned.
113
+ #
114
+ # @return [Register?]
115
+ # Get the register with name +name+.
116
+ #
117
+ # @example
118
+ # Registers.get_register('eax')
119
+ # #=> Register(eax)
120
+ # Registers.get_register(:ebx)
121
+ # #=> Register(ebx)
122
+ # Registers.get_register('xdd')
123
+ # #=> nil
124
+ def get_register(name)
125
+ return name if name.instance_of?(Register)
126
+ return INTEL[name.to_s] if name.instance_of?(String) || name.instance_of?(Symbol)
127
+
128
+ nil
129
+ end
130
+
131
+ def register?(obj)
132
+ !get_register(obj).nil?
133
+ end
134
+
135
+ def bits_required(value)
136
+ bits = 0
137
+ value = value.abs
138
+ while value.positive?
139
+ bits += 8
140
+ value >>= 8
141
+ end
142
+ bits
143
+ end
144
+
145
+ include ::Pwnlib::Context
146
+ end
147
+ end
148
+ end