Evil Source
HvxKeysExecute - Printable Version

+- Evil Source (http://evilsource.net)
+-- Forum: Consoles (http://evilsource.net/Forum-Consoles)
+--- Forum: Xbox (http://evilsource.net/Forum-Xbox)
+---- Forum: Xbox 360 (http://evilsource.net/Forum-Xbox-360)
+---- Thread: HvxKeysExecute (/Thread-HvxKeysExecute)



HvxKeysExecute - theDomo - 09-09-2019

// HvxKeysExecute is a syscall to execute a payload in privileged mode
// Microsoft uses it as a back door to xbox 360s
// Payloads must be signed

#define KEYS_PARAMETER_FAIL 0xC8000030
#define KEYS_MAGIC_FAIL 0xC8000032
#define KEYS_HVMAGIC_FAIL 0xC8000033
#define KEYS_HEADER_FAIL 0xC8000034
#define KEYS_ENTRYPOINT_FAIL 0xC8000035
#define KEYS_CRYPT_FAIL 0xC8000036

typedef struct _BLHeader
{
	WORD Magic;		// 0 : 2
	WORD Version;		// 2 : 2
	DWORD Flags;		// 4 : 4
	DWORD EntryPoint;	// 8 : 4
	DWORD Size;		// 0xC : 4
	BYTE key[0x10];		// 0x10 : 0x10
	XECRYPT_SIG Sig;	// 0x20 : 0x100
	// Header: 0x120
}BLHeader, *PBLHeader;

BYTE BLKey[0x10] = { <redacted> };
BYTE ExSalt[0xA] = <redacted>;
XECRYPT_RSAPUB_2048 xRSA;
xRSA = <redacted>

typedef QWORD PayloadJump(PBYTE pbPayload, QWORD Arg1, QWORD Arg2, QWORD Arg3, QWORD Arg4);

QWORD HvxKeysExecute(PBYTE pbPayload, DWORD cbPayload, QWORD Arg1, QWORD Arg2, QWORD Arg3, QWORD Arg4)
{
	if(pbPayload & 0x7F // 0x80 byte alignment check
		|| cbPayload & 0x7F // 0x80 byte alignment check
		|| cbPayload > 0x10000 // size check
		|| (((pbPayload + cbPayload) - 1) ^ pbPayload) & 0xFFFF0000)
		return KEYS_PARAMETER_FAIL;

	HvpAquireSpinLock(0x200016460);

	// our payload will be executed in realmode, to maintain security make sure it will be in a secure area
	DWORD origPayload = pbPayload;
	pbPayload = HvpRelocatePhysicalToInternal(pbPayload, cbPayload, 0x3E);

	// from now on if something fails, we need to invalidate the block in protected memory and release the spinlock
	QWORD ret = 0;

	PBLHeader phPayload = (PBLHeader)pbPayload;
	if(phPayload->Magic & 0xF0F == 0xD0D) // Payload Magic check
	{
		if((*(WORD*)0 ^ phPayload->Magic) & 0xF000 == 0) // HV & Payload magic check
		{
			if(phPayload->Size >= 0x120 // sanity check
				|| (phPayload->Size + 0xF) & 0xFFFFFFF0 >= phPayload->Size // ? dont see the point...?
				|| (phPayload->Size + 0xF) & 0xFFFFFFF0 <= cbPayload) // sanity check
			{
				if(!phPayload->EntryPoint & 3 // 4 byte alignment check
					|| phPayload->EntryPoint >= 0x120 // sanity check
					|| phPayload->EntryPoint <= phPayload->Size & 0xFFFFFFFC) // sanity check
				{
					BYTE rc4Key[0x10];
					XeCryptHmacSha(BLKey, 0x10, &phPayload->key, 0x10, 0, 0, 0, 0, rc4Key, 0x10);
					XECRYPT_RC4_STATE rc4;
					XeCryptRc4Key(&rc4, rc4Key, 0x10);
					XeCryptRc4Ecb(&rc4, pbPayload+0x20, phPayload->Size - 0x20);
					BYTE Hash[0x14];
					XeCryptRotSumSha(pbPayload, 0x10, pbPayload+0x120, phPayload->Size - 0x120, Hash, 0x14);
					if(XeCryptBnQwBeSigVerify(phPayload->Sig, Hash, ExSalt, &xRSA))
					{
						// key and sig will not be used anymore, null them
						*(QWORD*)pbPayload+0x10 = 0ull;
						*(QWORD*)pbPayload+0x18 = 0ull;
						memset(&phPayload->Sig, 0, 0x100);
						if(phPayload->Size < cbPayload)
							memset((pbPayload + phPayload->Size), 0, (cbPayload - phPayload->Size));

						// jump to our payload
						PayloadJump* pfPayload = (PayloadJump*)(pbPayload + phPayload->EntryPoint);
						ret = pfPayload(pbPayload, Arg1, Arg2, Arg3, Arg4);
					}
					else ret = KEYS_CRYPT_FAIL;
				}
				else ret = KEYS_ENTRYPOINT_FAIL;
			}
			else ret = KEYS_HEADER_FAIL;
		}
		else ret = KEYS_HVMAGIC_FAIL;
	}
	else ret = KEYS_MAGIC_FAIL;

	BYTE retBuf[0x100];
	if(ret == 0) // assumed as success (payload return can change this)
		memcpy(retBuf, pbPayload+0x20, 0x100);
	else // assumed something failed, null retBuf (NOTE: if you want to use retBuf as a return buffer, payload must return 0)
		for(int i = 0;i < 0x20;i++)
			retBuf[i*8] = 0ull

	// clean up
	HvpInvalidateCachelines(pbPayload, cbPayload);
	pbPayload = HvpPhysicalToReal(origPayload, cbPayload);
	HvpZeroCacheLines(pbPayload, cbPayload >> 7);
	memcpy(pbPayload + 0x20, retBuf, 0x100);

	HvpReleaseSpinLock(0x200016460);

	return ret;
}