Based upon this MSVC Windows disassembly, is there a method to determine the number of bytes between the labels jmp_code_start and jmp_code_finish? Manually counting the opcode bytes B8 D0 10 36 00 2D C3 00 00 00 89 45 FC FF 55 FC shows there are 16 bytes but that's tedious. Perhaps there's a better technique?
int main(int argc, char* argv[])
{
003610D0 66 90 xchg ax,ax
003610D2 55 push ebp
003610D3 8B EC mov ebp,esp
003610D5 51 push ecx
jmp_code_start:;
char (*jmp)() = (char*)&main - sizeof(shellcode);
003610D6 B8 D0 10 36 00 mov eax,offset main (03610D0h)
003610DB 2D C3 00 00 00 sub eax,0C3h
003610E0 89 45 FC mov dword ptr [jmp],eax
jmp();
003610E3 FF 55 FC call dword ptr [jmp]
jmp_code_finish:;
return 0;
003610E6 33 C0 xor eax,eax
}
I tried this code but it gave errors:
int jmp_size = jmp_code_finish - jmp_code_start;
printf("jmp_size %d", jmp_size);
The original source code is
#include <windows.h>
#include <stdio.h>
// 195 bytes small 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[])
{
jmp_code_start:;
char (*jmp)() = (char*)&main - sizeof(shellcode);
jmp();
jmp_code_finish:;
return 0;
}
Based upon the supplied answer, this code below now works!
#include <windows.h>
#include <stdio.h>
// 195 bytes small 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";
void shellcode_func(void);
void dummy_function(void);
int main(int argc, char* argv[])
{
size_t jmp_size = (size_t)dummy_function - (size_t)shellcode_func;
return 0;
}
__declspec(naked) void shellcode_func(void) {
char (*jmp)();
jmp = (char*)&main - sizeof(shellcode);
jmp();
}
void dummy_function(void) {}
WARNING
After determining the code size is 16 bytes, using that exact code elsewhere can differ in size i.e., 17 bytes. The compiler chooses which registers to use and directly affects the number of opcode bytes generated.
char (*jmp)();
jmp = (char*)&main - sizeof(shellcode);
005E10D5 B9 C0 10 5E 00 mov ecx,offset main (05E10C0h)
005E10DA 81 E9 C0 00 00 00 sub ecx,0C0h
005E10E0 89 4D FC mov dword ptr [jmp],ecx
jmp();
005E10E3 FF 55 FC call dword ptr [jmp]
char (*jmp)();
jmp = (char*)&main - sizeof(shellcode);
005E11B0 B8 C0 10 5E 00 mov eax,offset main (05E10C0h)
005E11B5 2D C0 00 00 00 sub eax,0C0h
005E11BA 89 45 FC mov dword ptr [jmp],eax
jmp();
005E11BD FF 55 FC call dword ptr [jmp]
There is no way to do this in standard C.
But in practice - you can usually accomplish this with code like:
__declspec(naked) void shellcode_func(void) {
char (*jmp)();
jmp = (char*)&main - sizeof(shellcode);
jmp();
}
void dummy_function(void) {}
int main() {
size_t jmp_size = (size_t)dummy_function - (size_t)shellcode_func;
}
the __declspec(naked)
attribute (available as __attribute__((naked))
in GCC) is necessary for ensuring that the shellcode function is defined without a function prologue or epilogue - thus maintaining its original size in bytes.