Initial commit

This commit is contained in:
Xoro-1337
2025-11-06 15:36:24 -05:00
parent a738b93280
commit b24c1ddcbc
45 changed files with 65790 additions and 0 deletions

3630
xbdm/dmserv.c Normal file
View File

@@ -0,0 +1,3630 @@
/*
Copyright (c) 2013 Nathan LeRoux
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "dmincludes.h"
DMCONN rgdmc[CONNECTION_MAX];
SOCKET sockServ, sockName;
const char rgchHex[] = "0123456789ABCDEF";
char *rgszDumpMode[] = { "smart", "enabled", "disabled" };
/* BEGIN MICROSOFT CODE */
int SgnCompareRgch(const char *sz1, const char *sz2, int cch)
{
while(cch-- && *sz1) {
char ch1 = *sz1++;
char ch2 = *sz2++;
if(ch1 >= 'a' && ch2 <= 'z')
ch1 -= 32;
if(ch2 >= 'a' && ch2 <= 'z')
ch2 -= 32;
if(ch1 != ch2)
return ch1 - ch2;
}
if(*sz1)
return *sz1;
return cch < 0 ? 0 : -*sz2;
}
BOOL FEqualRgch(const char *sz1, const char *sz2, int cch)
{
return SgnCompareRgch(sz1, sz2, cch) == 0;
}
DWORD DwHexFromSz(LPCSTR sz, LPCSTR *szOut)
{
DWORD dw = 0;
for(;;) {
if(*sz >= '0' && *sz <= '9')
dw = dw * 16 + (*sz - '0');
else if(*sz >= 'A' && *sz <= 'F')
dw = dw * 16 + (*sz - 'A' + 10);
else if(*sz >= 'a' && *sz <= 'f')
dw = dw * 16 + (*sz - 'a' + 10);
else
break;
++sz;
}
if(szOut)
*szOut = sz;
return dw;
}
DWORD DwFromSz(LPCSTR sz, int *pcchUsed)
{
DWORD dw = 0;
LPCSTR szStart = sz;
/* Process decimal, octal, or hex */
if(*sz == '0') {
++sz;
if(*sz == 'x')
dw = DwHexFromSz(++sz, &sz);
else
while(*sz >= '0' && *sz <= '7')
dw = dw * 8 + (*sz++ - '0');
} else
while(*sz >= '0' && *sz <= '9')
dw = dw * 10 + (*sz++ - '0');
if(pcchUsed)
*pcchUsed = sz - szStart;
return dw;
}
__inline BOOL FIsSpace(char ch)
{
return ch == ' ' || ch == '\015' || ch == 0;
}
const char *PchGetParam(LPCSTR szCmd, LPCSTR szKey, BOOL fNeedValue)
{
const char *pchTok;
int cchTok;
BOOL fQuote = FALSE;
/* Skip the command */
for(pchTok = szCmd; !FIsSpace(*pchTok); ++pchTok);
while(*pchTok) {
/* Skip leading spaces */
while(*pchTok && FIsSpace(*pchTok))
++pchTok;
if(!*pchTok)
return NULL;
for(cchTok = 0; !FIsSpace(pchTok[cchTok]); ++cchTok) {
if(pchTok[cchTok] == '=') {
if(FEqualRgch(szKey, pchTok, cchTok))
return pchTok + cchTok + 1; /* Skip the '=' */
break;
}
}
/* If we didn't see the '=' we need to check anyway */
if(!fNeedValue && pchTok[cchTok] != '=' && FEqualRgch(szKey, pchTok,
cchTok))
return pchTok + cchTok;
/* No match, so we need to skip past the value */
pchTok += cchTok;
while(*pchTok && (!FIsSpace(*pchTok) || fQuote))
if(*pchTok++ == '"')
fQuote = !fQuote;
}
return NULL;
}
void GetParam(LPCSTR szLine, LPSTR szBuf, int cchBuf)
{
int cch = 0;
BOOL fQuote = FALSE;
while(cch < cchBuf-1 && *szLine && (!FIsSpace(*szLine) || fQuote)) {
if(*szLine == '"') {
if(fQuote && szLine[1] == '"') {
/* Double quote inside a string gets copied as a single
* quote */
szBuf[cch++] = '"';
szLine += 2;
} else {
fQuote = !fQuote;
++szLine;
}
} else
szBuf[cch++] = *szLine++;
}
szBuf[cch] = 0;
}
BOOL FGetSzParam(LPCSTR szLine, LPCSTR szKey, LPSTR szBuf, int cchBuf)
{
LPCSTR pch = PchGetParam(szLine, szKey, TRUE);
if(!pch)
return FALSE;
GetParam(pch, szBuf, cchBuf);
return TRUE;
}
BOOL FGetDwParam(LPCSTR szLine, LPCSTR szKey, DWORD *pdw)
{
int cch;
char sz[32];
LPCSTR pch = PchGetParam(szLine, szKey, TRUE);
if(!pch)
return FALSE;
GetParam(pch, sz, sizeof sz);
*pdw = DwFromSz(sz, &cch);
return FIsSpace(sz[cch]);
}
/* END MICROSOFT CODE */
BOOL FGetVectorParam(LPCSTR szLine, LPCSTR szKey, float *pvr)
{
char sz[63];
int j = 0, i;
LPCSTR pch = PchGetParam(szLine, szKey, TRUE);
if(!pch)
return FALSE;
GetParam(pch, sz, sizeof sz);
for(i = 0;i < 4;i++)
{
((DWORD*)pvr)[i] = DwFromSz(sz + j, NULL);
do{ j++; } while(sz[j] != ',');
if(i < 3 && (sz[j] != ',') && !FIsSpace(sz[j]))
return FALSE;
j++;
}
return TRUE;
}
BOOL FGetQwordParam(LPCSTR szLine, LPCSTR szKey, ULARGE_INTEGER *plu)
{
int cch;
char sz[32];
LPCSTR pch;
pch = PchGetParam(szLine, szKey, TRUE);
if(!pch)
return FALSE;
GetParam(pch, sz, sizeof sz - 1);
sz[sizeof sz - 1] = 0;
/* Verify the 0q prefix */
if(sz[0] != '0' || sz[1] != 'q')
return FALSE;
/* Make sure we have a bunch of hex characters */
for(cch = 2; cch < sizeof sz && !FIsSpace(sz[cch]); ++cch) {
if(!(sz[cch] >= '0' && sz[cch] <= '9' ||
sz[cch] >= 'A' && sz[cch] <= 'F' ||
sz[cch] >= 'a' && sz[cch] <= 'f'))
return FALSE;
}
cch -= 2;
if(cch <= 0)
return FALSE;
/* Move the text out to the end of the string and fill the preceding
* characters with zeroes */
memmove(&sz[sizeof sz - 1 - cch], &sz[2], cch);
memset(sz, '0', sizeof sz - 1 - cch);
/* Now parse out the two dwords */
plu->LowPart = DwHexFromSz(&sz[sizeof sz - 9], NULL);
sz[sizeof sz - 9] = 0;
plu->HighPart = DwHexFromSz(&sz[sizeof sz - 17], NULL);
return TRUE;
}
BOOL FGetNamedDwParam(LPCSTR szLine, LPCSTR szKey, DWORD *pdw, LPSTR szResp)
{
if(!FGetDwParam(szLine, szKey, pdw)) {
RtlSprintf(szResp, "missing %s", szKey);
return FALSE;
}
return TRUE;
}
ULONG UlAddrFromSz(LPCSTR sz)
{
ULONG ul;
int ib;
int ich;
for(ib = 0; ib < 4; ++ib) {
BYTE b = 0;
for(ich = 0; ich < 3; ++ich) {
if(sz[ich] < '0' || sz[ich] > '9')
break;
b = 10 * b + (sz[ich] - '0');
}
if(ich == 0 || sz[ich] != (ib == 3 ? 0 : '.'))
return 0;
sz += ich + 1;
((BYTE *)&ul)[ib ^ 3] = b;
}
return ul;
}
void GetFileAttrSz(LPSTR sz, ULONG dwAttributes, PLARGE_INTEGER pliChange,
PLARGE_INTEGER pliCreate, PLARGE_INTEGER pliSize)
{
RtlSprintf(sz, "sizehi=0x%x sizelo=0x%x createhi=0x%08x createlo=0x%08x "
"changehi=0x%08x changelo=0x%08x%s%s%s", pliSize->HighPart,
pliSize->LowPart, pliCreate->HighPart, pliCreate->LowPart,
pliChange->HighPart, pliChange->LowPart,
dwAttributes & FILE_ATTRIBUTE_DIRECTORY ? " directory" : "",
dwAttributes & FILE_ATTRIBUTE_READONLY ? " readonly" : "",
dwAttributes & FILE_ATTRIBUTE_HIDDEN ? " hidden" : "");
}
VOID FStopServ()
{
int i;
closesocket(sockServ);
closesocket(sockName);
for(i = 0;i < CONNECTION_MAX;i++)
if(rgdmc[i].bActive)
closesocket(rgdmc[i].s);
}
int FSend(SOCKET s, LPCSTR fmt, ...)
{
char buf[0x200];
va_list list;
va_start(list, fmt);
RtlVsnprintf(buf, sizeof(buf), fmt, list);
va_end(list);
return send(s, buf, strlen(buf), 0);
}
int FSendLine(SOCKET s, LPCSTR fmt, ...)
{
char buf[0x202];
int i;
va_list list;
va_start(list, fmt);
i = RtlVsnprintf(buf, sizeof(buf) - 2, fmt, list);
va_end(list);
strcat(buf, "\r\n");
return send(s, buf, i + 2, 0);
}
LPCSTR SzStdResponse(HRESULT hr)
{
LPCSTR pszResp;
switch(hr) {
case XBDM_LINE_TOO_LONG:
pszResp = "line too long";
break;
case XBDM_NOSUCHFILE:
pszResp = "file not found";
break;
case XBDM_NOMODULE:
pszResp = "no such module";
break;
case XBDM_MEMUNMAPPED:
pszResp = "memory not mapped";
break;
case XBDM_NOTHREAD:
pszResp = "no such thread";
break;
case XBDM_INVALIDCMD:
pszResp = "unknown command";
break;
case XBDM_NOTSTOPPED:
pszResp = "not stopped";
break;
case XBDM_ALREADYSTOPPED:
pszResp = "already stopped";
break;
case XBDM_MUSTCOPY:
pszResp = "file must be copied";
break;
case XBDM_ALREADYEXISTS:
pszResp = "file already exists";
break;
case XBDM_DIRNOTEMPTY:
pszResp = "directory not empty";
break;
case XBDM_BADFILENAME:
pszResp = "filename is invalid";
break;
case XBDM_CANNOTCREATE:
pszResp = "file cannot be created";
break;
case XBDM_DEVICEFULL:
pszResp = "no room on device";
break;
case XBDM_MULTIRESPONSE:
pszResp = "multiline response follows";
break;
case XBDM_BINRESPONSE:
pszResp = "binary response follows";
break;
case XBDM_READYFORBIN:
pszResp = "send binary data";
break;
case XBDM_CANNOTACCESS:
pszResp = "access denied";
break;
case XBDM_NOTDEBUGGABLE:
pszResp = "not debuggable";
break;
case XBDM_BADCOUNTTYPE:
pszResp = "type invalid";
break;
case XBDM_COUNTUNAVAILABLE:
pszResp = "data not available";
break;
case XBDM_NOTLOCKED:
pszResp = "box is not locked";
break;
case XBDM_KEYXCHG:
pszResp = "key exchange required";
break;
case XBDM_MUSTBEDEDICATED:
pszResp = "dedicated connection required";
break;
case E_OUTOFMEMORY:
pszResp = "out of memory";
break;
case E_UNEXPECTED:
pszResp = "unexpected error";
break;
case E_INVALIDARG:
pszResp = "bad parameter";
break;
case XBDM_NOERR:
pszResp = "OK";
break;
default:
pszResp = "";
break;
}
return pszResp;
}
int SendHrSzResp(SOCKET s, HRESULT hr, LPCSTR szResp, LPSTR szBuf)
{
/* Make sure we have an error code we like */
if(((hr >> 16) & 0x7fff) != FACILITY_XBDM) {
hr = SUCCEEDED(hr) ? XBDM_NOERR : XBDM_UNDEFINED;
if(!szResp)
szResp = SzStdResponse(E_UNEXPECTED);
} else if((hr & 0xffff) > 0xff)
hr = XBDM_UNDEFINED;
if(FAILED(hr))
szBuf[0] = '4';
else
szBuf[0] = '2';
szBuf[1] = (char) ('0' + (hr & 0xffff) / 10); // overflow?
szBuf[2] = (char) ('0' + (hr & 0xffff) % 10);
szBuf[3] = '-';
szBuf[4] = ' ';
if(szResp != szBuf) {
if(szResp)
strcpy(szBuf + 5, szResp);
else
szBuf[5] = 0;
}
return FSendLine(s, "%s", szBuf);
}
VOID DoReadWrite(PDMCONN pdmc, BOOL bCanRead)
{
int i, j;
DWORD dw;
char sz[0x200];
char resp[0x200];
HRESULT hr;
if(!pdmc->bConversation)
{
// We are not currently in a handling function
// Check for shutdown
if(pdmc->bShutdown)
{
if(!pdmc->bKeepAlive)
closesocket(pdmc->s);
ZeroMemory(pdmc, sizeof(DMCONN));
return;
}
// First, scan the buffer to search for newlines
for(dw = 0;dw < pdmc->dwRecv && (pdmc->szRecv[dw] != '\n');dw++);
// If i == pdmc->dwRecv then there are no commands in the buffer
if(dw == pdmc->dwRecv)
{
// Recieve into the buffer
if(bCanRead)
{
i = recv(pdmc->s, (char*)pdmc->szRecv + pdmc->dwRecv, sizeof(pdmc->szRecv) - pdmc->dwRecv, 0);
if(i <= 0)
{
pdmc->bShutdown = TRUE;
return;
}
pdmc->dwRecv += i;
}
}
// Scan the buffer for a newline
for(dw = 0;dw < pdmc->dwRecv && (pdmc->szRecv[dw] != '\n');dw++);
if(dw != pdmc->dwRecv)
{
// We found a command
if(pdmc->bTooLong)
{
SendHrSzResp(pdmc->s, XBDM_LINE_TOO_LONG, "", sz);
pdmc->bTooLong = FALSE;
pdmc->dwRecv = 0;
return;
}
// Find the command name
for(i = 0;(pdmc->szRecv[i]) && (pdmc->szRecv[i] != '\r') && (pdmc->szRecv[i] != '\n') && (pdmc->szRecv[i] != ' ');i++)
sz[i] = pdmc->szRecv[i];
sz[i] = 0;
// Now we just walk the list with our super inefficient algo of BRUTE FORCE SEARCHING
for(j = 0;j < cchcmd && stricmp(sz, rgbcmd[j].szName);j++);
if(j == cchcmd) // Command not found
{
SendHrSzResp(pdmc->s, XBDM_INVALIDCMD, SzStdResponse(XBDM_INVALIDCMD), sz);
memcpy(sz, pdmc->szRecv, dw - 1);
sz[dw - 1] = 0;
DbgPrint("[xbdm] unknown command \"%s\"\n", sz);
}
else if((rgbcmd[j].dwPriv & pdmc->dwPriv) != rgbcmd[j].dwPriv)
{
// Not enough permissions
SendHrSzResp(pdmc->s, XBDM_CANNOTACCESS, SzStdResponse(XBDM_CANNOTACCESS), sz);
}
else
{
// Command foundzorz
// Copy the whole string over
for(i = 0;(pdmc->szRecv[i] != '\r') && (pdmc->szRecv[i] != '\n');i++)
sz[i] = pdmc->szRecv[i];
sz[i] = 0;
resp[0] = 0;
// Setup some final state information
pdmc->dmcc.Buffer = NULL;
pdmc->dmcc.BufferSize = 0;
pdmc->dmcc.BytesRemaining = 0;
pdmc->dmcc.CustomData = &pdmc->dmcd;
pdmc->dmcc.DataSize = -1;
pdmc->dmcc.HandlingFunction = NULL;
pdmc->hr = hr = rgbcmd[j].pdmcp(sz, resp, sizeof(resp), &pdmc->dmcc);
if(hr == XBDM_MULTIRESPONSE
|| hr == XBDM_BINRESPONSE
|| hr == XBDM_READYFORBIN)
pdmc->bConversation = TRUE;
if(!pdmc->bKeepAlive)
{
if(resp[0])
{
if(SendHrSzResp(pdmc->s, hr, resp, sz) <= 0)
pdmc->bShutdown = TRUE;
}
else if(SendHrSzResp(pdmc->s, hr, SzStdResponse(hr), sz) <= 0)
pdmc->bShutdown = TRUE;
}
}
// Fetch the index of the \n
for(i = 0;pdmc->szRecv[i] != '\n';i++);
// Move the memory
memmove(pdmc->szRecv, pdmc->szRecv + (i + 1), sizeof(pdmc->szRecv) - (i + 1));
// Adjust the vars
pdmc->dwRecv -= i + 1;
}
else if(pdmc->dwRecv == sizeof(pdmc->szRecv))
pdmc->bTooLong = TRUE; // Overflow....
// On overflow, just ignore the rest of the data until newline
if(pdmc->bTooLong)
pdmc->dwRecv = 0;
}
else
{
// We are currently in a handling function
ASSERT(pdmc->dmcc.HandlingFunction);
if(pdmc->dmcc.Buffer == NULL)
{
pdmc->dmcc.Buffer = pdmc->szBuf;
pdmc->dmcc.BufferSize = sizeof(pdmc->szBuf);
}
// Check for shutdown
if(pdmc->bShutdown)
{
if(pdmc->hr == XBDM_READYFORBIN)
{
// Multiline responses are free to continue, but they wont go anywhere
pdmc->dmcc.DataSize = 0;
pdmc->bConversation = FALSE;
}
}
if(pdmc->hr == XBDM_READYFORBIN)
{
if(bCanRead)
{
if(!pdmc->bShutdown)
{
i = recv(pdmc->s, (char*)pdmc->dmcc.Buffer,
pdmc->dmcc.BytesRemaining > pdmc->dmcc.BufferSize ? pdmc->dmcc.BufferSize : pdmc->dmcc.BytesRemaining,
0);
if(i <= 0)
{
pdmc->dmcc.DataSize = 0;
pdmc->bShutdown = TRUE;
}
else
pdmc->dmcc.DataSize = i;
}
hr = pdmc->dmcc.HandlingFunction(&pdmc->dmcc, resp, sizeof(resp));
if(!pdmc->bShutdown)
{
if(pdmc->dmcc.BytesRemaining == 0)
{
if(hr == XBDM_MULTIRESPONSE
|| hr == XBDM_BINRESPONSE
|| hr == XBDM_READYFORBIN)
{
pdmc->hr = hr;
pdmc->bConversation = TRUE;
pdmc->dmcc.DataSize = 0;
}
else
{
pdmc->bConversation = FALSE;
pdmc->dmcc.HandlingFunction = NULL;
}
SendHrSzResp(pdmc->s, hr, SzStdResponse(hr), sz);
}
}
if(pdmc->bShutdown)
pdmc->bConversation = FALSE;
}
}
else
{
if(pdmc->bShutdown || pdmc->dmcc.DataSize == 0 || pdmc->dmcc.DataSize == -1)
{
// Multiline/binary
pdmc->dmcc.DataSize = -1;
#ifdef _DEBUG
hr = pdmc->dmcc.HandlingFunction(&pdmc->dmcc, NULL, 0x100); // This way i can catch those annoying errors
#else
hr = pdmc->dmcc.HandlingFunction(&pdmc->dmcc, NULL, 0);
#endif
pdmc->Buffer = pdmc->dmcc.Buffer;
}
if(pdmc->bShutdown)
{
if(FAILED(hr)
|| hr == XBDM_MULTIRESPONSE
|| hr == XBDM_BINRESPONSE
|| hr == XBDM_READYFORBIN) // Just let them keep talking
pdmc->bConversation = FALSE;
}
else
{
if(hr == XBDM_ENDOFLIST
|| hr == XBDM_MULTIRESPONSE
|| hr == XBDM_BINRESPONSE
|| hr == XBDM_READYFORBIN)
{
if(pdmc->hr == XBDM_MULTIRESPONSE)
FSend(pdmc->s, ".\r\n");
pdmc->bConversation = FALSE;
if(hr == XBDM_MULTIRESPONSE
|| hr == XBDM_BINRESPONSE
|| hr == XBDM_READYFORBIN)
{
pdmc->hr = hr;
pdmc->bConversation = TRUE;
}
else
pdmc->dmcc.HandlingFunction = NULL;
}
else if(NT_SUCCESS(hr))
{
if(pdmc->dmcc.DataSize == -1)
{
// Null terminated string with a newline
if(FSend(pdmc->s, "%s\r\n", pdmc->dmcc.Buffer) <= 0)
pdmc->bShutdown = TRUE;
}
else if(pdmc->dmcc.DataSize != 0)
{
// Binary data
if((i = send(pdmc->s, (char*)pdmc->Buffer, pdmc->dmcc.DataSize, 0)) <= 0)
pdmc->bShutdown = TRUE;
pdmc->dmcc.DataSize -= i;
pdmc->Buffer = (PVOID)((DWORD)pdmc->Buffer + i);
}
}
else
{
if(pdmc->dmcc.DataSize == -1)
FSend(pdmc->s, "%s\r\n", pdmc->dmcc.Buffer);
// Forcefully terminate the connection
pdmc->bShutdown = TRUE;
pdmc->bConversation = FALSE;
}
}
}
}
}
VOID AnswerName(SOCKET s)
{
struct {
BYTE bRequest;
BYTE cchName;
char szName[256];
} nm;
SOCKADDR_IN sin;
int cbAddr = sizeof(sin);
int cbPkt;
cbPkt = recvfrom(s, (char*)&nm, sizeof(nm), 0, (SOCKADDR*)&sin, &cbAddr);
switch(nm.bRequest)
{
case 1:
case 3:
if(nm.bRequest == 1)
{
nm.bRequest = 0;
if(cbPkt < 2 || cbPkt < (2 + nm.cchName))
break;
if(!nm.cchName || strcmpi(nm.szName, g_dmGlobals.rgchDbgName))
break;
}
nm.bRequest = 2;
break;
default:
nm.bRequest = 0;
break;
}
if(nm.bRequest)
sendto(s, (char*)&nm, cbPkt, 0, (SOCKADDR*)&sin, cbAddr);
}
ULONG __stdcall ServerThread(LPVOID lpParam)
{
SOCKET sock;
BOOL bReuse;
SOCKADDR_IN sin;
FD_SET readfds, writefds;
struct timeval timeout;
XNADDR xna;
DMTD *pdmtd;
int i;
KeSetBasePriorityThread(PsGetCurrentThread(), THREAD_PRIORITY_TIME_CRITICAL);
pdmtd = DmGetCurrentDmtd();
pdmtd->DebugFlags |= DMFLAG_DEBUGTHREAD;
VSetThreadName(-1, "Debugger Command Thread");
ZeroMemory(rgdmc, sizeof(rgdmc));
do
{
// Well, this IS the server thread, so if we can't start a server then screw you
Sleep(5000);
sockServ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
} while(sockServ == INVALID_SOCKET);
bReuse = TRUE;
if(setsockopt(sockServ, SOL_SOCKET, SO_DECRYPTSOCK, (char*)&bReuse, sizeof(bReuse)))
{
DbgPrint("[xbdm] failed %i\n", WSAGetLastError());
DebugBreak();
}
if(setsockopt(sockServ, SOL_SOCKET, SO_REUSEADDR, (char*)&bReuse, sizeof(bReuse)))
{
DbgPrint("[xbdm] failed %i\n", WSAGetLastError());
DebugBreak();
}
sin.sin_family = AF_INET;
sin.sin_port = 730;
sin.sin_addr.s_addr = INADDR_ANY;
if(bind(sockServ, (SOCKADDR*)&sin, sizeof(sin))
|| listen(sockServ, 8))
{
DbgPrint("[xbdm] failed %i\n", WSAGetLastError());
DebugBreak();
goto abortsocket;
}
sockName = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(setsockopt(sockName, SOL_SOCKET, SO_DECRYPTSOCK, (char*)&bReuse, sizeof(bReuse)))
{
DbgPrint("[xbdm] failed %i\n", WSAGetLastError());
DebugBreak();
}
if(setsockopt(sockName, SOL_SOCKET, SO_REUSEADDR, (char*)&bReuse, sizeof(bReuse)))
{
DbgPrint("[xbdm] failed %i\n", WSAGetLastError());
DebugBreak();
}
if(setsockopt(sockName, SOL_SOCKET, SO_BROADCAST, (char*)&bReuse, sizeof(bReuse)))
{
DbgPrint("[xbdm] failed %i\n", WSAGetLastError());
DebugBreak();
}
if(bind(sockName, (SOCKADDR*)&sin, sizeof(sin)))
{
DbgPrint("[xbdm] failed %i\n", WSAGetLastError());
DebugBreak();
}
DbgPrint("[xbdm] server started\n");
for(;;)
{
readfds.fd_count = 0;
writefds.fd_count = 0;
FD_SET(sockServ, &readfds);
FD_SET(sockName, &readfds);
for(i = 0;i < CONNECTION_MAX;i++)
{
if(rgdmc[i].bActive)
FD_SET(rgdmc[i].s, &readfds);
}
timeout.tv_sec = 0;
timeout.tv_usec = 0;
if(g_dmGlobals.bDirty)
{
FWriteGlobals();
g_dmGlobals.bDirty = FALSE;
}
if(!g_dmGlobals.bHasIp)
{
i = XNetGetTitleXnAddr(&xna);
if(i != XNET_GET_XNADDR_PENDING)
{
DbgPrint("[xbdm] IP Address Acquired [%i.%i.%i.%i] (0x%08x)\n",
xna.ina.S_un.S_un_b.s_b1, xna.ina.S_un.S_un_b.s_b2,
xna.ina.S_un.S_un_b.s_b3, xna.ina.S_un.S_un_b.s_b4,
i);
g_dmGlobals.bHasIp = TRUE;
}
}
// Yield to others (its the right thing to do)
Sleep(0);
ProcessQueuedNotifications();
select(0, &readfds, &writefds, NULL, &timeout);
if(FD_ISSET(sockName, &readfds))
AnswerName(sockName);
if(FD_ISSET(sockServ, &readfds))
{
i = sizeof(sin);
sock = accept(sockServ, (SOCKADDR*)&sin, &i);
for(i = 0;i < CONNECTION_MAX;i++)
{
if(!rgdmc[i].bActive)
{
rgdmc[i].bActive = TRUE;
rgdmc[i].s = sock;
memcpy(&rgdmc[i].sin, &sin, sizeof(sin));
break;
}
}
if(i == CONNECTION_MAX)
{
// No more connection slots
FSendLine(sock, "401- max number of connections exceeded");
closesocket(sock);
}
else
{
// Some quick init
// Give all permissions, as we don't have locking yet
rgdmc[i].dwPriv = DMPL_PRIV_READ | DMPL_PRIV_WRITE | DMPL_PRIV_CONFIGURE | DMPL_PRIV_CONTROL;
// Only give hypervisor access if its enabled
if(g_dmGlobals.bHypervisorEnabled)
rgdmc[i].dwPriv |= DMPL_PRIV_HVX_MASK;
// Say hello!
FSendLine(rgdmc[i].s, "201- connected");
}
}
for(i = 0;i < CONNECTION_MAX;i++)
{
if(rgdmc[i].bActive)
DoReadWrite(&rgdmc[i], FD_ISSET(rgdmc[i].s, &readfds));
}
}
abortsocket:
closesocket(sockServ);
DebugBreak();
return 0;
}
DMHRAPI HrGetAltAddr(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
XNADDR xna;
DWORD dw;
if(!pdmcc)
return E_FAIL;
dw = XNetGetTitleXnAddr(&xna);
if(dw == XNET_GET_XNADDR_PENDING || dw == XNET_GET_XNADDR_NONE)
return E_FAIL;
RtlSnprintf(szResponse, cchResponse, "addr=0x%08x", xna.ina.s_addr);
return XBDM_NOERR;
}
DMHRAPI HrEndConversation(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
PDMCONN pdmc;
if(!pdmcc)
return E_FAIL;
// Snag the structure
pdmc = CONTAINING_RECORD(pdmcc, DMCONN, dmcc);
// Say goodbye
strcpy(szResponse, "bye");
// Signal shutdown
pdmc->bShutdown = TRUE;
return XBDM_NOERR;
}
DMHRAPI HrMagicReboot(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
PDMCONN pdmc;
char szTmp[MAX_PATH];
char szLaunchPath[MAX_PATH];
char szMountPath[MAX_PATH];
char szCmdLine[MAX_PATH];
DWORD dwMask = 0;
HRESULT hr = XBDM_NOERR;
szCmdLine[0] = 0;
szMountPath[0] = 0;
szLaunchPath[0] = 0;
if(PchGetParam(szCommand, "wait", FALSE))
dwMask = DMBOOT_WAIT;
else if(PchGetParam(szCommand, "stop", FALSE))
dwMask = DMBOOT_STOP;
if(PchGetParam(szCommand, "cold", FALSE))
dwMask |= DMBOOT_COLD;
// TODO: if(stopped and exception) flag |= cold
if(FGetSzParam(szCommand, "title", szTmp, sizeof(szTmp)))
{
if(szTmp[0] == '\\')
strcpy_s(szLaunchPath, sizeof(szLaunchPath), szTmp);
else if(FAILED(FFileNameToObName(szTmp, szLaunchPath, sizeof(szLaunchPath))))
hr = XBDM_NOSUCHFILE;
}
if(FGetSzParam(szCommand, "directory", szTmp, sizeof(szTmp)))
{
if(szTmp[0] == '\\')
strcpy_s(szMountPath, sizeof(szMountPath), szTmp);
else if(FAILED(FFileNameToObName(szTmp, szMountPath, sizeof(szMountPath))))
hr = XBDM_NOSUCHFILE;
}
FGetSzParam(szCommand, "cmdline", szCmdLine, sizeof(szCmdLine));
if(NT_SUCCESS(hr))
{
if(dwMask & DMBOOT_COLD)
{
pdmc = CONTAINING_RECORD(pdmcc, DMCONN, dmcc);
FSendLine(pdmc->s, "200- OK");
Sleep(200);
FStopServ();
}
DmRebootEx(dwMask, szLaunchPath, szMountPath, szCmdLine);
}
return XBDM_NOERR;
}
DMHRAPI HrGetConsoleFeatures(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
if(!pdmcc)
return E_FAIL;
strcpy_s(szResponse, cchResponse, "DEBUGGING");
if(g_dmGlobals.dwConsoleColor & CONSOLE_COLOR_FLAG_BLUE)
strcat_s(szResponse, cchResponse, " 1GB_RAM");
return XBDM_NOERR;
}
DMHRAPI HrGetConsoleType(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
if(!pdmcc)
return E_FAIL;
if(g_dmGlobals.dwConsoleColor & CONSOLE_COLOR_FLAG_BLACK)
strcpy_s(szResponse, cchResponse, "devkit");
else if(g_dmGlobals.dwConsoleColor & CONSOLE_COLOR_FLAG_WHITE)
strcpy_s(szResponse, cchResponse, "testkit");
else
strcpy_s(szResponse, cchResponse, "reviewerkit");
return XBDM_NOERR;
}
DMHRAPI HrDbgName(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
char sz[256];
if(FGetSzParam(szCommand, "name", sz, sizeof(sz)))
{
strcpy_s(g_dmGlobals.rgchDbgName, 256, sz);
g_dmGlobals.bDirty = TRUE;
return XBDM_NOERR;
}
strcpy_s(szResponse, cchResponse, g_dmGlobals.rgchDbgName);
return XBDM_NOERR;
}
DMHRAPI HrDrivemap(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
if(PchGetParam(szCommand, "internal", FALSE))
g_dmGlobals.bDriveMap = TRUE;
else
g_dmGlobals.bDriveMap = FALSE;
g_dmGlobals.bDirty = TRUE;
return XBDM_NOERR;
}
DMHRAPI HrReportHelpInfo(PDM_CMDCONT pdmcc, LPSTR szResponse, DWORD cchResponse)
{
if((int)pdmcd->cch >= cchcmd)
return XBDM_ENDOFLIST;
strcpy_s((char*)pdmcc->Buffer, pdmcc->BufferSize, rgbcmd[pdmcd->cch].szName);
pdmcd->cch++;
return XBDM_NOERR;
}
DMHRAPI HrHelp(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
if(!pdmcc)
return E_FAIL;
pdmcc->HandlingFunction = HrReportHelpInfo;
pdmcc->BufferSize = 1;
pdmcd->cch = 0;
strcpy_s(szResponse, cchResponse, "command names follow");
return XBDM_MULTIRESPONSE;
}
DMHRAPI HrReboot(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
if(!pdmcc)
return E_FAIL;
FStopServ();
HalReturnToFirmware(6);
return XBDM_NOERR;
}
DMHRAPI HrSetSystemTime(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
ULARGE_INTEGER lu, luUnused;
if(!pdmcc)
return E_FAIL;
if(!FGetDwParam(szCommand, "clockhi", &lu.HighPart) || !FGetDwParam(szCommand, "clocklo", &lu.LowPart))
return XBDM_CLOCKNOTSET;
NtSetSystemTime(&lu, &luUnused);
XnpNoteSystemTime();
g_dmGlobals.fClockSet = TRUE;
return XBDM_NOERR;
}
DMHRAPI HrGetSystemTime(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
ULARGE_INTEGER lu;
if(!pdmcc)
return E_FAIL;
if(!g_dmGlobals.fClockSet)
return XBDM_CLOCKNOTSET;
KeQuerySystemTime(&lu);
RtlSnprintf(szResponse, cchResponse, "high=0x%x low=0x%x", lu.HighPart, lu.LowPart);
return XBDM_NOERR;
}
DMHRAPI HrShutdown(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
if(!pdmcc)
return E_FAIL;
FStopServ();
HalReturnToFirmware(5);
return XBDM_NOERR;
}
DMHRAPI HrSpew(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
DbgPrint("SPEW: %s\n", szCommand);
return XBDM_NOERR;
}
DMHRAPI HrReportXbeInfo(PDM_CMDCONT pdmcc, LPSTR szResponse, DWORD cchResponse)
{
PDM_XBE pdxbe = (PDM_XBE)pdmcc->CustomData;
int i;
if(pdmcc->BytesRemaining == 3)
{
DmFreePool(pdmcc->CustomData);
return XBDM_ENDOFLIST;
}
else if(pdmcc->BytesRemaining == 2)
{
i = strlen(pdxbe->LaunchPath);
pdxbe->LaunchPath[i++] = '"';
pdxbe->LaunchPath[i + 1] = 0;
memmove(pdxbe->LaunchPath + 6, pdxbe->LaunchPath, i++);
memcpy(pdxbe->LaunchPath, "name=\"", 6);
pdmcc->Buffer = pdxbe->LaunchPath;
pdmcc->BytesRemaining++;
}
else if(pdmcc->BytesRemaining == 1)
{
RtlSnprintf((char*)pdmcc->Buffer, pdmcc->BufferSize, "timestamp=0x%08x checksum=0x%08x", pdxbe->TimeStamp, pdxbe->CheckSum);
pdmcc->BytesRemaining++;
}
return XBDM_NOERR;
}
DMHRAPI HrGetXbeInfo(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
PDM_XBE pdxbe;
DWORD dwFlags = 0;
char sz[0x200];
LPCSTR szName;
HRESULT hr;
if(!pdmcc)
return E_FAIL;
if(PchGetParam(szCommand, "running", FALSE))
szName = NULL;
else if(FGetSzParam(szCommand, "name", sz, sizeof(sz)))
{
szName = sz;
if(PchGetParam(szCommand, "ondiskonly", FALSE))
dwFlags = DM_XBEONDISKONLY;
}
else
{
strcpy_s(szResponse, cchResponse, "missing name");
return E_FAIL;
}
pdxbe = (PDM_XBE)DmAllocatePoolWithTag(sizeof(DM_XBE), 'Xbdm');
pdmcc->CustomData = pdxbe;
if(!pdxbe)
return E_OUTOFMEMORY;
hr = DmGetXbeInfoEx(szName, pdxbe, dwFlags);
if(NT_SUCCESS(hr))
{
pdmcc->HandlingFunction = HrReportXbeInfo;
pdmcc->BytesRemaining = 1;
hr = XBDM_MULTIRESPONSE;
}
else
DmFreePool(pdxbe);
return hr;
}
DMHRAPI HrReportDriveList(PDM_CMDCONT pdmcc, LPSTR szResponse, DWORD cchResponse)
{
CHAR sz[MAX_PATH];
NTSTATUS st;
ANSI_STRING as;
OBJECT_ATTRIBUTES oa;
BOOL bExists = FALSE;
OBJECT_DIRECTORY_INFORMATION odi;
HANDLE h;
int i;
start:
if(pdmcd->cch == 0)
{
// List from our interal list
i = Drives[pdmcd->DriveList.CurrentDrive].Visibility;
// Check verbosity
if(i != 0 && !(i == 1 && !g_dmGlobals.bDriveMap))
{
// Get name
strcpy(sz, Drives[pdmcd->DriveList.CurrentDrive].DriveName);
i = strlen(sz);
strcat(sz, ":\\");
st = FCreateFile(&h, SYNCHRONIZE, sz, NULL, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_OPEN, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
if(NT_SUCCESS(st))
{
sz[i] = 0;
bExists = TRUE;
NtClose(h);
}
}
pdmcd->DriveList.CurrentDrive++;
if(pdmcd->DriveList.CurrentDrive >= cchDrives)
{
// Move on to the actual object enumeration
pdmcd->cch = 1;
RtlInitAnsiString(&as, "\\??");
oa.Attributes = OBJ_CASE_INSENSITIVE;
oa.ObjectName = &as;
oa.RootDirectory = NULL;
pdmcd->DriveList.CurrentDrive = 0;
st = NtOpenDirectoryObject(&pdmcd->h, &oa);
if(FAILED(st))
{
pdmcd->h = INVALID_HANDLE_VALUE;
pdmcd->cch = 2;
}
}
}
else if(pdmcd->cch == 1)
{
// List the objects
st = NtQueryDirectoryObject(pdmcd->h, &odi, sizeof(odi), (pdmcd->DriveList.CurrentDrive == 0), (PULONG)&pdmcd->DriveList.CurrentDrive, NULL);
if(NT_SUCCESS(st))
{
// Attempt to open the device that we found
memcpy(sz, odi.Name.Buffer, odi.Name.Length);
// But first, check the drive list
sz[odi.Name.Length - 1] = 0;
for(i = 0;i < cchDrives;i++)
{
if(!strcmpi(Drives[i].DriveName, sz))
{
bExists = TRUE;
break;
}
}
if(bExists)
bExists = FALSE;
else
{
strcat(sz, ":\\");
st = FCreateFile(&h, SYNCHRONIZE, sz, NULL, 0,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_OPEN, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
if(NT_SUCCESS(st))
{
NtClose(h);
sz[odi.Name.Length - 1] = 0;
bExists = TRUE;
}
}
}
else
{
NtClose(pdmcd->h);
pdmcd->cch = 2;
}
}
else
return XBDM_ENDOFLIST;
if(bExists)
RtlSnprintf((char*)pdmcc->Buffer, pdmcc->BufferSize, "drivename=\"%s\"", sz);
else
goto start;
return XBDM_NOERR;
}
DMHRAPI HrGetDriveList(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
if(!pdmcc)
return E_FAIL;
pdmcd->cch = 0;
pdmcd->DriveList.CurrentDrive = 0;
pdmcd->h = INVALID_HANDLE_VALUE;
pdmcc->BytesRemaining = 1;
pdmcc->HandlingFunction = HrReportDriveList;
return XBDM_MULTIRESPONSE;
}
DMHRAPI HrReportDriveFreeSpace(PDM_CMDCONT pdmcc, LPSTR szResponse, DWORD cchResponse)
{
FILE_FS_SIZE_INFORMATION fsi;
IO_STATUS_BLOCK iosb;
DWORD dwBPU;
ULARGE_INTEGER ulFree, ulTotal;
NTSTATUS st;
if(pdmcd->cch)
return XBDM_ENDOFLIST;
pdmcd->cch = 1;
st = NtQueryVolumeInformationFile(pdmcd->h, &iosb, &fsi, sizeof(fsi), FileFsSizeInformation);
if(FAILED(st))
{
RtlSnprintf((char*)pdmcc->Buffer, pdmcc->BufferSize, "unknown error (%d)", st);
return E_FAIL;
}
dwBPU = fsi.SectorsPerAllocationUnit * fsi.BytesPerSector;
ulFree.QuadPart = fsi.AvailableAllocationUnits.QuadPart * dwBPU;
ulTotal.QuadPart = fsi.TotalAllocationUnits.QuadPart * dwBPU;
RtlSnprintf((char*)pdmcc->Buffer, pdmcc->BufferSize, "freetocallerlo=0x%08x freetocallerhi=0x%08x totalbyteslo=0x%08x totalbyteshi=0x%08x totalfreebyteslo=0x%08x totalfreebyteshi=0x%08x",
ulFree.LowPart, ulFree.HighPart, ulTotal.LowPart, ulTotal.HighPart, ulFree.LowPart, ulFree.HighPart);
return XBDM_NOERR;
}
DMHRAPI HrGetDriveFreeSpace(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
NTSTATUS st;
char sz[MAX_PATH];
if(!pdmcc)
return E_FAIL;
if(!FGetSzParam(szCommand, "name", sz, sizeof(sz)))
{
strcpy(szResponse, "missing name");
return E_FAIL;
}
st = FCreateFile(&pdmcd->h, FILE_READ_ATTRIBUTES, sz, NULL, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN,
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
if(FAILED(st))
return XBDM_CANNOTACCESS;
pdmcd->cch = 0;
pdmcc->HandlingFunction = HrReportDriveFreeSpace;
return XBDM_MULTIRESPONSE;
}
DMHRAPI HrReportDirList(PDM_CMDCONT pdmcc, LPSTR szResponse, DWORD cchResponse)
{
NTSTATUS st;
IO_STATUS_BLOCK iosb;
FILE_DIRECTORY_INFORMATION fna;
HRESULT hr = XBDM_NOERR;
ZeroMemory(&fna, sizeof(fna));
st = NtQueryDirectoryFile(pdmcd->h, NULL, NULL, NULL, &iosb,
&fna, sizeof(fna), NULL, NULL);
if(NT_SUCCESS(st))
{
RtlSnprintf((char*)pdmcc->Buffer, pdmcc->BufferSize, "name=\"%s\" ", fna.FileName);
GetFileAttrSz((char*)pdmcc->Buffer + strlen((char*)pdmcc->Buffer), fna.FileAttributes,
&fna.LastWriteTime, &fna.CreationTime, &fna.EndOfFile);
}
else
{
NtClose(pdmcd->h);
hr = XBDM_ENDOFLIST;
}
return hr;
}
DMHRAPI HrGetDirList(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
NTSTATUS st;
CHAR sz[MAX_PATH];
if(!pdmcc)
return E_FAIL;
if(!FGetSzParam(szCommand, "name", sz, sizeof(sz)))
{
strcpy(szResponse, "missing name");
return E_FAIL;
}
pdmcc->BytesRemaining = 1;
pdmcc->HandlingFunction = HrReportDirList;
st = FCreateFile(&pdmcd->h, FILE_LIST_DIRECTORY | SYNCHRONIZE, sz, NULL, 0,
FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN,
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
return NT_SUCCESS(st) ? XBDM_MULTIRESPONSE : XBDM_CANNOTACCESS;
}
DMHRAPI HrDvdEject(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
DWORD dwEject = 1;
if(!pdmcc)
return E_FAIL;
FGetDwParam(szCommand, "eject", &dwEject);
HalOpenCloseODDTray(dwEject);
return XBDM_NOERR;
}
DMHRAPI HrDelete(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
FILE_DISPOSITION_INFORMATION fdi;
IO_STATUS_BLOCK iosb;
char sz[MAX_PATH];
NTSTATUS st;
HANDLE h;
BOOL b;
if(!pdmcc)
return E_FAIL;
if(!FGetSzParam(szCommand, "name", sz, sizeof(sz)))
{
strcpy_s(szResponse, cchResponse, "missing name");
return E_FAIL;
}
b = (BOOL)PchGetParam(szCommand, "dir", FALSE);
st = FCreateFile(&h, DELETE | SYNCHRONIZE, sz, NULL, 0, 0,
FILE_OPEN, (b ? FILE_DIRECTORY_FILE : FILE_NON_DIRECTORY_FILE)
| FILE_SYNCHRONOUS_IO_NONALERT);
if(FAILED(st))
return XBDM_CANNOTACCESS;
ZeroMemory(&fdi, sizeof(fdi));
fdi.DeleteFile = TRUE;
st = NtSetInformationFile(h, &iosb, &fdi, sizeof(fdi), FileDispositionInformation);
NtClose(h);
if(FAILED(st))
return XBDM_CANNOTACCESS;
return XBDM_NOERR;
}
DMHRAPI HrCreateDirectory(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
char sz[MAX_PATH];
NTSTATUS st;
HANDLE h;
if(!pdmcc)
return E_FAIL;
if(!FGetSzParam(szCommand, "name", sz, sizeof(sz)))
{
strcpy_s(szResponse, cchResponse, "missing name");
return E_FAIL;
}
st = FCreateFile(&h, FILE_LIST_DIRECTORY | SYNCHRONIZE, sz,
NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_CREATE, FILE_DIRECTORY_FILE |
FILE_SYNCHRONOUS_IO_NONALERT);
if(FAILED(st))
{
if(st == STATUS_OBJECT_NAME_COLLISION)
return XBDM_ALREADYEXISTS;
return XBDM_CANNOTCREATE;
}
NtClose(h);
return XBDM_NOERR;
}
DMHRAPI HrRenameFile(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
char sz[MAX_PATH];
char szNew[MAX_PATH];
IO_STATUS_BLOCK iosb;
NTSTATUS st;
HANDLE h;
FILE_RENAME_INFORMATION fri;
if(!pdmcc)
return E_FAIL;
if(!FGetSzParam(szCommand, "newname", sz, sizeof(sz)))
{
strcpy_s(szResponse, cchResponse, "missing newname");
return E_FAIL;
}
if(FAILED(FFileNameToObName(sz, szNew, sizeof(szNew))))
{
strcpy_s(szResponse, cchResponse, "new name does not exist");
return XBDM_NOSUCHFILE;
}
if(!FGetSzParam(szCommand, "name", sz, sizeof(sz)))
{
strcpy_s(szResponse, cchResponse, "missing name");
return E_FAIL;
}
st = FCreateFile(&h, GENERIC_WRITE | SYNCHRONIZE, sz, NULL, 0, 0,
FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT);
if(FAILED(st))
return XBDM_CANNOTACCESS;
ZeroMemory(&fri, sizeof(fri));
RtlInitAnsiString(&fri.FileName, szNew);
fri.ReplaceIfExists = FALSE;
fri.RootDirectory = NULL;
st = NtSetInformationFile(h, &iosb, &fri, sizeof(fri), FileRenameInformation);
NtClose(h);
if(st == STATUS_NOT_SAME_DEVICE)
return XBDM_MUSTCOPY;
if(FAILED(st))
return XBDM_CANNOTCREATE;
return XBDM_NOERR;
}
DMHRAPI HrReportFileAttributes(PDM_CMDCONT pdmcc, LPSTR szResponse, DWORD cchResponse)
{
if(pdmcd->cch)
return XBDM_ENDOFLIST;
pdmcd->cch = 1;
GetFileAttrSz((LPSTR)pdmcc->Buffer, pdmcd->fni.fni.FileAttributes,
&pdmcd->fni.fni.LastWriteTime, &pdmcd->fni.fni.CreationTime,
&pdmcd->fni.fni.EndOfFile);
return XBDM_NOERR;
}
DMHRAPI HrGetFileAttr(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
char sz[MAX_PATH];
char osz[MAX_PATH];
ANSI_STRING as;
NTSTATUS st;
OBJECT_ATTRIBUTES oa;
if(!pdmcc)
return E_FAIL;
if(!FGetSzParam(szCommand, "name", sz, sizeof(sz)))
{
strcpy_s(szResponse, cchResponse, "missing name");
return E_FAIL;
}
if(FAILED(FFileNameToObName(sz, osz, sizeof(osz))))
return XBDM_NOSUCHFILE;
RtlInitAnsiString(&as, osz);
oa.Attributes = OBJ_CASE_INSENSITIVE;
oa.RootDirectory = NULL;
oa.ObjectName = &as;
pdmcc->HandlingFunction = HrReportFileAttributes;
pdmcc->BytesRemaining = 1;
pdmcd->cch = 0;
st = NtQueryFullAttributesFile(&oa, &pdmcd->fni.fni);
return NT_SUCCESS(st) ? XBDM_MULTIRESPONSE : XBDM_NOSUCHFILE;
}
DMHRAPI HrSetFileAttr(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
NTSTATUS st;
HANDLE h;
IO_STATUS_BLOCK iosb;
char sz[MAX_PATH];
FILE_NETWORK_OPEN_INFORMATION fna;
FILE_BASIC_INFORMATION fba;
DWORD dwAttrMask = 0;
DWORD dwAttrNew = 0;
DWORD dwT = 0;
if(!pdmcc)
return E_FAIL;
if(!FGetSzParam(szCommand, "name", sz, sizeof(sz)))
{
strcpy_s(szResponse, cchResponse, "missing name");
return E_FAIL;
}
st = FCreateFile(&h, SYNCHRONIZE, sz, NULL, 0,
FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN,
FILE_SYNCHRONOUS_IO_NONALERT);
if(FAILED(st))
return XBDM_CANNOTACCESS;
st = NtQueryInformationFile(h, &iosb, &fna, sizeof(fna), FileNetworkOpenInformation);
if(FAILED(st))
{
NtClose(h);
return XBDM_CANNOTACCESS;
}
ZeroMemory(&fba, sizeof(fba));
if(FGetDwParam(szCommand, "readonly", &dwT))
{
dwAttrMask |= FILE_ATTRIBUTE_READONLY;
if(dwT)
dwAttrNew |= FILE_ATTRIBUTE_READONLY;
}
if(FGetDwParam(szCommand, "hidden", &dwT))
{
dwAttrMask |= FILE_ATTRIBUTE_HIDDEN;
if(dwT)
dwAttrNew |= FILE_ATTRIBUTE_HIDDEN;
}
FGetDwParam(szCommand, "createhi", (DWORD*)&fba.CreationTime.HighPart);
FGetDwParam(szCommand, "createlo", (DWORD*)&fba.ChangeTime.LowPart);
FGetDwParam(szCommand, "changehi", (DWORD*)&fba.LastWriteTime.HighPart);
FGetDwParam(szCommand, "changelo", (DWORD*)&fba.LastWriteTime.LowPart);
fba.FileAttributes = fna.FileAttributes ^ ((fna.FileAttributes ^ dwAttrNew) & dwAttrMask);
if(!fba.FileAttributes)
fba.FileAttributes = FILE_ATTRIBUTE_NORMAL;
st = NtSetInformationFile(h, &iosb, &fba, sizeof(fba), FileBasicInformation);
NtClose(h);
return NT_SUCCESS(st) ? XBDM_NOERR : XBDM_CANNOTACCESS;
}
DMHRAPI HrReportMemoryEx(PDM_CMDCONT pdmcc, LPSTR szResponse, DWORD cchResponse)
{
DWORD chars, addr, read = 0;
BYTE mem;
if(!pdmcd->cch)
{
pdmcc->BytesRemaining = 0;
DmFreePool(pdmcc->Buffer);
return XBDM_ENDOFLIST;
}
chars = pdmcd->cch;
if(chars > 0x400)
{
chars = 0x400;
((PBYTE)pdmcc->Buffer)[1] = 0x00;
}
else
((PBYTE)pdmcc->Buffer)[1] = 0x80;
((PBYTE)pdmcc->Buffer)[0] = 0;
for(addr = pdmcd->mem.Address;addr < pdmcd->mem.Address + chars;addr++)
{
if(FGetMemory(addr, &mem))
{
((PBYTE)pdmcc->Buffer)[addr - pdmcd->mem.Address + 2] = mem;
read++;
}
else
{
pdmcd->cch = 0;
((PBYTE)pdmcc->Buffer)[1] = 0x80;
break;
}
}
*(PWORD)pdmcc->Buffer |= _byteswap_ushort((WORD)read);
if(pdmcd->cch)
pdmcd->cch -= read;
pdmcd->mem.Address += read;
pdmcc->BytesRemaining = 1;
pdmcc->DataSize = read + 2;
return XBDM_NOERR;
}
DMHRAPI HrGetMemoryEx(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
DWORD dwAddr, dwLength;
if(!pdmcc)
return E_FAIL;
if(!FGetNamedDwParam(szCommand, "addr", &dwAddr, szResponse)
|| !FGetNamedDwParam(szCommand, "length", &dwLength, szResponse))
return E_FAIL;
pdmcc->BufferSize = 0x402;
if(!(pdmcc->Buffer = DmAllocatePoolWithTag(pdmcc->BufferSize, 'xbdm')))
return E_OUTOFMEMORY;
pdmcc->BytesRemaining = 1;
pdmcc->HandlingFunction = HrReportMemoryEx;
pdmcd->cch = dwLength;
pdmcd->mem.Address = dwAddr;
return XBDM_BINRESPONSE;
}
DMHRAPI HrReportMemory(PDM_CMDCONT pdmcc, LPSTR szResponse, DWORD cchResponse)
{
DWORD chars;
DWORD addr;
BYTE b;
if(!pdmcd->cch)
return XBDM_ENDOFLIST;
chars = pdmcd->cch;
if(chars > 64)
chars = 64;
for(addr = pdmcd->mem.Address;addr < pdmcd->mem.Address + chars;addr++)
{
if(FGetMemory(addr, &b))
{
((PBYTE)pdmcc->Buffer)[(addr - pdmcd->mem.Address) * 2] = rgchHex[(b >> 4) & 0xf];
((PBYTE)pdmcc->Buffer)[(addr - pdmcd->mem.Address) * 2 + 1] = rgchHex[b & 0xf];
}
else
((PBYTE)pdmcc->Buffer)[(addr - pdmcd->mem.Address) * 2] = ((PBYTE)pdmcc->Buffer)[(addr - pdmcd->mem.Address) * 2 + 1] = '?';
}
((PBYTE)pdmcc->Buffer)[(addr - pdmcd->mem.Address) * 2] = 0;
pdmcd->cch -= chars;
pdmcd->mem.Address += chars;
return XBDM_NOERR;
}
DMHRAPI HrGetMemory(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
DWORD dwAddr, dwLength;
if(!pdmcc)
return E_FAIL;
if(!FGetNamedDwParam(szCommand, "addr", &dwAddr, szResponse)
|| !FGetNamedDwParam(szCommand, "length", &dwLength, szResponse))
return E_FAIL;
strcpy_s(szResponse, cchResponse, "memory data follows");
pdmcc->BytesRemaining = 1;
pdmcc->HandlingFunction = HrReportMemory;
pdmcd->cch = dwLength;
pdmcd->mem.Address = dwAddr;
return XBDM_MULTIRESPONSE;
}
DMHRAPI HrSetMemory(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
int i;
DWORD addr;
LPCSTR data;
char rgch[5];
DWORD page;
BOOL pageValid;
BYTE b;
int count = 0;
if(!pdmcc)
return E_FAIL;
if(!FGetNamedDwParam(szCommand, "addr", &addr, szResponse))
return E_FAIL;
data = PchGetParam(szCommand, "data", FALSE);
page = addr + 0x1000;
rgch[0] = '0';
rgch[1] = 'x';
rgch[4] = 0;
if(data)
{
for(;;count++, addr++)
{
if(FIsSpace(*data))
break;
for(i = 0;i < 2;i++)
{
if(!(*data >= '0' && *data <= '9' ||
*data >= 'a' && *data <= 'f' ||
*data >= 'A' && *data <= 'F'))
{
strcpy(szResponse, "syntax error in data");
return E_FAIL;
}
rgch[i + 2] = *data++;
}
b = (BYTE)DwFromSz(rgch, NULL);
if((addr ^ page) & 0xFFFFF000)
{
page = addr & 0xFFFFF000;
pageValid = MmIsAddressValid((LPVOID)addr);
}
if(pageValid)
DmSetMemory((PVOID)addr, 1, &b, NULL);
else
{
RtlSnprintf(szResponse, cchResponse, "set %d bytes", count);
return XBDM_MEMUNMAPPED;
}
}
}
RtlSnprintf(szResponse, cchResponse, "set %d bytes", count);
return XBDM_NOERR;
}
DMHRAPI HrReportModules(PDM_CMDCONT pdmcc, LPSTR szResponse, DWORD cchResponse)
{
DMN_MODLOAD_EX dmnex;
if(pdmcc->BytesRemaining == 2)
return XBDM_ENDOFLIST;
if(FAILED(DmWalkLoadedModulesEx((PDM_WALK_MODULES*)&pdmcd->rgb, &dmnex)))
{
DmCloseLoadedModules((PDM_WALK_MODULES)pdmcd->rgb);
pdmcc->BytesRemaining++;
}
RtlSnprintf((LPSTR)pdmcc->Buffer, pdmcc->BufferSize,
"name=\"%s\" base=0x%08x size=0x%08x check=0x%08x timestamp=0x%08x pdata=0x%08x psize=0x%08x %sthread=0x%08x osize=0x%08x",
dmnex.Name, dmnex.BaseAddress, dmnex.Size, dmnex.CheckSum, dmnex.TimeStamp, dmnex.PDataAddress, dmnex.PDataSize,
dmnex.Flags & DMN_MODFLAG_TLS ? "" : "dll", dmnex.ThreadId, dmnex.OriginalSize);
return XBDM_NOERR;
}
DMHRAPI HrGetModules(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
if(!pdmcc)
return E_FAIL;
pdmcd->rgb = NULL;
pdmcc->HandlingFunction = HrReportModules;
pdmcc->BytesRemaining = 1;
return XBDM_MULTIRESPONSE;
}
DMHRAPI HrStop(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
if(!pdmcc)
return E_FAIL;
return DwChangeExecState(DMN_EXEC_STOP, TRUE, TRUE, FALSE);
}
DMHRAPI HrGo(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
if(!pdmcc)
return E_FAIL;
return DwChangeExecState(DMN_EXEC_START, TRUE, TRUE, FALSE);
}
DMHRAPI HrReportScreenshot(PDM_CMDCONT pdmcc, LPSTR szResponse, DWORD cchResponse)
{
if(pdmcd->cch == 0)
{
RtlSnprintf((LPSTR)pdmcc->Buffer, pdmcc->BufferSize,
"pitch=0x%08x width=0x%08x height=0x%08x format=0x%08x offsetx=0x%08x offsety=0x%08x, framebuffersize=0x%08x sw=0x%08x sh=0x%08x colorspace=0x%x\r\n",
pdmcd->screen.p, pdmcd->screen.w, pdmcd->screen.h, pdmcd->screen.fmt, 0, 0, pdmcd->screen.size, pdmcd->screen.sw, pdmcd->screen.sh, 0);
pdmcd->cch = 1;
pdmcc->DataSize = strlen((char*)pdmcc->Buffer);
}
else if(pdmcd->cch == 1)
{
pdmcc->Buffer = (PVOID)pdmcd->screen.szFrame;
pdmcc->DataSize = pdmcc->BytesRemaining;
pdmcd->cch = 2;
}
else
{
if(NT_SUCCESS(pdmcd->hr))
DwChangeExecState(DMN_EXEC_START, TRUE, FALSE, FALSE);
return XBDM_ENDOFLIST;
}
return XBDM_NOERR;
}
DMHRAPI HrScreenshot(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
DWORD dwStart, ptrOffset;
char *frameBuffer;
LPDWORD lpgpu = (LPDWORD)0x7FC81740;
DISPLAY_INFORMATION display;
DWORD w, h, p, size;
DWORD vw, vh, vp, vs;
if(!pdmcc)
return E_FAIL;
pdmcd->hr = DwChangeExecState(DMN_EXEC_STOP, TRUE, FALSE, FALSE);
dwStart = *KeTimeStampBundle;
while((*lpgpu & 0x80000000) && (*KeTimeStampBundle - dwStart < 5000))
Sleep(100);
if(*lpgpu & 0x80000000)
{
if(NT_SUCCESS(pdmcd->hr))
DwChangeExecState(DMN_EXEC_START, TRUE, FALSE, FALSE);
strcpy_s(szResponse, cchResponse, "can't lock GPU");
return E_FAIL;
}
ptrOffset = *((DWORD*)0x7FC86110);
frameBuffer = (char*)(0xC0000000 + ptrOffset);
if(!MmIsAddressValid(frameBuffer)) {
frameBuffer = (char*)(0xA0000000 + ptrOffset);
if(!MmIsAddressValid(frameBuffer)) {
frameBuffer = (char*)(0xDFFFF000 + ptrOffset);
}
}
VdGetCurrentDisplayInformation(&display);
w = display.FrontBufferWidth;
h = display.FrontBufferHeight;
p = w * 4;
size = h * p;
vw = w;vh = h;
if(vw % 128)
vw += (128 - vw % 128);
if(vh % 128)
vh += (128 - vh % 128);
vp = vw * 4;
vs = vh * vp;
pdmcc->HandlingFunction = HrReportScreenshot;
pdmcc->BytesRemaining = vs;
pdmcd->cch = 0;
pdmcd->screen.fmt = (((*((UINT*)0x7FC86104) >> 24) & 7) == 0) ? D3DFMT_A8R8G8B8 : D3DFMT_A2R10G10B10;
pdmcd->screen.w = w;
pdmcd->screen.h = h;
pdmcd->screen.sw = display.DisplayWidth;
pdmcd->screen.sh = display.DisplayHeight;
pdmcd->screen.p = p;
pdmcd->screen.size = vs;
pdmcd->screen.szFrame = frameBuffer;
return XBDM_BINRESPONSE;
}
DMHRAPI HrReportWalkMemory(PDM_CMDCONT pdmcc, LPSTR szResponse, DWORD cchResponse)
{
DWORD dwAddr, dwLength, dwProtect, dwPhys;
dwAddr = pdmcd->cch;
if(dwAddr == 0xFFFFFFFF)
return XBDM_ENDOFLIST;
while(!MmIsAddressValid((PVOID)dwAddr))
{
if(dwAddr == 0xFFFFF000)
return XBDM_ENDOFLIST;
dwAddr += 0x1000;
}
// dwAddr now contains a valid page start
dwProtect = XQueryMemoryProtect((LPVOID)dwAddr);
// Calc the length of the page
dwLength = 0x1000;
while(MmIsAddressValid((PVOID)(dwAddr + dwLength)) && (XQueryMemoryProtect((LPVOID)(dwAddr + dwLength)) == dwProtect))
{
if((dwAddr + dwLength) == 0)
break;
dwLength += 0x1000;
}
// Now dwLength contains the page length
if((dwAddr + dwLength) == 0)
pdmcd->cch = 0xFFFFFFFF;
else
pdmcd->cch = dwAddr + dwLength;
dwPhys = MmGetPhysicalAddress((PVOID)dwAddr);
RtlSnprintf((LPSTR)pdmcc->Buffer, pdmcc->BufferSize, "base=0x%0.8x size=0x%0.8x protect=0x%0.8x phys=0x%0.8x",
dwAddr, dwLength, dwProtect, dwPhys);
return XBDM_NOERR;
}
DMHRAPI HrWalkMemory(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
if(!pdmcc)
return E_FAIL;
pdmcd->cch = 0;
pdmcc->BytesRemaining = 1;
pdmcc->HandlingFunction = HrReportWalkMemory;
strcpy_s(szResponse, cchResponse, "Valid Virtual Address Ranges Follow");
return XBDM_MULTIRESPONSE;
}
DMHRAPI HrSetColor(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
char sz[0x10];
sz[0] = 0;
FGetSzParam(szCommand, "name", sz, sizeof(sz));
g_dmGlobals.dwConsoleColor = 0;
if(!stricmp(sz, "black"))
g_dmGlobals.dwConsoleColor = CONSOLE_COLOR_FLAG_BLACK;
else if(!stricmp(sz, "blue"))
g_dmGlobals.dwConsoleColor = CONSOLE_COLOR_FLAG_BLACK | CONSOLE_COLOR_FLAG_BLUE;
else if(!stricmp(sz, "bluegray"))
g_dmGlobals.dwConsoleColor = CONSOLE_COLOR_FLAG_WHITE | CONSOLE_COLOR_FLAG_BLUE;
else if(!stricmp(sz, "nosidecar"))
g_dmGlobals.dwConsoleColor = CONSOLE_COLOR_FLAG_NOSIDECAR;
else if(!stricmp(sz, "white"))
g_dmGlobals.dwConsoleColor = CONSOLE_COLOR_FLAG_WHITE;
g_dmGlobals.bDirty = TRUE;
return XBDM_NOERR;
}
DMHRAPI HrSendFileData(PDM_CMDCONT pdmcc, LPSTR szResponse, DWORD cchResponse)
{
NTSTATUS st;
DWORD cb;
if(pdmcc->BytesRemaining == 1)
{
// Send the length
*(LPDWORD)pdmcc->Buffer = _byteswap_ulong(pdmcd->cch);
pdmcc->DataSize = 4;
pdmcc->BytesRemaining = 2;
}
else if(pdmcc->BytesRemaining == 2)
{
// Send the file data
cb = pdmcc->BufferSize;
if(cb > pdmcd->cch)
cb = pdmcd->cch;
st = FReadFile(pdmcd->h, pdmcc->Buffer, cb);
if(FAILED(st))
ZeroMemory(pdmcc->Buffer, cb);
pdmcd->cch -= cb;
pdmcc->DataSize = cb;
if(pdmcd->cch == 0)
pdmcc->BytesRemaining = 3;
}
else
{
// Close and exit
NtClose(pdmcd->h);
DmFreePool(pdmcc->Buffer);
return XBDM_ENDOFLIST;
}
return XBDM_NOERR;
}
DMHRAPI HrGetFile(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
NTSTATUS st;
IO_STATUS_BLOCK iosb;
char sz[MAX_PATH];
FILE_NETWORK_OPEN_INFORMATION fni;
if(!pdmcc)
return E_FAIL;
if(!FGetSzParam(szCommand, "name", sz, sizeof(sz)))
{
strcpy_s(szResponse, cchResponse, "missing name");
return E_FAIL;
}
st = FCreateFile(&pdmcd->h, GENERIC_READ | SYNCHRONIZE, sz,
NULL, 0, 0, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT);
if(FAILED(st))
return XBDM_CANNOTACCESS;
st = NtQueryInformationFile(pdmcd->h, &iosb, &fni, sizeof(fni), FileNetworkOpenInformation);
if(FAILED(st))
{
NtClose(pdmcd->h);
return E_UNEXPECTED;
}
if(fni.EndOfFile.HighPart)
{
NtClose(pdmcd->h);
strcpy_s(szResponse, cchResponse, "file is too big");
return E_FAIL;
}
pdmcc->BufferSize = 0x3000;
pdmcc->Buffer = DmAllocatePoolWithTag(pdmcc->BufferSize, 'bdbd');
if(pdmcc->Buffer == NULL)
{
NtClose(pdmcd->h);
return E_OUTOFMEMORY;
}
pdmcd->cch = fni.EndOfFile.LowPart;
pdmcc->BytesRemaining = 1;
pdmcc->HandlingFunction = HrSendFileData;
return XBDM_BINRESPONSE;
}
DMHRAPI HrRecieveFileData(PDM_CMDCONT pdmcc, LPSTR szResponse, DWORD cchResponse)
{
FILE_DISPOSITION_INFORMATION fdi;
IO_STATUS_BLOCK iosb;
NTSTATUS st;
if(pdmcc->DataSize)
{
pdmcd->ib += pdmcc->DataSize;
pdmcc->BytesRemaining -= pdmcc->DataSize;
}
else if(pdmcc->BytesRemaining)
{
pdmcc->BytesRemaining = 0;
fdi.DeleteFile = TRUE;
NtSetInformationFile(pdmcd->h, &iosb, &fdi, sizeof(fdi), FileDispositionInformation);
pdmcd->fError = TRUE;
}
if(!pdmcc->BytesRemaining || pdmcd->ib == pdmcd->cchBuf)
{
if(pdmcd->h != INVALID_HANDLE_VALUE)
{
st = NtWriteFile(pdmcd->h, NULL, NULL, NULL, &iosb,
pdmcd->rgb, pdmcd->ib, NULL);
if(FAILED(st))
{
fdi.DeleteFile = TRUE;
NtSetInformationFile(pdmcd->h, &iosb, &fdi, sizeof(fdi), FileDispositionInformation);
NtClose(pdmcd->h);
pdmcd->fError = TRUE;
pdmcd->h = INVALID_HANDLE_VALUE;
}
else if(!pdmcc->BytesRemaining)
{
NtClose(pdmcd->h);
pdmcd->h = INVALID_HANDLE_VALUE;
}
}
pdmcc->Buffer = (char*)pdmcc->Buffer - pdmcd->ib;
pdmcd->ib = 0;
if(!pdmcc->BytesRemaining && pdmcc->Buffer)
DmFreePool(pdmcd->rgb);
}
if(pdmcd->rgb)
{
pdmcc->Buffer = pdmcd->rgb + pdmcd->ib;
pdmcc->BufferSize = pdmcd->cchBuf - pdmcd->ib;
}
if(pdmcd->fError)
{
DmFreePool(pdmcd->rgb);
NtClose(pdmcd->h);
pdmcd->h = INVALID_HANDLE_VALUE;
}
return pdmcd->fError ? E_UNEXPECTED : XBDM_NOERR;
}
DMHRAPI HrSendFile(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
NTSTATUS st;
char sz[MAX_PATH];
IO_STATUS_BLOCK iosb;
FILE_DISPOSITION_INFORMATION fdi;
LARGE_INTEGER liSize;
if(!pdmcc)
return E_FAIL;
if(!FGetSzParam(szCommand, "name", sz, sizeof(sz)))
{
strcpy_s(szResponse, cchResponse, "missing name");
return E_FAIL;
}
if(!FGetNamedDwParam(szCommand, "length", &pdmcd->cch, szResponse))
return E_FAIL;
liSize.HighPart = 0;
liSize.LowPart = pdmcd->cch;
st = FCreateFile(&pdmcd->h, GENERIC_WRITE | DELETE | SYNCHRONIZE,
sz, &liSize, 0, 0, FILE_OVERWRITE_IF,
FILE_SYNCHRONOUS_IO_NONALERT);
if(FAILED(st))
return XBDM_CANNOTCREATE;
st = NtSetInformationFile(pdmcd->h, &iosb, &liSize, sizeof(liSize), FileEndOfFileInformation);
if(FAILED(st))
{
fdi.DeleteFile = TRUE;
NtSetInformationFile(pdmcd->h, &iosb, &fdi, sizeof(fdi), FileDispositionInformation);
NtClose(pdmcd->h);
return XBDM_DEVICEFULL;
}
pdmcc->BufferSize = 0x4000;
pdmcc->Buffer = DmAllocatePoolWithTag(pdmcc->BufferSize, 'bdbd');
if(pdmcc->Buffer == NULL)
{
fdi.DeleteFile = TRUE;
NtSetInformationFile(pdmcd->h, &iosb, &fdi, sizeof(fdi), FileDispositionInformation);
NtClose(pdmcd->h);
return E_OUTOFMEMORY;
}
pdmcd->cchBuf = pdmcc->BufferSize;
pdmcd->cch = 0;
pdmcc->HandlingFunction = HrRecieveFileData;
pdmcd->ib = 0;
pdmcd->rgb = (LPSTR)pdmcc->Buffer;
pdmcd->fError = FALSE;
pdmcc->BytesRemaining = liSize.LowPart;
return XBDM_READYFORBIN;
}
DMHRAPI HrRecieveVolumeFileData(PDM_CMDCONT pdmcc, LPSTR szResponse, DWORD cchResponse)
{
// We act under the assumption that if the buffer is big enough, we get exactly however
// many bytes we asked for in BytesRemaining, otherwise we just get a full buffer
FILE_DISPOSITION_INFORMATION fdi;
IO_STATUS_BLOCK iosb;
#define st ((DWORD*)(pdmcd->rgb + 0x4000))[pdmcd->vfile.remain]
if(pdmcd->vfile.step != 3 && !pdmcc->DataSize)
{
// We lost the connection...
if(pdmcd->h != INVALID_HANDLE_VALUE)
{
fdi.DeleteFile = TRUE;
NtSetInformationFile(pdmcd->h, &iosb, &fdi, sizeof(fdi), FileDispositionInformation);
NtClose(pdmcd->h);
pdmcd->h = INVALID_HANDLE_VALUE;
}
DmFreePool(pdmcd->rgb);
pdmcc->BytesRemaining = 0;
return XBDM_ENDOFLIST;
}
else if(pdmcd->vfile.step == 0)
{
// Recieved file info block
#pragma pack(1)
typedef struct
{
DWORD dwSize;
ULONGLONG CreateTime;
ULONGLONG ChangeTime;
ULONGLONG FileSize;
DWORD FileAttributes;
} *__info;
__info fInfo = (__info)pdmcc->Buffer;
pdmcd->vfile.ChangeTime.QuadPart = fInfo->ChangeTime;
pdmcd->vfile.CreationTime.QuadPart = fInfo->CreateTime;
pdmcd->vfile.FileAttributes = fInfo->FileAttributes;
pdmcd->vfile.FileSize = (DWORD)fInfo->FileSize;
if(fInfo->FileSize > 0xFFFFFFFF)
st = E_FAIL; // File too big
else
st = STATUS_SUCCESS;
pdmcc->BytesRemaining = fInfo->dwSize - 0x20;
pdmcd->ib = 0;
pdmcd->vfile.step++;
}
else if(pdmcd->vfile.step == 1)
{
// Recieved file name
LARGE_INTEGER li;
if(NT_SUCCESS(st))
{
li.HighPart = 0;
li.LowPart = pdmcd->vfile.FileSize;
st = FCreateFile(&pdmcd->h, GENERIC_WRITE | DELETE | SYNCHRONIZE,
(char*)pdmcc->Buffer, &li, 0, 0, FILE_OVERWRITE_IF,
FILE_SYNCHRONOUS_IO_NONALERT);
}
pdmcc->BytesRemaining = pdmcd->vfile.FileSize;
pdmcd->vfile.step++;
}
else if(pdmcd->vfile.step == 2)
{
// Recieved file data
pdmcd->ib += pdmcc->DataSize;
pdmcc->BytesRemaining -= pdmcc->DataSize;
if((pdmcc->BytesRemaining == 0) || (pdmcd->ib == 0x4000))
{
// Write to file
if((pdmcd->h != INVALID_HANDLE_VALUE) && NT_SUCCESS(st))
{
st = NtWriteFile(pdmcd->h, NULL, NULL, NULL, &iosb, pdmcd->rgb, pdmcd->ib, NULL);
if(FAILED(st))
{
fdi.DeleteFile = TRUE;
NtSetInformationFile(pdmcd->h, &iosb, &fdi, sizeof(fdi), FileDispositionInformation);
NtClose(pdmcd->h);
pdmcd->h = INVALID_HANDLE_VALUE;
}
// Reset back to the start
pdmcd->ib = 0;
}
}
if(pdmcc->BytesRemaining == 0)
{
pdmcd->vfile.remain++;
if(pdmcd->h != INVALID_HANDLE_VALUE)
{
NtClose(pdmcd->h);
pdmcd->h = INVALID_HANDLE_VALUE;
}
if(pdmcd->vfile.remain == pdmcd->cch)
{
pdmcd->vfile.step++;
return XBDM_BINRESPONSE;
}
else
{
pdmcd->vfile.step = 0;
pdmcc->BytesRemaining = 0x20;
pdmcd->ib = 0;
}
}
}
else if(pdmcd->vfile.step == 3)
{
// Send back status codes
pdmcc->Buffer = pdmcd->rgb + 0x4000;
pdmcc->BytesRemaining = 1;
pdmcc->DataSize = pdmcd->cchBuf - 0x4000;
pdmcd->vfile.step++;
}
else if(pdmcd->vfile.step == 4)
{
DmFreePool(pdmcd->rgb);
return XBDM_ENDOFLIST; // Signal completion
}
// Fix up the values
if(pdmcd->vfile.step != 4)
{
pdmcc->Buffer = pdmcd->rgb + pdmcd->ib;
pdmcc->BufferSize = 0x4000 - pdmcd->ib;
}
#undef st
return XBDM_NOERR;
}
DMHRAPI HrSendVolumeFile(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
if(!pdmcc)
return E_FAIL;
if(!FGetNamedDwParam(szCommand, "count", &pdmcd->cch, szResponse))
return E_FAIL;
pdmcc->BufferSize = 0x4000 + pdmcd->cch * 4;
pdmcc->Buffer = DmAllocatePoolWithTag(pdmcc->BufferSize, 'bdbd');
if(!pdmcc->Buffer)
return E_OUTOFMEMORY;
ZeroMemory(pdmcc->Buffer, pdmcc->BufferSize);
pdmcd->rgb = (char*)pdmcc->Buffer;
pdmcc->HandlingFunction = HrRecieveVolumeFileData;
pdmcc->BytesRemaining = 0x20;
pdmcd->cchBuf = pdmcc->BufferSize;
pdmcd->vfile.remain = 0;
pdmcd->vfile.step = 0;
pdmcd->h = INVALID_HANDLE_VALUE;
return XBDM_READYFORBIN;
}
DMHRAPI HrHwInfo(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
if(!pdmcc)
return E_FAIL;
RtlSnprintf(szResponse, cchResponse,
"Hardware Info Follows\r\n"
"Flags : 0x%08x\r\n"
"NumberOfProcessors : 0x%02x\r\n"
"PCIBridgeRevisionID: 0x%02x\r\n"
"Reserved Bytes : 0x %02x %02x %02x %02x %02x %02x\r\n"
"BldrMagic : 0x%04x\r\n"
"BldrFlags : 0x%04x\r\n"
".",
XboxHardwareInfo->Flags, XboxHardwareInfo->NumberOfProcessors,
XboxHardwareInfo->PCIBridgeRevisionID,
XboxHardwareInfo->Reserved[0], XboxHardwareInfo->Reserved[1],
XboxHardwareInfo->Reserved[2], XboxHardwareInfo->Reserved[3],
XboxHardwareInfo->Reserved[4], XboxHardwareInfo->Reserved[5],
XboxHardwareInfo->BldrMagic, XboxHardwareInfo->BldrFlags);
return XBDM_NOERR;
}
DMHRAPI HrObjList(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
PDMCONN pdmc;
if(!pdmcc)
return E_FAIL;
pdmc = CONTAINING_RECORD(pdmcc, DMCONN, dmcc);
DumpAllObjects("\\", pdmc->s);
return XBDM_NOERR;
}
DMHRAPI HrSetDumpMode(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
int i;
for(i = 0;i <= DM_DUMPMODE_DISABLED;i++)
{
if(PchGetParam(szCommand, rgszDumpMode[i], FALSE))
break;
}
if(i > DM_DUMPMODE_DISABLED)
return XBDM_NOERR;
DmSetDumpMode(i);
strcpy_s(szResponse, cchResponse, rgszDumpMode[i]);
return XBDM_NOERR;
}
DMHRAPI HrNotify(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
DWORD dwPort;
PDMCONN conn;
if(!FGetNamedDwParam(szCommand, "reconnectport", &dwPort, szResponse))
return E_FAIL;
conn = CONTAINING_RECORD(pdmcc, DMCONN, dmcc);
FConvertToNotifySock(conn, dwPort);
return XBDM_NOERR;
}
DMHRAPI HrNotifyAt(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
DWORD dw;
if(!FGetNamedDwParam(szCommand, "port", &dw, szResponse))
return E_FAIL;
if(!PchGetParam(szCommand, "drop", FALSE))
return E_FAIL;
return FDropNotifySock(dw);
}
DMHRAPI HrAttachDebugger(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
DWORD dwPort;
BOOL fOverride;
fOverride = (BOOL)PchGetParam(szCommand, "override", FALSE);
if(PchGetParam(szCommand, "connect", FALSE))
{
if(g_dmGlobals.bDebugging && !fOverride)
return XBDM_ALREADYEXISTS;
g_dmGlobals.dwDebugPort = 0;
ZeroMemory(g_dmGlobals.rgchDebuggerName, sizeof(g_dmGlobals.rgchDebuggerName));
ZeroMemory(g_dmGlobals.rgchDebuggerUser, sizeof(g_dmGlobals.rgchDebuggerUser));
FGetDwParam(szCommand, "port", &g_dmGlobals.dwDebugPort);
FGetSzParam(szCommand, "name", g_dmGlobals.rgchDebuggerName, sizeof(g_dmGlobals.rgchDebuggerName));
FGetSzParam(szCommand, "user", g_dmGlobals.rgchDebuggerUser, sizeof(g_dmGlobals.rgchDebuggerUser));
g_dmGlobals.bDebugging = TRUE;
}
else if(PchGetParam(szCommand, "disconnect", FALSE))
{
if((g_dmGlobals.dwDebugPort == 0)
|| (FGetDwParam(szCommand, "port", &dwPort) && dwPort == g_dmGlobals.dwDebugPort)
|| fOverride)
{
ZeroMemory(g_dmGlobals.rgchDebuggerName, sizeof(g_dmGlobals.rgchDebuggerName));
ZeroMemory(g_dmGlobals.rgchDebuggerUser, sizeof(g_dmGlobals.rgchDebuggerUser));
g_dmGlobals.bDebugging = FALSE;
}
else
return XBDM_CANNOTACCESS;
}
else
{
strcpy_s(szResponse, cchResponse, "no command");
return E_FAIL;
}
return XBDM_NOERR;
}
DMHRAPI HrIsDebuggerAttached(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
const char *sz1, *sz2, *sz3, *sz4, *sz5, *sz6;
if(!pdmcc)
return E_FAIL;
if(!g_dmGlobals.bDebugging)
return XBDM_NOERR;
if(g_dmGlobals.rgchDebuggerUser[0])
{
sz1 = "user=\"";
sz2 = g_dmGlobals.rgchDebuggerUser;
sz3 = "\"";
}
else
{
sz1 = "";
sz2 = "";
sz3 = "";
}
if(g_dmGlobals.rgchDebuggerName[0])
{
sz4 = "name=\"";
sz5 = g_dmGlobals.rgchDebuggerName;
sz6 = "\"";
}
else
{
sz4 = "";
sz5 = "";
sz6 = "";
}
RtlSnprintf(szResponse, cchResponse, "%s%s%s%s%s%s%s",
sz1, sz2, sz3,
(sz1[0] && sz4[0]) ? " " : "",
sz4, sz5, sz6);
return XBDM_ALREADYEXISTS;
}
DMHRAPI HrReportSystemInfo(PDM_CMDCONT pdmcc, LPSTR szResponse, DWORD cchResponse)
{
char *sz;
switch(pdmcc->BytesRemaining)
{
case 1:
strcpy_s((char*)pdmcc->Buffer, pdmcc->BufferSize, "HDD=");
if(XboxHardwareInfo->Flags & 0x20)
strcat_s((char*)pdmcc->Buffer, pdmcc->BufferSize, "Enabled");
else
strcat_s((char*)pdmcc->Buffer, pdmcc->BufferSize, "Disabled");
break;
case 2:
strcpy_s((char*)pdmcc->Buffer, pdmcc->BufferSize, "Type=");
if(XboxHardwareInfo->Flags & 0x02000000)
sz = "TestKit";
else
sz = "DevKit";
strcat_s((char*)pdmcc->Buffer, pdmcc->BufferSize, sz);
break;
case 3:
strcpy_s((char*)pdmcc->Buffer, pdmcc->BufferSize, "Platform=");
switch(XboxHardwareInfo->Flags & 3)
{
case 0:
sz = "Alpha";
break;
case 1:
sz = "Mongrel";
break;
case 2:
sz = "Shiva";
break;
case 3:
sz = "Waternoose";
break;
default:
sz = "Unknown";
break;
}
strcat_s((char*)pdmcc->Buffer, pdmcc->BufferSize, sz);
strcat_s((char*)pdmcc->Buffer, pdmcc->BufferSize, " System=");
switch((XboxHardwareInfo->Flags >> 28) & 0xF)
{
case 0:
sz = "Xenon";
break;
case 1:
sz = "Zephyr";
break;
case 2:
sz = "Falcon";
break;
case 3:
sz = "Jasper";
break;
case 4:
sz = "Trinity";
break;
case 5:
sz = "Corona";
break;
case 6:
sz = "Winchester";
break;
default:
sz = "Unknown";
break;
}
strcat_s((char*)pdmcc->Buffer, pdmcc->BufferSize, sz);
break;
case 4:
RtlSnprintf((char*)pdmcc->Buffer, pdmcc->BufferSize, "BaseKrnl=%d.%d.%d.%d Krnl=%d.%d.%d.%d XDK=2.0.20353.0",
XboxKrnlBaseVersion->Major, XboxKrnlBaseVersion->Minor, XboxKrnlBaseVersion->Build,
(XboxKrnlBaseVersion->ApprovalType << 8) + XboxKrnlBaseVersion->QFE,
XboxKrnlVersion->Major, XboxKrnlVersion->Minor, XboxKrnlVersion->Build,
(XboxKrnlVersion->ApprovalType << 8) + XboxKrnlVersion->QFE);
break;
case 5:
return XBDM_ENDOFLIST;
}
pdmcc->BytesRemaining++;
return XBDM_NOERR;
}
DMHRAPI HrGetSystemInfo(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
if(!pdmcc)
return E_FAIL;
pdmcc->HandlingFunction = HrReportSystemInfo;
pdmcc->BytesRemaining = 1;
return XBDM_MULTIRESPONSE;
}
VOID PcregNext(DMCR* Context)
{
for(;;)
{
if(Context->CurrentRegister == cchregs)
{
Context->CurrentRegister = 0;
Context->Register = NULL;
return;
}
Context->Register = &rgbregs[Context->CurrentRegister];
Context->CurrentRegister++;
if(Context->Context.ContextFlags & Context->Register->Context)
break;
}
}
DMHRAPI HrReportContext(PDM_CMDCONT pdmcc, LPSTR szResponse, DWORD cchResponse)
{
int i;
DMCR *context = ((DMCR*)pdmcc->CustomData);
if(!context->Register)
{
DmFreePool(pdmcc->CustomData);
return XBDM_ENDOFLIST;
}
pdmcc->DataSize = 0;
for(i = 0;i < 4;i++)
{
if(context->Register->Size == 4)
{
pdmcc->DataSize += RtlSprintf((char*)pdmcc->Buffer + pdmcc->DataSize, "%s=0x%08x\r\n",
context->Register->Name, *(LPDWORD)((char*)&context->Context + context->Register->Offset));
}
else if(context->Register->Size == 8)
{
pdmcc->DataSize += RtlSprintf((char*)pdmcc->Buffer + pdmcc->DataSize, "%s=0q%016I64x\r\n",
context->Register->Name, *(QWORD*)((char*)&context->Context + context->Register->Offset));
}
else if(context->Register->Size == 16)
{
pdmcc->DataSize += RtlSprintf((char*)pdmcc->Buffer + pdmcc->DataSize, "%s=0x%08x,0x%08x,0x%08x,0x%08x\r\n",
context->Register->Name,
(LPDWORD)((char*)&context->Context + context->Register->Offset)[0],
(LPDWORD)((char*)&context->Context + context->Register->Offset)[1],
(LPDWORD)((char*)&context->Context + context->Register->Offset)[2],
(LPDWORD)((char*)&context->Context + context->Register->Offset)[3]);
}
PcregNext(context);
if(!context->Register)
break;
}
return XBDM_NOERR;
}
DMHRAPI HrGetContext(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
XCONTEXT context;
DWORD dwThreadId;
HRESULT hr;
if(!pdmcc)
return E_FAIL;
if(!FGetNamedDwParam(szCommand, "thread", &dwThreadId, szResponse))
return E_FAIL;
context.ContextFlags = 0;
if(PchGetParam(szCommand, "control", FALSE))
context.ContextFlags |= CONTEXT_CONTROL;
if(PchGetParam(szCommand, "int", FALSE))
context.ContextFlags |= CONTEXT_INTEGER;
if(PchGetParam(szCommand, "fp", FALSE))
context.ContextFlags |= CONTEXT_FLOATING_POINT;
if(PchGetParam(szCommand, "vr", FALSE))
context.ContextFlags |= CONTEXT_VECTOR;
if(PchGetParam(szCommand, "full", FALSE))
context.ContextFlags |= CONTEXT_FULL;
hr = DmGetThreadContext(dwThreadId, &context);
if(FAILED(hr))
return hr;
pdmcc->CustomData = DmAllocatePoolWithTag(sizeof(DMCR), 'dmcr');
if(!pdmcc->CustomData)
return E_OUTOFMEMORY;
((DMCR*)pdmcc->CustomData)->CurrentRegister = 0;
((DMCR*)pdmcc->CustomData)->Register = NULL;
memcpy(pdmcc->CustomData, &context, sizeof(XCONTEXT));
PcregNext(((DMCR*)pdmcc->CustomData));
pdmcc->HandlingFunction = HrReportContext;
return XBDM_MULTIRESPONSE;
}
DMHRAPI HrSetContext(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
DMCR dmcr;
DWORD dwThreadId;
HRESULT hr;
BOOL bCopy;
char sz[0x10];
if(!pdmcc)
return E_FAIL;
if(!FGetNamedDwParam(szCommand, "thread", &dwThreadId, szResponse))
return E_FAIL;
ZeroMemory(&dmcr, sizeof(DMCR));
dmcr.Context.ContextFlags = CONTEXT_FULL;
dmcr.CurrentRegister = 0;
dmcr.Register = NULL;
hr = DmGetThreadContext(dwThreadId, &dmcr.Context);
if(FAILED(hr))
return hr;
for(;;)
{
PcregNext(&dmcr);
if(dmcr.Register == NULL)
break;
if(dmcr.Register->Size == 4)
bCopy = FGetDwParam(szCommand, dmcr.Register->Name, (DWORD*)sz);
else if(dmcr.Register->Size == 8)
bCopy = FGetQwordParam(szCommand, dmcr.Register->Name, (ULARGE_INTEGER*)sz);
else if(dmcr.Register->Size == 0x10)
bCopy = FGetVectorParam(szCommand, dmcr.Register->Name, (float*)sz);
else
bCopy = FALSE;
if(bCopy)
memcpy((char*)&dmcr.Context + dmcr.Register->Offset, sz, dmcr.Register->Size);
}
hr = DmSetThreadContext(dwThreadId, &dmcr.Context);
return hr;
}
DMHRAPI HrReportThreadList(PDM_CMDCONT pdmcc, LPSTR szResponse, DWORD cchResponse)
{
if(pdmcd->cch == pdmcd->ib)
{
DmFreePool(pdmcd->rgb);
return XBDM_ENDOFLIST;
}
pdmcc->DataSize = 0;
while((pdmcc->DataSize + 0x10 < pdmcc->BufferSize)
&& (pdmcd->cch != pdmcd->ib))
{
pdmcc->DataSize += RtlSprintf((char*)pdmcc->Buffer + pdmcc->DataSize, "%d\r\n", ((LPDWORD)pdmcd->rgb)[pdmcd->ib]);
pdmcd->ib++;
}
return XBDM_NOERR;
}
DMHRAPI HrListThreads(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
HRESULT hr;
if(!pdmcc)
return E_FAIL;
pdmcd->rgb = (char*)DmAllocatePoolWithTag(0x400, 'xbdm');
pdmcd->cch = 0x100;
if(!pdmcd->rgb)
return E_OUTOFMEMORY;
hr = DmGetThreadList((LPDWORD)pdmcd->rgb, &pdmcd->cch);
if(FAILED(hr))
{
if(hr == XBDM_BUFFER_TOO_SMALL)
hr = E_UNEXPECTED;
DmFreePool(pdmcd->rgb);
}
else
{
hr = XBDM_MULTIRESPONSE;
strcpy_s(szResponse, cchResponse, "thread list follows");
pdmcc->HandlingFunction = HrReportThreadList;
pdmcd->ib = 0;
}
return hr;
}
DMHRAPI HrReportThreadListEx(PDM_CMDCONT pdmcc, LPSTR szResponse, DWORD cchResponse)
{
if(pdmcd->cch == pdmcd->ib)
{
DmFreePool(pdmcd->rgb);
return XBDM_ENDOFLIST;
}
pdmcc->DataSize = 0;
while((pdmcc->DataSize + 0x10 < pdmcc->BufferSize)
&& (pdmcd->cch != pdmcd->ib))
{
pdmcc->DataSize += RtlSprintf((char*)pdmcc->Buffer + pdmcc->DataSize, "%08X\r\n", ((LPDWORD)pdmcd->rgb)[pdmcd->ib]);
pdmcd->ib++;
}
return XBDM_NOERR;
}
DMHRAPI HrListThreadsEx(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
HRESULT hr;
if(!pdmcc)
return E_FAIL;
pdmcd->rgb = (char*)DmAllocatePoolWithTag(0x400, 'xbdm');
pdmcd->cch = 0x100;
if(!pdmcd->rgb)
return E_OUTOFMEMORY;
hr = DmGetThreadList((LPDWORD)pdmcd->rgb, &pdmcd->cch);
if(FAILED(hr))
{
if(hr == XBDM_BUFFER_TOO_SMALL)
hr = E_UNEXPECTED;
DmFreePool(pdmcd->rgb);
}
else
{
hr = XBDM_MULTIRESPONSE;
strcpy_s(szResponse, cchResponse, "thread list follows");
pdmcc->HandlingFunction = HrReportThreadListEx;
pdmcd->ib = 0;
}
return hr;
}
DMHRAPI HrGetCpuKey(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
QWORD fuses[12];
HvGetFuses(fuses);
RtlSnprintf(szResponse, cchResponse, "%016I64X%016I64X", fuses[3], fuses[5]);
return XBDM_NOERR;
}
DMHRAPI HrContinueThread(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
DWORD dwThreadId;
if(!FGetNamedDwParam(szCommand, "thread", &dwThreadId, szResponse))
return E_FAIL;
return DmContinueThread(dwThreadId, (BOOL)PchGetParam(szCommand, "exception", FALSE));
}
DMHRAPI HrDoStopOn(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, BOOL fStop)
{
DWORD dw = 0;
if(PchGetParam(szCommand, "all", FALSE))
dw = -1;
else
{
if(PchGetParam(szCommand, "fce", FALSE))
dw |= DMSTOP_FCE;
if(PchGetParam(szCommand, "debugstr", FALSE))
dw |= DMSTOP_DEBUGSTR;
if(PchGetParam(szCommand, "createthread", FALSE))
dw |= DMSTOP_CREATETHREAD;
if(PchGetParam(szCommand, "stacktrace", FALSE))
dw |= DMSTOP_STACKTRACE;
if(PchGetParam(szCommand, "modload", FALSE))
dw |= DMSTOP_MODLOAD;
}
return DmStopOn(dw, fStop);
}
DMHRAPI HrStopOn(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
return HrDoStopOn(szCommand, szResponse, cchResponse, TRUE);
}
DMHRAPI HrNoStopOn(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
return HrDoStopOn(szCommand, szResponse, cchResponse, FALSE);
}
DMHRAPI HrIsThreadStopped(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
DM_THREADSTOP dmts;
DWORD dwThreadId;
HRESULT hr;
if(!pdmcc)
return E_FAIL;
if(!FGetNamedDwParam(szCommand, "thread", &dwThreadId, szResponse))
return E_FAIL;
hr = DmIsThreadStopped(dwThreadId, &dmts);
if(FAILED(hr))
return hr;
if(dmts.NotifiedReason == DM_ASSERT)
RtlSnprintf(szResponse, cchResponse, "assert thread=0x%08x straddr=0x%08x strlen=0x%08x",
dmts.u.DebugStr.ThreadId, dmts.u.DebugStr.String, dmts.u.DebugStr.Length);
else if(dmts.NotifiedReason == DM_DEBUGSTR)
RtlSnprintf(szResponse, cchResponse, "debugstr thread=0x%08x stop", dmts.u.DebugStr.ThreadId);
else if(!FGetNotifySz(dmts.NotifiedReason, (ULONG_PTR)&dmts.u, szResponse, cchResponse))
strcpy_s(szResponse, cchResponse, "stopped");
return XBDM_NOERR;
}
DMHRAPI HrSuspendThread(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
DWORD dwThreadId;
if(!pdmcc)
return E_FAIL;
if(!FGetNamedDwParam(szCommand, "thread", &dwThreadId, szResponse))
return FALSE;
return DmSuspendThread(dwThreadId);
}
DMHRAPI HrResumeThread(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
DWORD dwThreadId;
if(!pdmcc)
return E_FAIL;
if(!FGetNamedDwParam(szCommand, "thread", &dwThreadId, szResponse))
return FALSE;
return DmResumeThread(dwThreadId);
}
DMHRAPI HrReportThreadInfo(PDM_CMDCONT pdmcc, LPSTR szResponse, DWORD cchResponse)
{
if(pdmcc->BytesRemaining == 2)
return XBDM_ENDOFLIST;
pdmcc->BytesRemaining++;
RtlSnprintf((char*)pdmcc->Buffer, pdmcc->BufferSize,
"suspend=%d priority=%d tlsbase=0x%08x start=0x%08x base=0x%08x limit=0x%08x slack=0x%08x createhi=0x%08x createlo=0x%08x nameaddr=0x%08x namelen=0x%08x proc=0x%02X lasterr=0x%08x",
pdmcd->dmti.SuspendCount, pdmcd->dmti.Priority, pdmcd->dmti.TlsBase, pdmcd->dmti.StartAddress,
pdmcd->dmti.StackBase, pdmcd->dmti.StackLimit, pdmcd->dmti.StackSlackSpace, pdmcd->dmti.CreateTime.dwHighDateTime,
pdmcd->dmti.CreateTime.dwLowDateTime, pdmcd->dmti.ThreadNameAddress,
pdmcd->dmti.ThreadNameLength, pdmcd->dmti.CurrentProcessor, pdmcd->dmti.LastError);
return XBDM_NOERR;
}
DMHRAPI HrGetThreadInfo(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
DWORD dwThreadId;
HRESULT hr;
if(!pdmcc)
return E_FAIL;
if(!FGetNamedDwParam(szCommand, "thread", &dwThreadId, szResponse))
return FALSE;
pdmcd->dmti.Size = sizeof(DM_THREADINFOEX);
hr = DmGetThreadInfoEx(dwThreadId, &pdmcd->dmti);
if(FAILED(hr))
return hr;
pdmcc->HandlingFunction = HrReportThreadInfo;
pdmcc->BytesRemaining = 1;
strcpy_s(szResponse, cchResponse, "thread info follows");
return XBDM_MULTIRESPONSE;
}
DMHRAPI HrReportModuleSections(PDM_CMDCONT pdmcc, LPSTR szResponse, DWORD cchResponse)
{
if(pdmcc->BytesRemaining == 3)
return XBDM_ENDOFLIST;
RtlSnprintf((char*)pdmcc->Buffer, pdmcc->BufferSize, "name=\"%s\" base=0x%08x size=0x%08x index=%d flags=%d",
pdmcd->dmsl.Name, pdmcd->dmsl.BaseAddress, pdmcd->dmsl.Size, pdmcd->dmsl.Index, pdmcd->dmsl.Flags);
if(pdmcc->BytesRemaining == 2)
pdmcc->BytesRemaining++;
else if(FAILED(DmWalkModuleSections((PDM_WALK_MODSECT*)&pdmcd->rgb, pdmcd->sz, &pdmcd->dmsl)))
{
pdmcc->BytesRemaining++;
DmCloseModuleSections((PDM_WALK_MODSECT)pdmcd->rgb);
}
return XBDM_NOERR;
}
DMHRAPI HrListModuleSections(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
if(!pdmcc)
return E_FAIL;
if(!FGetSzParam(szCommand, "name", pdmcd->sz, sizeof(pdmcd->sz)))
{
strcpy_s(szResponse, cchResponse, "missing name");
return E_FAIL;
}
pdmcd->rgb = NULL;
pdmcc->HandlingFunction = HrReportModuleSections;
pdmcc->BytesRemaining = 1;
if(NT_SUCCESS(DmWalkModuleSections((PDM_WALK_MODSECT*)&pdmcd->rgb, pdmcd->sz, &pdmcd->dmsl)))
return XBDM_MULTIRESPONSE;
return XBDM_NOSUCHFILE;
}
DMHRAPI HrGetProcessId(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
ULARGE_INTEGER time;
if(dwExecState == DMN_EXEC_PENDING)
return XBDM_NOTHREAD;
while(g_dmGlobals.dwPid == 0)
{
KeQuerySystemTime(&time);
g_dmGlobals.dwPid = time.LowPart + __mftb32();
}
RtlSnprintf(szResponse, cchResponse, "pid=0x%08x", g_dmGlobals.dwPid);
return XBDM_NOERR;
}
DMHRAPI HrReportXexField(PDM_CMDCONT pdmcc, LPSTR szResponse, DWORD cchResponse)
{
if(pdmcc->BytesRemaining == 3)
return XBDM_ENDOFLIST;
if(pdmcc->BytesRemaining == 1)
{
pdmcc->BytesRemaining++;
RtlSnprintf((char*)pdmcc->Buffer, pdmcc->BufferSize, "fieldsize=0x%08x", 4);
}
else if(pdmcc->BytesRemaining == 2)
{
pdmcc->BytesRemaining++;
RtlSnprintf((char*)pdmcc->Buffer, pdmcc->BufferSize, "%08X", (DWORD)pdmcd->rgb);
}
return XBDM_NOERR;
}
DMHRAPI HrGetXexField(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
PLDR_DATA_TABLE_ENTRY pldte;
char sz[MAX_PATH];
DWORD dw;
HRESULT hr;
if(!pdmcc)
return E_FAIL;
if(!FGetSzParam(szCommand, "module", sz, sizeof(sz)))
{
strcpy_s(szResponse, cchResponse, "missing module");
return E_FAIL;
}
if(!FGetNamedDwParam(szCommand, "field", &dw, szResponse))
return E_FAIL;
if(dw != 0x00010100)
{
DbgPrint("[xbdm] unknown command \"%s\"\n", szCommand);
return XBDM_INVALIDCMD;
}
hr = FGetModuleHandle(sz, &pldte, TRUE);
if(!pldte)
return XBDM_NOSUCHFILE;
pdmcd->rgb = (char*)RtlImageXexHeaderField(pldte->XexHeaderBase, dw);
pdmcc->HandlingFunction = HrReportXexField;
pdmcc->BytesRemaining = 1;
if(pdmcd->rgb)
return XBDM_MULTIRESPONSE;
else
return XBDM_FIELDNOTPRESENT;
}
DMHRAPI HrGetExecState(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
char *sz;
switch(dwExecState)
{
case DMN_EXEC_START:
sz = "start";
break;
case DMN_EXEC_STOP:
sz = "stop";
break;
case DMN_EXEC_PENDING:
sz = "pending";
break;
case DMN_EXEC_REBOOT:
sz = "reboot";
break;
case DMN_EXEC_PENDING_TITLE:
sz = "pending_title";
break;
case DMN_EXEC_REBOOT_TITLE:
sz = "reboot_title";
break;
}
RtlSnprintf(szResponse, cchResponse, "%s", sz);
return XBDM_NOERR;
}
DMHRAPI HrGetConsoleId(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
char sz[0xD];
NTSTATUS st;
ZeroMemory(sz, sizeof(sz));
st = XeKeysGetConsoleID(NULL, sz);
if(FAILED(st))
return (HRESULT)(st | 0x10000000);
RtlSnprintf(szResponse, cchResponse, "consoleid=%s", sz);
return XBDM_NOERR;
}
DMHRAPI HrBreak(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
HRESULT hr = XBDM_NOERR;
BOOL bClear;
DWORD dwAddr;
DWORD dwFlags;
DWORD dwSize;
if(PchGetParam(szCommand, "now", FALSE))
{
Sleep(250);
__emit(BREAKPOINT_BREAK);
}
else if(PchGetParam(szCommand, "start", FALSE))
{
if(FAILED(hr = DmSetInitialBreakpoint()))
strcpy_s(szResponse, cchResponse, "execution not pending");
}
else if(PchGetParam(szCommand, "clearall", FALSE))
DmRemoveAllBreakpoints();
else
{
bClear = (BOOL)PchGetParam(szCommand, "clear", FALSE);
if(FGetNamedDwParam(szCommand, "addr", &dwAddr, szResponse))
{
if(bClear)
DmRemoveBreakpoint((PVOID)dwAddr);
else
DmSetBreakpoint((PVOID)dwAddr);
}
else
{
if(FGetDwParam(szCommand, "read", &dwAddr))
dwFlags = DMBREAK_READ;
else if(FGetDwParam(szCommand, "write", &dwAddr))
dwFlags = DMBREAK_WRITE;
else if(FGetDwParam(szCommand, "readwrite", &dwAddr))
dwFlags = DMBREAK_READWRITE;
else if(FGetDwParam(szCommand, "execute", &dwAddr))
dwFlags = DMBREAK_EXECUTE;
else
hr = E_FAIL;
if(NT_SUCCESS(hr))
{
if(bClear)
dwFlags = DMBREAK_NONE;
else if(!FGetNamedDwParam(szCommand, "size", &dwSize, szResponse))
hr = E_FAIL;
if(NT_SUCCESS(hr))
DmSetDataBreakpoint((PVOID)dwAddr, dwFlags, dwSize);
}
}
}
if(NT_SUCCESS(hr))
szResponse[0] = 0;
return hr;
}
DMHRAPI HrGetDebuggerVersion(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
strcpy_s(szResponse, cchResponse, "2.0.20353.0");
return XBDM_NOERR;
}
DMHRAPI HrKhoungDm(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
VdDisplayFatalError(69);
return XBDM_NOERR;
}
DMHRAPI HrWhoMadeThis(LPCSTR szCommand, LPSTR szResponse,
DWORD cchResponse, PDM_CMDCONT pdmcc)
{
strcpy_s(szResponse, cchResponse, "Xoro did, of course ;)");
return XBDM_NOERR;
}
// Please keep in alphabetical order!
// And use these permission defines when adding commands!
/*
#define DMPL_PRIV_READ For reading from the console
#define DMPL_PRIV_WRITE For writing to the console (files)
#define DMPL_PRIV_CONTROL For controlling the console (must have this to do ANYTHING debug related!!!)
#define DMPL_PRIV_CONFIGURE For configuring the console
#define DMPL_PRIV_MANAGE For managing the console (must have this to edit accounts!!!)
#define DMPL_PRIV_HVX For ANYTHING that has to do with the hypervisor expansion(s)
*/
DMCMD rgbcmd[] =
{
{ "altaddr", DMPL_PRIV_READ, HrGetAltAddr }, // Gets the title ip address
{ "break", DMPL_PRIV_CONTROL, HrBreak }, // Manages breakpoints
{ "bye", 0, HrEndConversation }, // Ends the connection
{ "consolefeatures", DMPL_PRIV_READ, HrGetConsoleFeatures }, // Gets the console features (debug, ram)
{ "consoletype", DMPL_PRIV_READ, HrGetConsoleType }, // Gets the console type (test, dev)
{ "continue", DMPL_PRIV_CONTROL, HrContinueThread }, // Continues a thread
{ "dbgname", DMPL_PRIV_READ, HrDbgName }, // Gets the console name
{ "debugger", DMPL_PRIV_CONTROL, HrAttachDebugger }, // Signals that a debugger has been attached or deattached
{ "delete", DMPL_PRIV_WRITE, HrDelete }, // Deletes a file or directory
{ "dirlist", DMPL_PRIV_READ, HrGetDirList }, // Gets a list of items in a folder
{ "dmversion", DMPL_PRIV_CONTROL, HrGetDebuggerVersion }, // Gets the debugger version
{ "drivefreespace", DMPL_PRIV_READ, HrGetDriveFreeSpace }, // Gets some stats about the drive's volume size
{ "drivelist", DMPL_PRIV_READ, HrGetDriveList }, // Gets the list of connected drives
{ "drivemap", DMPL_PRIV_CONTROL, HrDrivemap }, // Sets if FLASH:\\ is visible in the drive browser
{ "dumpmode", DMPL_PRIV_CONFIGURE, HrSetDumpMode }, // Configures the crash dump mode
{ "dvdeject", DMPL_PRIV_CONTROL, HrDvdEject }, // Opens or closes the dvd tray
{ "getconsoleid", DMPL_PRIV_CONTROL, HrGetConsoleId }, // Gets the console id
{ "getcontext", DMPL_PRIV_CONTROL, HrGetContext }, // Gets a thread context
{ "getcpukey", DMPL_PRIV_HVX, HrGetCpuKey }, // Gets the cpu key
{ "getexecstate", DMPL_PRIV_CONTROL, HrGetExecState }, // Displays the execution state
{ "getfile", DMPL_PRIV_READ, HrGetFile }, // Xbox->PC transfer
{ "getfileattributes", DMPL_PRIV_READ, HrGetFileAttr }, // Gets file attributes
{ "getmem", DMPL_PRIV_CONTROL, HrGetMemory }, // Gets memory
{ "getmemex", DMPL_PRIV_CONTROL, HrGetMemoryEx }, // Gets memory in data
{ "getpid", DMPL_PRIV_CONTROL, HrGetProcessId }, // Gets the process id
{ "go", DMPL_PRIV_CONTROL, HrGo }, // Continues all threads
{ "help", 0, HrHelp }, // Gets info on every command
{ "hwinfo", 0, HrHwInfo }, // Does some listing of stuff for cOz
{ "khoungdm", DMPL_PRIV_CONTROL, HrKhoungDm }, // E69
{ "isdebugger", DMPL_PRIV_CONTROL, HrIsDebuggerAttached }, // Gets info on the current debugger
{ "isstopped", DMPL_PRIV_CONTROL, HrIsThreadStopped }, // Returns information on a stopped thread
{ "magicboot", DMPL_PRIV_CONTROL, HrMagicReboot }, // Changes the currently running title, and/or reboots the console
{ "mkdir", DMPL_PRIV_WRITE, HrCreateDirectory }, // Creates a folder
{ "modsections", DMPL_PRIV_WRITE, HrListModuleSections }, // Lists the module sections
{ "modules", DMPL_PRIV_CONTROL, HrGetModules }, // Returns a list of all the loaded modules (exe, dll)
{ "nostopon", DMPL_PRIV_CONTROL, HrNoStopOn }, // Changes what we stop on
{ "notify", DMPL_PRIV_CONTROL, HrNotify }, // Creates a notification channel
{ "notifyat", DMPL_PRIV_CONTROL, HrNotifyAt }, // Manages a notification channel
{ "objlist", 0, HrObjList }, // Lists objects for cOz
{ "rename", DMPL_PRIV_WRITE, HrRenameFile }, // Renames a file or directory
{ "resume", DMPL_PRIV_CONTROL, HrResumeThread }, // Resumes a thread
{ "screenshot", DMPL_PRIV_CONTROL, HrScreenshot }, // Takes a screenshot
{ "sendfile", DMPL_PRIV_WRITE, HrSendFile }, // PC->Xbox transfer
{ "sendvfile", DMPL_PRIV_WRITE, HrSendVolumeFile }, // PC->Xbox transfer with several files
{ "setcolor", DMPL_PRIV_CONTROL, HrSetColor }, // Sets the color of the console in neighborhood
{ "setcontext", DMPL_PRIV_CONTROL, HrSetContext }, // Sets a thread context
{ "setfileattributes", DMPL_PRIV_WRITE, HrSetFileAttr }, // Sets file attributes
{ "setmem", DMPL_PRIV_CONTROL, HrSetMemory }, // Sets memory
{ "setsystime", DMPL_PRIV_CONFIGURE, HrSetSystemTime }, // Sets the system time
{ "shutdown", DMPL_PRIV_CONTROL, HrShutdown }, // Shuts down the console
{ "stop", DMPL_PRIV_CONTROL, HrStop }, // Stops all threads
{ "stopon", DMPL_PRIV_CONTROL, HrStopOn }, // Changes what we stop on
{ "spew", DMPL_PRIV_CONTROL, HrSpew }, // Spews debug output
{ "suspend", DMPL_PRIV_CONTROL, HrSuspendThread }, // Suspends a thread
{ "systeminfo", DMPL_PRIV_READ, HrGetSystemInfo }, // Gets system info
{ "systime", DMPL_PRIV_CONFIGURE, HrGetSystemTime }, // Sets the system time
{ "threadex", DMPL_PRIV_CONTROL, HrListThreadsEx }, // Lists threads in a different format
{ "threadinfo", DMPL_PRIV_CONTROL, HrGetThreadInfo }, // Returns info on a thread
{ "threads", DMPL_PRIV_CONTROL, HrListThreads }, // Gets a list of threads
{ "xbeinfo", DMPL_PRIV_READ, HrGetXbeInfo }, // Gets information on the running executable
{ "xexfield", DMPL_PRIV_CONTROL, HrGetXexField }, // Gets an xex field
{ "walkmem", DMPL_PRIV_CONTROL, HrWalkMemory }, // Lists memory and protection pages
{ "whomadethis", DMPL_PRIV_CONTROL, HrWhoMadeThis }, // Guess who
};
int cchcmd = (sizeof(rgbcmd) / sizeof(DMCMD));