pwntools 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (153) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +6 -3
  3. data/lib/pwn.rb +1 -0
  4. data/lib/pwnlib/abi.rb +1 -0
  5. data/lib/pwnlib/asm.rb +83 -42
  6. data/lib/pwnlib/constants/constant.rb +4 -1
  7. data/lib/pwnlib/constants/constants.rb +3 -0
  8. data/lib/pwnlib/constants/linux/amd64.rb +2 -0
  9. data/lib/pwnlib/constants/linux/i386.rb +2 -0
  10. data/lib/pwnlib/context.rb +10 -1
  11. data/lib/pwnlib/dynelf.rb +7 -2
  12. data/lib/pwnlib/elf/elf.rb +79 -6
  13. data/lib/pwnlib/errors.rb +3 -2
  14. data/lib/pwnlib/ext/array.rb +2 -1
  15. data/lib/pwnlib/ext/helper.rb +3 -2
  16. data/lib/pwnlib/ext/integer.rb +2 -1
  17. data/lib/pwnlib/ext/string.rb +3 -2
  18. data/lib/pwnlib/logger.rb +21 -1
  19. data/lib/pwnlib/memleak.rb +1 -0
  20. data/lib/pwnlib/pwn.rb +5 -1
  21. data/lib/pwnlib/reg_sort.rb +5 -0
  22. data/lib/pwnlib/runner.rb +53 -0
  23. data/lib/pwnlib/shellcraft/generators/amd64/common/common.rb +2 -0
  24. data/lib/pwnlib/shellcraft/generators/amd64/common/infloop.rb +1 -0
  25. data/lib/pwnlib/shellcraft/generators/amd64/common/memcpy.rb +5 -1
  26. data/lib/pwnlib/shellcraft/generators/amd64/common/mov.rb +4 -0
  27. data/lib/pwnlib/shellcraft/generators/amd64/common/nop.rb +2 -0
  28. data/lib/pwnlib/shellcraft/generators/amd64/common/popad.rb +1 -0
  29. data/lib/pwnlib/shellcraft/generators/amd64/common/pushstr.rb +3 -1
  30. data/lib/pwnlib/shellcraft/generators/amd64/common/pushstr_array.rb +1 -0
  31. data/lib/pwnlib/shellcraft/generators/amd64/common/ret.rb +1 -0
  32. data/lib/pwnlib/shellcraft/generators/amd64/common/setregs.rb +3 -2
  33. data/lib/pwnlib/shellcraft/generators/amd64/linux/cat.rb +3 -2
  34. data/lib/pwnlib/shellcraft/generators/amd64/linux/execve.rb +1 -0
  35. data/lib/pwnlib/shellcraft/generators/amd64/linux/exit.rb +1 -0
  36. data/lib/pwnlib/shellcraft/generators/amd64/linux/linux.rb +2 -0
  37. data/lib/pwnlib/shellcraft/generators/amd64/linux/ls.rb +1 -0
  38. data/lib/pwnlib/shellcraft/generators/amd64/linux/open.rb +1 -0
  39. data/lib/pwnlib/shellcraft/generators/amd64/linux/sh.rb +3 -2
  40. data/lib/pwnlib/shellcraft/generators/amd64/linux/sleep.rb +24 -0
  41. data/lib/pwnlib/shellcraft/generators/amd64/linux/syscall.rb +1 -0
  42. data/lib/pwnlib/shellcraft/generators/helper.rb +11 -2
  43. data/lib/pwnlib/shellcraft/generators/i386/common/common.rb +2 -0
  44. data/lib/pwnlib/shellcraft/generators/i386/common/infloop.rb +1 -0
  45. data/lib/pwnlib/shellcraft/generators/i386/common/memcpy.rb +34 -0
  46. data/lib/pwnlib/shellcraft/generators/i386/common/mov.rb +3 -0
  47. data/lib/pwnlib/shellcraft/generators/i386/common/nop.rb +2 -0
  48. data/lib/pwnlib/shellcraft/generators/i386/common/pushstr.rb +2 -0
  49. data/lib/pwnlib/shellcraft/generators/i386/common/pushstr_array.rb +1 -0
  50. data/lib/pwnlib/shellcraft/generators/i386/common/setregs.rb +3 -2
  51. data/lib/pwnlib/shellcraft/generators/i386/linux/cat.rb +3 -2
  52. data/lib/pwnlib/shellcraft/generators/i386/linux/execve.rb +1 -0
  53. data/lib/pwnlib/shellcraft/generators/i386/linux/exit.rb +1 -0
  54. data/lib/pwnlib/shellcraft/generators/i386/linux/linux.rb +2 -0
  55. data/lib/pwnlib/shellcraft/generators/i386/linux/ls.rb +1 -0
  56. data/lib/pwnlib/shellcraft/generators/i386/linux/open.rb +1 -0
  57. data/lib/pwnlib/shellcraft/generators/i386/linux/sh.rb +3 -2
  58. data/lib/pwnlib/shellcraft/generators/i386/linux/sleep.rb +24 -0
  59. data/lib/pwnlib/shellcraft/generators/i386/linux/syscall.rb +1 -0
  60. data/lib/pwnlib/shellcraft/generators/x86/common/common.rb +5 -3
  61. data/lib/pwnlib/shellcraft/generators/x86/common/infloop.rb +2 -0
  62. data/lib/pwnlib/shellcraft/generators/x86/common/memcpy.rb +17 -0
  63. data/lib/pwnlib/shellcraft/generators/x86/common/mov.rb +2 -0
  64. data/lib/pwnlib/shellcraft/generators/x86/common/pushstr.rb +2 -0
  65. data/lib/pwnlib/shellcraft/generators/x86/common/pushstr_array.rb +1 -0
  66. data/lib/pwnlib/shellcraft/generators/x86/common/setregs.rb +8 -6
  67. data/lib/pwnlib/shellcraft/generators/x86/linux/cat.rb +1 -0
  68. data/lib/pwnlib/shellcraft/generators/x86/linux/execve.rb +3 -0
  69. data/lib/pwnlib/shellcraft/generators/x86/linux/exit.rb +1 -0
  70. data/lib/pwnlib/shellcraft/generators/x86/linux/linux.rb +2 -0
  71. data/lib/pwnlib/shellcraft/generators/x86/linux/ls.rb +1 -0
  72. data/lib/pwnlib/shellcraft/generators/x86/linux/open.rb +1 -0
  73. data/lib/pwnlib/shellcraft/generators/x86/linux/sh.rb +1 -0
  74. data/lib/pwnlib/shellcraft/generators/x86/linux/sleep.rb +52 -0
  75. data/lib/pwnlib/shellcraft/generators/x86/linux/syscall.rb +10 -10
  76. data/lib/pwnlib/shellcraft/registers.rb +5 -1
  77. data/lib/pwnlib/shellcraft/shellcraft.rb +8 -3
  78. data/lib/pwnlib/timer.rb +6 -2
  79. data/lib/pwnlib/tubes/buffer.rb +4 -1
  80. data/lib/pwnlib/tubes/process.rb +2 -0
  81. data/lib/pwnlib/tubes/serialtube.rb +3 -1
  82. data/lib/pwnlib/tubes/sock.rb +7 -1
  83. data/lib/pwnlib/tubes/tube.rb +23 -3
  84. data/lib/pwnlib/ui.rb +21 -0
  85. data/lib/pwnlib/util/cyclic.rb +2 -0
  86. data/lib/pwnlib/util/fiddling.rb +37 -5
  87. data/lib/pwnlib/util/getdents.rb +1 -0
  88. data/lib/pwnlib/util/hexdump.rb +8 -5
  89. data/lib/pwnlib/util/lists.rb +3 -0
  90. data/lib/pwnlib/util/packing.rb +5 -2
  91. data/lib/pwnlib/util/ruby.rb +1 -0
  92. data/lib/pwnlib/version.rb +2 -1
  93. data/test/abi_test.rb +1 -0
  94. data/test/asm_test.rb +75 -85
  95. data/test/constants/constant_test.rb +1 -0
  96. data/test/constants/constants_test.rb +1 -0
  97. data/test/context_test.rb +1 -0
  98. data/test/data/assembly/aarch64.s +19 -0
  99. data/test/data/assembly/amd64.s +21 -0
  100. data/test/data/assembly/arm.s +9 -0
  101. data/test/data/assembly/i386.s +21 -0
  102. data/test/data/assembly/mips.s +16 -0
  103. data/test/data/assembly/mips64.s +6 -0
  104. data/test/data/assembly/powerpc.s +18 -0
  105. data/test/data/assembly/powerpc64.s +36 -0
  106. data/test/data/assembly/sparc.s +33 -0
  107. data/test/data/assembly/sparc64.s +5 -0
  108. data/test/data/assembly/thumb.s +37 -0
  109. data/test/data/echo.rb +1 -0
  110. data/test/dynelf_test.rb +3 -1
  111. data/test/elf/elf_test.rb +18 -0
  112. data/test/ext_test.rb +1 -0
  113. data/test/files/use_pwn.rb +1 -0
  114. data/test/files/use_pwnlib.rb +1 -0
  115. data/test/full_file_test.rb +6 -0
  116. data/test/logger_test.rb +24 -3
  117. data/test/memleak_test.rb +1 -0
  118. data/test/reg_sort_test.rb +1 -0
  119. data/test/runner_test.rb +32 -0
  120. data/test/shellcraft/infloop_test.rb +1 -0
  121. data/test/shellcraft/linux/cat_test.rb +1 -0
  122. data/test/shellcraft/linux/ls_test.rb +1 -0
  123. data/test/shellcraft/linux/sh_test.rb +1 -0
  124. data/test/shellcraft/linux/sleep_test.rb +68 -0
  125. data/test/shellcraft/linux/syscalls/execve_test.rb +1 -0
  126. data/test/shellcraft/linux/syscalls/exit_test.rb +1 -0
  127. data/test/shellcraft/linux/syscalls/open_test.rb +1 -0
  128. data/test/shellcraft/linux/syscalls/syscall_test.rb +1 -0
  129. data/test/shellcraft/memcpy_test.rb +20 -5
  130. data/test/shellcraft/mov_test.rb +1 -0
  131. data/test/shellcraft/nop_test.rb +1 -0
  132. data/test/shellcraft/popad_test.rb +1 -0
  133. data/test/shellcraft/pushstr_array_test.rb +1 -0
  134. data/test/shellcraft/pushstr_test.rb +1 -0
  135. data/test/shellcraft/registers_test.rb +1 -0
  136. data/test/shellcraft/ret_test.rb +1 -0
  137. data/test/shellcraft/setregs_test.rb +9 -8
  138. data/test/shellcraft/shellcraft_test.rb +1 -0
  139. data/test/test_helper.rb +28 -0
  140. data/test/timer_test.rb +2 -1
  141. data/test/tubes/buffer_test.rb +1 -0
  142. data/test/tubes/process_test.rb +8 -2
  143. data/test/tubes/serialtube_test.rb +1 -4
  144. data/test/tubes/sock_test.rb +1 -0
  145. data/test/tubes/tube_test.rb +10 -1
  146. data/test/ui_test.rb +18 -0
  147. data/test/util/cyclic_test.rb +1 -0
  148. data/test/util/fiddling_test.rb +8 -0
  149. data/test/util/getdents_test.rb +1 -0
  150. data/test/util/hexdump_test.rb +2 -1
  151. data/test/util/lists_test.rb +1 -0
  152. data/test/util/packing_test.rb +3 -2
  153. metadata +119 -59
