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
@@ -5,7 +5,7 @@ require 'pwnlib/context'
5
5
  module Pwnlib
6
6
  module Util
7
7
  # Some fiddling methods.
8
- # See {ClassMethods} for method details.
8
+ #
9
9
  # @example Call by specifying full module path.
10
10
  # require 'pwnlib/util/fiddling'
11
11
  # Pwnlib::Util::Fiddling.enhex('217') #=> '323137'
@@ -13,250 +13,286 @@ module Pwnlib
13
13
  # require 'pwn'
14
14
  # enhex('217') #=> '323137'
15
15
  module Fiddling
16
- # @note Do not create and call instance method here. Instead, call module method on {Fiddling}.
17
- module ClassMethods
18
- # Hex-encodes a string.
19
- #
20
- # @param [String] s
21
- # String to be encoded.
22
- # @return [String]
23
- # Hex-encoded string.
24
- #
25
- # @example
26
- # enhex('217') #=> '323137'
27
- def enhex(s)
28
- s.unpack('H*')[0]
29
- end
16
+ module_function
30
17
 
31
- # Hex-decodes a string.
32
- #
33
- # @param [String] s
34
- # String to be decoded.
35
- # @return [String]
36
- # Hex-decoded string.
37
- #
38
- # @example
39
- # unhex('353134') #=> '514'
40
- def unhex(s)
41
- [s].pack('H*')
42
- end
18
+ # Hex-encodes a string.
19
+ #
20
+ # @param [String] s
21
+ # String to be encoded.
22
+ #
23
+ # @return [String]
24
+ # Hex-encoded string.
25
+ #
26
+ # @example
27
+ # enhex('217') #=> '323137'
28
+ def enhex(s)
29
+ s.unpack('H*')[0]
30
+ end
43
31
 
44
- # Present number in hex format, same as python hex() do.
45
- #
46
- # @param [Integer] n
47
- # The number.
48
- #
49
- # @return [String]
50
- # The hex format string.
51
- #
52
- # @example
53
- # hex(0) #=> '0x0'
54
- # hex(-10) #=> '-0xa'
55
- # hex(0xfaceb00cdeadbeef) #=> '0xfaceb00cdeadbeef'
56
- def hex(n)
57
- (n < 0 ? '-' : '') + format('0x%x', n.abs)
58
- end
32
+ # Hex-decodes a string.
33
+ #
34
+ # @param [String] s
35
+ # String to be decoded.
36
+ #
37
+ # @return [String]
38
+ # Hex-decoded string.
39
+ #
40
+ # @example
41
+ # unhex('353134') #=> '514'
42
+ def unhex(s)
43
+ [s].pack('H*')
44
+ end
59
45
 
60
- # URL-encodes a string.
61
- #
62
- # @param [String] s
63
- # String to be encoded.
64
- # @return [String]
65
- # URL-encoded string.
66
- #
67
- # @example
68
- # urlencode('shikway') #=> '%73%68%69%6b%77%61%79'
69
- def urlencode(s)
70
- s.bytes.map { |b| format('%%%02x', b) }.join
71
- end
46
+ # Present number in hex format, same as python hex() do.
47
+ #
48
+ # @param [Integer] n
49
+ # The number.
50
+ #
51
+ # @return [String]
52
+ # The hex format string.
53
+ #
54
+ # @example
55
+ # hex(0) #=> '0x0'
56
+ # hex(-10) #=> '-0xa'
57
+ # hex(0xfaceb00cdeadbeef) #=> '0xfaceb00cdeadbeef'
58
+ def hex(n)
59
+ (n < 0 ? '-' : '') + format('0x%x', n.abs)
60
+ end
72
61
 
