Skip to content

Commit f8623eb

Browse files
committed
Add support for stage encoding to alpha_upper
1 parent 11f2712 commit f8623eb

File tree

3 files changed

+104
-19
lines changed

3 files changed

+104
-19
lines changed

lib/rex/encoder/alpha2/alpha_mixed.rb

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,28 +27,28 @@ def self.gen_decoder_prefix(reg, offset, modified_registers = [])
2727
# use inc ebx as a nop here so we still pad correctly
2828
if offset <= 16
2929
nop = 'C' * offset
30-
nop_regs.push(Rex::Arch::X86::EBX)
30+
nop_regs.push(Rex::Arch::X86::EBX) unless nop.empty?
3131

3232
mod = 'I' * (16 - offset) + nop + '7QZ' # dec ecx,,, push ecx, pop edx
33-
mod_regs.concat([
34-
Rex::Arch::X86::ECX,
35-
Rex::Arch::X86::EDX
36-
])
33+
mod_regs.push(Rex::Arch::X86::ECX) unless offset == 16
34+
mod_regs.concat(nop_regs)
35+
mod_regs.push(Rex::Arch::X86::EDX)
3736

3837
edxmod = 'J' * (17 - offset)
39-
edx_regs.push(Rex::Arch::X86::EDX)
38+
edx_regs.push(Rex::Arch::X86::EDX) unless edxmod.empty?
4039
else
4140
mod = 'A' * (offset - 16)
42-
mod_regs.push(Rex::Arch::X86::ECX)
41+
mod_regs.push(Rex::Arch::X86::ECX) unless mod.empty?
4342

4443
nop = 'C' * (16 - mod.length)
45-
nop_regs.push(Rex::Arch::X86::EBX)
44+
nop_regs.push(Rex::Arch::X86::EBX) unless nop.empty?
4645

4746
mod << nop + '7QZ'
47+
mod_regs.concat(nop_regs)
4848
mod_regs.push(Rex::Arch::X86::EDX)
4949

5050
edxmod = 'B' * (17 - (offset - 16))
51-
edx_regs.push(Rex::Arch::X86::EDX)
51+
edx_regs.push(Rex::Arch::X86::EDX) unless edxmod.empty?
5252
end
5353