@@ -1,4 +1,5 @@
1
1
  # encoding: ASCII-8BIT
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'pwnlib/shellcraft/generators/x86/common/pushstr'
4
5
  require 'pwnlib/shellcraft/generators/x86/common/pushstr_array'
@@ -34,6 +35,7 @@ module Pwnlib
34
35
  argv = case argv
35
36
  when String
36
37
  raise ArgumentError, "#{argv.inspect} is not a valid register name" unless register?(argv)
38
+
37
39
  argv
38
40
  when Array
39
41
  cat Common.pushstr_array(abi.register_arguments[2], argv)
@@ -46,6 +48,7 @@ module Pwnlib
46
48
  envp = case envp
47
49
  when String
48
50
  raise ArgumentError, "#{envp.inspect} is not a valid register name" unless register?(envp)
51
+
49
52
  envp
50
53
  when Hash
51
54
  cat Common.pushstr_array(abi.register_arguments[3], envp.map { |k, v| "#{k}=#{v}" })
@@ -1,4 +1,5 @@
1
1
  # encoding: ASCII-8BIT
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'pwnlib/shellcraft/generators/x86/linux/linux'
4
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'pwnlib/shellcraft/generators/helper'
2
4
 
3
5
  module Pwnlib
@@ -1,4 +1,5 @@
1
1
  # encoding: ASCII-8BIT
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'pwnlib/shellcraft/generators/x86/common/pushstr'
4
5
  require 'pwnlib/shellcraft/generators/x86/linux/linux'
