Skip to content

Commit 24290dc

Browse files
committed
Address x86/Bmp polyglot encoder feedback
1 parent cca0ba3 commit 24290dc

File tree

1 file changed

+44
-48
lines changed

1 file changed

+44
-48
lines changed

modules/encoders/x86/bmp_polyglot.rb

Lines changed: 44 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,20 @@
5252
# calculate the smallest increase of a 32-bit little endian integer which is
5353
# also a valid x86 jmp opcode of the specified minimum size.
5454
class SizeCalculator
55+
56+
BYTE_NOPS = [
57+
0x42, # inc edx
58+
0x45, # inc ebp
59+
0x4a, # dec edx
60+
0x4d, # dec ebp
61+
0x90, # xchg eax, eax / nop
62+
0xf5, # cmc
63+
0xf8, # clc
64+
0xf9, # stc
65+
0xfc, # cld
66+
0xfd # std
67+
]
68+
5569
def initialize(size, minimum_jump)
5670
@original_size = size
5771
raise if minimum_jump < 0 || minimum_jump > 0xff
@@ -72,30 +86,30 @@ def new_size_long
7286
size = [ @original_size ].pack('V').unpack('CCCC')
7387

7488
0.upto(2) do |i|
75-
b0 = size[i]
76-
b1 = size[i + 1]
77-
b2 = size[i + 2].to_i
78-
b3 = size[i + 3].to_i
79-
b4 = size[i + 4].to_i
89+
byte_0 = size[i]
90+
byte_1 = size[i + 1]
91+
byte_2 = size[i + 2].to_i
92+
byte_3 = size[i + 3].to_i
93+
byte_4 = size[i + 4].to_i
8094
min_jmp = (@minimum_jump - 5 - i)
8195

82-
if [b2, b3, b4].inject{ |sum, x| sum + x } > 0 # this jmp would be too large
83-
if b0 > 0xfd
96+
if byte_2 + byte_3 + byte_4 > 0 # this jmp would be too large
97+
if byte_0 > 0xfd
8498
size = increment_size(size, i)
8599
end
86-
size[i] = round_up_to_nop(b0)
100+
size[i] = round_up_to_nop(byte_0)
87101
next
88102
end
89103

90-
if b0 > 0xe9
91-
if b0 > 0xfd
104+
if byte_0 > 0xe9
105+
if byte_0 > 0xfd
92106
size = increment_size(size, i)
93107
end
94-
size[i] = round_up_to_nop(b0)
108+
size[i] = round_up_to_nop(byte_0)
95109
else
96110
size[i] = 0xe9
97-
b1 = min_jmp if b1 < min_jmp
98-
size[i + 1] = b1
111+
byte_1 = min_jmp if byte_1 < min_jmp
112+
size[i + 1] = byte_1
99113
return size.pack('CCCC').unpack('V')[0]
100114
end
101115
end
@@ -106,24 +120,24 @@ def new_size_short
106120
size = [ @original_size ].pack('V').unpack('CCCC')
107121

108122
0.upto(2) do |i|
109-
b0 = size[i]
110-
b1 = size[i + 1]
123+
byte_0 = size[i]
124+
byte_1 = size[i + 1]
111125
min_jmp = (@minimum_jump - 2 - i)
112126

113-
if b0 > 0xeb
114-
if b0 > 0xfd
127+
if byte_0 > 0xeb
128+
if byte_0 > 0xfd
115129
size = increment_size(size, i)
116130
end
117-
size[i] = round_up_to_nop(b0)
131+
size[i] = round_up_to_nop(byte_0)
118132
else
119133
size[i] = 0xeb
120-
if b1 > 0x7f
121-
b1 = min_jmp
134+
if byte_1 > 0x7f
135+
byte_1 = min_jmp
122136
size = increment_size(size, i + 1)
123-
elsif b1 < min_jmp
124-
b1 = min_jmp
137+
elsif byte_1 < min_jmp
138+
byte_1 = min_jmp
125139
end
126-
size[i + 1] = b1
140+
size[i + 1] = byte_1
127141
return size.pack('CCCC').unpack('V')[0]
128142
end
129143
end
@@ -158,21 +172,7 @@ def increment_size(size, byte)
158172
end
159173

