rex-bin_tools 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +7 -0
  2. checksums.yaml.gz.sig +1 -0
  3. data.tar.gz.sig +0 -0
  4. data/.gitignore +9 -0
  5. data/.rspec +2 -0
  6. data/.travis.yml +5 -0
  7. data/CODE_OF_CONDUCT.md +52 -0
  8. data/Gemfile +4 -0
  9. data/LICENSE +27 -0
  10. data/README.md +22 -0
  11. data/Rakefile +6 -0
  12. data/bin/console +14 -0
  13. data/bin/msfbinscan +284 -0
  14. data/bin/msfelfscan +120 -0
  15. data/bin/msfmachscan +100 -0
  16. data/bin/msfpescan +184 -0
  17. data/bin/setup +8 -0
  18. data/data/identify.txt +3043 -0
  19. data/lib/rex/assembly/nasm.rb +104 -0
  20. data/lib/rex/bin_tools.rb +13 -0
  21. data/lib/rex/bin_tools/version.rb +5 -0
  22. data/lib/rex/elfparsey.rb +9 -0
  23. data/lib/rex/elfparsey/elf.rb +121 -0
  24. data/lib/rex/elfparsey/elfbase.rb +265 -0
  25. data/lib/rex/elfparsey/exceptions.rb +25 -0
  26. data/lib/rex/elfscan.rb +10 -0
  27. data/lib/rex/elfscan/scanner.rb +226 -0
  28. data/lib/rex/elfscan/search.rb +44 -0
  29. data/lib/rex/image_source.rb +10 -0
  30. data/lib/rex/image_source/disk.rb +58 -0
  31. data/lib/rex/image_source/image_source.rb +48 -0
  32. data/lib/rex/image_source/memory.rb +35 -0
  33. data/lib/rex/machparsey.rb +9 -0
  34. data/lib/rex/machparsey/exceptions.rb +31 -0
  35. data/lib/rex/machparsey/mach.rb +209 -0
  36. data/lib/rex/machparsey/machbase.rb +408 -0
  37. data/lib/rex/machscan.rb +9 -0
  38. data/lib/rex/machscan/scanner.rb +217 -0
  39. data/lib/rex/peparsey.rb +10 -0
  40. data/lib/rex/peparsey/exceptions.rb +30 -0
  41. data/lib/rex/peparsey/pe.rb +210 -0
  42. data/lib/rex/peparsey/pe_memdump.rb +61 -0
  43. data/lib/rex/peparsey/pebase.rb +1662 -0
  44. data/lib/rex/peparsey/section.rb +128 -0
  45. data/lib/rex/pescan.rb +11 -0
  46. data/lib/rex/pescan/analyze.rb +366 -0
  47. data/lib/rex/pescan/scanner.rb +230 -0
  48. data/lib/rex/pescan/search.rb +68 -0
  49. data/rex-bin_tools.gemspec +32 -0
  50. metadata +284 -0
  51. metadata.gz.sig +0 -0