@@ -1,4 +1,5 @@
1
1
  # encoding: ASCII-8BIT
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'pwnlib/shellcraft/generators/x86/linux/linux'
4
5
 
@@ -1,4 +1,5 @@
1
1
  # encoding: ASCII-8BIT
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'pwnlib/shellcraft/generators/x86/linux/execve'
4
5
  require 'pwnlib/shellcraft/generators/x86/linux/linux'
@@ -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
@@ -1,7 +1,9 @@
1
1
  # encoding: ASCII-8BIT
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'pwnlib/shellcraft/generators/x86/common/setregs'
4
5
  require 'pwnlib/shellcraft/generators/x86/linux/linux'
6
+ require 'pwnlib/util/ruby'
5
7
 
6
8
  module Pwnlib
7
9
  module Shellcraft
@@ -23,25 +25,23 @@ module Pwnlib
23
25
  # #=> nil
24
26
  def syscall(*arguments)
25
27
  abi = ::Pwnlib::ABI::ABI.syscall
26
- syscall, arg0, arg1, arg2, arg3, arg4, arg5 = arguments
27
- if syscall.respond_to?(:to_s) && syscall.to_s.start_with?('SYS_')
28
- syscall_repr = syscall.to_s[4..-1] + '(%s)'
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)'
29
33
  args = []
