1
0
Fork 0
mirror of https://github.com/eliboa/TegraRcmGUI.git synced 2024-12-28 19:16:02 +00:00
TegraRcmGUI/TegraRcmSmash.cpp

301 lines
No EOL
7.6 KiB
C++

/*
* TegraRcmShash.cpp (by rajkosto)
* A reimplementation of fusee-launcher by ktemkin in C++ for Windows platforms.
* https://github.com/rajkosto/TegraRcmSmash
*
*
*/
#include "stdafx.h"
#include "TegraRcmSmash.h"
class RCMDeviceHacker
{
public:
RCMDeviceHacker(KUSB_DRIVER_API& usbDriver_, KUSB_HANDLE usbHandle_) : usbHandle(usbHandle_), usbDriver(&usbDriver_), totalWritten(0), currentBuffer(0) {}
~RCMDeviceHacker()
{
if (usbHandle != nullptr)
{
usbDriver->Free(usbHandle);
usbHandle = nullptr;
}
}
static constexpr u32 PACKET_SIZE = 0x1000;
int getDriverVersion(libusbk::version_t& outVersion)
{
HANDLE masterHandle = INVALID_HANDLE_VALUE;
if (!libusbk_getInternals(usbHandle, &masterHandle) || masterHandle == nullptr || masterHandle == INVALID_HANDLE_VALUE)
return -int(ERROR_INVALID_HANDLE);
libusbk::libusb_request myRequest;
memset(&myRequest, 0, sizeof(myRequest));
const auto retVal = BlockingIoctl(masterHandle, libusbk::LIBUSB_IOCTL_GET_VERSION, &myRequest, sizeof(myRequest), &myRequest, sizeof(myRequest));
if (retVal > 0)
outVersion = myRequest.version;
return retVal;
}
int read(u8* outBuf, size_t outBufSize)
{
UINT lengthTransferred = 0;
const auto retVal = usbDriver->ReadPipe(usbHandle, 0x81, outBuf, (UINT)outBufSize, &lengthTransferred, nullptr);
if (retVal == FALSE)
return -int(GetLastError());
else
return int(lengthTransferred);
}
int write(const u8* data, size_t dataLen, size_t packetSize = PACKET_SIZE)
{
int bytesRemaining = (int)dataLen;
size_t bytesWritten = 0;
while (bytesRemaining > 0)
{
const size_t bytesToWrite = (bytesRemaining < (int)packetSize) ? bytesRemaining : (int)packetSize;
const auto retVal = writeSingleBuffer(&data[bytesWritten], bytesToWrite);
if (retVal < 0)
return retVal;
else if (retVal < (int)bytesToWrite)
return int(bytesWritten) + retVal;
bytesWritten += retVal;
bytesRemaining -= retVal;
}
return (int)bytesWritten;
}
int readDeviceId(u8* deviceIdBuf, size_t idBufSize)
{
if (idBufSize < 0x10)
return -int(ERROR_INSUFFICIENT_BUFFER);
return read(deviceIdBuf, 0x10);
}
int switchToHighBuffer()
{
if (currentBuffer == 0)
{
u8 tempZeroDatas[PACKET_SIZE];
memset(tempZeroDatas, 0, sizeof(tempZeroDatas));
const auto writeRes = write(tempZeroDatas, sizeof(tempZeroDatas));
if (writeRes < 0)
return writeRes;
assert(currentBuffer != 0);
return writeRes;
}
else
return 0;
}
int smashTheStack(int length = -1)
{
constexpr u32 STACK_END = 0x40010000;
if (length < 0)
length = STACK_END - getCurrentBufferAddress();
if (length < 1)
return 0;
HANDLE masterHandle = INVALID_HANDLE_VALUE;
if (!libusbk_getInternals(usbHandle, &masterHandle) || masterHandle == nullptr || masterHandle == INVALID_HANDLE_VALUE)
return -int(ERROR_INVALID_HANDLE);
libusbk::libusb_request rawRequest;
memset(&rawRequest, 0, sizeof(rawRequest));
rawRequest.timeout = 1000; //ms
rawRequest.status.index = 0;
rawRequest.status.recipient = 0x02; //RECIPIENT_ENDPOINT
ByteVector threshBuf(length, 0);
const auto retVal = BlockingIoctl(masterHandle, libusbk::LIBUSB_IOCTL_GET_STATUS, &rawRequest, sizeof(rawRequest), &threshBuf[0], threshBuf.size());
if (retVal < 0)
{
const auto theError = -retVal;
if (theError == ERROR_SEM_TIMEOUT) //timed out, which means it probably smashed
return (int)threshBuf.size();
return theError;
}
else
return retVal;
}
protected:
u32 getCurrentBufferAddress() const
{
return (currentBuffer == 0) ? 0x40005000u : 0x40009000u;
}
u32 toggleBuffer()
{
const auto prevBuffer = currentBuffer;
currentBuffer = (currentBuffer == 0) ? 1u : 0u;
return prevBuffer;
}
int writeSingleBuffer(const u8* data, size_t dataLen)
{
toggleBuffer();
UINT lengthTransferred = 0;
const auto retVal = usbDriver->WritePipe(usbHandle, 0x01, (u8*)data, (UINT)dataLen, &lengthTransferred, nullptr);
if (retVal == FALSE)
return -int(GetLastError());
else
return (int)lengthTransferred;
}
static int BlockingIoctl(HANDLE driverHandle, DWORD ioctlCode, const void* inputBytes, size_t numInputBytes, void* outputBytes, size_t numOutputBytes)
{
WinHandle theEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr);
if (theEvent.get() == nullptr || theEvent.get() == INVALID_HANDLE_VALUE)
return false;
OVERLAPPED overlapped;
memset(&overlapped, 0, sizeof(overlapped));
if (DeviceIoControl(driverHandle, ioctlCode, (LPVOID)inputBytes, (DWORD)numInputBytes, (LPVOID)outputBytes, (DWORD)numOutputBytes, nullptr, &overlapped) == FALSE)
{
const auto errCode = GetLastError();
if (errCode != ERROR_IO_PENDING)
return -int(errCode);
}
DWORD bytesReceived = 0;
if (GetOverlappedResult(driverHandle, &overlapped, &bytesReceived, TRUE) == FALSE)
{
const auto errCode = GetLastError();
return -int(errCode);
}
return (int)bytesReceived;
}
KUSB_HANDLE usbHandle;
KUSB_DRIVER_API* usbDriver;
size_t totalWritten;
u32 currentBuffer;
};
static KLST_DEVINFO pluggedInDevice;
static WinHandle gotDeviceEvent;
static u32 deviceVid = 0x0955;
static u32 devicePid = 0x7321;
static void KUSB_API HotPlugEventCallback(KHOT_HANDLE Handle, KLST_DEVINFO_HANDLE DeviceInfo, KLST_SYNC_FLAG NotificationType)
{
if (NotificationType == KLST_SYNC_FLAG_ADDED && DeviceInfo != nullptr &&
DeviceInfo->Common.Vid == deviceVid && DeviceInfo->Common.Pid == devicePid)
{
memcpy(&pluggedInDevice, DeviceInfo, sizeof(pluggedInDevice));
SetEvent(gotDeviceEvent.get());
}
}
static WinHandle finishedUpEvent;
static BOOL WINAPI ConsoleSignalHandler(DWORD signal)
{
switch (signal)
{
case CTRL_CLOSE_EVENT:
case CTRL_LOGOFF_EVENT:
case CTRL_SHUTDOWN_EVENT:
case CTRL_C_EVENT:
memset(&pluggedInDevice, 0, sizeof(pluggedInDevice));
SetEvent(gotDeviceEvent.get());
if (WaitForSingleObject(finishedUpEvent.get(), 1000) == WAIT_OBJECT_0)
finishedUpEvent = WinHandle();
else
_ftprintf(stderr, TEXT("Timed out waiting for cleanup, forcibly closing\n"));
default:
break;
}
return TRUE;
}
TegraRcmSmash::TegraRcmSmash()
{
}
TegraRcmSmash::~TegraRcmSmash()
{
}
int TegraRcmSmash::RcmStatus()
{
KLST_DEVINFO_HANDLE deviceInfo = nullptr;
KLST_HANDLE deviceList = nullptr;
if (!LstK_Init(&deviceList, KLST_FLAG_NONE))
{
const auto errorCode = GetLastError();
// Win32 error trying to list USB devices
return -6;
}
auto lstKgrd = MakeScopeGuard([&deviceList]()
{
if (deviceList != nullptr)
{
LstK_Free(deviceList);
deviceList = nullptr;
}
});
// Get the number of devices contained in the device list.
UINT deviceCount = 0;
LstK_Count(deviceList, &deviceCount);
if (deviceCount == 0 || LstK_FindByVidPid(deviceList, deviceVid, devicePid, &deviceInfo) == FALSE)
{
// No device found in RCM Mode
return -5;
}
if (deviceInfo != nullptr)
{
if (deviceInfo->DriverID != KUSB_DRVID_LIBUSBK)
{
/*
Wrong driver => need to install libusbK driver
*/
return -4;
}
KUSB_DRIVER_API Usb;
LibK_LoadDriverAPI(&Usb, deviceInfo->DriverID);
// Initialize the device
KUSB_HANDLE handle = nullptr;
if (!Usb.Init(&handle, deviceInfo))
{
const auto errorCode = GetLastError();
// Failed to handle device
return -3;
}
RCMDeviceHacker rcmDev(Usb, handle); handle = nullptr;
libusbk::version_t usbkVersion;
memset(&usbkVersion, 0, sizeof(usbkVersion));
const auto versRetVal = rcmDev.getDriverVersion(usbkVersion);
if (versRetVal <= 0)
{
// Failed to get USB driver version
return -2;
}
else if (usbkVersion.major != 3 || usbkVersion.minor != 0 || usbkVersion.micro != 7)
{
// Wrong USB driver version
return -1;
}
}
return 0;
}