#include #include #include #include "board/qr.h" #include "hook/table.h" #include "hook/iobuf.h" #include "hook/iohook.h" #include "hooklib/uart.h" #include "hooklib/fdshark.h" #include "util/dprintf.h" #include "util/dump.h" /* * Scans QR Codes that the Taiko twitter sometimes * puts out to unlock songs and other things. Huge * thanks to mon for writing most of this! */ static HRESULT qr_handle_irp_locked(struct irp *irp); static HRESULT qr_handle_irp(struct irp *irp); static struct uart qr_uart; static CRITICAL_SECTION qr_lock; static uint8_t qr_written_bytes[520]; static uint8_t qr_readable_bytes[520]; static bool reader_active; HRESULT qr_hook_init(const struct qr_config *cfg, unsigned int port) { assert(cfg != NULL); if (!cfg->enable) { return S_FALSE; } if (cfg->port > 0) { port = cfg->port; } dprintf("QR: Init on COM%d\n", port); uart_init(&qr_uart, port); qr_uart.written.bytes = qr_written_bytes; qr_uart.written.nbytes = sizeof(qr_written_bytes); qr_uart.readable.bytes = qr_readable_bytes; qr_uart.readable.nbytes = sizeof(qr_readable_bytes); InitializeCriticalSection(&qr_lock); return iohook_push_handler(qr_handle_irp); return S_OK; } /* QR port opened all requests and responses end with 0x55 0x00 all requests appear to start with 0x57 0x00 followed by a command code Requests: Lamp on: 57 00 17 52 00 02 00 01 00 55 00 Lamp off: 57 00 17 52 00 01 00 01 00 55 00 Scan off: 57 00 19 00 55 00 Scan on : 57 00 18 00 55 00 Responses: Bit index 2 appears to be used as a status code "OK" : 31 00 00 00 55 00 example QR code (thx tung) [83,49,50,0,0,255,255,17,1,0,67,79,76,76,65,66,79,95,84,79,72,79,95,50,48,50,48,238,255] WRITE: 00000000: W..R.....U. */ static HRESULT qr_handle_irp(struct irp* irp) { HRESULT hr; assert(irp != NULL); // dprintf("QR: IRP request to %ls\n", irp->open_filename); if (!uart_match_irp(&qr_uart, irp)) { return iohook_invoke_next(irp); } EnterCriticalSection(&qr_lock); hr = qr_handle_irp_locked(irp); LeaveCriticalSection(&qr_lock); return hr; } static HRESULT qr_handle_irp_locked(struct irp* irp) { HRESULT hr; #if 0 if (irp->op == IRP_OP_WRITE) { dprintf("WRITE:\n"); dump_const_iobuf(&irp->write); } #endif #if 0 if (irp->op == IRP_OP_READ) { dprintf("READ:\n"); dump_iobuf(&qr_uart.readable); } #endif if (irp->op == IRP_OP_OPEN) { dprintf("QR: port opened\n"); ///* Unfortunately the card reader UART gets opened and closed // repeatedly */ //if (!qr_started) { // dprintf("NFC Assembly: Starting backend DLL\n"); // hr = aime_io_init(); // qr_started = true; // qr_start_hr = hr; // if (FAILED(hr)) { // dprintf("NFC Assembly: Backend error: %x\n", (int)hr); // return hr; // } //} //else { // hr = qr_start_hr; // if (FAILED(hr)) { // return hr; // } //} } if (irp->op == IRP_OP_READ) { // page up key if (reader_active && GetAsyncKeyState(VK_PRIOR) & 0x8000) { dprintf("QR: Scanning\n"); // data from scans is literally just sent as raw bytes, nothing fancy lol // https://twitter.com/taiko_team/status/1377425481855799299 unsigned char taiko_aprilfools_2021[] = { 0x53, 0x31, 0x32, 0x00, 0x01, 0xC3, 0x93, 0xC3, 0xA1, 0xC2, 0x92, 0xC3, 0x87, 0xC4, 0xA0, 0x44, 0x16, 0xC3, 0xB8, 0x4B, 0xC2, 0xA0, 0x44, 0xC3, 0xBD, 0xC3, 0xBA, 0x29, 0xC5, 0xB6, 0xC3, 0xA5, 0x06, 0xE1, 0xB8, 0x9F, 0x2A, 0x43, 0x6F, 0x25, 0x79, 0xC2, 0x84, 0x2B, 0xC2, 0x90, 0x29, 0xC2, 0xAE, 0xC3, 0xAD, 0x54, 0x3E, 0xC3, 0xAB, 0x0A }; /*const uint8_t scan_response[] = { 83,49,50,0,0,255,255,17,1,0,67,79,76,76,65,66,79,95,84,79,72,79,95,50,48,50,48,238,255 };*/ iobuf_write(&qr_uart.readable, taiko_aprilfools_2021, sizeof(taiko_aprilfools_2021)); } } hr = uart_handle_irp(&qr_uart, irp); if (FAILED(hr) || irp->op != IRP_OP_WRITE) { return hr; } const uint8_t scan_on[] = { 0x57, 0x00, 0x18, 0x00, 0x55, 0x00, }; const uint8_t scan_off[] = { 0x57, 0x00, 0x19, 0x00, 0x55, 0x00, }; const uint8_t qr_response[6] = { 0x31, 0x00, 0x00, 0x00, 0x55, 0x00 }; if (qr_uart.written.pos == sizeof(scan_on) && memcmp(qr_uart.written.bytes, scan_on, sizeof(scan_on)) == 0) { if (!reader_active) { dprintf("QR: Scanning enabled\n"); } reader_active = true; } else if (qr_uart.written.pos == sizeof(scan_off) && memcmp(qr_uart.written.bytes, scan_off, sizeof(scan_off)) == 0) { if (reader_active) { dprintf("QR: Scanning disabled\n"); } reader_active = false; } iobuf_write(&qr_uart.readable, qr_response, sizeof(qr_response)); qr_uart.written.pos = 0; return hr; }