30
34
  else
31
- syscall_repr = 'syscall(%s)'
35
+ fmt = 'syscall(%s)'
32
36
  args = [syscall ? syscall.inspect : '?']
33
37
  end
34
38
  # arg0 to arg5
35
39
  1.upto(6) do |i|
36
40
  args.push(arguments[i] ? arguments[i].inspect : '?')
37
41
  end
38
-
39
42
  args.pop while args.last == '?'
40
- syscall_repr = format(syscall_repr, args.join(', '))
41
- registers = abi.register_arguments
42
- arguments = [syscall, arg0, arg1, arg2, arg3, arg4, arg5]
43
- reg_ctx = registers.zip(arguments).to_h
44
- cat "/* call #{syscall_repr} */"
43
+
44
+ cat "/* call #{format(fmt, args.join(', '))} */"
45
45
  cat Common.setregs(reg_ctx) if arguments.any? { |v| !v.nil? }
46
46
  cat abi.syscall_str
47
47
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'pwnlib/context'
2
4
 
3
5
  module Pwnlib
@@ -55,6 +57,7 @@ module Pwnlib
55
57
  @size = size
56
58
  X86_ORDERED.each do |row|
57
59
  next unless row.include?(name)
60
+
58
61
  @bigger = row[0, row.index(name)]
59
62
  @smaller = row[(row.index(name) + 1)..-1]
60
63
  @native64 = row[0]
@@ -122,6 +125,7 @@ module Pwnlib
122
125
  def get_register(name)
123
126
  return name if name.instance_of?(Register)
124
127
  return INTEL[name.to_s] if name.instance_of?(String) || name.instance_of?(Symbol)
128
+
125
129
  nil
126
130
  end
127
131
 
@@ -132,7 +136,7 @@ module Pwnlib
132
136
  def bits_required(value)
133
137
  bits = 0
134
138
  value = value.abs
135
- while value > 0
139
+ while value.positive?
136
140
  bits += 8
137
141
  value >>= 8
138
142
  end
@@ -1,4 +1,5 @@
1
1
  # encoding: ASCII-8BIT
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'singleton'
4
5
 
@@ -19,7 +20,7 @@ module Pwnlib
19
20
 
20
21
  # All files under generators/ will be required.
21
22
  def initialize
22
- Dir[File.join(__dir__, 'generators', '**', '*.rb')].each do |f|
23
+ Dir[File.join(__dir__, 'generators', '**', '*.rb')].sort.each do |f|
23
24
  require f
24
25
  end
25
26
  end
@@ -29,15 +30,17 @@ module Pwnlib
29
30
  #
30
31
  # With this method, +context.local(arch: 'amd64') { shellcraft.sh }+ will invoke
31
32
  # {Shellcraft::Generators::Amd64::Linux#sh}.
32
- def method_missing(method, *args, &block)
33
+ def method_missing(method, *args, **kwargs, &block)
33
34
  mod = find_module_for(method)
34
35
  return super if mod.nil?
35
- mod.public_send(method, *args, &block)
36
+
37
+ mod.public_send(method, *args, **kwargs, &block)
36
38
  end
37
39
 
38
40
  # For +respond_to?+.
39
41
  def respond_to_missing?(method, include_private = false)
40
42
  return true if find_module_for(method)
43
+
41
44
  super
42
45
  end
43
46
 
@@ -55,9 +58,11 @@ module Pwnlib
55
58
  # try search in Common module
56
59
  common_module = arch_module.const_get(:Common)