5454
regprefix = {

lib/rex/encoder/alpha2/alpha_upper.rb

Lines changed: 67 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,47 @@ module Alpha2
99
class AlphaUpper < Generic
1010
def self.default_accepted_chars ; ('B' .. 'Z').to_a + ('0' .. '9').to_a ; end
1111

12-
def self.gen_decoder_prefix(reg, offset)
13-
if (offset > 20)
14-
raise "Critical: Offset is greater than 20"
12+
# Generates the decoder stub prefix
13+
#
14+
# @param [String] reg the register pointing to the encoded payload
15+
# @param [Fixnum] offset the offset to reach the encoded payload
16+
# @param [Array] modified_registers accounts the registers modified by the stub
17+
# @return [String] the alpha upper decoder stub prefix
18+
def self.gen_decoder_prefix(reg, offset, modified_registers = [])
19+
if offset > 20
20+
raise 'Critical: Offset is greater than 20'
1521
end
1622

23+
mod_registers = []
24+
nop_regs = []
25+
mod_regs = []
26+
edx_regs = []
27+
1728
# use inc ebx as a nop here so we still pad correctly
1829
if (offset <= 10)
1930
nop = 'C' * offset
31+
nop_regs.push(Rex::Arch::X86::EBX) unless nop.empty?
32+
2033
mod = 'I' * (10 - offset) + nop + 'QZ' # dec ecx,,, push ecx, pop edx
34+
mod_regs.push(Rex::Arch::X86::ECX) unless offset == 10
35+
mod_regs.concat(nop_regs)
36+
mod_regs.push(Rex::Arch::X86::EDX)
37+
2138
edxmod = 'J' * (11 - offset)
39+
edx_regs.push(Rex::Arch::X86::EDX) unless edxmod.empty?
2240
else
2341
mod = 'A' * (offset - 10)
42+
mod_regs.push(Rex::Arch::X86::ECX) unless mod.empty?
43+
2444
nop = 'C' * (10 - mod.length)
45+
nop_regs.push(Rex::Arch::X86::EBX) unless nop.empty?
46+
2547
mod << nop + 'QZ'
48+
mod_regs.concat(nop_regs)
49+
mod_regs.push(Rex::Arch::X86::EDX)
50+
2651
edxmod = 'B' * (11 - (offset - 10))
52+
edx_regs.push(Rex::Arch::X86::EDX) unless edxmod.empty?
2753
end
2854
regprefix = {
2955
'EAX' => 'PY' + mod, # push eax, pop ecx
@@ -33,20 +59,41 @@ def self.gen_decoder_prefix(reg, offset)
3359
'ESP' => 'TY' + mod, # push esp, pop ecx
3460
'EBP' => 'UY' + mod, # push ebp, pop ecx
3561
'ESI' => 'VY' + mod, # push esi, pop ecx
36-
'EDI' => 'WY' + mod, # push edi, pop edi
62+
'EDI' => 'WY' + mod, # push edi, pop ecx
3763
}
3864

3965
reg.upcase!
40-
if (not regprefix.keys.include? reg)
66+
unless regprefix.keys.include?(reg)
4167
raise ArgumentError.new("Invalid register name")
4268
end
43-
return regprefix[reg]
4469

70+
case reg
71+
when 'EDX'
72+
mod_registers.concat(edx_regs)
73+
mod_registers.concat(nop_regs)
74+
mod_registers.push(Rex::Arch::X86::ECX)
75+
else
76+
mod_registers.push(Rex::Arch::X86::ECX)
77+
mod_registers.concat(mod_regs)
78+
end
79+
80+
mod_registers.uniq!
81+
modified_registers.concat(mod_registers)
82+
83+
return regprefix[reg]
4584
end
4685

47-
def self.gen_decoder(reg, offset)
86+
# Generates the decoder stub
87+
#
88+
# @param [String] reg the register pointing to the encoded payload
89+
# @param [Fixnum] offset the offset to reach the encoded payload
90+
# @param [Array] modified_registers accounts the registers modified by the stub
91+
# @return [String] the alpha upper decoder stub
92+
def self.gen_decoder(reg, offset, modified_registers = [])
93+
mod_registers = []
94+
4895
decoder =
49-
gen_decoder_prefix(reg, offset) +
96+
gen_decoder_prefix(reg, offset, mod_registers) +
5097
"V" + # push esi
5198
"T" + # push esp
5299
"X" + # pop eax
@@ -73,6 +120,18 @@ def self.gen_decoder(reg, offset)
73120
"JJ" + # jnz * --------------------
74121
"I" # first encoded char, fixes the above J
75122

123+
mod_registers.concat(
124+
[
125+
Rex::Arch::X86::ESP,
126+
Rex::Arch::X86::EAX,
127+
Rex::Arch::X86::ESI,
128+
Rex::Arch::X86::ECX,
129+
Rex::Arch::X86::EDX
130+
])
131+
132+
mod_registers.uniq!
133+
modified_registers.concat(mod_registers)
134+
76135
return decoder
77136
end
78137

modules/encoders/x86/alpha_upper.rb

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ def initialize
3434
# being encoded.
3535
#
3636
def decoder_stub(state)
37+
modified_registers = []
3738
reg = datastore['BufferRegister']
3839
off = (datastore['BufferOffset'] || 0).to_i
3940
buf = ''
@@ -44,8 +45,15 @@ def decoder_stub(state)
4445
buf = 'VTX630WTX638VXH49HHHPVX5AAQQPVX5YYYYP5YYYD5KKYAPTTX638TDDNVDDX4Z4A63861816'
4546
reg = 'ECX'
4647
off = 0
48+
modified_registers.concat (
49+
[
50+
Rex::Arch::X86::ESP,
51+
Rex::Arch::X86::EDI,
52+
Rex::Arch::X86::ESI,
53+
Rex::Arch::X86::EAX
54+
])
4755
else
48-
res = Rex::Arch::X86.geteip_fpu(state.badchars)
56+
res = Rex::Arch::X86.geteip_fpu(state.badchars, modified_registers)
4957
if (not res)
5058
raise EncodingError, "Unable to generate geteip code"
5159
end
@@ -55,7 +63,15 @@ def decoder_stub(state)
5563
reg.upcase!
5664
end
5765

58-
buf + Rex::Encoder::Alpha2::AlphaUpper::gen_decoder(reg, off)
66+
stub = buf + Rex::Encoder::Alpha2::AlphaUpper::gen_decoder(reg, off, modified_registers)
67+
68+
# Sanity check that saved_registers doesn't overlap with modified_registers
69+
modified_registers.uniq!
70+
if (modified_registers & saved_registers).length > 0
71+
raise BadGenerateError
72+
end
73+
74+
stub
5975
end
6076

6177
#
@@ -72,4 +88,14 @@ def encode_block(state, block)
7288
def encode_end(state)
7389
state.encoded += Rex::Encoder::Alpha2::AlphaUpper::add_terminator()
7490
end
91+
92+
# Indicate that this module can preserve some registers
93+
def can_preserve_registers?
94+
true
95+
end
96+
97+
# Convert the SaveRegisters to an array of x86 register constants
98+
def saved_registers
99+
Rex::Arch::X86.register_names_to_ids(datastore['SaveRegisters'])
100+
end
75101
end

0 commit comments

Comments
 (0)