xbox-kernel/private/ntos/net/halw.cpp
2020-09-30 17:17:25 +02:00

1837 lines
49 KiB
C++

// ---------------------------------------------------------------------------------------
// halw.cpp
//
// Copyright (C) Microsoft Corporation
// ---------------------------------------------------------------------------------------
#include "xnp.h"
#include "xnver.h"
#ifdef XNET_FEATURE_WINDOWS
#include <stdlib.h>
#include <stdio.h>
#include <malloc.h>
#include <rsa.h>
#include <rc4.h>
#include <sha.h>
#include <modes.h>
#include <des.h>
#include <tripldes.h>
#include <benaloh.h>
#include <shahmac.h>
#include <cryptkeys.h>
// ---------------------------------------------------------------------------------------
// Hal Dpc Support
// ---------------------------------------------------------------------------------------
struct CHalDpc
{
LONG _lInitLock; // Spin lock to synchronize VLanInit/VLanTerm
UINT _cRefs; // Number of times HalDpcInit called
HANDLE _hEvent; // Handle to signalling event for dispatch thread
HANDLE _hThread; // Thread handle for dispatch thread
BOOL _fShutdown; // TRUE to shutdown the dispatch thread
DWORD _dwThreadId; // Thread Id of dispatch thread
DWORD _dwDpcThreadId; // Thread Id of thread currently at dispatch level
INT _iThreadPriority; // Old thread priority of thread at dispatch level
LIST_ENTRY _dpcq; // Queued KDPCs
LIST_ENTRY _timerq; // Queued KTIMERs
CRITICAL_SECTION _cs; // Synchronization
};
CHalDpc g_HalDpc;
DWORD WINAPI HalDpcThreadProc(void *)
{
PKDPC pkdpc;
PKTIMER pktimer;
DWORD dwNow;
DWORD dwWait;
LONG lWait;
while (1)
{
EnterCriticalSection(&g_HalDpc._cs);
if (g_HalDpc._fShutdown)
break;
Assert(g_HalDpc._dwThreadId == GetCurrentThreadId());
Assert(g_HalDpc._dwDpcThreadId == 0);
g_HalDpc._dwDpcThreadId = g_HalDpc._dwThreadId;
Assert(g_HalDpc._dwDpcThreadId != 0);
while (!IsListEmpty(&g_HalDpc._dpcq))
{
pkdpc = (PKDPC)RemoveHeadList(&g_HalDpc._dpcq);
pkdpc->DpcListEntry.Flink = NULL;
pkdpc->DeferredRoutine(pkdpc,
pkdpc->DeferredContext,
pkdpc->SystemArgument1,
pkdpc->SystemArgument2);
}
dwWait = INFINITE;
if (!IsListEmpty(&g_HalDpc._timerq))
{
while (1)
{
dwNow = GetTickCount();
dwWait = INFINITE;
pktimer = (PKTIMER)g_HalDpc._timerq.Flink;
pkdpc = NULL;
while (pktimer != (PKTIMER)&g_HalDpc._timerq)
{
lWait = (LONG)(pktimer->DueTime - dwNow);
if (lWait <= 0)
{
pktimer->DueTime = dwNow + pktimer->Period;
pkdpc = pktimer->Dpc;
break;
}
if (dwWait > (DWORD)lWait)
dwWait = (DWORD)lWait;
pktimer = (PKTIMER)pktimer->TimerListEntry.Flink;
}
if (pkdpc == NULL)
break;
pkdpc->DeferredRoutine(pkdpc,
pkdpc->DeferredContext,
pkdpc->SystemArgument1,
pkdpc->SystemArgument2);
}
}
Assert(g_HalDpc._dwThreadId == GetCurrentThreadId());
Assert(g_HalDpc._dwDpcThreadId == g_HalDpc._dwThreadId);
g_HalDpc._dwDpcThreadId = 0;
LeaveCriticalSection(&g_HalDpc._cs);
WaitForSingleObject(g_HalDpc._hEvent, dwWait);
}
return(0);
}
void HalDpcCleanup()
{
BOOL fResult = FALSE;
if (g_HalDpc._hThread)
{
Assert(g_HalDpc._dwDpcThreadId == GetCurrentThreadId());
g_HalDpc._fShutdown = TRUE;
LeaveCriticalSection(&g_HalDpc._cs);
SetEvent(g_HalDpc._hEvent);
WaitForSingleObject(g_HalDpc._hThread, INFINITE);
CloseHandle(g_HalDpc._hThread);
}
if (g_HalDpc._hEvent)
{
CloseHandle(g_HalDpc._hEvent);
}
DeleteCriticalSection(&g_HalDpc._cs);
memset(&g_HalDpc, 0, sizeof(g_HalDpc));
}
BOOL HalDpcInit()
{
BOOL fResult = FALSE;
while (InterlockedCompareExchange(&g_HalDpc._lInitLock, 1, 0))
{
Sleep(10);
}
if (g_HalDpc._cRefs == 0)
{
InitializeCriticalSection(&g_HalDpc._cs);
InitializeListHead(&g_HalDpc._dpcq);
InitializeListHead(&g_HalDpc._timerq);
g_HalDpc._hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (g_HalDpc._hEvent == NULL)
{
TraceSz1(Warning, "HalDpcInit - CreateEvent failed (%d)", GetLastError());
goto ret;
}
g_HalDpc._hThread = CreateThread(NULL, 0, HalDpcThreadProc, NULL, 0, &g_HalDpc._dwThreadId);
if (g_HalDpc._hThread == NULL)
{
TraceSz1(Warning, "HalDpcInit - CreateThread failed (%d)", GetLastError());
goto ret;
}
// Increase the priority of the DPC thread so that is preempts any user thread,
// and also preempts the VLan thread (which runs at THREAD_PRIORITY_ABOVE_NORMAL).
SetThreadPriority(g_HalDpc._hThread, THREAD_PRIORITY_HIGHEST);
}
g_HalDpc._cRefs += 1;
fResult = TRUE;
ret:
if (!fResult)
{
HalDpcCleanup();
}
g_HalDpc._lInitLock = 0;
return(fResult);
}
BOOL HalDpcTerm()
{
BOOL fResult = FALSE;
while (InterlockedCompareExchange(&g_HalDpc._lInitLock, 1, 0))
{
Sleep(10);
}
Assert(g_HalDpc._cRefs > 0);
if (--g_HalDpc._cRefs == 0)
{
HalDpcCleanup();
fResult = TRUE;
}
g_HalDpc._lInitLock = 0;
return(fResult);
}
// ---------------------------------------------------------------------------------------
// CXnHal
// ---------------------------------------------------------------------------------------
NTSTATUS CXnHal::HalInit(XNetInitParams * pxnip)
{
TCHECK(USER);
if (!HalDpcInit())
{
return(NETERR_MEMORY);
}
strncpy(_achXbox, pxnip->pszXbox ? pxnip->pszXbox : "xb1@Lan", sizeof(_achXbox) - 1);
SetInitFlag(INITF_HAL);
return(NETERR_OK);
}
void CXnHal::HalTerm()
{
TCHECK(UDPC);
SetInitFlag(INITF_HAL_TERM);
if (TestInitFlag(INITF_HAL))
{
if (HalDpcTerm())
{
SetInitFlag(INITF_HAL_STOP);
}
}
}
KIRQL CXnHal::KeGetCurrentIrql()
{
ICHECK(HAL, USER|UDPC|SDPC);
DWORD dwThreadId = GetCurrentThreadId();
if (dwThreadId == g_HalDpc._dwDpcThreadId)
return(DISPATCH_LEVEL);
else
{
Assert(dwThreadId != g_HalDpc._dwThreadId);
return(PASSIVE_LEVEL);
}
}
KIRQL CXnHal::KeRaiseIrqlToDpcLevel()
{
ICHECK(HAL, USER|UDPC|SDPC);
DWORD dwThreadId = GetCurrentThreadId();
EnterCriticalSection(&g_HalDpc._cs);
Assert(dwThreadId != g_HalDpc._dwThreadId || dwThreadId == g_HalDpc._dwDpcThreadId);
if (dwThreadId == g_HalDpc._dwDpcThreadId)
{
LeaveCriticalSection(&g_HalDpc._cs);
Assert(DISPATCH_LEVEL != PASSIVE_LEVEL);
return(DISPATCH_LEVEL);
}
g_HalDpc._dwDpcThreadId = dwThreadId;
Assert(g_HalDpc._dwDpcThreadId != 0);
Assert(dwThreadId != g_HalDpc._dwThreadId);
if (dwThreadId != g_HalDpc._dwThreadId)
{
g_HalDpc._iThreadPriority = GetThreadPriority(GetCurrentThread());
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
}
return(PASSIVE_LEVEL);
}
void CXnHal::KeLowerIrql(KIRQL kirql)
{
TCHECK(USER|UDPC|SDPC);
if (TestInitFlag(INITF_HAL_STOP))
{
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL);
}
else if (kirql == PASSIVE_LEVEL)
{
DWORD dwThreadId = GetCurrentThreadId();
Assert(dwThreadId != g_HalDpc._dwThreadId);
Assert(dwThreadId == g_HalDpc._dwDpcThreadId);
g_HalDpc._dwDpcThreadId = 0;
if (dwThreadId != g_HalDpc._dwThreadId)
{
SetThreadPriority(GetCurrentThread(), g_HalDpc._iThreadPriority);
}
LeaveCriticalSection(&g_HalDpc._cs);
}
}
void CXnHal::KeInitializeDpc(PRKDPC Dpc, PKDEFERRED_ROUTINE DeferredRoutine, PVOID DeferredContext)
{
ICHECK(HAL, USER|UDPC|SDPC);
Dpc->DeferredRoutine = DeferredRoutine;
Dpc->DeferredContext = DeferredContext;
Dpc->DpcListEntry.Flink = NULL;
}
BOOLEAN CXnHal::KeInsertQueueDpc(PRKDPC Dpc, PVOID SystemArgument1, PVOID SystemArgument2)
{
ICHECK(HAL, USER|UDPC|SDPC);
if (Dpc->DpcListEntry.Flink == NULL)
{
EnterCriticalSection(&g_HalDpc._cs);
if (Dpc->DpcListEntry.Flink == NULL)
{
Dpc->SystemArgument1 = SystemArgument1;
Dpc->SystemArgument2 = SystemArgument2;
AssertList(&g_HalDpc._dpcq);
InsertTailList(&g_HalDpc._dpcq, &Dpc->DpcListEntry);
}
LeaveCriticalSection(&g_HalDpc._cs);
SetEvent(g_HalDpc._hEvent);
}
return(TRUE);
}
BOOLEAN CXnHal::KeRemoveQueueDpc(PRKDPC Dpc)
{
ICHECK(HAL, USER|UDPC|SDPC);
if (Dpc->DpcListEntry.Flink != NULL)
{
EnterCriticalSection(&g_HalDpc._cs);
if (Dpc->DpcListEntry.Flink != NULL)
{
AssertListEntry(&g_HalDpc._dpcq, &Dpc->DpcListEntry);
RemoveEntryList(&Dpc->DpcListEntry);
Dpc->DpcListEntry.Flink = NULL;
}
LeaveCriticalSection(&g_HalDpc._cs);
}
return(TRUE);
}
void CXnHal::KeInitializeTimer(PKTIMER Timer)
{
ICHECK(HAL, USER|UDPC|SDPC);
Timer->TimerListEntry.Flink = NULL;
}
BOOLEAN CXnHal::KeSetTimerEx(PKTIMER Timer, LARGE_INTEGER DueTime, LONG Period, PKDPC Dpc)
{
ICHECK(HAL, USER|UDPC|SDPC);
EnterCriticalSection(&g_HalDpc._cs);
if (Timer->TimerListEntry.Flink == NULL)
{
AssertList(&g_HalDpc._timerq);
Timer->DueTime = GetTickCount() + (DWORD)(DueTime.QuadPart / -10000);
Timer->Period = Period;
Timer->Dpc = Dpc;
InsertTailList(&g_HalDpc._timerq, &Timer->TimerListEntry);
}
LeaveCriticalSection(&g_HalDpc._cs);
SetEvent(g_HalDpc._hEvent);
return(TRUE);
}
BOOLEAN CXnHal::KeCancelTimer(PKTIMER Timer)
{
ICHECK(HAL, USER|UDPC|SDPC);
if (Timer->TimerListEntry.Flink != NULL)
{
EnterCriticalSection(&g_HalDpc._cs);
if (Timer->TimerListEntry.Flink != NULL)
{
AssertListEntry(&g_HalDpc._timerq, &Timer->TimerListEntry);
RemoveEntryList(&Timer->TimerListEntry);
Timer->TimerListEntry.Flink = NULL;
}
LeaveCriticalSection(&g_HalDpc._cs);
}
return(TRUE);
}
CRaiseToDpc::CRaiseToDpc(CXnHal * pXnHal)
{
_pXnHal = pXnHal;
_irql = pXnHal->KeRaiseIrqlToDpcLevel();
Assert(_irql == PASSIVE_LEVEL || _irql == DISPATCH_LEVEL);
Assert(GetCurrentThreadId() != g_HalDpc._dwThreadId || _irql == DISPATCH_LEVEL);
}
CRaiseToDpc::~CRaiseToDpc()
{
Assert(GetCurrentThreadId() != g_HalDpc._dwThreadId || _irql == DISPATCH_LEVEL);
Assert(_irql == PASSIVE_LEVEL || _irql == DISPATCH_LEVEL);
_pXnHal->KeLowerIrql((KIRQL)_irql);
}
#ifdef XNET_FEATURE_ASSERT
BOOL CXnHal::HalThreadCheck(UINT uiCheck)
{
DWORD dwThreadId = GetCurrentThreadId();
if (dwThreadId != g_HalDpc._dwDpcThreadId)
return(uiCheck & USER);
else if (dwThreadId == g_HalDpc._dwThreadId)
return(uiCheck & SDPC);
else
return(uiCheck & UDPC);
}
#endif
void CXnHal::HalEnterDpc()
{
EnterCriticalSection(&g_HalDpc._cs);
}
BOOL CXnHal::HalTryEnterDpc()
{
return(TryEnterCriticalSection(&g_HalDpc._cs));
}
void CXnHal::HalLeaveDpc()
{
LeaveCriticalSection(&g_HalDpc._cs);
}
// ---------------------------------------------------------------------------------------
// CXnHal::SetInitFlag
// ---------------------------------------------------------------------------------------
void CXnHal::SetInitFlag(DWORD dwFlag)
{
DWORD dwFlagsOld, dwFlagsNew;
while (1)
{
dwFlagsOld = _dwInitFlags;
Assert((dwFlagsOld & dwFlag) == 0);
dwFlagsNew = dwFlagsOld | dwFlag;
if (InterlockedCompareExchange((LONG *)&_dwInitFlags, (LONG)dwFlagsNew, (LONG)dwFlagsOld) == (LONG)dwFlagsOld)
break;
TraceSz(Warning, "CXnHal::SetInitFlag: Thread/DPC contention. Retrying.");
}
}
// ---------------------------------------------------------------------------------------
// Hal System Memory
// ---------------------------------------------------------------------------------------
DefineTag(VMem, 0);
DefineTag(VMemFront, 0);
DWORD g_dwVMem = 0;
BOOL VMemIsEnabled()
{
#ifdef XNET_FEATURE_VMEM
if (g_dwVMem == 0)
{
char * pszVMem = getenv("VMEM");
g_dwVMem = VMEM_CHECKED;
if (pszVMem)
{
g_dwVMem |= VMEM_ENABLED;
if (lstrcmpiA(pszVMem, "frontside") != 0)
{
g_dwVMem |= VMEM_BACKSIDESTRICT;
}
}
else if (Tag(VMem))
{
g_dwVMem |= VMEM_ENABLED;
if (!Tag(VMemFront))
g_dwVMem |= VMEM_BACKSIDESTRICT;
}
if (g_dwVMem & VMEM_ENABLED)
{
TraceSz1(VMem, "Enabled for %s byte faults", (g_dwVMem & VMEM_BACKSIDESTRICT) ? "next" : "prev");
}
}
return(g_dwVMem & VMEM_ENABLED);
#else
return(FALSE);
#endif
}
void * HalAlloc(size_t cb, ULONG tag)
{
#ifdef XNET_FEATURE_VMEM
if (VMemIsEnabled())
{
return(VMemAlloc(cb));
}
#endif
return(LocalAlloc(LMEM_FIXED, cb));
}
void * HalAllocZ(size_t cb, ULONG tag)
{
#ifdef XNET_FEATURE_VMEM
if (VMemIsEnabled())
{
void * pv = VMemAlloc(cb);
if (pv)
{
memset(pv, 0, cb);
}
return(pv);
}
#endif
return(LocalAlloc(LPTR, cb));
}
void HalFree(void * pv)
{
#ifdef XNET_FEATURE_VMEM
if (VMemIsEnabled())
{
VMemFree(pv);
return;
}
#endif
if (pv)
{
LocalFree(pv);
}
}
// ---------------------------------------------------------------------------------------
// Hal Randomness
// ---------------------------------------------------------------------------------------
UINT CXnHal::HalRandGather(BYTE * pb, UINT cb)
{
memset(pb, 0xAA, cb);
QueryPerformanceCounter((LARGE_INTEGER *)pb);
GetSystemTimeAsFileTime((FILETIME *)(pb + sizeof(LARGE_INTEGER)));
return(cb);
}
// ---------------------------------------------------------------------------------------
// Hal Crypto
// ---------------------------------------------------------------------------------------
void
XcSHAInit(
IN PUCHAR pbSHAContext
)
{
A_SHAInit((A_SHA_CTX*)pbSHAContext);
}
void
XcSHAUpdate(
IN PUCHAR pbSHAContext,
IN PUCHAR pbInput,
IN ULONG dwInputLength
)
{
A_SHAUpdate((A_SHA_CTX*)pbSHAContext, pbInput, dwInputLength);
}
void
XcSHAFinal(
IN PUCHAR pbSHAContext,
IN PUCHAR pbDigest
)
{
A_SHAFinal((A_SHA_CTX*)pbSHAContext, pbDigest);
}
void
XcRC4Key(
IN PUCHAR pbKeyStruct,
IN ULONG dwKeyLength,
IN PUCHAR pbKey
)
{
rc4_key((RC4_KEYSTRUCT*)pbKeyStruct, dwKeyLength, pbKey);
}
void
XcRC4Crypt(
IN PUCHAR pbKeyStruct,
IN ULONG dwInputLength,
IN PUCHAR pbInput
)
{
rc4((RC4_KEYSTRUCT*)pbKeyStruct, dwInputLength, pbInput);
}
void
XcHMAC(
IN PBYTE pbKeyMaterial,
IN ULONG cbKeyMaterial,
IN PBYTE pbData,
IN ULONG cbData,
IN PBYTE pbData2,
IN ULONG cbData2,
OUT PBYTE HmacData // length must be A_SHA_DIGEST_LEN
)
{
#define HMAC_K_PADSIZE 64
#define HMAC_KI_XOR_FACTOR ((DWORD)0x36363636)
#define HMAC_KO_XOR_FACTOR ((DWORD)0x5C5C5C5C)
BYTE Kipad[HMAC_K_PADSIZE];
BYTE Kopad[HMAC_K_PADSIZE];
BYTE HMACTmp[HMAC_K_PADSIZE+A_SHA_DIGEST_LEN];
ULONG dwBlock;
A_SHA_CTX shaHash;
// truncate
if (cbKeyMaterial > HMAC_K_PADSIZE)
cbKeyMaterial = HMAC_K_PADSIZE;
RtlZeroMemory(Kipad, HMAC_K_PADSIZE);
RtlCopyMemory(Kipad, pbKeyMaterial, cbKeyMaterial);
RtlZeroMemory(Kopad, HMAC_K_PADSIZE);
RtlCopyMemory(Kopad, pbKeyMaterial, cbKeyMaterial);
//
// Kipad, Kopad are padded sMacKey. Now XOR across...
//
for(dwBlock=0; dwBlock<HMAC_K_PADSIZE/sizeof(DWORD); dwBlock++)
{
((DWORD*)Kipad)[dwBlock] ^= HMAC_KI_XOR_FACTOR;
((DWORD*)Kopad)[dwBlock] ^= HMAC_KO_XOR_FACTOR;
}
//
// prepend Kipad to data, Hash to get H1
//
A_SHAInit(&shaHash);
A_SHAUpdate(&shaHash, Kipad, HMAC_K_PADSIZE);
if (cbData != 0)
{
A_SHAUpdate(&shaHash, pbData, cbData);
}
if (cbData2 != 0)
{
A_SHAUpdate(&shaHash, pbData2, cbData2);
}
// Finish off the hash
A_SHAFinal(&shaHash,HMACTmp+HMAC_K_PADSIZE);
// prepend Kopad to H1, hash to get HMAC
RtlCopyMemory(HMACTmp, Kopad, HMAC_K_PADSIZE);
// final hash: output value into passed-in buffer
A_SHAInit(&shaHash);
A_SHAUpdate(&shaHash,HMACTmp, sizeof(HMACTmp));
A_SHAFinal(&shaHash,HmacData);
}
// compute A = B ^ C mod D, N = len of params in DWORDs
ULONG
XcModExp(
IN LPDWORD pA,
IN LPDWORD pB,
IN LPDWORD pC,
IN LPDWORD pD,
IN ULONG dwN
)
{
//
// compute A = B ^ C mod D
//
return BenalohModExp(pA, pB, pC, pD, dwN);
}
void
XcDESKeyParity(
IN PUCHAR pbKey,
IN ULONG dwKeyLength
)
{
desparityonkey(pbKey, dwKeyLength);
}
void
XcKeyTable(
IN ULONG dwCipher,
OUT PUCHAR pbKeyTable,
IN PUCHAR pbKey
)
{
if (dwCipher == XC_SERVICE_DES_CIPHER)
{
deskey((DESTable*)pbKeyTable, pbKey);
}
else
{
// Assume XC_SERVICE_DES3_CIPHER:
tripledes3key((PDES3TABLE)pbKeyTable, pbKey);
}
}
void
XcBlockCrypt(
IN ULONG dwCipher,
IN PUCHAR pbOutput,
IN PUCHAR pbInput,
IN PUCHAR pbKeyTable,
IN ULONG dwOp
)
{
void (RSA32API *pCipher)(BYTE *, BYTE *, void *, int) = (dwCipher == XC_SERVICE_DES_CIPHER) ? des : tripledes;
(*pCipher)( pbOutput, pbInput, pbKeyTable, dwOp );
}
void
XcBlockCryptCBC(
IN ULONG dwCipher,
IN ULONG dwInputLength,
IN PUCHAR pbOutput,
IN PUCHAR pbInput,
IN PUCHAR pbKeyTable,
IN ULONG dwOp,
IN PUCHAR pbFeedback
)
{
BYTE *pbInputEnd = pbInput + dwInputLength;
void (RSA32API *pCipher)(BYTE *, BYTE *, void *, int) = (dwCipher == XC_SERVICE_DES_CIPHER) ? des : tripledes;
while (pbInput < pbInputEnd)
{
CBC(pCipher, XC_SERVICE_DES_BLOCKLEN, pbOutput, pbInput, pbKeyTable, dwOp, pbFeedback);
pbInput += XC_SERVICE_DES_BLOCKLEN;
pbOutput += XC_SERVICE_DES_BLOCKLEN;
}
}
DWORD
XcCalcKeyLen(
IN PBYTE pbPublicKey
)
{
LPBSAFE_PUB_KEY pPubKey = (LPBSAFE_PUB_KEY)pbPublicKey;
return pPubKey->keylen;
}
//
// Reverse ASN.1 Encodings of possible hash identifiers.
//
static char * shaEncodings[] = {
// 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
"\x0f\x14\x04\x00\x05\x1a\x02\x03\x0e\x2b\x05\x06\x09\x30\x21\x30",
"\x0d\x14\x04\x1a\x02\x03\x0e\x2b\x05\x06\x07\x30\x1f\x30",
"\x00" };
BOOL XcVerifyPKCS1SigningFmt(
IN BSAFE_PUB_KEY* pKey,
IN BYTE* pbDigest,
IN BYTE* pbPKCS1Format
)
{
BYTE** rgEncOptions;
BYTE rgbTmpHash[A_SHA_DIGEST_LEN + 16];
DWORD i;
DWORD cb;
BYTE* pbStart;
DWORD cbTmp;
rgEncOptions = (BYTE **)shaEncodings;
//
// reverse the hash to match the signature.
//
for (i = 0; i < A_SHA_DIGEST_LEN; i++) {
rgbTmpHash[i] = pbDigest[A_SHA_DIGEST_LEN - (i + 1)];
}
//
// see if it matches.
//
if (memcmp(rgbTmpHash, pbPKCS1Format, A_SHA_DIGEST_LEN)) {
return FALSE;
}
cb = A_SHA_DIGEST_LEN;
//
// check for any signature type identifiers
//
for (i = 0; 0 != *rgEncOptions[i]; i += 1) {
pbStart = (LPBYTE)rgEncOptions[i];
cbTmp = *pbStart++;
if (0 == memcmp(&pbPKCS1Format[cb], pbStart, cbTmp)) {
// adjust the end of the hash data.
cb += cbTmp;
break;
}
}
//
// check to make sure the rest of the PKCS #1 padding is correct
//
if ((0x00 != pbPKCS1Format[cb]) || (0x00 != pbPKCS1Format[pKey->datalen]) ||
(0x1 != pbPKCS1Format[pKey->datalen - 1])) {
return FALSE;
}
for (i = cb + 1; i < (DWORD)pKey->datalen - 1; i++) {
if (0xff != pbPKCS1Format[i]) {
return FALSE;
}
}
return TRUE;
}
BOOLEAN
XcVerifyDigest(
IN PBYTE pbSig,
IN PBYTE pbPublicKey,
IN PBYTE pbWorkspace,
IN PBYTE pbCompareDigest
)
{
LPBSAFE_PUB_KEY pPubKey = (LPBSAFE_PUB_KEY)pbPublicKey;
PBYTE pbOutput;
PBYTE pbInput;
DWORD dwSigLen;
dwSigLen = (pPubKey->bitlen + 7) / 8;
pbOutput = pbWorkspace;
pbInput = (PBYTE)((ULONG_PTR)pbWorkspace + pPubKey->keylen);
memset(pbInput, 0, pPubKey->keylen);
memcpy(pbInput, pbSig, dwSigLen);
if (!BSafeEncPublic(pPubKey, pbInput, pbOutput)) {
return FALSE;
}
if (!XcVerifyPKCS1SigningFmt(pPubKey, pbCompareDigest, pbOutput)) {
return FALSE;
}
return TRUE;
}
ULONG
XcPKGetKeyLen(
IN PUCHAR pbPubKey
)
{
return XcCalcKeyLen(pbPubKey);
}
BOOLEAN
XcVerifyPKCS1Signature(
IN PUCHAR pbSig,
IN PUCHAR pbPubKey,
IN PUCHAR pbDigest
)
{
BYTE* pbWorkspace = (BYTE *)_alloca( 2 * XcCalcKeyLen(pbPubKey) );
if ( pbWorkspace == NULL )
{
return FALSE;
}
return XcVerifyDigest(pbSig, pbPubKey, pbWorkspace, pbDigest);
}
VOID WINAPI XShaHmacInitialize(
IN PBYTE pbKey,
IN DWORD cbKey,
IN OUT XSHAHMAC_CONTEXT Shactx
)
{
HRESULT hr = S_OK;
BYTE rgbKipad[HMAC_K_PADSIZE];
ULONG dwBlock;
// Shorten length if longer than our K padding
if (cbKey > HMAC_K_PADSIZE)
cbKey = HMAC_K_PADSIZE;
// Build our Kipad
memset(rgbKipad, 0, HMAC_K_PADSIZE);
memcpy(rgbKipad, pbKey, cbKey);
for (dwBlock = 0;
dwBlock < (HMAC_K_PADSIZE/sizeof(DWORD));
dwBlock++)
{
((DWORD*)rgbKipad)[dwBlock] ^= HMAC_KI_XOR_FACTOR;
}
// Initialize our SHA1 Hmac context
XcSHAInit(Shactx);
// Run our Kipad through this ...
XcSHAUpdate(Shactx, rgbKipad, HMAC_K_PADSIZE);
}
//
// Function to update the Hmac
//
VOID WINAPI XShaHmacUpdate(
IN XSHAHMAC_CONTEXT Shactx,
IN PBYTE pbData,
IN DWORD cbData
)
{
XcSHAUpdate(Shactx, pbData, cbData);
}
//
// Function to calculate the final Hmac
//
VOID WINAPI XShaHmacComputeFinal(
IN XSHAHMAC_CONTEXT Shactx,
IN PBYTE pbKey,
IN DWORD cbKey,
OUT PBYTE pbHmac
)
{
HRESULT hr = S_OK;
BYTE rgbKopad[HMAC_K_PADSIZE + A_SHA_DIGEST_LEN];
ULONG dwBlock;
// Shorten length if longer than our K padding
if (cbKey > HMAC_K_PADSIZE)
cbKey = HMAC_K_PADSIZE;
// Build our Kipad
memset(rgbKopad, 0, HMAC_K_PADSIZE);
memcpy(rgbKopad, pbKey, cbKey);
for (dwBlock = 0;
dwBlock < (HMAC_K_PADSIZE/sizeof(DWORD));
dwBlock++)
{
((DWORD*)rgbKopad)[dwBlock] ^= HMAC_KO_XOR_FACTOR;
}
// Finish off the hash, and place the result right
// after the Kopad data
XcSHAFinal(Shactx, rgbKopad + HMAC_K_PADSIZE);
// Do another hash, now with the Kopad data
XcSHAInit(Shactx);
XcSHAUpdate(Shactx, rgbKopad, sizeof(rgbKopad));
XcSHAFinal(Shactx, pbHmac);
}
// ---------------------------------------------------------------------------------------
// VMem
//
// VMem allocates memory using the operating system's low-level virtual allocator. It
// arranges for an allocation to start at the very beginning of a page, with a non-
// accessable page just before it, or for it to end at the very end of a page, with a
// non-accessible page just after it. The idea is to catch memory overwrites quickly.
//
// The layout of an allocation is as follows:
//
// +--- page VMEMINFO structure
// |
// | +--- pv if using front-side-strict memory allocations
// | |
// | | +--- filled with pattern to detect back-side overwrite
// v v v
// +--------+--------+--------+--------+--------+--------+
// |VMEMINFO| NO |[User's memory area]XXXXXX| NO |
// | | ACCESS |XXXXXX[User's memory area]| ACCESS |
// +--------+--------+--------+--------+--------+--------+
// ^ ^
// | +--- pv if using back-side-strict memory allocations
// |
// +--- filled with pattern to detect front-side overwrite
//
// ---------------------------------------------------------------------------------------
#ifdef XNET_FEATURE_VMEM
#define PAGE_SIZE 4096
DWORD
VMemQueryProtect(void * pv, DWORD cb)
{
MEMORY_BASIC_INFORMATION mbi = { 0 };
VirtualQuery(pv, &mbi, sizeof(mbi));
return (mbi.Protect ? mbi.Protect : mbi.AllocationProtect);
}
VMEMINFO *
VMemIsValid(void * pv)
{
VMEMINFO * pvmi;
BYTE * pb;
UINT cb;
if (pv == NULL)
{
return NULL;
}
pvmi = (VMEMINFO *)(((DWORD_PTR)pv & ~(PAGE_SIZE - 1)) - PAGE_SIZE * 2);
if (VMemQueryProtect(pvmi, PAGE_SIZE) != PAGE_READONLY)
{
Rip("VMemIsValid - VMEMINFO page is not marked READONLY");
return NULL;
}
if (pv != pvmi->pv)
{
Rip("VMemIsValid - VMEMINFO doesn't point back to pv");
return NULL;
}
if (VMemQueryProtect((BYTE *)pvmi + PAGE_SIZE, PAGE_SIZE) != PAGE_NOACCESS)
{
Rip("VMemIsValid - can't detect first no-access page");
return NULL;
}
if (VMemQueryProtect((BYTE *)pvmi + PAGE_SIZE * 2, pvmi->cbFill1 + pvmi->cb + pvmi->cbFill2) != PAGE_READWRITE)
{
Rip("VMemIsValid - user memory block is not all writable");
return NULL;
}
if (pvmi->cbFill1)
{
pb = (BYTE *)pvmi + PAGE_SIZE * 2;
cb = pvmi->cbFill1;
for (; cb > 0; --cb, ++pb)
{
if (*pb != 0x1A)
{
Rip("VMemIsValid - detected user memory pre-data overwrite");
return NULL;
}
}
}
if (pvmi->cbFill2)
{
pb = (BYTE *)pvmi + PAGE_SIZE * 2 + pvmi->cbFill1 + pvmi->cb;
cb = pvmi->cbFill2;
for (; cb > 0; --cb, ++pb)
{
if (*pb != 0x3A)
{
Rip("VMemIsValid - detected user memory post-data overwrite");
return NULL;
}
}
}
if (VMemQueryProtect((BYTE *)pvmi + PAGE_SIZE * 2 + pvmi->cbFill1 + pvmi->cb + pvmi->cbFill2, PAGE_SIZE) != PAGE_NOACCESS)
{
Rip("VMemIsValid - can't detect second no-access page");
return NULL;
}
return(pvmi);
}
void *
VMemAlloc(size_t cb)
{
DWORD dwFlags = g_dwVMem;
void * pv1, * pv2, * pv3;
size_t cbUser, cbPage;
DWORD dwOldProtect;
VMEMINFO * pvmi;
if (cb == 0)
{
cb = 1;
}
if ( (dwFlags & VMEM_BACKSIDESTRICT)
&& (dwFlags & VMEM_BACKSIDEALIGN8))
cbUser = (cb + 7) & ~7;
else
cbUser = cb;
cbPage = (cbUser + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
pv1 = VirtualAlloc(0, cbPage + PAGE_SIZE * 3, MEM_RESERVE, PAGE_NOACCESS);
if (pv1 == NULL)
{
return(NULL);
}
pv2 = VirtualAlloc(pv1, PAGE_SIZE, MEM_COMMIT, PAGE_READWRITE);
if (pv2 == NULL)
{
return(NULL);
}
pvmi = (VMEMINFO *)pv2;
pvmi->cb = cb;
pvmi->dwFlags = dwFlags;
pv3 = VirtualAlloc((BYTE *)pv1 + PAGE_SIZE * 2, cbPage, MEM_COMMIT, PAGE_READWRITE);
if (pv3 == NULL)
{
return(NULL);
}
if (dwFlags & VMEM_BACKSIDESTRICT)
{
pvmi->cbFill1 = cbPage - cbUser;
pvmi->cbFill2 = cbUser - cb;
}
else
{
pvmi->cbFill1 = 0;
pvmi->cbFill2 = cbPage - cbUser;
}
Assert(pvmi->cbFill1 + cb + pvmi->cbFill2 == cbPage);
if (pvmi->cbFill1)
{
memset((BYTE *)pv3, 0x1A, pvmi->cbFill1);
}
memset((BYTE *)pv3 + pvmi->cbFill1, 0x2A, cb);
if (pvmi->cbFill2)
{
memset((BYTE *)pv3 + pvmi->cbFill1 + cb, 0x3A, pvmi->cbFill2);
}
pvmi->pv = (BYTE *)pv3 + pvmi->cbFill1;
VirtualProtect(pv1, PAGE_SIZE, PAGE_READONLY, &dwOldProtect);
Assert(VMemIsValid(pvmi->pv));
return(pvmi->pv);
}
void
VMemFree(void * pv)
{
VMEMINFO * pvmi = VMemIsValid(pv);
if (pvmi)
{
if (!VirtualFree(pvmi, 0, MEM_RELEASE))
{
Rip("VmemFree - VirtualFree failed");
}
}
}
#endif // XNET_FEATURE_VMEM
// ---------------------------------------------------------------------------------------
// Assert support
// ---------------------------------------------------------------------------------------
#ifdef XNET_FEATURE_ASSERT
struct MBOT { char * psz; int id; };
DWORD WINAPI DbgAssertPopOnThreadFn(MBOT * pmbot)
{
pmbot->id = MessageBoxExA(NULL, pmbot->psz, "Assert",
MB_SYSTEMMODAL|MB_SETFOREGROUND|MB_OKCANCEL|MB_ICONWARNING|MB_DEFBUTTON2,
0);
return(0);
}
int DbgAssertPop(const char * pszExpr, const char * pszFile, int iLine, const char * pszMsg)
{
char ach[256];
if (pszMsg)
_snprintf(ach, sizeof(ach), "%s\n%s\n%s (%d)", pszExpr, pszMsg, pszFile, iLine);
else
_snprintf(ach, sizeof(ach), "%s\n%s (%d)", pszExpr, pszFile, iLine);
MBOT mbot = { ach, 0 };
DWORD dwThread;
HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)DbgAssertPopOnThreadFn,
&mbot, 0, &dwThread);
if (!hThread)
DbgAssertPopOnThreadFn(&mbot);
else
{
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);
}
return(mbot.id == IDCANCEL);
}
#endif
// ---------------------------------------------------------------------------------------
// Trace support
// ---------------------------------------------------------------------------------------
#ifdef XNET_FEATURE_TRACE
CTagInit::CTagInit(int * pi, const char * pszTag)
{
int i = GetPrivateProfileIntA("tags", pszTag, -1, "\\xnettags.ini");
if (i != -1)
{
*pi = i;
}
}
#endif
// ---------------------------------------------------------------------------------------
// XBox File System Abstraction Layer
// ---------------------------------------------------------------------------------------
BOOL HalCreateDirectory(const char * pszDir, BOOL fHidden, BOOL * pfAlreadyExists)
{
WIN32_FIND_DATA fd;
HANDLE hFind = FindFirstFile(pszDir, &fd);
*pfAlreadyExists = FALSE;
if (hFind == INVALID_HANDLE_VALUE)
{
if (GetLastError() != ERROR_FILE_NOT_FOUND)
{
TraceSz2(Warning, "HalCreateDirectory: FindFirstFile '%s' failed (%08lX)", pszDir, GetLastError());
return(FALSE);
}
if (!CreateDirectory(pszDir, NULL))
{
TraceSz2(Warning, "HalCreateDirectory: CreateDirectory '%s' failed (%08lX)", pszDir, GetLastError());
return(FALSE);
}
if (fHidden && !SetFileAttributes(pszDir, FILE_ATTRIBUTE_HIDDEN))
{
TraceSz2(Warning, "HalCreateDirectory: SetFileAttributes '%s' failed (%08lX)", pszDir, GetLastError());
return(FALSE);
}
}
else
{
if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0)
{
TraceSz1(Warning, "HalCreateDirectory: Cannot create directory '%s' because file exists there", pszDir);
return(FALSE);
}
FindClose(hFind);
*pfAlreadyExists = TRUE;
}
return(TRUE);
}
BOOL HalGetPath(const char * pszXbox, const char * pszPathIn, char * pszPathOut)
{
char achXbox[MAX_PATH];
char achRoot[MAX_PATH];
char achTemp[MAX_PATH];
char * pch;
BOOL fAlreadyExists;
strncpy(achXbox, pszXbox, sizeof(achXbox));
for (pch = achXbox; *pch && *pch != '@'; ++pch) ;
*pch = 0;
// Make sure directory c:\$xbox exists
strcpy(achRoot, "c:\\$xbox");
HalCreateDirectory(achRoot, TRUE, &fAlreadyExists);
// Make sure directory c:\$xbox\<pszXbox> exists
strcat(achRoot, "\\");
strcat(achRoot, achXbox);
HalCreateDirectory(achRoot, FALSE, &fAlreadyExists);
if (!fAlreadyExists)
{
char achDir[MAX_PATH];
strcpy(achDir, achRoot);
strcat(achDir, "\\partition1");
HalCreateDirectory(achDir, FALSE, &fAlreadyExists);
strcpy(achDir, achRoot);
strcat(achDir, "\\partition1\\TDATA");
HalCreateDirectory(achDir, FALSE, &fAlreadyExists);
strcpy(achDir, achRoot);
strcat(achDir, "\\partition1\\CACHE");
HalCreateDirectory(achDir, FALSE, &fAlreadyExists);
strcpy(achDir, achRoot);
strcat(achDir, "\\partition1\\devkit");
HalCreateDirectory(achDir, FALSE, &fAlreadyExists);
strcpy(achDir, achRoot);
strcat(achDir, "\\partition2");
HalCreateDirectory(achDir, FALSE, &fAlreadyExists);
}
// Handle special "eeprom" path
if (lstrcmpiA(pszPathIn, "eeprom") == 0)
{
sprintf(pszPathOut, "%s\\eeprom.bin", achRoot);
return(TRUE);
}
// Handle special "volume" path
if (lstrcmpiA(pszPathIn, "\\Device\\Harddisk0\\partition0") == 0)
{
sprintf(pszPathOut, "%s\\config.bin", achRoot);
// Make sure this file exists and has room for all the config sectors
HANDLE hFile = CreateFile(pszPathOut, GENERIC_READ|GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
TraceSz2(Warning, "HalGetPath: CreateFile '%s' failed (%08lX)", pszPathOut, GetLastError());
return(FALSE);
}
DWORD dwSize = GetFileSize(hFile, NULL);
DWORD dwExpect = (XBOX_CONFIG_SECTOR_INDEX + XBOX_NUM_CONFIG_SECTORS) * XBOX_HD_SECTOR_SIZE;
if (dwSize != dwExpect)
{
if (dwSize != 0)
{
TraceSz3(Warning, "HalGetPath: '%s' has incorrect size (%d bytes); should be %d bytes. Repairing.",
pszPathOut, dwSize, dwExpect);
}
BYTE ab[(XBOX_CONFIG_SECTOR_INDEX + XBOX_NUM_CONFIG_SECTORS) * XBOX_HD_SECTOR_SIZE];
memset(ab, 0, sizeof(ab));
if (SetFilePointer(hFile, 0, NULL, FILE_BEGIN) == 0xFFFFFFFF)
{
TraceSz2(Warning, "HalGetPath: SetFilePointer '%s' failed (%08lX)", pszPathOut, GetLastError());
CloseHandle(hFile);
return(FALSE);
}
if (!WriteFile(hFile, ab, sizeof(ab), &dwExpect, NULL))
{
TraceSz2(Warning, "HalGetPath: WriteFile '%s' failed (%08lX)", pszPathOut, GetLastError());
CloseHandle(hFile);
return(FALSE);
}
Assert(dwExpect == sizeof(ab));
}
CloseHandle(hFile);
return(TRUE);
}
// Handle Harddisk0 paths
if (_strnicmp(pszPathIn, "\\Device\\Harddisk0\\", 18) == 0)
{
sprintf(pszPathOut, "%s\\%s", achRoot, pszPathIn + 18);
return(TRUE);
}
TraceSz1(Warning, "HalGetPath: Don't understand path '%s'", pszPathIn);
return(FALSE);
}
HANDLE HalCreateFile(char * pszXbox, LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
char achPath[MAX_PATH];
if (!HalGetPath(pszXbox, lpFileName, achPath))
{
TraceSz2(Warning, "HalCreateFile: HalGetPath('%s','%s') failed", pszXbox, lpFileName);
return(INVALID_HANDLE_VALUE);
}
return(CreateFile(achPath, dwDesiredAccess, dwShareMode, lpSecurityAttributes,
dwCreationDisposition, dwFlagsAndAttributes, hTemplateFile));
}
NTSTATUS HalNtOpenFile(char * pszXbox, PHANDLE FileHandle, ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock,
ULONG ShareAccess, ULONG OpenOptions)
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
char achPath[MAX_PATH];
if (!HalGetPath(pszXbox, (char *)ObjectAttributes->ObjectName->Buffer, achPath))
{
TraceSz2(Warning, "HalNtOpenFile: HalGetPath('%s','%s') failed",
pszXbox, (char *)ObjectAttributes->ObjectName->Buffer);
*FileHandle = INVALID_HANDLE_VALUE;
}
else
{
*FileHandle = CreateFile(achPath, DesiredAccess & (GENERIC_READ|GENERIC_WRITE),
ShareAccess & (FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE),
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
}
if (*FileHandle != INVALID_HANDLE_VALUE)
{
status = STATUS_SUCCESS;
}
return(status);
}
NTSTATUS HalNtCreateFile(char * pszXbox, PHANDLE FileHandle, ACCESS_MASK DesiredAccess,
POBJECT_ATTRIBUTES ObjectAttributes, PIO_STATUS_BLOCK IoStatusBlock,
PLARGE_INTEGER AllocationSize, ULONG FileAttributes,
ULONG ShareAccess, ULONG CreateDisposition, ULONG CreateOptions)
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
char achPath[MAX_PATH];
if (!HalGetPath(pszXbox, (char *)ObjectAttributes->ObjectName->Buffer, achPath))
{
TraceSz2(Warning, "HalNtCreateFile: HalGetPath('%s','%s') failed",
pszXbox, (char *)ObjectAttributes->ObjectName->Buffer);
*FileHandle = INVALID_HANDLE_VALUE;
}
else
{
DWORD dwDisposition = CREATE_ALWAYS;
switch (CreateDisposition)
{
case FILE_SUPERSEDE: dwDisposition = TRUNCATE_EXISTING; break;
case FILE_OPEN: dwDisposition = OPEN_ALWAYS; break;
case FILE_CREATE: dwDisposition = CREATE_NEW; break;
case FILE_OPEN_IF: dwDisposition = CREATE_ALWAYS; break;
case FILE_OVERWRITE: dwDisposition = CREATE_ALWAYS; break;
case FILE_OVERWRITE_IF: dwDisposition = TRUNCATE_EXISTING; break;
}
*FileHandle = CreateFile(achPath, DesiredAccess & (GENERIC_READ|GENERIC_WRITE),
ShareAccess & (FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE),
NULL, dwDisposition, FILE_ATTRIBUTE_NORMAL, NULL);
}
if (*FileHandle != INVALID_HANDLE_VALUE)
{
status = STATUS_SUCCESS;
}
return(status);
}
NTSTATUS HalNtReadFile(char * pszXbox, HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine,
PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer, ULONG Length,
PLARGE_INTEGER ByteOffset)
{
if (SetFilePointer(FileHandle, ByteOffset->LowPart, &ByteOffset->HighPart, FILE_BEGIN) == 0xFFFFFFFF)
{
TraceSz1(Warning, "HalNtReadFile: SetFilePointer failed (%08lX)", GetLastError());
return(STATUS_UNSUCCESSFUL);
}
DWORD dwRead;
if (!ReadFile(FileHandle, Buffer, Length, &dwRead, NULL))
{
TraceSz1(Warning, "HalNtReadFile: ReadFile failed (%08lX)", GetLastError());
return(STATUS_UNSUCCESSFUL);
}
if (dwRead != Length)
{
TraceSz2(Warning, "HalNtReadFile: ReadFile returned only %d bytes (%d requested)", dwRead, Length);
return(STATUS_UNSUCCESSFUL);
}
return(STATUS_SUCCESS);
}
NTSTATUS HalNtWriteFile(char * pszXbox, HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine,
PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer,
ULONG Length, PLARGE_INTEGER ByteOffset)
{
if (SetFilePointer(FileHandle, ByteOffset->LowPart, &ByteOffset->HighPart, FILE_BEGIN) == 0xFFFFFFFF)
{
TraceSz1(Warning, "HalNtWriteFile: SetFilePointer failed (%08lX)", GetLastError());
return(STATUS_UNSUCCESSFUL);
}
DWORD dwWrite;
if (!WriteFile(FileHandle, Buffer, Length, &dwWrite, NULL))
{
TraceSz1(Warning, "HalNtWriteFile: WriteFile failed (%08lX)", GetLastError());
return(STATUS_UNSUCCESSFUL);
}
if (dwWrite != Length)
{
TraceSz2(Warning, "HalNtWriteFile: WriteFile wrote only %d bytes (%d requested)", dwWrite, Length);
return(STATUS_UNSUCCESSFUL);
}
return(STATUS_SUCCESS);
}
NTSTATUS HalNtClose(char * pszXbox, HANDLE Handle)
{
if (Handle != INVALID_HANDLE_VALUE)
{
CloseHandle(Handle);
}
return(STATUS_SUCCESS);
}
// ---------------------------------------------------------------------------------------
// EEPROM
// ---------------------------------------------------------------------------------------
BOOL HalSaveEEPROM(char * pszXbox, EEPROM_LAYOUT * peeprom)
{
HANDLE hFile = INVALID_HANDLE_VALUE;
BOOL fResult = FALSE;
DWORD dwSize;
char achPath[MAX_PATH];
if (!HalGetPath(pszXbox, "eeprom", achPath))
{
TraceSz1(Warning, "HalSaveEEPROM: HalGetPath('%s','eeprom') failed", pszXbox);
goto ret;
}
hFile = CreateFile(achPath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
TraceSz2(Warning, "HalSaveEEPROM: CreateFile '%s' failed (%08lX)", achPath, GetLastError());
goto ret;
}
if (!WriteFile(hFile, peeprom, sizeof(EEPROM_LAYOUT), &dwSize, NULL))
{
TraceSz2(Warning, "HalSaveEEPROM: WriteFile '%s' failed (%08lX)", achPath, GetLastError());
goto ret;
}
fResult = TRUE;
ret:
if (hFile != INVALID_HANDLE_VALUE)
{
CloseHandle(hFile);
}
return(fResult);
}
BOOL HalLoadEEPROM(char * pszXbox, EEPROM_LAYOUT * peeprom)
{
HANDLE hFile = INVALID_HANDLE_VALUE;
BOOL fResult = FALSE;
DWORD dwSize;
char achPath[MAX_PATH];
if (!HalGetPath(pszXbox, "eeprom", achPath))
{
TraceSz1(Warning, "HalLoadEEPROM: HalGetPath('%s','eeprom') failed", pszXbox);
goto ret;
}
hFile = CreateFile(achPath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE)
{
TraceSz2(Warning, "HalLoadEEPROM: CreateFile '%s' failed (%08lX)", achPath, GetLastError());
goto ret;
}
if (SetFilePointer(hFile, 0, NULL, FILE_BEGIN) == 0xFFFFFFFF)
{
TraceSz2(Warning, "HalLoadEEPROM: SetFilePointer '%s' failed (%08lX)", achPath, GetLastError());
goto ret;
}
dwSize = GetFileSize(hFile, NULL);
if (dwSize == sizeof(EEPROM_LAYOUT))
{
if (!ReadFile(hFile, peeprom, sizeof(EEPROM_LAYOUT), &dwSize, NULL))
{
TraceSz2(Warning, "HalLoadEEPROM: ReadFile '%s' failed (%08lX)", achPath, GetLastError());
goto ret;
}
}
else
{
CloseHandle(hFile);
hFile = INVALID_HANDLE_VALUE;
if (dwSize != 0)
{
TraceSz3(Warning, "HalLoadEEPROM: '%s' is incorrect size (%d bytes); should be %d bytes. Repairing.",
achPath, dwSize, sizeof(EEPROM_LAYOUT));
}
memset(peeprom, 0, sizeof(EEPROM_LAYOUT));
XBOX_ENCRYPTED_SETTINGS * pes = (XBOX_ENCRYPTED_SETTINGS *)&peeprom->EncryptedSection;
XBOX_FACTORY_SETTINGS * pfs = (XBOX_FACTORY_SETTINGS *)&peeprom->FactorySection;
memset(pfs->SerialNumber, '9', sizeof(pfs->SerialNumber));
Assert(sizeof(pfs->OnlineKey) == DEVKIT_ONLINE_RAND_KEY_LEN);
memcpy(pfs->OnlineKey, DEVKIT_ONLINE_RAND_KEY, sizeof(pfs->OnlineKey));
BYTE abHdKey[16] = { 0 };
MorphKeyByHardDriveKeyEx(abHdKey, pfs->OnlineKey, sizeof(pfs->OnlineKey));
HalSaveEEPROM(pszXbox, peeprom);
}
fResult = TRUE;
ret:
if (hFile != INVALID_HANDLE_VALUE)
{
CloseHandle(hFile);
}
return(fResult);
}
NTSTATUS HalExQueryNonVolatileSetting(char * pszXbox, ULONG ValueIndex, ULONG * Type, VOID * Value, ULONG ValueLength, ULONG * ResultLength)
{
EEPROM_LAYOUT eeprom;
NTSTATUS status = STATUS_UNSUCCESSFUL;
*Type = 0;
*ResultLength = 0;
if (HalLoadEEPROM(pszXbox, &eeprom))
{
XBOX_FACTORY_SETTINGS * pfs = (XBOX_FACTORY_SETTINGS *)&eeprom.FactorySection;
switch (ValueIndex)
{
case XC_FACTORY_ETHERNET_ADDR:
{
if (ValueLength == sizeof(pfs->EthernetAddr))
{
memcpy(Value, pfs->EthernetAddr, ValueLength);
*Type = REG_BINARY;
*ResultLength = ValueLength;
status = STATUS_SUCCESS;
}
break;
}
case XC_FACTORY_SERIAL_NUMBER:
{
if (ValueLength == sizeof(pfs->SerialNumber))
{
memcpy(Value, pfs->SerialNumber, ValueLength);
*Type = REG_BINARY;
*ResultLength = ValueLength;
status = STATUS_SUCCESS;
}
break;
}
case XC_FACTORY_ONLINE_KEY:
{
if (ValueLength == sizeof(pfs->OnlineKey))
{
memcpy(Value, pfs->OnlineKey, ValueLength);
*Type = REG_BINARY;
*ResultLength = ValueLength;
status = STATUS_SUCCESS;
}
break;
}
}
AssertSz1(status == STATUS_SUCCESS, "HalExQueryNonVolatileSetting: Unrecognized ValueIndex (%d)", ValueIndex);
}
return(STATUS_SUCCESS);
}
NTSTATUS HalExSaveNonVolatileSetting(char * pszXbox, ULONG ValueIndex, ULONG Type, const VOID * Value, ULONG ValueLength)
{
EEPROM_LAYOUT eeprom;
NTSTATUS status = STATUS_UNSUCCESSFUL;
if (HalLoadEEPROM(pszXbox, &eeprom))
{
XBOX_FACTORY_SETTINGS * pfs = (XBOX_FACTORY_SETTINGS *)&eeprom.FactorySection;
switch (ValueIndex)
{
case XC_FACTORY_ETHERNET_ADDR:
{
if (Type == REG_BINARY && ValueLength == sizeof(pfs->EthernetAddr))
{
memcpy(pfs->EthernetAddr, Value, ValueLength);
status = STATUS_SUCCESS;
}
break;
}
case XC_FACTORY_SERIAL_NUMBER:
{
if (Type == REG_BINARY && ValueLength == sizeof(pfs->SerialNumber))
{
memcpy(pfs->SerialNumber, Value, ValueLength);
status = STATUS_SUCCESS;
}
break;
}
case XC_FACTORY_ONLINE_KEY:
{
if (Type == REG_BINARY && ValueLength == sizeof(pfs->OnlineKey))
{
memcpy(pfs->OnlineKey, Value, ValueLength);
status = STATUS_SUCCESS;
}
break;
}
}
AssertSz2(status == STATUS_SUCCESS, "HalExSaveNonVolatileSetting: Unrecognized ValueIndex (%d) Type (%d)", ValueIndex, Type);
}
if (status == STATUS_SUCCESS && !HalSaveEEPROM(pszXbox, &eeprom))
{
status = STATUS_UNSUCCESSFUL;
}
return(status);
}
// ---------------------------------------------------------------------------------------
#endif