57
60
  return common_module if common_module.singleton_methods.include?(method)
61
+
58
62
  # search in ${os} module
59
63
  os_module = arch_module.const_get(context.os.capitalize)
60
64
  return os_module if os_module.singleton_methods.include?(method)
65
+
61
66
  nil
62
67
  end
63
68
 
@@ -1,4 +1,5 @@
1
1
  # encoding: ASCII-8BIT
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'time'
4
5
 
@@ -29,11 +30,13 @@ module Pwnlib
29
30
 
30
31
  def timeout
31
32
  return @timeout || ::Pwnlib::Context.context.timeout unless started?
33
+
32
34
  @deadline == :forever ? :forever : [@deadline - Time.now, 0].max
33
35
  end
34
36
 
35
37
  def timeout=(timeout)
36
38
  raise "Can't change timeout when countdown" if started?
39
+
37
40
  @timeout = timeout
38
41
  end
39
42
 
@@ -41,13 +44,14 @@ module Pwnlib
41
44
  # NOTE(Darkpi): timeout = nil means default value for the first time, and nop after that.
42
45
  def countdown(timeout = nil)
43
46
  raise ArgumentError, 'Need a block for countdown' unless block_given?
47
+
44
48
  if started?
45
49
  return yield if timeout.nil?
50
+
46
51
  raise 'Nested countdown not permitted'
47
52
  end
48
53
 
49
- timeout ||= @timeout
50
- timeout ||= ::Pwnlib::Context.context.timeout
54
+ timeout ||= @timeout || ::Pwnlib::Context.context.timeout
51
55
 
52
56
  @deadline = timeout == :forever ? :forever : Time.now + timeout
53
57
 
@@ -1,4 +1,5 @@
1
1
  # encoding: ASCII-8BIT
2
+ # frozen_string_literal: true
2
3
 
3
4
  module Pwnlib
4
5
  module Tubes
@@ -35,6 +36,7 @@ module Pwnlib
35
36
  else
36
37
  data = data.to_s.dup
37
38
  return if data.empty?
39
+
38
40
  @data << data
39
41
  end
40
42
  @size += data.size
@@ -53,6 +55,7 @@ module Pwnlib
53
55
  else
54
56
  data = data.to_s.dup
55
57
  return if data.empty?
58
+
56
59
  @data.unshift(data)
57
60
  end
58
61
  @size += data.size
@@ -61,7 +64,7 @@ module Pwnlib
61
64
 
62
65
  # Retrieves bytes from the buffer.
63
66
  #
64
- # @param [Integer] n
67
+ # @param [Integer?] n
65
68
  # Maximum number of bytes to fetch.
66
69
  #
67
70
  # @return [String]
@@ -1,4 +1,5 @@
1
1
  # encoding: ASCII-8BIT
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'pwnlib/errors'
4
5
  require 'pwnlib/tubes/tube'
@@ -140,6 +141,7 @@ module Pwnlib
140
141
  def recv_raw(size)
141
142
  o, = IO.select([@o], [], [], @timeout)
142
143
  return if o.nil?
144
+
143
145
  @o.readpartial(size)
144
146
  rescue Errno::EIO, Errno::EPIPE, IOError
145
147
  raise ::Pwnlib::Errors::EndOfTubeError
@@ -1,4 +1,5 @@
1
1
  # encoding: ASCII-8BIT
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'rubyserial'
4
5
 
@@ -69,6 +70,7 @@ module Pwnlib
69
70
  while @serial_timer.active?
70
71
  data += @conn.read(numbytes - data.length)
71
72
  break unless data.empty?
73
+
72
74
  sleep 0.1
73
75
  end
74
76
  # XXX(JonathanBeverley): should we reverse @convert_newlines here?
@@ -94,7 +96,7 @@ module Pwnlib
94
96
 
95
97
  data.gsub!(context.newline, "\r\n") if @convert_newlines
96
98
  begin
97
- return @conn.write(data)
99
+ @conn.write(data)
98
100
  rescue RubySerial::Error
99
101
  close
100
102
  raise ::Pwnlib::Errors::EndOfTubeError
@@ -1,4 +1,5 @@
1
1
  # encoding: ASCII-8BIT
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'socket'
4
5
 
@@ -42,6 +43,7 @@ module Pwnlib
42
43
  def close(direction = :both)
43
44
  if direction == :both
44
45
  return if @sock.closed?
46
+
45
47
  @closed[:read] = @closed[:write] = true
46
48
  @sock.close
47
49
  else