73
- # URL-decodes a string.
74
- #
75
- # @param [String] s
76
- # String to be decoded.
77
- # @param [Boolean] ignore_invalid
78
- # Whether invalid encoding should be ignore.
79
- # If set to +true+,
80
- # invalid encoding in input are left intact to output.
81
- # @return [String]
82
- # URL-decoded string.
83
- # @raise [ArgumentError]
84
- # If +ignore_invalid+ is +false+,
85
- # and there are invalid encoding in input.
86
- #
87
- # @example
88
- # urldecode('test%20url') #=> 'test url'
89
- # urldecode('%qw%er%ty') #=> raise ArgumentError
90
- # urldecode('%qw%er%ty', true) #=> '%qw%er%ty'
91
- def urldecode(s, ignore_invalid = false)
92
- res = ''
93
- n = 0
94
- while n < s.size
95
- if s[n] != '%'
96
- res << s[n]
62
+ # URL-encodes a string.
63
+ #
64
+ # @param [String] s
65
+ # String to be encoded.
66
+ #
67
+ # @return [String]
68
+ # URL-encoded string.
69
+ #
70
+ # @example
71
+ # urlencode('shikway') #=> '%73%68%69%6b%77%61%79'
72
+ def urlencode(s)
73
+ s.bytes.map { |b| format('%%%02x', b) }.join
74
+ end
75
+
76
+ # URL-decodes a string.
77
+ #
78
+ # @param [String] s
79
+ # String to be decoded.
80
+ # @param [Boolean] ignore_invalid
81
+ # Whether invalid encoding should be ignore.
82
+ # If set to +true+, invalid encoding in input are left intact to output.
83
+ #
84
+ # @return [String]
85
+ # URL-decoded string.
86
+ #
87
+ # @raise [ArgumentError]
88
+ # If +ignore_invalid+ is +false+, and there are invalid encoding in input.
89
+ #
90
+ # @example
91
+ # urldecode('test%20url') #=> 'test url'
92
+ # urldecode('%qw%er%ty') #=> raise ArgumentError
93
+ # urldecode('%qw%er%ty', true) #=> '%qw%er%ty'
94
+ def urldecode(s, ignore_invalid = false)
95
+ res = ''
96
+ n = 0
97
+ while n < s.size
98
+ if s[n] != '%'
99
+ res << s[n]
100
+ n += 1
101
+ else
102
+ cur = s[n + 1, 2]
103
+ if cur =~ /[0-9a-fA-F]{2}/
104
+ res << cur.to_i(16).chr
105
+ n += 3
106
+ elsif ignore_invalid
107
+ res << '%'
97
108
  n += 1
98
109
  else
99
- cur = s[n + 1, 2]
100
- if cur =~ /[0-9a-fA-F]{2}/
101
- res << cur.to_i(16).chr
102
- n += 3
103
- elsif ignore_invalid
104
- res << '%'
105
- n += 1
106
- else
107
- raise ArgumentError, 'Invalid input to urldecode'
108
- end
110
+ raise ArgumentError, 'Invalid input to urldecode'
109
111
  end
110
112
  end
111
- res
112
113
  end
114
+ res
115
+ end
113
116
 
