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,104 @@
1
+ # -*- coding: binary -*-
2
+
3
+ require 'tempfile'
4
+ require 'rex/file'
5
+ require 'rex/text'
6
+
7
+ module Rex
8
+ module Assembly
9
+
10
+ ###
11
+ #
12
+ # This class uses assembly to assemble and disassemble stuff.
13
+ #
14
+ ###
15
+ class Nasm
16
+
17
+ @@nasm_path = 'assembly'
18
+ @@ndisasm_path = 'ndisasm'
19
+
20
+ #
21
+ # Ensures that the assembly environment is sane.
22
+ #
23
+ def self.check
24
+ @@nasm_path =
25
+ Rex::FileUtils.find_full_path('assembly') ||
26
+ Rex::FileUtils.find_full_path('assembly.exe') ||
27
+ Rex::FileUtils.find_full_path('nasmw.exe') ||
28
+ raise(RuntimeError, "No assembly installation was found.")
29
+
30
+ @@ndisasm_path =
31
+ Rex::FileUtils.find_full_path('ndisasm') ||
32
+ Rex::FileUtils.find_full_path('ndisasm.exe') ||
33
+ Rex::FileUtils.find_full_path('ndisasmw.exe') ||
34
+ raise(RuntimeError, "No ndisasm installation was found.")
35
+ end
36
+
37
+ #
38
+ # Assembles the supplied assembly and returns the raw opcodes.
39
+ #
40
+ def self.assemble(assembly, bits=32)
41
+ check
42
+
43
+ # Open the temporary file
44
+ tmp = Tempfile.new('nasmXXXX')
45
+ tmp.binmode
46
+
47
+ tpath = tmp.path
48
+ opath = tmp.path + '.out'
49
+
50
+ # Write the assembly data to a file
51
+ tmp.write("BITS #{bits}\n" + assembly)
52
+ tmp.flush()
53
+ tmp.seek(0)
54
+
55
+ # Run assembly
56
+ if (system(@@nasm_path, '-f', 'bin', '-o', opath, tpath) == false)
57
+ raise RuntimeError, "Assembler did not complete successfully: #{$?.exitstatus}"
58
+ end
59
+
60
+ # Read the assembled text
61
+ rv = ::IO.read(opath)
62
+
63
+ # Remove temporary files
64
+ File.unlink(opath)
65
+ tmp.close(true)
66
+
67
+ rv
68
+ end
69
+
70
+ #
71
+ # Disassembles the supplied raw opcodes
72
+ #
73
+ def self.disassemble(raw, bits=32)
74
+ check
75
+
76
+ tmp = Tempfile.new('nasmout')
77
+ tmp.binmode
78
+
79
+ tfd = File.open(tmp.path, "wb")
80
+
81
+ tfd.write(raw)
82
+ tfd.flush()
83
+ tfd.close
84
+
85
+ p = ::IO.popen("\"#{@@ndisasm_path}\" -b #{bits} \"#{tmp.path}\"")
86
+ o = ''
87
+
88
+ begin
89
+ until p.eof?
90
+ o += p.read
91
+ end
92
+ ensure
93
+ p.close
94
+ end
95
+
96
+ tmp.close(true)
97
+
98
+ o
99
+ end
100
+
101
+ end
102
+
103
+ end
104
+ end
@@ -0,0 +1,13 @@
1
+ require "rex/bin_tools/version"
2
+ require 'rex/image_source'
3
+ require 'rex/elfparsey'
4
+ require 'rex/elfscan'
5
+ require 'rex/machparsey'
6
+ require 'rex/machscan'
7
+ require 'rex/peparsey'
8
+ require 'rex/pescan'
9
+
10
+ module Rex
11
+ module BinTools
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ module Rex
2
+ module BinTools
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,9 @@
1
+ # -*- coding: binary -*-
2
+
3
+ module Rex
4
+ module ElfParsey
5
+
6
+ end
7
+ end
8
+
9
+ require 'rex/elfparsey/elf'
@@ -0,0 +1,121 @@
1
+ # -*- coding: binary -*-
2
+
3
+ require 'rex/elfparsey/elfbase'
4
+ require 'rex/elfparsey/exceptions'
5
+ require 'rex/image_source'
6
+
7
+ module Rex
8
+ module ElfParsey
9
+ class Elf < ElfBase
10
+
11
+ attr_accessor :elf_header, :program_header, :base_addr, :isource
12
+
13
+ def initialize(isource)
14
+ offset = 0
15
+ base_addr = 0
16
+
17
+ # ELF Header
18
+ elf_header = ElfHeader.new(isource.read(offset, ELF_HEADER_SIZE))
19
+
20
+ # Data encoding
21
+ ei_data = elf_header.e_ident[EI_DATA,1].unpack("C")[0]
22
+
23
+ e_phoff = elf_header.e_phoff
24
+ e_phentsize = elf_header.e_phentsize
25
+ e_phnum = elf_header.e_phnum
26
+
27
+ # Program Header Table
28
+ program_header = []
29
+
30
+ e_phnum.times do |i|
31
+ offset = e_phoff + (e_phentsize * i)
32
+
33
+ program_header << ProgramHeader.new(
34
+ isource.read(offset, PROGRAM_HEADER_SIZE), ei_data
35
+ )
36
+
37
+ if program_header[-1].p_type == PT_LOAD && program_header[-1].p_flags & PF_EXEC > 0
38
+ base_addr = program_header[-1].p_vaddr
39
+ end
40
+
41
+ end
42
+
43
+ self.elf_header = elf_header
44
+ self.program_header = program_header
45
+ self.base_addr = base_addr
46
+ self.isource = isource
47
+ end
48
+
49
+ def self.new_from_file(filename, disk_backed = false)
50
+
51
+ file = ::File.new(filename)
52
+ # file.binmode # windows... :\
53
+
54
+ if disk_backed
55
+ return self.new(ImageSource::Disk.new(file))
56
+ else
57
+ obj = new_from_string(file.read)
58
+ file.close
59
+ return obj
60
+ end
61
+ end
62
+
63
+ def self.new_from_string(data)
64
+ return self.new(ImageSource::Memory.new(data))
65
+ end
66
+
67
+ #
68
+ # Returns true if this binary is for a 64-bit architecture.
69
+ #
70
+ def ptr_64?
71
+ unless [ ELFCLASS32, ELFCLASS64 ].include?(
72
+ elf_header.e_ident[EI_CLASS,1].unpack("C*")[0])
73
+ raise ElfHeaderError, 'Invalid class', caller
74
+ end
75
+
76
+ elf_header.e_ident[EI_CLASS,1].unpack("C*")[0] == ELFCLASS64
77
+ end
78
+
79
+ #
80
+ # Returns true if this binary is for a 32-bit architecture.
81
+ # This check does not take into account 16-bit binaries at the moment.
82
+ #
83
+ def ptr_32?
84
+ ptr_64? == false
85
+ end
86
+
87
+ #
88
+ # Converts a virtual address to a string representation based on the
89
+ # underlying architecture.
90
+ #
91
+ def ptr_s(rva)
92
+ (ptr_32?) ? ("0x%.8x" % rva) : ("0x%.16x" % rva)
93
+ end
94
+
95
+ def offset_to_rva(offset)
96
+ base_addr + offset
97
+ end
98
+
99
+ def rva_to_offset(rva)
100
+ rva - base_addr
101
+ end
102
+
103
+ def read(offset, len)
104
+ isource.read(offset, len)
105
+ end
106
+
107
+ def read_rva(rva, len)
108
+ isource.read(rva_to_offset(rva), len)
109
+ end
110
+
111
+ def index(*args)
112
+ isource.index(*args)
113
+ end
114
+
115
+ def close
116
+ isource.close
117
+ end
118
+
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,265 @@
1
+ # -*- coding: binary -*-
2
+
3
+ require 'rex/struct2'
4
+
5
+ module Rex
6
+ module ElfParsey
7
+ class ElfBase
8
+
9
+ # ELF Header
10
+
11
+ ELF_HEADER_SIZE = 52
12
+
13
+ EI_NIDENT = 16
14
+
15
+ ELF32_EHDR_LSB = Rex::Struct2::CStructTemplate.new(
16
+ [ 'string', 'e_ident', EI_NIDENT, '' ],
17
+ [ 'uint16v', 'e_type', 0 ],
18
+ [ 'uint16v', 'e_machine', 0 ],
19
+ [ 'uint32v', 'e_version', 0 ],
20
+ [ 'uint32v', 'e_entry', 0 ],
21
+ [ 'uint32v', 'e_phoff', 0 ],
22
+ [ 'uint32v', 'e_shoff', 0 ],
23
+ [ 'uint32v', 'e_flags', 0 ],
24
+ [ 'uint16v', 'e_ehsize', 0 ],
25
+ [ 'uint16v', 'e_phentsize', 0 ],
26
+ [ 'uint16v', 'e_phnum', 0 ],
27
+ [ 'uint16v', 'e_shentsize', 0 ],
28
+ [ 'uint16v', 'e_shnum', 0 ],
29
+ [ 'uint16v', 'e_shstrndx', 0 ]
30
+ )
31
+
32
+ ELF32_EHDR_MSB = Rex::Struct2::CStructTemplate.new(
33
+ [ 'string', 'e_ident', EI_NIDENT, '' ],
34
+ [ 'uint16n', 'e_type', 0 ],
35
+ [ 'uint16n', 'e_machine', 0 ],
36
+ [ 'uint32n', 'e_version', 0 ],
37
+ [ 'uint32n', 'e_entry', 0 ],
38
+ [ 'uint32n', 'e_phoff', 0 ],
39
+ [ 'uint32n', 'e_shoff', 0 ],
40
+ [ 'uint32n', 'e_flags', 0 ],
41
+ [ 'uint16n', 'e_ehsize', 0 ],
42
+ [ 'uint16n', 'e_phentsize', 0 ],
43
+ [ 'uint16n', 'e_phnum', 0 ],
44
+ [ 'uint16n', 'e_shentsize', 0 ],
45
+ [ 'uint16n', 'e_shnum', 0 ],
46
+ [ 'uint16n', 'e_shstrndx', 0 ]
47
+ )
48
+
49
+ # e_type This member identifies the object file type
50
+
51
+ ET_NONE = 0 # No file type
52
+ ET_REL = 1 # Relocatable file
53
+ ET_EXEC = 2 # Executable file
54
+ ET_DYN = 3 # Shared object file
55
+ ET_CORE = 4 # Core file
56
+ ET_LOPROC = 0xff00 # Processor-specific
57
+ ET_HIPROC = 0xffff # Processor-specific
58
+
59
+ #
60
+ # e_machine This member's value specifies the required architecture for an
61
+ # individual file.
62
+ #
63
+
64
+ # ET_NONE = 0 # No machine
65
+ EM_M32 = 1 # AT&T WE 32100
66
+ EM_SPARC = 2 # SPARC
67
+ EM_386 = 3 # Intel Architecture
68
+ EM_68K = 4 # Motorola 68000
69
+ EM_88K = 5 # Motorola 88000
70
+ EM_860 = 7 # Intel 80860
71
+ EM_MIPS = 8 # MIPS RS3000 Big-Endian
72
+ EM_MIPS_RS4_BE = 10 # MIPS RS4000 Big-Endian
73
+
74
+ # e_version This member identifies the object file version
75
+
76
+ EV_NONE = 0 # Invalid version
77
+ EV_CURRENT = 1 # Current version
78
+
79
+
80
+ # ELF Identification
81
+
82
+ # e_ident[] Identification indexes
83
+
84
+ EI_MAG0 = 0 # File identification
85
+ EI_MAG1 = 1 # File identification
86
+ EI_MAG2 = 2 # File identification
87
+ EI_MAG3 = 3 # File identification
88
+ EI_CLASS = 4 # File class
89
+ EI_DATA = 5 # Data encoding
90
+ EI_VERSION = 6 # File version
91
+ EI_PAD = 7 # Start of padding bytes
92
+ # EI_NIDENT = 16 # Size of e_ident[]
93
+
94
+ #
95
+ # EI_MAG0 to EI_MAG3 A file's first 4 bytes hold a "magic number",
96
+ # identifying the file as an ELF object file.
97
+ #
98
+
99
+ ELFMAG0 = 0x7f # e_ident[EI_MAG0]
100
+ ELFMAG1 = ?E # e_ident[EI_MAG1]
101
+ ELFMAG2 = ?L # e_ident[EI_MAG2]
102
+ ELFMAG3 = ?F # e_ident[EI_MAG3]
103
+
104
+ ELFMAG = ELFMAG0.chr + ELFMAG1.chr + ELFMAG2.chr + ELFMAG3.chr
105
+
106
+ # EI_CLASS Identifies the file's class, or capacity
107
+
108
+ ELFCLASSNONE = 0 # Invalid class
109
+ ELFCLASS32 = 1 # 32-bit objects
110
+ ELFCLASS64 = 2 # 64-bit objects
111
+
112
+ #
113
+ # EI_DATA Specifies the data encoding of the processor-specific data in
114
+ # the object file. The following encodings are currently defined.
115
+ #
116
+
117
+ ELFDATANONE = 0 # Invalid data encoding
118
+ ELFDATA2LSB = 1 # Least significant byte first
119
+ ELFDATA2MSB = 2 # Most significant byte first
120
+
121
+ class GenericStruct
122
+ attr_accessor :struct
123
+ def initialize(_struct)
124
+ self.struct = _struct
125
+ end
126
+
127
+ # The following methods are just pass-throughs for struct
128
+
129
+ # Access a value
130
+ def v
131
+ struct.v
132
+
133
+ end
134
+
135
+ # Access a value by array
136
+ def [](*args)
137
+ struct[*args]
138
+ end
139
+
140
+ # Obtain an array of all fields
141
+ def keys
142
+ struct.keys
143
+ end
144
+
145
+ def method_missing(meth, *args)
146
+ v[meth.to_s] || (raise NoMethodError.new, meth)
147
+ end
148
+ end
149
+
150
+ class GenericHeader < GenericStruct
151
+ end
152
+
153
+ class ElfHeader < GenericHeader
154
+ def initialize(rawdata)
155
+
156
+ # Identify the data encoding and parse ELF Header
157
+ elf_header = ELF32_EHDR_LSB.make_struct
158
+
159
+ if !elf_header.from_s(rawdata)
160
+ raise ElfHeaderError, "Couldn't parse ELF Header", caller
161
+ end
162
+
163
+ if elf_header.v['e_ident'][EI_DATA,1].unpack('C')[0] == ELFDATA2MSB
164
+ elf_header = ELF32_EHDR_MSB.make_struct
165
+
166
+ if !elf_header.from_s(rawdata)
167
+ raise ElfHeaderError, "Couldn't parse ELF Header", caller
168
+ end
169
+ end
170
+
171
+ unless [ ELFDATA2LSB, ELFDATA2MSB ].include?(
172
+ elf_header.v['e_ident'][EI_DATA,1].unpack('C')[0])
173
+ raise ElfHeaderError, "Invalid data encoding", caller
174
+ end
175
+
176
+ # Identify the file as an ELF object file
177
+ unless elf_header.v['e_ident'][EI_MAG0, 4] == ELFMAG
178
+ raise ElfHeaderError, 'Invalid magic number', caller
179
+ end
180
+
181
+ self.struct = elf_header
182
+ end
183
+
184
+ def e_ident
185
+ struct.v['e_ident']
186
+ end
187
+
188
+ end
189
+
190
+
191
+ # Program Header
192
+
193
+ PROGRAM_HEADER_SIZE = 32
194
+
195
+ ELF32_PHDR_LSB = Rex::Struct2::CStructTemplate.new(
196
+ [ 'uint32v', 'p_type', 0 ],
197
+ [ 'uint32v', 'p_offset', 0 ],
198
+ [ 'uint32v', 'p_vaddr', 0 ],
199
+ [ 'uint32v', 'p_paddr', 0 ],
200
+ [ 'uint32v', 'p_filesz', 0 ],
201
+ [ 'uint32v', 'p_memsz', 0 ],
202
+ [ 'uint32v', 'p_flags', 0 ],
203
+ [ 'uint32v', 'p_align', 0 ]
204
+ )
205
+
206
+ ELF32_PHDR_MSB = Rex::Struct2::CStructTemplate.new(
207
+ [ 'uint32n', 'p_type', 0 ],
208
+ [ 'uint32n', 'p_offset', 0 ],
209
+ [ 'uint32n', 'p_vaddr', 0 ],
210
+ [ 'uint32n', 'p_paddr', 0 ],
211
+ [ 'uint32n', 'p_filesz', 0 ],
212
+ [ 'uint32n', 'p_memsz', 0 ],
213
+ [ 'uint32n', 'p_flags', 0 ],
214
+ [ 'uint32n', 'p_align', 0 ]
215
+ )
216
+
217
+ # p_flags This member tells which permissions should have the segment
218
+
219
+ # Flags
220
+
221
+ PF_EXEC = 1
222
+ PF_WRITE = 2
223
+ PF_READ = 4
224
+
225
+
226
+ #
227
+ # p_type This member tells what kind of segment this array element
228
+ # describes or how to interpret the array element's information.
229
+ #
230
+
231
+ # Segment Types
232
+
233
+ PT_NULL = 0
234
+ PT_LOAD = 1
235
+ PT_DYNAMIC = 2
236
+ PT_INTERP = 3
237
+ PT_NOTE = 4
238
+ PT_SHLIB = 5
239
+ PT_PHDR = 6
240
+ PT_LOPROC = 0x70000000
241
+ PT_HIPROC = 0x7fffffff
242
+
243
+ class ProgramHeader < GenericHeader
244
+ def initialize(rawdata, ei_data)
245
+ # Identify the data encoding and parse Program Header
246
+ if ei_data == ELFDATA2LSB
247
+ program_header = ELF32_PHDR_LSB.make_struct
248
+ elsif ei_data == ELFDATA2MSB
249
+ program_header = ELF32_PHDR_MSB.make_struct
250
+ else
251
+ raise ElfHeaderError, "Invalid data encoding", caller
252
+ end
253
+
254
+ if !program_header.from_s(rawdata)
255
+ raise ProgramHeaderError, "Couldn't parse Program Header", caller
256
+ end
257
+
258
+ self.struct = program_header
259
+ end
260
+
261
+ end
262
+
263
+ end
264
+ end
265
+ end