@@ -55,6 +57,7 @@ module Pwnlib
55
57
 
56
58
  def shutdown(direction)
57
59
  return if @closed[direction]
60
+
58
61
  @closed[direction] = true
59
62
 
60
63
  if direction.equal?(:read)
@@ -70,6 +73,7 @@ module Pwnlib
70
73
 
71
74
  def send_raw(data)
72
75
  raise ::Pwnlib::Errors::EndOfTubeError if @closed[:write]
76
+
73
77
  begin
74
78
  @sock.write(data)
75
79
  rescue Errno::EPIPE, Errno::ECONNRESET, Errno::ECONNREFUSED
@@ -80,10 +84,12 @@ module Pwnlib
80
84
 
81
85
  def recv_raw(size)
82
86
  raise ::Pwnlib::Errors::EndOfTubeError if @closed[:read]
87
+
83
88
  begin
84
89
  rs, = IO.select([@sock], [], [], @timeout)
85
90
  return if rs.nil?
86
- return @sock.readpartial(size)
91
+
92
+ @sock.readpartial(size)
87
93
  rescue Errno::ECONNREFUSED, Errno::ECONNRESET, Errno::ECONNABORTED, EOFError
88
94
  shutdown(:read)
89
95
  raise ::Pwnlib::Errors::EndOfTubeError
@@ -1,4 +1,5 @@
1
1
  # encoding: ASCII-8BIT
2
+ # frozen_string_literal: true
2
3
 
3
4
  require 'pwnlib/context'
4
5
  require 'pwnlib/errors'
@@ -59,6 +60,7 @@ module Pwnlib
59
60
  # @!macro raise_timeout
60
61
  def recv(num_bytes = nil, timeout: nil)
61
62
  return '' if @buffer.empty? && !fillbuffer(timeout: timeout)
63
+
62
64
  @buffer.get(num_bytes)
63
65
  end
64
66
  alias read recv
@@ -99,8 +101,9 @@ module Pwnlib
99
101
  # @!macro raise_timeout
100
102
  def recvpred(timeout: nil)
101
103
  raise ArgumentError, 'Need a block for recvpred' unless block_given?
104
+
102
105
  @timer.countdown(timeout) do
103
- data = ''
106
+ data = +''
104
107
  begin
105
108
  until yield(data)
106
109
  return '' unless @timer.active?
@@ -108,6 +111,7 @@ module Pwnlib
108
111
  c = recv(1)
109
112
 
110
113
  return '' if c.empty?
114
+
111
115
  data << c
112
116
  end
113
117
  data.slice!(0..-1)
@@ -161,12 +165,13 @@ module Pwnlib
161
165
  max_len = delims.map(&:size).max
162
166
  @timer.countdown(timeout) do
163
167
  data = Buffer.new
164
- matching = ''
168
+ matching = +''
165
169
  begin
166
170
  while @timer.active?
167
171
  s = recv(1)
168
172
 
169
173
  return '' if s.empty?
174
+
170
175
  matching << s
171
176
 
172
177
  sidx = matching.size
@@ -174,6 +179,7 @@ module Pwnlib
174
179
  delims.each do |d|
175
180
  idx = matching.index(d)
176
181
  next unless idx
182
+
177
183
  if idx + d.size <= sidx + match_len
178
184
  sidx = idx
179
185
  match_len = d.size
@@ -265,6 +271,19 @@ module Pwnlib
265
271
  recvpred(timeout: timeout) { |data| data =~ regex }
266
272
  end
267
273
 
274
+ # Receives data until reaching EOF or a timeout is occurred.
275
+ #
276
+ # @!macro timeout_definition
277
+ #
278
+ # @return [String]
279
+ # Returns the data received.
280
+ def recvall(timeout: nil)
281
+ recvn(1 << 63, timeout: timeout)
282
+ rescue ::Pwnlib::Errors::EndOfTubeError, ::Pwnlib::Errors::TimeoutError
283
+ @buffer.get
284
+ end
285
+ alias readall recvall
286
+
268
287
  # Sends data.
269
288
  #
270
289
  # @param [String] data
@@ -323,8 +342,9 @@ module Pwnlib
323
342
  # #=> nil
324
343
  def puts(*objs)
325
344
  return write(context.newline) if objs.empty?
345
+
326
346
  objs = *objs.flatten
327
- s = ''
347
+ s = +''
328
348
  objs.map(&:to_s).each do |elem|
329
349
  s << elem
330
350
  s << context.newline unless elem.end_with?(context.newline)