bananatools/board/bpreader.c

339 lines
11 KiB
C

#include <windows.h>
#include <stdint.h>
#include <stdbool.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"
#include "board/bpreader.h"
const uint8_t BPREADER_CMD_GO_NEXT[6] = { 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00 };
static HRESULT bp_handle_irp(struct irp *irp);
static HRESULT bp_handle_irp_locked(struct irp *irp);
static HRESULT crack_bpreader_request();
static HRESULT build_bpreader_response();
static struct bpreader_config *config;
static struct uart bp_uart;
static CRITICAL_SECTION bp_lock;
static uint8_t bp_written_bytes[520];
static uint8_t bp_readable_bytes[520];
static uint8_t last_cmd = 0;
static uint16_t read_ct = 0;
HRESULT bpreader_init(struct bpreader_config *cfg, uint16_t port)
{
config = cfg;
if (!config->enable) {
return S_OK;
}
if (cfg->port < 0) {
port = cfg->port;
}
uart_init(&bp_uart, port);
bp_uart.written.bytes = bp_written_bytes;
bp_uart.written.nbytes = sizeof(bp_written_bytes);
bp_uart.readable.bytes = bp_readable_bytes;
bp_uart.readable.nbytes = sizeof(bp_readable_bytes);
InitializeCriticalSection(&bp_lock);
dprintf("Reader: Init\n");
return iohook_push_handler(bp_handle_irp);
}
void bpreader_congif_load(struct bpreader_config *cfg, const wchar_t *filename)
{
assert(cfg != NULL);
assert(filename != NULL);
cfg->enable = GetPrivateProfileIntW(L"reader", L"enable", 1, filename);
cfg->port = GetPrivateProfileIntW(L"reader", L"port", 0, filename);
GetPrivateProfileStringW(
L"reader",
L"access_code",
L"",
cfg->access_code,
_countof(cfg->access_code),
filename);
}
static HRESULT bp_handle_irp(struct irp *irp)
{
HRESULT hr;
assert(irp != NULL);
if (uart_match_irp(&bp_uart, irp)) {
EnterCriticalSection(&bp_lock);
hr = bp_handle_irp_locked(irp);
LeaveCriticalSection(&bp_lock);
}
else {
return iohook_invoke_next(irp);
}
return hr;
}
static HRESULT bp_handle_irp_locked(struct irp *irp)
{
HRESULT hr;
if (irp->op == IRP_OP_OPEN) {
dprintf("Reader: Starting backend\n");
}
hr = uart_handle_irp(&bp_uart, irp);
if (FAILED(hr)) {
return hr;
}
#if 0
if (irp->op == IRP_OP_WRITE) {
dprintf("WRITE:\n");
dump_iobuf(&bp_uart.written);
}
#endif
if (irp->op == IRP_OP_WRITE) {
read_ct = 0;
if (bp_uart.written.bytes[0] == 0x55) {
dprintf("Reader: Hello\n");
bp_uart.written.pos = 0; // consume the written buffer
}
else if (bp_uart.written.bytes[3] == 0x00) {
bp_uart.written.pos = 0; // consume the written buffer
}
return hr;
}
else if (irp->op == IRP_OP_READ) {
if (!read_ct) {
dump_iobuf(&bp_uart.written);
hr = crack_bpreader_request();
}
switch (bp_uart.written.bytes[3]) {
case 0x02:
if (!read_ct) {
dprintf("Reader: Unknown 0x02\n");
uint8_t buff[] = { 0x00, 0x00, 0xFF, 0x05,
0xFB, 0xD5, 0x0D, 0x00, 0x06, 0x00, 0x18, 0x00 };
hr = iobuf_write(&bp_uart.readable, buff, sizeof(buff));
}
bp_uart.written.pos = 0;
break;
case 0x03:
if (!read_ct) {
dprintf("Reader: Unknown 0x03\n");
uint8_t buff[] = { 0x00, 0x00, 0xFF, 0x02,
0xFE, 0xD5, 0x19, 0x12, 0x00 };
hr = iobuf_write(&bp_uart.readable, buff, sizeof(buff));
}
bp_uart.written.pos = 0;
break;
case 0x04:
if (!read_ct && bp_uart.written.bytes[6] == 0x0E && last_cmd == 0x04) {
dprintf("Reader: Unknown second 0x04\n");
uint8_t buff[] = { 0x00, 0x00, 0xFF, 0x02,
0xFE, 0xD5, 0x0F, 0x1C, 0x00 };
hr = iobuf_write(&bp_uart.readable, buff, sizeof(buff));
}
else if (!read_ct) {
dprintf("Reader: Unknown 0x04\n");
uint8_t buff[] = { 0x00, 0x00, 0xFF, 0x02,
0xFE, 0xD5, 0x33, 0xF8, 0x00 };
hr = iobuf_write(&bp_uart.readable, buff, sizeof(buff));
}
bp_uart.written.pos = 0;
break;
case 0x06:
if (!read_ct) {
dprintf("Reader: Unknown 0x06\n");
uint8_t buff[] = { 0x00, 0x00, 0xFF, 0x02,
0xFE, 0xD5, 0x33, 0xF8, 0x00 };
hr = iobuf_write(&bp_uart.readable, buff, sizeof(buff));
}
bp_uart.written.pos = 0;
break;
case 0x05:
if (!read_ct) {
dprintf("Reader: Unknown 0x05\n");
uint8_t buff[] = { 0x00, 0x00, 0xFF, 0x03,
0xFD, 0xD5, 0x09, 0x00, 0x22, 0x00 };
hr = iobuf_write(&bp_uart.readable, buff, sizeof(buff));
}
bp_uart.written.pos = 0;
break;
case 0x09:
if (!read_ct) {
dprintf("Reader: Poll card\n");
uint8_t buff[37] = {};
if (GetAsyncKeyState(VK_RETURN) & 0x8000) {
dprintf("Reader: Touch card %ls\n", config->access_code);
uint8_t buff2[] = {
0x00, 0x00, 0xFF, 0x18, 0xE8, 0xD5, 0x4B, 0x01, 0x01, 0x14, 0x01, // Data
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // IDm
0x00, 0xF1, 0x00, 0x00, 0x00, 0x01, 0x43, 0x00, // PMm
0x88, 0xB4, // System Code
0x00, 0x00 };
/*uint8_t buff2[] = {
0x00, 0x00, 0xFF, 0x0C, 0xF4, 0xD5, 0x4B, 0x01, 0x01,
0x00, 0x04, // ATQA
0x08, //SAK
0x04, // Unknown
0x42, 0xF0, 0x00, 0x00, // S/N
0xB0, 0x00 }; // Footer*/
memcpy_s(buff, sizeof(buff), buff2, sizeof(buff2));
} else {
uint8_t buff2[] = { 0x00, 0x00, 0xFF, 0x03, 0xFD, 0xD5, 0x4B, 0x00, 0xE0, 0x00 };
memcpy_s(buff, sizeof(buff), buff2, sizeof(buff2));
}
hr = iobuf_write(&bp_uart.readable, buff, sizeof(buff));
}
bp_uart.written.pos = 0;
break;
case 0x0E:
if (!read_ct) {
dprintf("Reader: Unknown 0x0E\n");
uint8_t buff[] = { 0x00, 0x00, 0xff, 0x02,
0xfe, 0xd5, 0x33, 0xf8, 0x00 };
hr = iobuf_write(&bp_uart.readable, buff, sizeof(buff));
}
bp_uart.written.pos = 0;
break;
case 0x12:
if (!read_ct) {
dprintf("Reader: Unknown 0x12\n");
uint8_t buff[] = { 0x00, 0x00, 0xFF, 0x0a,
0xf6, 0xd5, 0x07, 0xff, 0x3f, 0x0e, 0xf1, 0xff, 0x3f, 0x0e, 0xf1, 0xaa, 0x00 };
hr = iobuf_write(&bp_uart.readable, buff, sizeof(buff));
}
bp_uart.written.pos = 0;
break;
case 0x14:
if (!read_ct) {
dprintf("Reader: Unknown 0x14\n");
uint8_t buff[] = { 0x00, 0x00, 0xFF, 0x20, 0xE0, 0xD5, 0xA1,
0x00, 0x1D, 0x07, // Unknown
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // IDm
0x00, 0x00, 0x01, // Unknown
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // IDm
0x00, 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Unknown
0x00, 0x00 };
hr = iobuf_write(&bp_uart.readable, buff, sizeof(buff));
}
bp_uart.written.pos = 0;
break;
case 0x18:
if (!read_ct) {
dprintf("Reader: Unknown 0x18\n");
uint8_t buff[] = { 0x00, 0x00, 0xFF, 0x0D,
0xF3, 0xD5, 0x07, 0xDC, 0xF4, 0x3F, 0x11, 0x4D, 0x85, 0x61, 0xF1, 0x26,
0x6A, 0x87, 0xC9, 0x00 };
hr = iobuf_write(&bp_uart.readable, buff, sizeof(buff));
}
bp_uart.written.pos = 0;
break;
default:
dprintf("Reader: Unknown Command %02X\n", last_cmd);
dump_iobuf(&bp_uart.written);
break;
}
read_ct++;
}
if (FAILED(hr)) {
dprintf("Reader: HR failed %lX", hr);
}
#if 0
if (irp->op == IRP_OP_READ) {
dprintf("READ:\n");
dump_iobuf(&bp_uart.readable);
}
#endif
bp_uart.written.pos = 0; // consume the written buffer
return hr;
}
static HRESULT crack_bpreader_request() {
struct bpreader_cmd_header header = { bp_uart.written.bytes[0], bp_uart.written.bytes[1], bp_uart.written.bytes[2],
bp_uart.written.bytes[3], bp_uart.written.bytes[4], bp_uart.written.bytes[5], bp_uart.written.bytes[6],
};
assert(header.padding0_00 == 0);
assert(header.padding1_00 == 0);
assert(header.padding2_ff == 0xFF);
assert(header.d_identifier == 0xD4);
switch(header.cmd) {
case 0x06:
dprintf("Reader: Cmd 0x06\n");
break;
case 0x08:
dprintf("Reader: Cmd 0x08\n");
break;
case 0x12:
dprintf("Reader: Cmd 0x12\n");
break;
case 0x18:
dprintf("Reader: Initialize\n");
break;
case 0x0C:
dprintf("Reader: Cmd 0x0C\n");
break;
case 0x0E:
dprintf("Reader: Set Output\n");
break;
case 0x32:
dprintf("Reader: Cmd 0x32\n");
break;
case 0x40:
dprintf("Reader: Read Banapass\n"); // 01 03 00 -> Chip ID; 01 30 01 -> Thing after chip ID; 01 60 30 -> send key a
break;
case 0x4A:
dprintf("Reader: Poll Card\n"); // 01 01 00 ff ff 01 00 -> Felica; 01 00 -> Banapass
break;
case 0xA0:
dprintf("Reader: Read Felica\n");
break;
default:
dprintf("Reader: Unknown command 0x%02x\n", header.cmd);
}
return S_OK;
}
static HRESULT build_bpreader_response() {
return S_OK;
}