160174
def round_up_to_nop(opcode)
161-
byte_nops = [
162-
0x42, # inc edx
163-
0x45, # inc ebp
164-
0x4a, # dec edx
165-
0x4d, # dec ebp
166-
0x90, # xchg eax, eax / nop
167-
0xf5, # cmc
168-
0xf8, # clc
169-
0xf9, # stc
170-
0xfc, # cld
171-
0xfd # std
172-
]
173-
byte_nops.each do |nop|
174-
return nop if opcode <= nop
175-
end
175+
BYTE_NOPS.find { |nop| opcode <= nop }
176176
end
177177

178178
end
@@ -278,7 +278,6 @@ def make_destego_stub(shellcode_size, padding, lsbs = 1)
278278
get_eip_nop = Proc.new { |b| [0x90, 0x40 + b.regnum_of([bit_reg, byte_reg, dst_addr_reg, src_addr_reg].sample), 0x48 + b.regnum_of([bit_reg, byte_reg, dst_addr_reg, src_addr_reg].sample)].sample.chr }
279279
get_eip = Proc.new { |b|
280280
[
281-
Proc.new { |b| get_eip_nop.call(b) + "\xe8\x00\x00\x00\x00" + (0x58 + b.regnum_of(src_addr_reg)).chr },
282281
Proc.new { |b| "\xe8" + [0, 1].sample.chr + "\x00\x00\x00" + get_eip_nop.call(b) + (0x58 + b.regnum_of(src_addr_reg)).chr },
283282
Proc.new { |b| "\xe8\xff\xff\xff\xff" + (0xc0 + b.regnum_of([bit_reg, byte_reg, dst_addr_reg, src_addr_reg].sample)).chr + (0x58 + b.regnum_of(src_addr_reg)).chr },
284283
].sample.call(b)
@@ -378,24 +377,24 @@ def stegoify(shellcode, data, lsbs = 1)
378377
data
379378
end
380379

381-
def validate_dib_header(bmp)
382-
dib_header = bmp.read(DIB_HEADER_SIZE)
380+
def validate_dib_header(dib_header)
383381
size, _, _, _, bbp, compression, _, _, _, _, _ = dib_header.unpack('VVVvvVVVVVV')
384382
raise EncodingError, 'Bad .bmp DIB header, must be 40-byte BITMAPINFOHEADER' if size != DIB_HEADER_SIZE
385383
raise EncodingError, 'Bad .bmp DIB header, bits per pixel must be must be either 24 or 32' if bbp != 24 && bbp != 32
386384
raise EncodingError, 'Bad .bmp DIB header, compression can not be used' if compression != 0
387-
dib_header
388385
end
389386

390387
def encode(buf, badchars = nil, state = nil, platform = nil)
391388
in_bmp = File.open(datastore['BitmapFile'], 'rb')
392389

393390
header = in_bmp.read(BM_HEADER_SIZE)
391+
dib_header = in_bmp.read(DIB_HEADER_SIZE)
392+
image_data = in_bmp.read
393+
in_bmp.close
394+
394395
header, original_size, _, _, original_offset = header.unpack('vVvvV')
395396
raise EncodingError, 'Bad .bmp header, must be 0x424D (BM)' if header != 0x4d42
396-
397-
dib_header = validate_dib_header(in_bmp)
398-
image_data = in_bmp.read
397+
validate_dib_header(dib_header)
399398

400399
lsbs = calc_required_lsbs(buf.length, image_data.length)
401400

@@ -413,11 +412,8 @@ def encode(buf, badchars = nil, state = nil, platform = nil)
413412
bmp_img = ''
414413
bmp_img << [0x4d42, details[:new_size], 0, 0, new_offset].pack('vVvvV')
415414
bmp_img << dib_header
416-
417415
bmp_img << pre_image_data
418416
bmp_img << stegoify(buf, image_data, lsbs)
419-
420-
in_bmp.close
421417
bmp_img
422418
end
423419
end

0 commit comments

Comments
 (0)