114
- # Converts the argument to an array of bits.
115
- #
116
- # @param [String, Integer] s
117
- # Input to be converted into bits.
118
- # If input is integer,
119
- # output would be padded to byte aligned.
120
- # @param [String] endian
121
- # Endian for conversion.
122
- # Can be any value accepted by context (See {Context::ContextType}).
123
- # @param zero
124
- # Object representing a 0-bit.
125
- # @param one
126
- # Object representing a 1-bit.
127
- # @return [Array]
128
- # An array consisting of +zero+ and +one+.
129
- #
130
- # @example
131
- # bits(314) #=> [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0]
132
- # bits('orz', zero: '-', one: '+').join #=> '-++-++++-+++--+--++++-+-'
133
- # bits(128, endian: 'little') #=> [0, 0, 0, 0, 0, 0, 0, 1]
134
- def bits(s, endian: 'big', zero: 0, one: 1)
135
- context.local(endian: endian) do
136
- is_little = context.endian == 'little'
137
- case s
138
- when String
139
- v = 'B*'
140
- v.downcase! if is_little
141
- s.unpack(v)[0].chars.map { |ch| ch == '1' ? one : zero }
142
- when Integer
143
- # TODO(Darkpi): What should we do to negative number?
144
- raise ArgumentError, 's must be non-negative' unless s >= 0
145
- r = s.to_s(2).chars.map { |ch| ch == '1' ? one : zero }
146
- r.unshift(zero) until (r.size % 8).zero?
147
- is_little ? r.reverse : r
148
- else
149
- raise ArgumentError, 's must be either String or Integer'
150
- end
117
+ # Converts the argument to an array of bits.
118
+ #
119
+ # @param [String, Integer] s
120
+ # Input to be converted into bits.
121
+ # If input is integer, output would be padded to byte aligned.
122
+ # @param [String] endian
123
+ # Endian for conversion.
124
+ # Can be any value accepted by context (See {Context::ContextType}).
125
+ # @param zero
126
+ # Object representing a 0-bit.
127
+ # @param one
128
+ # Object representing a 1-bit.
129
+ #
130
+ # @return [Array]
131
+ # An array consisting of +zero+ and +one+.
132
+ #
133
+ # @example
134
+ # bits(314) #=> [0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0]
135
+ # bits('orz', zero: '-', one: '+').join #=> '-++-++++-+++--+--++++-+-'
136
+ # bits(128, endian: 'little') #=> [0, 0, 0, 0, 0, 0, 0, 1]
137
+ def bits(s, endian: 'big', zero: 0, one: 1)
138
+ context.local(endian: endian) do
139
+ is_little = context.endian == 'little'
140
+ case s
141
+ when String
142
+ v = 'B*'
143
+ v.downcase! if is_little
144
+ s.unpack(v)[0].chars.map { |ch| ch == '1' ? one : zero }
145
+ when Integer
146
+ # TODO(Darkpi): What should we do to negative number?
147
+ raise ArgumentError, 's must be non-negative' unless s >= 0
148
+ r = s.to_s(2).chars.map { |ch| ch == '1' ? one : zero }
149
+ r.unshift(zero) until (r.size % 8).zero?
150
+ is_little ? r.reverse : r
151
+ else
152
+ raise ArgumentError, 's must be either String or Integer'
151
153
  end
152
154
  end
155
+ end
153
156
 
154
- # Simple wrapper around {#bits}, which converts output to string.
155
- #
156
- # @param (see #bits)
157
- # @return [String]
158
- #
159
- # @example
160
- # bits_str('GG') #=> '0100011101000111'
161
- def bits_str(s, endian: 'big', zero: 0, one: 1)
162
- bits(s, endian: endian, zero: zero, one: one).join
163
- end
157
+ # Simple wrapper around {.bits}, which converts output to string.
158
+ #
159
+ # @param (see .bits)
160
+ #
161
+ # @return [String]
162
+ # The output of {.bits} joined.
163
+ #
164
+ # @example
165
+ # bits_str('GG') #=> '0100011101000111'
166
+ def bits_str(s, endian: 'big', zero: 0, one: 1)
167
+ bits(s, endian: endian, zero: zero, one: one).join
168
+ end
164
169
 
