diff --git a/data/shellcode/block_api.x86.graphml b/data/shellcode/block_api.x86.graphml
index f9b0949b67..4779c0c569 100644
--- a/data/shellcode/block_api.x86.graphml
+++ b/data/shellcode/block_api.x86.graphml
@@ -26,14 +26,14 @@
0x1003
instruction
- 31c0
- xor eax, eax
+ 31d2
+ xor edx, edx
0x1005
instruction
- 648b5030
- mov edx, dword ptr fs:[eax + 0x30]
+ 648b5230
+ mov edx, dword ptr fs:[edx + 0x30]
0x1009
@@ -49,7 +49,6 @@
-
@@ -90,37 +89,30 @@
0x1018
instruction
+ 31c0
+ xor eax, eax
+
+
+ 0x101a
+ instruction
ac
lodsb al, byte ptr [esi]
-
- 0x1019
- instruction
- 3c61
- cmp al, 0x61
-
0x101b
instruction
- 7c02
- jl 0x101f
+ 3c61
+ cmp al, 0x61
-
-
-
-
-
- 0x101d
- block
-
- 0x101d
- block
-
+
0x101d
instruction
- 2c20
- sub al, 0x20
+ 7c02
+ jl 0x1021
+
+
+
@@ -132,167 +124,172 @@
0x101f
instruction
+ 2c20
+ sub al, 0x20
+
+
+
+
+ 0x1021
+ block
+
+ 0x1021
+ block
+
+ 0x1021
+ instruction
c1cf0d
ror edi, 0xd
-
- 0x1022
+
+ 0x1024
instruction
01c7
add edi, eax
-
- 0x1024
- instruction
- e2f2
- loop 0x1018
-
-
-
-
-
-
- 0x1026
- block
-
- 0x1026
- block
-
+
0x1026
instruction
- 52
- push edx
-
-
- 0x1027
- instruction
- 57
- push edi
-
-
- 0x1028
- instruction
- 8b5210
- mov edx, dword ptr [edx + 0x10]
-
-
- 0x102b
- instruction
- 8b4a3c
- mov ecx, dword ptr [edx + 0x3c]
-
-
- 0x102e
- instruction
- 8b4c1178
- mov ecx, dword ptr [ecx + edx + 0x78]
-
-
- 0x1032
- instruction
- e348
- jecxz 0x107c
-
-
-
-
-
-
-
-
-
-
-
- 0x1034
- block
-
- 0x1034
- block
-
- 0x1034
- instruction
- 01d1
- add ecx, edx
-
-
- 0x1036
- instruction
- 51
- push ecx
-
-
- 0x1037
- instruction
- 8b5920
- mov ebx, dword ptr [ecx + 0x20]
-
-
- 0x103a
- instruction
- 01d3
- add ebx, edx
-
-
- 0x103c
- instruction
- 8b4918
- mov ecx, dword ptr [ecx + 0x18]
-
-
-
-
-
-
-
-
-
-
- 0x103f
- block
-
- 0x103f
- block
-
- 0x103f
- instruction
- e33a
- jecxz 0x107b
-
-
-
-
- 0x1041
- block
-
- 0x1041
- block
-
- 0x1041
- instruction
49
dec ecx
-
- 0x1042
+
+ 0x1027
instruction
- 8b348b
- mov esi, dword ptr [ebx + ecx*4]
+ 75ef
+ jne 0x1018
-
+
+
+
+
+
+
+ 0x1029
+ block
+
+ 0x1029
+ block
+
+ 0x1029
+ instruction
+ 52
+ push edx
+
+
+ 0x102a
+ instruction
+ 57
+ push edi
+
+
+ 0x102b
+ instruction
+ 8b5210
+ mov edx, dword ptr [edx + 0x10]
+
+
+ 0x102e
+ instruction
+ 8b423c
+ mov eax, dword ptr [edx + 0x3c]
+
+
+ 0x1031
+ instruction
+ 01d0
+ add eax, edx
+
+
+ 0x1033
+ instruction
+ 8b4078
+ mov eax, dword ptr [eax + 0x78]
+
+
+ 0x1036
+ instruction
+ 85c0
+ test eax, eax
+
+
+ 0x1038
+ instruction
+ 744c
+ je 0x1086
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0x103a
+ block
+
+ 0x103a
+ block
+
+ 0x103a
+ instruction
+ 01d0
+ add eax, edx
+
+
+ 0x103c
+ instruction
+ 50
+ push eax
+
+
+ 0x103d
+ instruction
+ 8b4818
+ mov ecx, dword ptr [eax + 0x18]
+
+
+ 0x1040
+ instruction
+ 8b5820
+ mov ebx, dword ptr [eax + 0x20]
+
+
+ 0x1043
+ instruction
+ 01d3
+ add ebx, edx
+
+
+
+
+
+
+
+
+ 0x1045
+ block
+
+ 0x1045
+ block
+
0x1045
instruction
- 01d6
- add esi, edx
+ 85c9
+ test ecx, ecx
-
+
0x1047
instruction
- 31ff
- xor edi, edi
+ 743c
+ je 0x1085
-
-
-
+
@@ -304,271 +301,315 @@
0x1049
instruction
- ac
- lodsb al, byte ptr [esi]
+ 49
+ dec ecx
0x104a
instruction
- c1cf0d
- ror edi, 0xd
+ 8b348b
+ mov esi, dword ptr [ebx + ecx*4]
0x104d
instruction
- 01c7
- add edi, eax
+ 01d6
+ add esi, edx
0x104f
instruction
+ 31ff
+ xor edi, edi
+
+
+
+
+
+
+
+ 0x1051
+ block
+
+ 0x1051
+ block
+
+ 0x1051
+ instruction
+ 31c0
+ xor eax, eax
+
+
+ 0x1053
+ instruction
+ ac
+ lodsb al, byte ptr [esi]
+
+
+ 0x1054
+ instruction
+ c1cf0d
+ ror edi, 0xd
+
+
+ 0x1057
+ instruction
+ 01c7
+ add edi, eax
+
+
+ 0x1059
+ instruction
38e0
cmp al, ah
-
- 0x1051
+
+ 0x105b
instruction
- 75f6
- jne 0x1049
+ 75f4
+ jne 0x1051
-
-
-
-
-
+
+
+
+
+
+
+
+
-
- 0x1053
+
+ 0x105d
block
- 0x1053
+ 0x105d
block
-
- 0x1053
+
+ 0x105d
instruction
037df8
add edi, dword ptr [ebp - 8]
-
- 0x1056
+
+ 0x1060
instruction
3b7d24
cmp edi, dword ptr [ebp + 0x24]
-
- 0x1059
+
+ 0x1063
instruction
- 75e4
- jne 0x103f
+ 75e0
+ jne 0x1045
-
-
+
+
-
- 0x105b
+
+ 0x1065
block
- 0x105b
+ 0x1065
block
-
- 0x105b
+
+ 0x1065
instruction
58
pop eax
-
- 0x105c
+
+ 0x1066
instruction
8b5824
mov ebx, dword ptr [eax + 0x24]
-
- 0x105f
+
+ 0x1069
instruction
01d3
add ebx, edx
-
- 0x1061
+
+ 0x106b
instruction
668b0c4b
mov cx, word ptr [ebx + ecx*2]
-
- 0x1065
+
+ 0x106f
instruction
8b581c
mov ebx, dword ptr [eax + 0x1c]
-
- 0x1068
+
+ 0x1072
instruction
01d3
add ebx, edx
-
- 0x106a
+
+ 0x1074
instruction
8b048b
mov eax, dword ptr [ebx + ecx*4]
-
- 0x106d
+
+ 0x1077
instruction
01d0
add eax, edx
-
- 0x106f
+
+ 0x1079
instruction
89442424
mov dword ptr [esp + 0x24], eax
-
- 0x1073
+
+ 0x107d
instruction
5b
pop ebx
-
- 0x1074
+
+ 0x107e
instruction
5b
pop ebx
-
- 0x1075
+
+ 0x107f
instruction
61
popal
-
- 0x1076
+
+ 0x1080
instruction
59
pop ecx
-
- 0x1077
+
+ 0x1081
instruction
5a
pop edx
-
- 0x1078
+
+ 0x1082
instruction
51
push ecx
-
- 0x1079
+
+ 0x1083
instruction
ffe0
jmp eax
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
- 0x107b
+
+ 0x1085
block
- 0x107b
+ 0x1085
block
-
- 0x107b
+
+ 0x1085
+ instruction
+ 58
+ pop eax
+
+
+
+
+ 0x1086
+ block
+
+ 0x1086
+ block
+
+ 0x1086
instruction
5f
pop edi
-
-
-
- 0x107c
- block
-
- 0x107c
- block
-
- 0x107c
- instruction
- 5f
- pop edi
-
-
- 0x107d
+
+ 0x1087
instruction
5a
pop edx
-
- 0x107e
+
+ 0x1088
instruction
8b12
mov edx, dword ptr [edx]
-
- 0x1080
+
+ 0x108a
instruction
- eb8d
+ eb83
jmp 0x100f
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/lib/msf/core/payload/windows/block_api.rb b/lib/msf/core/payload/windows/block_api.rb
index ab108c6b9f..fa7a74a4f8 100644
--- a/lib/msf/core/payload/windows/block_api.rb
+++ b/lib/msf/core/payload/windows/block_api.rb
@@ -15,6 +15,7 @@ module Payload::Windows::BlockApi
def asm_block_api(opts={})
Rex::Payloads::Shuffle.from_graphml_file(
File.join(Msf::Config.install_root, 'data', 'shellcode', 'block_api.x86.graphml'),
+ arch: ARCH_X86,
name: 'api_call'
)
end
diff --git a/lib/msf/core/payload/windows/x64/block_api.rb b/lib/msf/core/payload/windows/x64/block_api.rb
index ca5f36e67a..ec58e0e997 100644
--- a/lib/msf/core/payload/windows/x64/block_api.rb
+++ b/lib/msf/core/payload/windows/x64/block_api.rb
@@ -15,6 +15,7 @@ module Payload::Windows::BlockApi_x64
def asm_block_api(opts={})
Rex::Payloads::Shuffle.from_graphml_file(
File.join(Msf::Config.install_root, 'data', 'shellcode', 'block_api.x64.graphml'),
+ arch: ARCH_X64,
name: 'api_call'
)
end
diff --git a/lib/rex/payloads/shuffle.rb b/lib/rex/payloads/shuffle.rb
index 3bbff16f64..8c9e9bae69 100644
--- a/lib/rex/payloads/shuffle.rb
+++ b/lib/rex/payloads/shuffle.rb
@@ -8,38 +8,67 @@ require 'rex/parser/graphml'
##
module Rex
module Payloads
- module Shuffle
+ class Shuffle
+
+ FLOW_INSTRUCTIONS = {}
+ FLOW_INSTRUCTIONS[ARCH_X86] = %w{ call jae jb jbe jc jcxz je jecxz jg jge jl jle jmp jna jnae jnb jnbe jnc jne jng jnge jnl jnle jno jnp jns jnz jo jp jpe jpo js jz }.freeze
+ FLOW_INSTRUCTIONS[ARCH_X64] = (FLOW_INSTRUCTIONS[ARCH_X86] + %w{ jrcxz }).freeze
#
- # Shuffle instructions from a GraphML data file.
+ # Shuffle instructions from a GraphML data file and return the assembly source. If an architecture is specified
+ # and supported, labels will be added for control flow instructions such as jumps and calls. Labels are necessary
+ # if any post processing is performed on the source (such as for obfuscation).
#
# @param file_path [String] The file path to load the GraphML data from.
# @param name [String] An optional symbol name to apply to the assembly source.
- def self.from_graphml_file(file_path, name: nil)
+ def self.from_graphml_file(file_path, arch: nil, name: nil)
graphml = Rex::Parser::GraphML.from_file(file_path)
- instructions = self.shuffle_instructions(graphml)
- instructions = (["#{name}:"] + instructions.map { |instruction| ' ' + instruction}) unless name.nil?
- instructions.join("\n") + "\n"
- end
-
- #
- # Load constraint information from GraphML data and then use it to shuffle the instructions. Constraints are
- # expected to be identified as edges between instruction nodes that define ordering precedence. Each instruction
- # node must specify it's instruction source and binary representation (encoded in hex).
- #
- # @param graphml [Rex::Parser::GraphML::Element::GraphML] The graph to load the instruction data from.
- # @return [Array] The array of assembly instructions.
- def self.shuffle_instructions(graphml)
- # build an array of all of the graphs representing basic blocks, sorted by their address
blocks = graphml.graphs.filter { |graph| graph.attributes['type'] == 'block' }.sort_by { |graph| graph.attributes['address'] }
- blocks.map { |block| self.process_block(block) }.flatten
+ blocks.map! { |block| { node: block, instructions: self.process_block(block) } }
+
+ label_prefix = Rex::Text.rand_text_alpha_lower(4)
+ labeler = lambda { |address| "loc_#{label_prefix}#{ address.to_s(16).rjust(4, '0') }" }
+
+ source_lines = []
+ labeled = []
+ label_refs = []
+ blocks.each do |block|
+ source_lines << labeler.call(block[:node].attributes['address']) + ':'
+ labeled << block[:node].attributes['address']
+ # by default use the raw binary instruction to avoid syntax compatibility issues with metasm
+ instructions = block[:instructions].map { |node| 'db ' + node.attributes['instruction.hex'].strip.chars.each_slice(2).map { |hex| '0x' + hex.join }.join(', ') }
+ unless arch.nil?
+ raise ArgumentError, 'Unsupported architecture' if FLOW_INSTRUCTIONS[arch].nil?
+
+ # if a supported architecture was specified, use the original source and apply the necessary labels
+ block[:instructions].each_with_index do |node, index|
+ next unless match = /^(?\S+)\s+(?0x[a-f0-9]+)$/.match(node.attributes['instruction.source'])
+ next unless FLOW_INSTRUCTIONS[arch].include? match[:mnemonic]
+
+ address = Integer(match[:address])
+ instructions[index] = "#{match[:mnemonic]} #{labeler.call(address)}"
+ label_refs << address
+ end
+ end
+
+ source_lines += instructions
+ end
+
+ unless label_refs.all? { |address| labeled.include? address }
+ # raise this here so it's closer to the source of the problem :(
+ raise StandardError, 'Missing label reference'
+ end
+
+
+ source_lines = ([name + ':'] + source_lines.map { |source_line| ' ' + source_line}) unless name.nil?
+ source_lines.join("\n") + "\n"
end
private
#
- # Process the specified graph element which represents a single basic block in assembly. This graph element contains
- # nodes representing each of its instructions.
+ # Process the specified graph element which represents a single basic block in assembly. This graph element
+ # contains nodes representing each of its instructions.
#
def self.process_block(block)
path = []
@@ -63,8 +92,9 @@ module Rex
end
end
- path.map { |node| 'db ' + node.attributes['instruction.hex'].strip.chars.each_slice(2).map { |hex| '0x' + hex.join }.join(', ') }
+ path
end
+
end
end
end