Class: Msf::Encoder
Overview
This class is the base class that all encoders inherit from.
Direct Known Subclasses
Defined Under Namespace
Modules: Type Classes: Alphanum, NonAlpha, NonUpper, Xor, XorAdditiveFeedback, XorDynamic
Constant Summary
Constants inherited from Module
Module::REPLICANT_EXTENSION_DS_KEY
Constants included from Module::ModuleInfo
Module::ModuleInfo::UpdateableOptions
Instance Attribute Summary collapse
-
#available_space ⇒ Object
The amount of space available to the encoder, which may be nil, indicating that the smallest possible encoding should be used.
Attributes inherited from Module
#error, #job_id, #license, #platform, #privileged, #references, #user_data
Attributes included from Framework::Offspring
Attributes included from Module::UUID
Attributes included from Rex::Ui::Subscriber::Input
Attributes included from Rex::Ui::Subscriber::Output
Attributes included from Module::Privileged
Attributes included from Module::Options
Attributes included from Module::ModuleStore
Attributes included from Module::ModuleInfo
Attributes included from Module::FullName
Attributes included from Module::DataStore
Attributes included from Module::Author
Attributes included from Module::Arch
Attributes included from Module::Alert
#alerts, #you_have_been_warned
Class Method Summary collapse
-
.type ⇒ Object
Returns MODULE_ENCODER to indicate that this is an encoder module.
Instance Method Summary collapse
-
#can_preserve_registers? ⇒ Boolean
Determines whether the encoder can preserve registers at all.
-
#decoder_block_size ⇒ Object
Returns the size of each logical encoding block, in bytes.
-
#decoder_hash ⇒ Object
Returns the module’s decoder hash or an empty hash.
-
#decoder_key_offset ⇒ Object
Returns the offset to the key associated with the decoder stub.
-
#decoder_key_pack ⇒ Object
Returns the byte-packing character that should be used to encode the key.
-
#decoder_key_size ⇒ Object
Returns the size of the key, in bytes.
-
#decoder_stub(state) ⇒ Object
Returns the decoder stub to use based on the supplied state.
-
#do_encode(state) ⇒ Object
Performs the actual encoding operation after the encoder state has been initialized and is ready to go.
-
#encode(buf, badchars = nil, state = nil, platform = nil) ⇒ Object
This method generates an encoded version of the supplied buffer in buf using the bad characters as guides.
-
#encode_begin(state) ⇒ Object
Called when encoding is about to start immediately after the encoding state has been initialized.
-
#encode_block(state, block) ⇒ Object
Called once for each block being encoded based on the attributes of the decoder.
-
#encode_end(state) ⇒ Object
Called after encoding has completed.
-
#encode_finalize_stub(state, stub) ⇒ Object
This callback allows a derived class to finalize a stub after a key have been selected.
-
#encoder_type ⇒ Object
Returns the type or types of encoders that this specific module classifies as.
-
#find_bad_keys(buf, badchars) ⇒ Object
protected
Returns the list of bad keys associated with this encoder.
-
#find_context_key(buf, badchars, state) ⇒ Object
protected
Parses a context information file in an effort to find a compatible key.
-
#find_key(buf, badchars, state) ⇒ Object
protected
This method finds a compatible key for the supplied buffer based also on the supplied bad characters list.
-
#find_key_verify(buf, key_bytes, badchars) ⇒ Object
protected
Determines if the key selected by find_key is usable.
-
#has_badchars?(buf, badchars) ⇒ Boolean
protected
Returns the index of any bad characters found in the supplied buffer.
-
#init_platform(platform) ⇒ Object
protected
This provides a hook method for platform specific processing prior to the rest of encode() running.
-
#init_state(state) ⇒ Object
protected
Initializes the encoding state supplied as an argument to the attributes that have been defined for this decoder stub, such as key offset, size, and pack.
-
#initialize(info) ⇒ Encoder
constructor
Initializes an encoder module instance using the supplied information hash.
-
#integer_to_key_bytes(integer) ⇒ Object
protected
Convert an integer into the individual key bytes based on the decoder’s key size and packing requirements.
-
#key_bytes_to_buffer(key_bytes) ⇒ Object
protected
Convert individual key bytes into a byte buffer.
-
#key_bytes_to_integer(key_bytes) ⇒ Object
protected
Convert individual key bytes into a single integer based on the decoder’s key size and packing requirements.
-
#modified_registers ⇒ Object
A list of registers always modified by the encoder.
-
#obtain_key(buf, badchars, state) ⇒ Object
protected
Obtains the key to use during encoding.
-
#prepend_buf ⇒ Object
Returns a string that should be prepended to the encoded version of the buffer before returning it to callers.
-
#preserves_stack? ⇒ Boolean
Determines whether the encoder can preserve the stack frame.
-
#to_native(buf) ⇒ Object
Provides the encoder with an opportunity to return the native format (as in the format the code will be in when it executes on the target).
-
#type ⇒ Object
Returns MODULE_ENCODER to indicate that this is an encoder module.
Methods inherited from Module
#adapted_refname, #adapter_refname, #black_listed_auth_filenames, cached?, #debugging?, #default_cred?, #default_options, #fail_with, #file_path, #framework, #has_check?, #orig_cls, #owner, #perform_extensions, #platform?, #platform_to_s, #post_auth?, #register_extensions, #register_parent, #replicant, #required_cred_options, #set_defaults, #stage_refname, #stager_refname, #workspace
Methods included from Module::Reliability
#reliability, #reliability_to_s
Methods included from Module::Stability
Methods included from Module::SideEffects
#side_effects, #side_effects_to_s
Methods included from Module::UUID
Methods included from Module::UI
Methods included from Module::UI::Message
#print_error, #print_good, #print_prefix, #print_status, #print_warning
Methods included from Module::UI::Message::Verbose
#vprint_error, #vprint_good, #vprint_status, #vprint_warning
Methods included from Module::UI::Line
#print_line, #print_line_prefix
Methods included from Module::UI::Line::Verbose
Methods included from Rex::Ui::Subscriber
Methods included from Rex::Ui::Subscriber::Input
Methods included from Rex::Ui::Subscriber::Output
#flush, #print, #print_blank_line, #print_error, #print_good, #print_line, #print_status, #print_warning
Methods included from Module::Type
#auxiliary?, #encoder?, #evasion?, #exploit?, #nop?, #payload?, #post?
Methods included from Module::Ranking
Methods included from Module::Privileged
Methods included from Module::Options
#deregister_option_group, #deregister_options, #register_advanced_options, #register_evasion_options, #register_option_group, #register_options, #validate
Methods included from Module::Network
#comm, #support_ipv6?, #target_host, #target_port
Methods included from Module::ModuleStore
Methods included from Module::ModuleInfo
#alias, #description, #disclosure_date, #info_fixups, #merge_check_key, #merge_info, #merge_info_advanced_options, #merge_info_alias, #merge_info_description, #merge_info_evasion_options, #merge_info_name, #merge_info_options, #merge_info_string, #merge_info_version, #name, #notes, #update_info
Methods included from Module::FullName
#aliases, #fullname, #promptname, #realname, #refname, #shortname
Methods included from Module::DataStore
#import_defaults, #import_target_defaults, #share_datastore
Methods included from Module::Compatibility
#compat, #compatible?, #init_compat
Methods included from Module::Author
Methods included from Module::Auth
Methods included from Module::Arch
#arch?, #arch_to_s, #each_arch
Methods included from Module::Alert
#add_alert, #add_error, #add_info, #add_warning, #alert_user, #errors, #get_alerts, included, #infos, #is_usable?, #warnings, #without_prompt
Constructor Details
#initialize(info) ⇒ Encoder
Initializes an encoder module instance using the supplied information hash.
155 156 157 158 159 |
# File 'lib/msf/core/encoder.rb', line 155 def initialize(info) super({ 'Platform' => '' # All platforms by default }.update(info)) end |
Instance Attribute Details
#available_space ⇒ Object
The amount of space available to the encoder, which may be nil, indicating that the smallest possible encoding should be used.
448 449 450 |
# File 'lib/msf/core/encoder.rb', line 448 def available_space @available_space end |
Class Method Details
.type ⇒ Object
Returns MODULE_ENCODER to indicate that this is an encoder module.
171 172 173 |
# File 'lib/msf/core/encoder.rb', line 171 def self.type return Msf::MODULE_ENCODER end |
Instance Method Details
#can_preserve_registers? ⇒ Boolean
Determines whether the encoder can preserve registers at all
426 427 428 |
# File 'lib/msf/core/encoder.rb', line 426 def can_preserve_registers? false end |
#decoder_block_size ⇒ Object
Returns the size of each logical encoding block, in bytes. This is typically the same as decoder_key_size.
216 217 218 |
# File 'lib/msf/core/encoder.rb', line 216 def decoder_block_size return decoder_hash['BlockSize'] end |
#decoder_hash ⇒ Object
Returns the module’s decoder hash or an empty hash.
231 232 233 |
# File 'lib/msf/core/encoder.rb', line 231 def decoder_hash module_info['Decoder'] || {} end |
#decoder_key_offset ⇒ Object
Returns the offset to the key associated with the decoder stub.
201 202 203 |
# File 'lib/msf/core/encoder.rb', line 201 def decoder_key_offset return decoder_hash['KeyOffset'] end |
#decoder_key_pack ⇒ Object
Returns the byte-packing character that should be used to encode the key.
224 225 226 |
# File 'lib/msf/core/encoder.rb', line 224 def decoder_key_pack return decoder_hash['KeyPack'] || 'V' end |
#decoder_key_size ⇒ Object
Returns the size of the key, in bytes.
208 209 210 |
# File 'lib/msf/core/encoder.rb', line 208 def decoder_key_size return decoder_hash['KeySize'] end |
#decoder_stub(state) ⇒ Object
Returns the decoder stub to use based on the supplied state.
194 195 196 |
# File 'lib/msf/core/encoder.rb', line 194 def decoder_stub(state) return decoder_hash['Stub'] || '' end |
#do_encode(state) ⇒ Object
Performs the actual encoding operation after the encoder state has been initialized and is ready to go.
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 |
# File 'lib/msf/core/encoder.rb', line 307 def do_encode(state) # Copy the decoder stub since we may need to modify it stub = decoder_stub(state).dup if (state.key != nil and state.decoder_key_offset) # Substitute the decoder key in the copy of the decoder stub with the # one that we found real_key = state.key # If we're using context encoding, the actual value we use for # substitution is the context address, not the key we use for # encoding real_key = state.context_address if (state.context_encoding) stub[state.decoder_key_offset,state.decoder_key_size] = [ real_key.to_i ].pack(state.decoder_key_pack) else stub = encode_finalize_stub(state, stub) end # Walk the buffer encoding each block along the way offset = 0 if (decoder_block_size) while (offset < state.buf.length) block = state.buf[offset, decoder_block_size] # Append here (String#<<) instead of creating a new string with # String#+ because the allocations kill performance with large # buffers. This isn't usually noticeable on most shellcode, but # when doing stage encoding on meterpreter (~750k bytes) the # difference is 2 orders of magnitude. state.encoded << encode_block(state, block + ("\x00" * (decoder_block_size - block.length))) offset += decoder_block_size end else state.encoded = encode_block(state, state.buf) end # Prefix the decoder stub to the encoded buffer state.encoded = stub + state.encoded # Last but not least, do one last badchar pass to see if the stub + # encoded payload leads to any bad char issues... if ((badchar_idx = has_badchars?(state.encoded, state.badchars)) != nil) raise BadcharError.new(state.encoded, badchar_idx, stub.length, state.encoded[badchar_idx]), "The #{self.name} encoder failed to encode without bad characters.", caller end return true end |
#encode(buf, badchars = nil, state = nil, platform = nil) ⇒ Object
This method generates an encoded version of the supplied buffer in buf using the bad characters as guides. On success, an encoded and functional version of the supplied buffer will be returned. Otherwise, an exception will be thrown if an error is encountered during the encoding process.
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 |
# File 'lib/msf/core/encoder.rb', line 248 def encode(buf, badchars = nil, state = nil, platform = nil) # Configure platform hints if necessary init_platform(platform) if platform # Initialize an empty set of bad characters badchars = '' if (!badchars) # Initialize the encoding state and key as necessary if (state == nil) state = EncoderState.new end # Prepend data to the buffer as necessary buf = prepend_buf + buf init_state(state) # Save the buffer in the encoding state state.badchars = badchars || '' state.buf = buf # If this encoder is key-based and we don't already have a key, find one if ((decoder_key_size) and (state.key == nil)) # Find a key that doesn't contain and won't generate any bad # characters state.init_key(obtain_key(buf, badchars, state)) if (state.key == nil) raise NoKeyError, "A key could not be found for the #{self.name} encoder.", caller end end # Reset the encoded buffer at this point since it may have been changed # while finding a key. state.encoded = '' # Call encode_begin to do any encoder specific pre-processing encode_begin(state) # Perform the actual encoding operation with the determined state do_encode(state) # Call encoded_end to do any encoder specific post-processing encode_end(state) if arch?(ARCH_CMD) dlog("#{self.name} result: #{state.encoded}") end # Return the encoded buffer to the caller return state.encoded end |
#encode_begin(state) ⇒ Object
Called when encoding is about to start immediately after the encoding state has been initialized.
386 387 388 |
# File 'lib/msf/core/encoder.rb', line 386 def encode_begin(state) return nil end |
#encode_block(state, block) ⇒ Object
Called once for each block being encoded based on the attributes of the decoder.
409 410 411 |
# File 'lib/msf/core/encoder.rb', line 409 def encode_block(state, block) return block end |
#encode_end(state) ⇒ Object
Called after encoding has completed.
401 402 403 |
# File 'lib/msf/core/encoder.rb', line 401 def encode_end(state) return nil end |
#encode_finalize_stub(state, stub) ⇒ Object
This callback allows a derived class to finalize a stub after a key have been selected. The finalized stub should be returned.
394 395 396 |
# File 'lib/msf/core/encoder.rb', line 394 def encode_finalize_stub(state, stub) stub end |
#encoder_type ⇒ Object
Returns the type or types of encoders that this specific module classifies as. If there is more than one type, the values should be separated by whitespace.
187 188 189 |
# File 'lib/msf/core/encoder.rb', line 187 def encoder_type module_info['EncoderType'] || Type::Unspecified end |
#find_bad_keys(buf, badchars) ⇒ Object (protected)
Returns the list of bad keys associated with this encoder.
632 633 634 |
# File 'lib/msf/core/encoder.rb', line 632 def find_bad_keys(buf, badchars) return Array.new(decoder_key_size) { Hash.new } end |
#find_context_key(buf, badchars, state) ⇒ Object (protected)
Parses a context information file in an effort to find a compatible key
545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 |
# File 'lib/msf/core/encoder.rb', line 545 def find_context_key(buf, badchars, state) # Make sure our context information file is sane if !File.exist?(datastore['ContextInformationFile']) raise NoKeyError, "A context information file must specified when using context encoding", caller end # Holds the address and key that we ultimately find address = nil key = nil # Now, parse records from the information file searching for entries # that are compatible with our bad character set File.open(datastore['ContextInformationFile']) { |f| begin # Keep looping until we hit an EOF error or we find # a compatible key while key.nil? # Read in the header type, chunk_base_address, size = f.read(9).unpack('CNN') offset = 0 # Read in the blob of data that will act as our key state data = f.read(size) # If the address doesn't contain bad characters, check to see # the data itself will result in bad characters being generated while data.length > decoder_key_size # Extract the current set of key bytes key_bytes = [] # My ruby is rusty data[0, decoder_key_size].each_byte { |b| key_bytes << b } # If the key verifies correctly, we need to check it's address if find_key_verify(buf, key_bytes, badchars) address = chunk_base_address + offset # Pack it to byte form so that we can check each byte for # bad characters address_bytes = integer_to_key_bytes(address) # Scan each byte and see what we've got going on to make sure # no funny business is happening with the address invalid_key = false address_bytes.each { |byte| if badchars.index(byte.chr) invalid_key = true end } if invalid_key == false key = key_bytes_to_integer(key_bytes) break end end # If it didn't verify, then we need to proceed data = data[1, data.length - 1] offset += 1 end end rescue EOFError end } # If the key is nil after all is said and done, then we failed to locate # a compatible context-sensitive key if key.nil? raise NoKeyError, "No context key could be located in #{datastore['ContextInformationFile']}", caller # Otherwise, we successfully determined the key, now we need to update # the encoding state with our context address and set context encoding # to true so that the encoders know to use it else ilog("#{refname}: Successfully found context address @ #{"%.8x" % address} using key #{"%.8x" % key}") state.context_address = address state.context_encoding = true end return key end |
#find_key(buf, badchars, state) ⇒ Object (protected)
This method finds a compatible key for the supplied buffer based also on the supplied bad characters list. This is meant to make encoders more reliable and less prone to bad character failure by doing a fairly complete key search before giving up on an encoder.
494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 |
# File 'lib/msf/core/encoder.rb', line 494 def find_key(buf, badchars, state) # Otherwise, we use the traditional method key_bytes = [ ] cur_key = [ ] bad_keys = find_bad_keys(buf, badchars) found = false allset = [*(0..255)] # Keep chugging until we find something...right while (!found) # Scan each byte position 0.upto(decoder_key_size - 1) { |index| # Subtract the bad and leave the good good_keys = allset - bad_keys[index].keys # Was there anything left for this index? if (good_keys.length == 0) # Not much we can do about this :( return nil end # Set the appropriate key byte key_bytes[index] = good_keys[ rand(good_keys.length) ] } # Assume that we're going to rock this... found = true # Scan each byte and see what we've got going on to make sure # no funny business is happening key_bytes.each { |byte| if (badchars.index(byte.chr) != nil) found = false end } found = find_key_verify(buf, key_bytes, badchars) if found end # Do we have all the key bytes accounted for? if (key_bytes.length != decoder_key_size) return nil end return key_bytes_to_integer(key_bytes) end |
#find_key_verify(buf, key_bytes, badchars) ⇒ Object (protected)
Determines if the key selected by find_key is usable
677 678 679 |
# File 'lib/msf/core/encoder.rb', line 677 def find_key_verify(buf, key_bytes, badchars) true end |
#has_badchars?(buf, badchars) ⇒ Boolean (protected)
Returns the index of any bad characters found in the supplied buffer.
639 640 641 642 643 644 645 646 647 648 649 |
# File 'lib/msf/core/encoder.rb', line 639 def has_badchars?(buf, badchars) badchars.each_byte { |badchar| idx = buf.index(badchar.chr) if (idx != nil) return idx end } return nil end |
#init_platform(platform) ⇒ Object (protected)
This provides a hook method for platform specific processing prior to the rest of encode() running
472 473 474 |
# File 'lib/msf/core/encoder.rb', line 472 def init_platform(platform) end |
#init_state(state) ⇒ Object (protected)
Initializes the encoding state supplied as an argument to the attributes that have been defined for this decoder stub, such as key offset, size, and pack.
457 458 459 460 461 462 463 464 465 466 |
# File 'lib/msf/core/encoder.rb', line 457 def init_state(state) # Update the state with default decoder information state.decoder_key_offset = decoder_key_offset state.decoder_key_size = decoder_key_size state.decoder_key_pack = decoder_key_pack state.decoder_stub = nil # Restore the original buffer in case it was modified. state.buf = state.orig_buf end |
#integer_to_key_bytes(integer) ⇒ Object (protected)
Convert an integer into the individual key bytes based on the decoder’s key size and packing requirements
670 671 672 |
# File 'lib/msf/core/encoder.rb', line 670 def integer_to_key_bytes(integer) return [ integer.to_i ].pack(decoder_key_pack).unpack('C*')[0, decoder_key_size] end |
#key_bytes_to_buffer(key_bytes) ⇒ Object (protected)
Convert individual key bytes into a byte buffer
662 663 664 |
# File 'lib/msf/core/encoder.rb', line 662 def key_bytes_to_buffer(key_bytes) return key_bytes.pack('C*')[0, decoder_key_size] end |
#key_bytes_to_integer(key_bytes) ⇒ Object (protected)
Convert individual key bytes into a single integer based on the decoder’s key size and packing requirements
655 656 657 |
# File 'lib/msf/core/encoder.rb', line 655 def key_bytes_to_integer(key_bytes) return key_bytes_to_buffer(key_bytes).unpack(decoder_key_pack)[0] end |
#modified_registers ⇒ Object
A list of registers always modified by the encoder
433 434 435 |
# File 'lib/msf/core/encoder.rb', line 433 def modified_registers [] end |
#obtain_key(buf, badchars, state) ⇒ Object (protected)
Obtains the key to use during encoding. If context encoding is enabled, special steps are taken. Otherwise, the derived class is given an opportunity to find the key.
480 481 482 483 484 485 486 |
# File 'lib/msf/core/encoder.rb', line 480 def obtain_key(buf, badchars, state) if datastore['EnableContextEncoding'] return find_context_key(buf, badchars, state) else return find_key(buf, badchars, state) end end |
#prepend_buf ⇒ Object
Returns a string that should be prepended to the encoded version of the buffer before returning it to callers.
372 373 374 |
# File 'lib/msf/core/encoder.rb', line 372 def prepend_buf return '' end |
#preserves_stack? ⇒ Boolean
Determines whether the encoder can preserve the stack frame
440 441 442 |
# File 'lib/msf/core/encoder.rb', line 440 def preserves_stack? false end |
#to_native(buf) ⇒ Object
Provides the encoder with an opportunity to return the native format (as in the format the code will be in when it executes on the target). In general, the same buffer is returned to the caller. However, for things like unicode, the buffer is unicod encoded and then returned.
419 420 421 |
# File 'lib/msf/core/encoder.rb', line 419 def to_native(buf) buf end |
#type ⇒ Object
Returns MODULE_ENCODER to indicate that this is an encoder module.
178 179 180 |
# File 'lib/msf/core/encoder.rb', line 178 def type return Msf::MODULE_ENCODER end |