165
- # Reverse of {#bits} and {#bits_str}, convert an array of bits back to string.
166
- #
167
- # @param [String, Array<String, Integer, Boolean>] s
168
- # String or array of bits to be convert back to string.
169
- # <tt>[0, '0', false]</tt> represents 0-bit,
170
- # and <tt>[1, '1', true]</tt> represents 1-bit.
171
- # @param [String] endian
172
- # Endian for conversion.
173
- # Can be any value accepted by context (See {Context::ContextType}).
174
- # @raise [ArgumentError]
175
- # If input contains value not in <tt>[0, 1, '0', '1', true, false]</tt>.
176
- #
177
- # @example
178
- # unbits('0100011101000111') #=> 'GG'
179
- # unbits([0, 1, 0, 1, 0, 1, 0, 0]) #=> 'T'
180
- # unbits('0100011101000111', endian: 'little') #=> "\xE2\xE2"
181
- def unbits(s, endian: 'big')
182
- s = s.chars if s.is_a?(String)
183
- context.local(endian: endian) do
184
- is_little = context.endian == 'little'
185
- bytes = s.map do |c|
186
- case c
187
- when '1', 1, true then '1'
188
- when '0', 0, false then '0'
189
- else raise ArgumentError, "cannot decode value #{c.inspect} into a bit"
190
- end
170
+ # Reverse of {.bits} and {.bits_str}, convert an array of bits back to string.
171
+ #
172
+ # @param [String, Array<String, Integer, Boolean>] s
173
+ # String or array of bits to be convert back to string.
174
+ # <tt>[0, '0', false]</tt> represents 0-bit, and <tt>[1, '1', true]</tt> represents 1-bit.
175
+ # @param [String] endian
176
+ # Endian for conversion.
177
+ # Can be any value accepted by context (See {Context::ContextType}).
178
+ #
179
+ # @return [String]
180
+ # A string with bits from +s+.
181
+ #
182
+ # @raise [ArgumentError]
183
+ # If input contains value not in <tt>[0, 1, '0', '1', true, false]</tt>.
184
+ #
185
+ # @example
186
+ # unbits('0100011101000111') #=> 'GG'
187
+ # unbits([0, 1, 0, 1, 0, 1, 0, 0]) #=> 'T'
188
+ # unbits('0100011101000111', endian: 'little') #=> "\xE2\xE2"
189
+ def unbits(s, endian: 'big')
190
+ s = s.chars if s.is_a?(String)
191
+ context.local(endian: endian) do
192
+ is_little = context.endian == 'little'
193
+ bytes = s.map do |c|
194
+ case c
195
+ when '1', 1, true then '1'
196
+ when '0', 0, false then '0'
197
+ else raise ArgumentError, "cannot decode value #{c.inspect} into a bit"
191
198
  end
192
- [bytes.join].pack(is_little ? 'b*' : 'B*')
193
199
  end
200
+ [bytes.join].pack(is_little ? 'b*' : 'B*')
194
201
  end
202
+ end
195
203
 
196
- # Reverse the bits of each byte in input string.
197
- #
198
- # @param [String] s
199
- # Input string.
200
- # @return [String]
201
- # The string with bits of each byte reversed.
202
- #
203
- # @example
204
- # bitswap('rb') #=> 'NF'
205
- def bitswap(s)
206
- unbits(bits(s, endian: 'big'), endian: 'little')
207
- end
204
+ # Reverse the bits of each byte in input string.
205
+ #
206
+ # @param [String] s
207
+ # Input string.
208
+ #
209
+ # @return [String]
210
+ # The string with bits of each byte reversed.
211
+ #
212
+ # @example
213
+ # bitswap('rb') #=> 'NF'
214
+ def bitswap(s)
215
+ unbits(bits(s, endian: 'big'), endian: 'little')
216
+ end
208
217
 
