HvxExpansionInstall
Jump to navigation
Jump to search
A system call for "installing" code under Hypervisor context. Registers an HvxExpansion structure in the expansion table
Reversed Pseudocode
// r0 is 0x70 // Parameters are taken in r3 and r4, respectively // r2, r5 - r9 are 0 typedef struct _EXP_HEADER { DWORD Magic; // "SIGM" or "SIGC" DWORD Flags; // Used in verifcation Flags = 1, 2 DWORD Size; // Should be <= size used to install BYTE ShaHash[0x14]; // SHA-1 digest of everything after header BYTE AESFeed[0x10]; XECRYPT_SIG Sig; // RSA sig of the first 0x30 bytes of the header ; 0x100 length ; encrypted //DWORD ExpID; } EXP_HEADER, *PEXP_HEADER typedef struct _HV_EXPANSION_SECTION_INFO { DWORD Size1; // Length of some kind DWORD Size2; // Length of code data DWORD Size3; // Length of some kind DWORD Padding; // 0x10 Align } EXP_SECTION_INFO; typedef struct _HV_EXPANSION_INFO { DWORD ExpansionId; // Id to be used when called after install DWORD ExpansionFlags; // Compared with something in HV DWORD ExpansionVersion; // Used to lock to a hv version DWORD ExpansionVersion2; // Used to lock to a hv version QWORD Reserved; // Havent seen this used QWORD Unknown; // Compared with something in HV DWORD ExpansionDataPos1; // Position of expansion data/info DWORD ExpansionDataLen1; // Length DWORD ExpansionDataPos2; // Position of expansion data/info DWORD ExpansionDataLen2; // Length } EXP_INFO; typedef struct _HV_EXPANSION { EXP_HEADER Header; // Expansion Header EXP_INFO ExpansionInfo; // Expansion Info EXP_SECTION_INFO SectionInfo; // Sections pointed to by ExInfo DWORD ExpansionCode[1]; // 0x10 Align } EXP; QWORD HvxExpansionInstall(PVOID pExpAddy, DWORD cExpSize) { // Check 0x80 byte alignment on payload address if(pExpAddy & 0x7F) return 0xC8007000; // Check 0x80 byte alignment on payload size if(cExpSize & 0x7F) return 0xC8007001; // Unknown check, if I had to guess its checking if you requested too much memory or if the address is out of range // Similar check is found in similar operations if(((((pExpAddy + cExpSize) - 1) ^ pExpAddy) & 0xFFFF0000) != 0) return 0xC8007001; // relocates exp data to an internal location, replaces pExpAddy with new address HvpAquireSpinLock(0x200016918); pExpAddy = HvpRelocatePhysicalToProtected(pExpAddy, cExpSize, 0x3A); BYTE Hash1[0x14] = 0; PBYTE AESKey = 0; XECRYPT_RSA xRsa; PEXP_HEADER pExpHeader = (PEXP_HEADER)pExpAddy; DWORD MagicVersion = pExpHeader->Magic; // Check what type of expansion we're dealing with if(MagicVersion == 0x48585052) // "HVPR" { if(pExpHeader->Flags & 3) //bits 1 and 2 in flags must be cleared for this type return 0xC8007003; xRsa = *(XECRYPT_RSA*)0x0000000200016280; // public RSA key AESKey = (PBYTE)0x0000000200016270; // 1BL Key XeCryptRotSumSha(pExpAddy, 0x30, 0, 0, Hash1, 0x14); // hash the header minus the sig } else if(MagicVersion == 0x48585043) // "HVPC" { // RSA Key check? Data its checking is null on RGH and XDK. Possible variable key? #ifdef DEVKIT xRsa = *(XECRYPT_RSA*)(*(QWORD*)0x0000000200016A00)+0x200; #else xRsa = *(XECRYPT_RSA*)(*(QWORD*)0x0000000200016950)+0x200; #endif if(xRsa.cqw != 0x20) return 0xC8007002; if((pExpHeader->Flags & 3) != 3) // flags 1 and 2 must be set for this type return 0xC8007003; #ifdef DEVKIT if(!(pExpHeader->Flags & 2)) // if bit 2 is cleared, data is not encrypted AESKey = 0; // data is decrypted, do not decrypt else #endif AESKey = (PBYTE)0x20; // CPU Key XeCryptHmacSha(0x20, 0x10, pExpAddy, 0x30, 0, 0, 0, 0, Hash1, 0x14); } else return 0xC8007002; // invalid expansion type // check if the header has been tampered with if(!XeCryptBnQwBeSigVerify(pExpHeader->Sig, Hash1, (PBYTE)0x0000000200016664, xRsa)) return 0xC8007003; if(pExpHeader->Size > cExpSize) // size in header must be <= size requested return 0xC8007003; if(AESKey != 0) // check if the key has been set. if not, skip decryption { XECRYPT_AES_STATE aes; XeCryptAesKey(&aes, AESKey); XeCryptAesCbc(&aes, pExpAddy+0x130, (pExpHeader->Size)-0x130, pExpAddy+0x130, &(pExpHeader->AESFeed), 0); } // check if the expansion has been tampered with XeCryptSha(pExpAddy+0x130, (pExpHeader->Size)-0x130, 0, 0, 0, 0, Hash1, 0x14); if(XeCryptMemDiff(pExpHeader->ShaHash, Hash1, 0x14)) return 0xC8007003; // go to the install function QWORD ret = InstallExpansion(pExpAddy); HvpZeroCacheLines(pExpAddy, cExpSize >> 7); HvpRelocateProtectedToPhysical(pExpAddy, cExpSize, 0x3A); HvpReleaseSpinLock(0x200016918); return ret; }