@@ -0,0 +1,128 @@
1
+ # -*- coding: binary -*-
2
+
3
+ require 'rex/peparsey/exceptions'
4
+ require 'rex/peparsey/pebase'
5
+ require 'rex/struct2'
6
+
7
+ module Rex
8
+ module PeParsey
9
+ class Section
10
+ attr_accessor :_section_header, :_isource
11
+ attr_accessor :base_rva
12
+
13
+ #
14
+ # Initialize a section.
15
+ #
16
+ # isource - The ImageSource class backing the image
17
+ # base_vma - The address of this section base
18
+ # section_header - The section header (struct2) although this is not
19
+ # required, which is why there is a base_vma. This can be nil.
20
+ #
21
+ def initialize(isource, base_rva, section_header = nil)
22
+ self._isource = isource
23
+ self.base_rva = base_rva
24
+ self._section_header = section_header
25
+ end
26
+
27
+ def file_offset
28
+ _isource.file_offset
29
+ end
30
+
31
+ def size
32
+ _isource.size
33
+ end
34
+
35
+ def name
36
+ # a section header is not required
37
+ return nil if !_section_header
38
+
39
+ # FIXME make this better...
40
+ _section_header.v['Name'].gsub(/\x00+$/n, '')
41
+ end
42
+
43
+ def flags
44
+ # a section header is not required
45
+ return nil if !_section_header
46
+ _section_header.v['Characteristics']
47
+ end
48
+
49
+ def vma
50
+ # a section header is not required
51
+ return nil if !_section_header
52
+ _section_header.v['VirtualAddress']
53
+ end
54
+
55
+ def raw_size
56
+ # a section header is not required
57
+ return nil if !_section_header
58
+ _section_header.v['SizeOfRawData']
59
+ end
60
+
61
+ def _check_offset(offset, len = 1)
62
+ if offset < 0 || offset+len > size
63
+ raise BoundsError, "Offset #{offset} outside of section", caller
64
+ end
65
+ end
66
+
67
+ def read(offset, len)
68
+ _check_offset(offset, len)
69
+ return _isource.read(offset, len)
70
+ end
71
+
72
+ def read_rva(rva, len)
73
+ return read(rva_to_offset(rva), len)
74
+ end
75
+
76
+ def read_asciiz(offset)
77
+ _check_offset(offset)
78
+ return _isource.read_asciiz(offset)
79
+ end
80
+
81
+ def read_asciiz_rva(rva)
82
+ return read_asciiz(rva_to_offset(rva))
83
+ end
84
+
85
+ def index(*args)
86
+ _isource.index(*args)
87
+ end
88
+
89
+ def offset_to_rva(offset)
90
+ if !contains_offset?(offset)
91
+ raise BoundsError, "Offset #{offset} outside of section", caller
92
+ end
93
+
94
+ return offset + base_rva
95
+ end
96
+
97
+ def file_offset_to_rva(foffset)
98
+ return offset_to_rva(foffset - file_offset)
99
+ end
100
+
101
+ def rva_to_offset(rva)
102
+ offset = rva - base_rva
103
+ if !contains_offset?(offset)
104
+ raise BoundsError, "RVA #{rva} outside of section", caller
105
+ end
106
+
107
+ return offset
108
+ end
109
+
110
+ def rva_to_file_offset(rva)
111
+ return rva_to_offset(rva) + file_offset
112
+ end
113
+
114
+ def contains_offset?(offset)
115
+ offset >= 0 && offset < size
116
+ end
117
+
118
+ def contains_file_offset?(foffset)
119
+ contains_offset?(foffset - file_offset)
120
+ end
121
+
122
+ def contains_rva?(rva)
123
+ contains_offset?(rva - base_rva)
124
+ end
125
+
126
+ end
127
+
128
+ end end
@@ -0,0 +1,11 @@
1
+ # -*- coding: binary -*-
2
+
3
+ module Rex
4
+ module PeScan
5
+
6
+ end
7
+ end
8
+
9
+ require 'rex/pescan/analyze'
10
+ require 'rex/pescan/scanner'
11
+ require 'rex/pescan/search'
@@ -0,0 +1,366 @@
1
+ # -*- coding: binary -*-
2
+ module Rex
3
+ module PeScan
4
+ module Analyze
5
+
6
+ require "rex/text/table"
7
+
8
+ class Fingerprint
9
+ attr_accessor :pe
10
+
11
+ def initialize(pe)
12
+ self.pe = pe
13
+ end
14
+
15
+ def config(param)
16
+ @sigs = {}
17
+
18
+ name = nil
19
+ regx = ''
20
+ epon = 0
21
+ sidx = 0
22
+
23
+ fd = File.open(param['database'], 'rb')
24
+ fd.each_line do |line|
25
+ case line
26
+ when /^\s*#/
27
+ next
28
+ when /\[\s*(.*)\s*\]/
29
+ if (name)
30
+ @sigs[ name ] = [regx, epon]
31
+ end
32
+ name = $1 + " [#{ sidx+=1 }]"
33
+ epon = 0
34
+ next
35
+ when /signature\s*=\s*(.*)/
36
+ pat = $1.strip
37
+ regx = ''
38
+ pat.split(/\s+/).each do |c|
39
+ next if c.length != 2
40
+ regx << (c.index('?') ? '.' : "\\x#{c}")
41
+ end
42
+ when /ep_only\s*=\s*(.*)/
43
+ epon = ($1 =~ /^T/i) ? 1 : 0
44
+ end
45
+ end
46
+
47
+ if (name and ! @sigs[name])
48
+ @sigs[ name ] = [regx, epon]
49
+ end
50
+
51
+ fd.close
52
+ end
53
+
54
+ def scan(param)
55
+ config(param)
56
+
57
+ epa = pe.hdr.opt.AddressOfEntryPoint
58
+ buf = pe.read_rva(epa, 256) || ""
59
+
60
+ @sigs.each_pair do |name, data|
61
+ begin
62
+ if (buf.match(Regexp.new('^' + data[0], nil, 'n')))
63
+ $stdout.puts param['file'] + ": " + name
64
+ end
65
+ rescue RegexpError
66
+ $stderr.puts "Invalid signature: #{name} #{data[0]}"
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ class Information
73
+ attr_accessor :pe
74
+
75
+ def initialize(pe)
76
+ self.pe = pe
77
+ end
78
+
79
+ def add_fields(tbl, obj, fields)
80
+ fields.each do |name|
81
+ begin
82
+ tbl << [name, "0x%.8x" % obj.send(name)]
83
+ rescue ::NoMethodError => e
84
+ $stderr.puts "Invalid field #{name}"
85
+ end
86
+ end
87
+ end
88
+
89
+ def scan(param)
90
+
91
+ $stdout.puts "\n\n"
92
+
93
+ tbl = table("Image Headers", ['Name', 'Value'])
94
+ add_fields(tbl, pe.hdr.file, %W{
95
+ Characteristics
96
+ SizeOfOptionalHeader
97
+ PointerToSymbolTable
98
+ TimeDateStamp
99
+ NumberOfSections
100
+ Machine
101
+ })
102
+ $stdout.puts tbl.to_s
103
+ $stdout.puts "\n\n"
104
+
105
+ tbl = table("Optional Image Headers", ['Name', 'Value'])
106
+ add_fields(tbl, pe.hdr.opt, %W{
107
+ ImageBase
108
+ Magic
109
+ MajorLinkerVersion
110
+ MinorLinkerVersion
111
+ SizeOfCode
112
+ SizeOfInitializeData
113
+ SizeOfUninitializeData
114
+ AddressOfEntryPoint
115
+ BaseOfCode
116
+ BaseOfData
117
+ SectionAlignment
118
+ FileAlignment
119
+ MajorOperatingSystemVersion
120
+ MinorOperatingSystemVersion
121
+ MajorImageVersion
122
+ MinorImageVersion
123
+ MajorSubsystemVersion
124
+ MinorSubsystemVersion
125
+ Win32VersionValue
126
+ SizeOfImage
127
+ SizeOfHeaders
128
+ CheckSum
129
+ Subsystem
130
+ DllCharacteristics
131
+ SizeOfStackReserve
132
+ SizeOfStackCommit
133
+ SizeOfHeapReserve
134
+ SizeOfHeapCommit
135
+ LoaderFlags
136
+ NumberOfRvaAndSizes
137
+ })
138
+
139
+ $stdout.puts tbl.to_s
140
+ $stdout.puts "\n\n"
141
+
142
+ # Get DllCharacteristics (in Integer)
143
+ dllcharacteristics = pe.hdr.opt.struct[23].value
144
+
145
+ if (dllcharacteristics > 0)
146
+ tbl = table("DllCharacteristics", ['Flag', 'Value'])
147
+
148
+ # http://msdn.microsoft.com/en-us/library/ms680339(v=vs.85).aspx
149
+ traits = {
150
+ :ASLR => 'False', #IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE
151
+ :Integrity => 'False', #IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY
152
+ :NX => 'False', #IMAGE_DLLCHARACTERISTICS_NX_COMPAT
153
+ :Isolation => 'False', #IMAGE_DLLCHARACTERISTICS_NO_ISOLATION
154
+ :SEH => 'False', #IMAGE_DLLCHARACTERISTICS_NO_SEH
155
+ :Bind => 'False', #IMAGE_DLLCHARACTERISTICS_NO_BIND
156
+ :WDM => 'False', #IMAGE_DLLCHARACTERISTICS_WDM_DRIVER
157
+ :Terminal => 'False' #IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE
158
+ }
159
+
160
+ # Convert integer to an bit array
161
+ c_bits = ("%32d" %dllcharacteristics.to_s(2)).split('').map { |e| e.to_i }.reverse
162
+
163
+ # Check characteristics
164
+ traits[:ASLR] = 'True' if c_bits[6] == 1 #0x0040
165
+ traits[:Integrity] = 'True' if c_bits[7] == 1 #0x0080
166
+ traits[:NX] = 'True' if c_bits[8] == 1 #0x0100
167
+ traits[:Isolation] = 'True' if c_bits[9] == 1 #0x0200
168
+ traits[:SEH] = 'True' if c_bits[10] == 1 #0x0400
169
+ traits[:Bind] = 'True' if c_bits[11] == 1 #0x0800
170
+ traits[:WDM] = 'True' if c_bits[13] == 1 #2000
171
+ traits[:Terminal] = 'True' if c_bits[15] == 1 #0x8000
172
+
173
+ # Putting results to table
174
+ traits.each do |trait_name, trait_value|
175
+ tbl << [trait_name, trait_value]
176
+ end
177
+
178
+ $stdout.puts tbl.to_s
179
+ $stdout.puts "\n\n"
180
+ end
181
+
182
+ if (pe.exports)
183
+ tbl = table("Exported Functions", ['Ordinal', 'Name', 'Address'])
184
+ pe.exports.entries.each do |ent|
185
+ tbl << [ent.ordinal, ent.name, "0x%.8x" % pe.rva_to_vma(ent.rva)]
186
+ end
187
+ $stdout.puts tbl.to_s
188
+ $stdout.puts "\n\n"
189
+ end
190
+
191
+ # Rex::PeParsey::Pe doesn't seem to give us any offset information for each function,
192
+ # which makes it difficult to calculate the actual addresses for them. So instead we
193
+ # are using Metasm::COFF::ImportDirectory to do this task. The ability to see
194
+ # addresses is mainly for ROP.
195
+ if (pe.imports)
196
+ tbl = table("Imported Functions", ['Library', 'Address', 'Ordinal', 'Name'])
197
+ exefmt = Metasm::AutoExe.orshellcode{ Metasm.const_get('x86_64').new }
198
+ exe = exefmt.decode_file(pe._isource.file.path)
199
+ ibase = pe.image_base
200
+ exe_imports = exe.imports
201
+ exe_imports.each do |lib|
202
+ lib_name = lib.libname
203
+ ini_offset = lib.iat_p
204
+ func_table = lib.imports
205
+ offset = 0
206
+ func_table.each do |func|
207
+ func_addr = "0x%08x" %(ibase + ini_offset + offset)
208
+ tbl << [lib_name, func_addr, func.hint, func.name]
209
+ offset += 4
210
+ end
211
+ end
212
+
213
+ $stdout.puts tbl.to_s
214
+ $stdout.puts "\n\n"
215
+ end
216
+
217
+ if(pe.config)
218
+ tbl = table("Configuration Header", ['Name', 'Value'])
219
+ add_fields(tbl, pe.config, %W{
220
+ Size
221
+ TimeDateStamp
222
+ MajorVersion
223
+ MinorVersion
224
+ GlobalFlagsClear
225
+ GlobalFlagsSet
226
+ CriticalSectionDefaultTimeout
227
+ DeCommitFreeBlockThreshold
228
+ DeCommitTotalFreeThreshold
229
+ LockPrefixTable
230
+ MaximumAllocationSize
231
+ VirtualMemoryThreshold
232
+ ProcessAffinityMask
233
+ ProcessHeapFlags
234
+ CSDVersion
235
+ Reserved1
236
+ EditList
237
+ SecurityCookie
238
+ SEHandlerTable
239
+ SEHandlerCount
240
+ })
241
+ $stdout.puts tbl.to_s
242
+ $stdout.puts "\n\n"
243
+ end
244
+
245
+
246
+ if(pe.resources)
247
+ tbl = table("Resources", ['ID', 'Language', 'Code Page', 'Size', 'Name'])
248
+ pe.resources.keys.sort.each do |rkey|
249
+ res = pe.resources[rkey]
250
+ tbl << [rkey, res.lang, res.code, res.size, res.file]
251
+ end
252
+ $stdout.puts tbl.to_s
253
+ $stdout.puts "\n\n"
254
+ end
255
+
256
+ tbl = table("Section Header", ["Name", "VirtualAddress", "SizeOfRawData", "Characteristics"])
257
+ pe.sections.each do |sec|
258
+ tbl << [ sec.name, *[sec.vma, sec.raw_size, sec.flags].map{|x| "0x%.8x" % x} ]
259
+ end
260
+ $stdout.puts tbl.to_s
261
+ $stdout.puts "\n\n"
262
+
263
+ end
264
+
265
+ def table(name, cols)
266
+ Rex::Text::Table.new(
267
+ 'Header' => name,
268
+ 'Columns' => cols
269
+ )
270
+ end
271
+ end
272
+
273
+
274
+ class Ripper
275
+
276
+ require "fileutils"
277
+
278
+ attr_accessor :pe
279
+
280
+ def initialize(pe)
281
+ self.pe = pe
282
+ end
283
+
284
+ def scan(param)
285
+ dest = param['dir']
286
+
287
+ if (param['file'])
288
+ dest = File.join(dest, File.basename(param['file']))
289
+ end
290
+
291
+ ::FileUtils.mkdir_p(dest)
292
+
293
+ pe.resources.keys.sort.each do |rkey|
294
+ res = pe.resources[rkey]
295
+ path = File.join(dest, rkey.split('/')[1] + '_' + res.file)
296
+
297
+ fd = File.new(path, 'wb')
298
+ fd.write(res.data)
299
+ fd.close
300
+ end
301
+ end
302
+ end
303
+
304
+ class ContextMapDumper
305
+
306
+ attr_accessor :pe
307
+
308
+ def initialize(pe)
309
+ self.pe = pe
310
+ end
311
+
312
+ def scan(param)
313
+ dest = param['dir']
314
+ path = ''
315
+
316
+ ::FileUtils.mkdir_p(dest)
317
+
318
+ if(not (param['dir'] and param['file']))
319
+ $stderr.puts "No directory or file specified"
320
+ return
321
+ end
322
+
323
+ if (param['file'])
324
+ path = File.join(dest, File.basename(param['file']) + ".map")
325
+ end
326
+
327
+ fd = File.new(path, "wb")
328
+ pe.all_sections.each do |section|
329
+
330
+ # Skip over known bad sections
331
+ next if section.name == ".data"
332
+ next if section.name == ".reloc"
333
+
334
+ offset = 0
335
+ while offset < section.size
336
+ byte = section.read(offset, 1)[0]
337
+ if byte != 0
338
+ chunkbase = pe.rva_to_vma(section.base_rva) + offset
339
+ data = ''
340
+ while byte != 0
341
+ data << byte
342
+ offset += 1
343
+ byte = 0
344
+ byte = section.read(offset, 1)[0] if offset < section.size
345
+ end
346
+ buff = nil
347
+ buff = [ 0x01, chunkbase, data.length, data].pack("CNNA*") if data.length > 0
348
+
349
+ fd.write(buff) if buff
350
+ end
351
+ offset += 1
352
+ end
353
+
354
+ end
355
+
356
+
357
+ fd.close
358
+ end
359
+ end
360
+
361
+ # EOC
362
+
363
+ end
364
+ end
365
+ end
366
+