209
- # Reverse the bits of a number, and returns the result as number.
210
- #
211
- # @param [Integer] n
212
- # @param [Integer] bits
213
- # The bit length of +n+,
214
- # only the lower +bits+ bits of +n+ would be used.
215
- # Default to context.bits
216
- # @return [Integer]
217
- # The number with bits reversed.
218
- #
219
- # @example
220
- # bitswap_int(217, bits: 8) #=> 155
221
- def bitswap_int(n, bits: nil)
222
- context.local(bits: bits) do
223
- bits = context.bits
224
- n &= (1 << bits) - 1
225
- bits_str(n, endian: 'little').ljust(bits, '0').to_i(2)
226
- end
218
+ # Reverse the bits of a number, and returns the result as number.
219
+ #
220
+ # @param [Integer] n
221
+ # @param [Integer] bits
222
+ # The bit length of +n+,
223
+ # only the lower +bits+ bits of +n+ would be used.
224
+ # Default to +context.bits+.
225
+ #
226
+ # @return [Integer]
227
+ # The number with bits reversed.
228
+ #
229
+ # @example
230
+ # bitswap_int(217, bits: 8) #=> 155
231
+ def bitswap_int(n, bits: nil)
232
+ context.local(bits: bits) do
233
+ bits = context.bits
234
+ n &= (1 << bits) - 1
235
+ bits_str(n, endian: 'little').ljust(bits, '0').to_i(2)
227
236
  end
237
+ end
228
238
 
229
- # Base64-encodes a string.
230
- # Do NOT contains those stupid newline (with RFC 4648)
231
- #
232
- # @param [String] s
233
- # String to be encoded.
234
- # @return [String]
235
- # Base64-encoded string.
236
- #
237
- # @example
238
- # b64e('desu') #=> 'ZGVzdQ=='
239
- def b64e(s)
240
- [s].pack('m0')
241
- end
239
+ # Base64-encodes a string.
240
+ # Do NOT contains those stupid newline (with RFC 4648).
241
+ #
242
+ # @param [String] s
243
+ # String to be encoded.
244
+ #
245
+ # @return [String]
246
+ # Base64-encoded string.
247
+ #
248
+ # @example
249
+ # b64e('desu') #=> 'ZGVzdQ=='
250
+ def b64e(s)
251
+ [s].pack('m0')
252
+ end
242
253
 
243
- # Base64-decodes a string.
244
- #
245
- # @param [String] s
246
- # String to be decoded.
247
- # @return [String]
248
- # Base64-decoded string.
249
- #
250
- # @example
251
- # b64d('ZGVzdQ==') #=> 'desu'
252
- def b64d(s)
253
- s.unpack('m0')[0]
254
- end
254
+ # Base64-decodes a string.
255
+ #
256
+ # @param [String] s
257
+ # String to be decoded.
258
+ #
259
+ # @return [String]
260
+ # Base64-decoded string.
261
+ #
262
+ # @example
263
+ # b64d('ZGVzdQ==') #=> 'desu'
264
+ def b64d(s)
265
+ s.unpack('m0')[0]
266
+ end
255
267
 
256
- include ::Pwnlib::Context
268
+ # Find two strings that will xor into a given string, while only using a given alphabet.
269
+ #
270
+ # @param [String, Integer] data
271
+ # The desired string.
272
+ # @param [String] avoid
273
+ # The list of disallowed characters. Defaults to nulls and newlines.
274
+ #
275
+ # @return [(String, String)?]
276
+ # Two strings which will xor to the given string. If no such two strings exist, then nil is returned.
277
+ #
278
+ # @example
279
+ # xor_pair("test") #=> ["\x01\x01\x01\x01", 'udru']
280
+ def xor_pair(data, avoid: "\x00\n")
281
+ data = pack(data) if data.is_a?(Integer)
282
+ alphabet = 256.times.reject { |c| avoid.include?(c.chr) }
283
+ res1 = ''
284
+ res2 = ''
285
+ data.bytes.each do |c1|
286
+ # alphabet.shuffle! if context.randomize
287
+ c2 = alphabet.find { |c| alphabet.include?(c1 ^ c) }
288
+ return nil if c2.nil?
289
+ res1 << c2.chr
290
+ res2 << (c1 ^ c2).chr
291
+ end
292
+ [res1, res2]
257
293
  end
258
294
 
259
- extend ClassMethods
295
+ include ::Pwnlib::Context
260
296
  end
261
297
  end
262
298
  end