Created a Windows executable with options /hotpatch and /FUNCTIONPADMIN:195 which adds 195 bytes of padding to the beginning of main().
// Windows x86 null-free WinExec Calc.exe shellcode.
char shellcode[195] =
"\x89\xe5\x83\xec\x20\x31\xdb\x64\x8b\x5b\x30\x8b\x5b\x0c\x8b\x5b"
"\x1c\x8b\x1b\x8b\x1b\x8b\x43\x08\x89\x45\xfc\x8b\x58\x3c\x01\xc3"
"\x8b\x5b\x78\x01\xc3\x8b\x7b\x20\x01\xc7\x89\x7d\xf8\x8b\x4b\x24"
"\x01\xc1\x89\x4d\xf4\x8b\x53\x1c\x01\xc2\x89\x55\xf0\x8b\x53\x14"
"\x89\x55\xec\xeb\x32\x31\xc0\x8b\x55\xec\x8b\x7d\xf8\x8b\x75\x18"
"\x31\xc9\xfc\x8b\x3c\x87\x03\x7d\xfc\x66\x83\xc1\x08\xf3\xa6\x74"
"\x05\x40\x39\xd0\x72\xe4\x8b\x4d\xf4\x8b\x55\xf0\x66\x8b\x04\x41"
"\x8b\x04\x82\x03\x45\xfc\xc3\xba\x78\x78\x65\x63\xc1\xea\x08\x52"
"\x68\x57\x69\x6e\x45\x89\x65\x18\xe8\xb8\xff\xff\xff\x31\xc9\x51"
"\x68\x2e\x65\x78\x65\x68\x63\x61\x6c\x63\x89\xe3\x41\x51\x53\xff"
"\xd0\x31\xc9\xb9\x01\x65\x73\x73\xc1\xe9\x08\x51\x68\x50\x72\x6f"
"\x63\x68\x45\x78\x69\x74\x89\x65\x18\xe8\x87\xff\xff\xff\x31\xd2"
"\x52\xff\xd0";
int main(int argc, char* argv[])
{
char (*jmp)() = (char*)&main - sizeof(shellcode);
jmp();
}
The shellcode was written into the binary image 195 bytes prior to the start of main().
Upon disassembling, it shows there are 13 bytes of extra padding (0xCC):
00401000: CC CC CC CC CC CC CC CC CC CC CC CC CC 89 E5 83 IIIIIIIIIIIII%†Ÿ
00401010: EC 20 31 DB 64 8B 5B 30 8B 5B 0C 8B 5B 1C 8B 1B 1Ud<[0<[.<[.<.
00401020: 8B 1B 8B 43 08 89 45 FC 8B 58 3C 01 C3 8B 5B 78 <.<C.%E<X<.A<[x
00401030: 01 C3 8B 7B 20 01 C7 89 7D F8 8B 4B 24 01 C1 89 .A<{ .€%}o<K$.A%
00401040: 4D F4 8B 53 1C 01 C2 89 55 F0 8B 53 14 89 55 EC M“<S..A%Ud<S.%U
00401050: EB 32 31 C0 8B 55 EC 8B 7D F8 8B 75 18 31 C9 FC ‰21A<U<}o<u.1
00401060: 8B 3C 87 03 7D FC 66 83 C1 08 F3 A6 74 05 40 39 <<Ø.}fŸA.¢Ýt.@9
00401070: D0 72 E4 8B 4D F4 8B 55 F0 66 8B 04 41 8B 04 82 Dr„<M“<Udf<.A<.,
00401080: 03 45 FC C3 BA 78 78 65 63 C1 EA 08 52 68 57 69 .EA§xxecAˆ.RhWi
00401090: 6E 45 89 65 18 E8 B8 FF FF FF 31 C9 51 68 2E 65 nE%e.Š,˜˜˜1Qh.e
004010A0: 78 65 68 63 61 6C 63 89 E3 41 51 53 FF D0 31 C9 xehcalc%aAQS˜D1
004010B0: B9 01 65 73 73 C1 E9 08 51 68 50 72 6F 63 68 45 1.essA‚.QhProchE
004010C0: 78 69 74 89 65 18 E8 87 FF FF FF 31 D2 52 FF D0 xit%e.ŠØ˜˜˜1OR˜D
_main:
004010D0: 66 90 xchg ax,ax ; part of hot patching method.
004010D2: 55 push ebp
004010D3: 8B EC mov ebp,esp
004010D5: 51 push ecx
004010D6: B8 D0 10 40 00 mov eax,offset _main
004010DB: 2D C3 00 00 00 sub eax,0C3h
004010E0: 89 45 FC mov dword ptr [ebp-4],eax
004010E3: FF 55 FC call dword ptr [ebp-4]
004010E6: 33 C0 xor eax,eax
004010E8: 8B E5 mov esp,ebp
004010EA: 5D pop ebp
004010EB: C3 ret
If the hot patch padding is always a multiple of 16, can any extra bytes be safely used by the shellcode?

No, because the size of the previous function may vary.
ffunction has the offset0x00401000, andgis located afterwards. With/FUNCTIONPADMINgwill have the offset0x00401000 + <f size> + <at least 195>.<at least 195>is the smallest possible value to makegaligned on 16 bytes boundary. If<f size>is 13, then<at least 195>equals to 195, and there's no extra padding.Current MSVC pads with
0xCCwhich is one-byteint 3instruction. This can be used for checking if the padding is the right size, and if it isn't used already by another hotpatch.