From b5b797377f90eafd4b1b24880877992989e99b2f Mon Sep 17 00:00:00 2001 From: Kevin Trocolli Date: Mon, 25 Sep 2023 03:16:26 -0400 Subject: [PATCH] bpreader: add card reading --- board/bpreader.c | 272 ++++++++++++++++++++++++----------------------- board/bpreader.h | 44 ++++---- board/config.c | 13 +-- iccard/aime.c | 5 + iccard/mifare.h | 13 +++ 5 files changed, 176 insertions(+), 171 deletions(-) diff --git a/board/bpreader.c b/board/bpreader.c index f47b843..a7c4483 100644 --- a/board/bpreader.c +++ b/board/bpreader.c @@ -12,12 +12,15 @@ #include "util/dump.h" #include "util/hexstr.h" +#include "iccard/aime.h" +#include "iccard/mifare.h" + #include "board/bpreader.h" const uint8_t BPREADER_CMD_GO_NEXT[6] = { 0x00, 0x00, 0xFF, 0x00, 0xFF, 0x00 }; static bool flg = true; -static bool flg_second_pass = false; +static struct mifare card; static HRESULT bp_handle_irp(struct irp *irp); static HRESULT bp_handle_irp_locked(struct irp *irp); static HRESULT crack_bpreader_request(); @@ -35,7 +38,11 @@ static HRESULT bpreader_set_output_cmd(); static HRESULT bpreader_unk_08_cmd(); static HRESULT bpreader_unk_06_cmd(); static HRESULT bpreader_unk_0c_cmd(); +static HRESULT bpreader_unk_44_cmd(); +static HRESULT bpreader_unk_52_cmd(); static HRESULT bpreader_unk_54_cmd(); +static HRESULT bpreader_send_mifare_cmd(); +static HRESULT bpreader_empty_resp(); static struct bpreader_config *config; static struct uart bp_uart; @@ -54,6 +61,7 @@ HRESULT bpreader_init(struct bpreader_config *cfg, uint16_t port) if (cfg->port > 0) { port = cfg->port; } + uint8_t sec1[16] = { 0x00, 0x02, 0x4E, 0x42, 0x47, 0x49, 0x43, 0x36, 0x3A, 0xE7, 0xB5, 0x59, 0x45, 0x64, 0x0F, 0x3D }; uart_init(&bp_uart, port); bp_uart.written.bytes = bp_written_bytes; @@ -61,6 +69,13 @@ HRESULT bpreader_init(struct bpreader_config *cfg, uint16_t port) bp_uart.readable.bytes = bp_readable_bytes; bp_uart.readable.nbytes = sizeof(bp_readable_bytes); InitializeCriticalSection(&bp_lock); + + HRESULT hr = aime_card_populate(&card, cfg->access_code_bytes, sizeof(cfg->access_code_bytes)); + //memcpy_s(card.sectors[0].blocks[1].bytes, sizeof(card.sectors[0].blocks[1].bytes), sec1, sizeof(sec1)); + + if (FAILED(hr)) { + return hr; + } dprintf("Reader: Init\n"); return iohook_push_handler(bp_handle_irp); @@ -116,121 +131,13 @@ static HRESULT bp_handle_irp_locked(struct irp *irp) } else if (irp->op == IRP_OP_READ) { - if (flg) { - if (!read_ct || flg_second_pass) { - hr = crack_bpreader_request(); - } + if (!read_ct) { + hr = crack_bpreader_request(); } else { - 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 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; - } - } + // We need a delay here in order to properly + // "timeout" the DLL's read request. + Sleep(1); + } read_ct++; } @@ -245,9 +152,7 @@ static HRESULT bp_handle_irp_locked(struct irp *irp) } #endif - if (!flg_second_pass) { - bp_uart.written.pos = 0; // consume the written buffer - } + bp_uart.written.pos = 0; // consume the written buffer return hr; } @@ -265,19 +170,19 @@ static HRESULT crack_bpreader_request() { switch(header.cmd) { case 0x06: - dprintf("Reader: Cmd 0x06\n"); + // dprintf("Reader: Cmd 0x06\n"); return bpreader_unk_06_cmd(); case 0x08: - dprintf("Reader: Cmd 0x08\n"); + // dprintf("Reader: Cmd 0x08\n"); return bpreader_unk_08_cmd(); case 0x12: - dprintf("Reader: Cmd 0x12\n"); + // dprintf("Reader: Cmd 0x12\n"); return bpreader_generic_cmd(0x13); case 0x18: - dprintf("Reader: Initialize\n"); + // dprintf("Reader: Initialize\n"); return bpreader_init_cmd(); case 0x0C: @@ -289,15 +194,19 @@ static HRESULT crack_bpreader_request() { return bpreader_generic_cmd(0x0F); case 0x32: - dprintf("Reader: Cmd 0x32\n"); + // dprintf("Reader: Cmd 0x32\n"); return bpreader_generic_cmd(0x33); case 0x40: - dprintf("Reader: Read Banapass\n"); // 01 30 00 -> Chip ID; 01 30 01 -> Thing after chip ID; 01 30 02 -> Access Code; 01 60 30 -> send key a - break; + // dprintf("Reader: Read Mifare\n"); + return bpreader_send_mifare_cmd(); + + case 0x44: + dprintf("Reader: Cmd 0x44\n"); + return bpreader_unk_44_cmd(); case 0x4A: - dprintf("Reader: Poll Card\n"); + // dprintf("Reader: Poll Card\n"); return bpreader_poll_card_cmd(); case 0xA0: @@ -305,8 +214,8 @@ static HRESULT crack_bpreader_request() { break; case 0x52: - dprintf("Reader: Cmd 0x52\n"); - break; + //dprintf("Reader: Cmd 0x52\n"); + return bpreader_unk_52_cmd(); case 0x54: dprintf("Reader: Cmd 0x54\n"); @@ -420,7 +329,7 @@ static HRESULT bpreader_poll_card_cmd() int data_len = 1; size_t resp_len = 0; - if (GetAsyncKeyState(VK_RETURN) & 0x8000) { + if (GetAsyncKeyState(config->insert_card) & 0x8000) { dprintf("Reader: Touch card %ls\n", config->access_code); data.card_present = 0x01; @@ -429,12 +338,18 @@ static HRESULT bpreader_poll_card_cmd() data.atqa[1] = 0x04; data.sak = 0x08; data.unknown5 = 0x04; - memcpy_s(data.serial_number, sizeof(data.serial_number), config->chip_id_bytes, 4); + memcpy_s(data.serial_number, sizeof(data.serial_number), config->access_code_bytes, 4); data_len = sizeof(data); + + + resp_len = build_bpreader_response((uint8_t *)&data, data_len, &header, buff, sizeof(buff)); } - - resp_len = build_bpreader_response((uint8_t *)&data, data_len, &header, buff, sizeof(buff)); - + else { + data_len = 3; + uint8_t empty_buff[1] = {0}; + resp_len = build_bpreader_response((uint8_t *)&empty_buff, data_len, &header, buff, sizeof(buff)); + } + if (resp_len > 0) { HRESULT hr = iobuf_write(&bp_uart.readable, buff, resp_len); return hr; @@ -471,14 +386,14 @@ static HRESULT bpreader_unk_54_cmd() uint8_t bfr_data[1] = { 0x00 }; size_t resp_len = 0; - resp_len = build_bpreader_response(bfr_data, sizeof(bfr_data), &header, buff, sizeof(buff)); + resp_len = build_bpreader_response(bfr_data, 1, &header, buff, sizeof(buff)); if (resp_len > 0) { HRESULT hr = iobuf_write(&bp_uart.readable, buff, resp_len); return hr; } else { - dprintf("Reader: No data to return in bpreader_set_output_cmd!\n"); + dprintf("Reader: No data to return in bpreader_unk_54_cmd!\n"); return E_FAIL; } } @@ -532,3 +447,90 @@ static HRESULT bpreader_unk_0c_cmd() return E_FAIL; } } + +static HRESULT bpreader_send_mifare_cmd() +{ + struct bpreader_read_mifare_req req = { bp_uart.written.bytes[7], bp_uart.written.bytes[8], bp_uart.written.bytes[9] }; + struct bpreader_cmd_header header = { 0x00, 0x00, 0xFF, 0x03, 0xFD, 0xD5, 0x41 }; + uint8_t data[17] = { 0x00 }; + uint8_t buff[26] = { 0x00 }; + size_t resp_len = 0; + + switch (req.subcmd) { + case MIFARE_CMD_READ: + struct bpreader_read_mifare_resp_data resp; + + if (req.block > 3) { + dprintf("Reader: MIFARE block number %d is out of range!\n", req.block); + + return E_FAIL; + } + + dprintf("Reader: Mifare Read Block 0x%02X\n", req.block); + resp.padding = 0; + memcpy_s(resp.block, sizeof(resp.block), card.sectors[0].blocks[req.block].bytes, sizeof(card.sectors[0].blocks[req.block].bytes)); + header.data_len = 0x13; + resp_len = build_bpreader_response((uint8_t *)&resp, 0x11, &header, buff, sizeof(buff)); + break; + + case MIFARE_CMD_AUTH_KEY_A: + dprintf("Reader: Mifare Authentication with Key A\n"); + return iobuf_write(&bp_uart.readable, BPREADER_CMD_GO_NEXT, sizeof(BPREADER_CMD_GO_NEXT)); + break; + + case MIFARE_CMD_AUTH_KEY_B: + dprintf("Reader: Mifare Authentication with Key B\n"); + resp_len = build_bpreader_response(data, 1, &header, buff, sizeof(buff)); + break; + + default: + dprintf("Reader: Unknown Mifare Command 0x%02x\n", req.subcmd); + return E_FAIL; + } + + if (resp_len > 0) { + return iobuf_write(&bp_uart.readable, buff, resp_len); + + } else { + dprintf("Reader: No data to return in bpreader_send_mifare_cmd!\n"); + return E_FAIL; + } +} + +static HRESULT bpreader_unk_52_cmd() +{ + struct bpreader_cmd_header header = { 0x00, 0x00, 0xFF, 0x04, 0xFC, 0xD5, 0x53 }; + uint8_t buff[10] = { 0x00 }; + uint8_t bfr_data[2] = { 0x01, 0x00 }; + size_t resp_len = 0; + + resp_len = build_bpreader_response(bfr_data, 2, &header, buff, sizeof(buff)); + + if (resp_len > 0) { + HRESULT hr = iobuf_write(&bp_uart.readable, buff, resp_len); + return hr; + + } else { + dprintf("Reader: No data to return in bpreader_unk_52_cmd!\n"); + return E_FAIL; + } +} + +static HRESULT bpreader_unk_44_cmd() +{ + struct bpreader_cmd_header header = { 0x00, 0x00, 0xFF, 0x04, 0xFC, 0xD5, 0x45 }; + uint8_t buff[10] = { 0x00 }; + uint8_t bfr_data[2] = { 0x01, 0x00 }; + size_t resp_len = 0; + + resp_len = build_bpreader_response(bfr_data, 2, &header, buff, sizeof(buff)); + + if (resp_len > 0) { + HRESULT hr = iobuf_write(&bp_uart.readable, buff, resp_len); + return hr; + + } else { + dprintf("Reader: No data to return in bpreader_unk_44_cmd!\n"); + return E_FAIL; + } +} diff --git a/board/bpreader.h b/board/bpreader.h index a5db1cd..7f64d91 100644 --- a/board/bpreader.h +++ b/board/bpreader.h @@ -6,46 +6,31 @@ struct bpreader_config { bool enable; uint16_t port; + uint8_t insert_card; wchar_t access_code[21]; - wchar_t chip_id[33]; uint8_t access_code_bytes[10]; - uint8_t chip_id_bytes[16]; }; HRESULT bpreader_init(struct bpreader_config *cfg, uint16_t port); /* bpreader packet format WIP -n = final offset +maybe rcs956? +Response packet | Offset | Meaning | |--------|--------------------------------------------------------------------| -| 0 | Always 00 | -| 1 | Always 00 | +| 0 | Preamble, Always 00 | +| 1 | Packet start, Always 00 | | 2 | Always FF | Header | 3 | len(Data), 0 means no data | -| 4 | FF - ((sum of header bytes) & FF) if data is present | +| 4 | (0x100 - data_len) & FF if data is present | |--------|--------------------------------------------------------------------| -| 5 | Always D5 (resp) or D4 (req) if data is present, identifier? | +| 5 | Always 0xD5 (success) or 0x7F (failure) | | 6 | Command if data is present | Data | 7..n-2 | Data if data is present | |--------|--------------------------------------------------------------------| -| n-1 | FF - ((sum of head + data bytes) & FF) if data is present, else FF | Footer -| n | Always 00 | - -Commands -| Command | Response | Meaning | Response Data (not including leading 0xD5) | -|---------|----------|----------------------------------------------------|------------------------------------------------------------------------| -| 0x00 | 0x00 | Wait Next Command | None | -| 0x02 | 0x05 | Unknown | 0x0D, 0x00, 0x06, 0x00 | -| 0x03 | 0x02 | Unknown, first command and then sent randomly | 0x19 | -| 0x04 | 0x02 | Unknown, only command seen to change it's req data | 0x0F/0x33 | -| 0x05 | 0x03 | Unknown | 0x09, 0x00 | -| 0x06 | 0x02 | Unknown | 0x0F | -| 0x09 | 0x18 | Poll for card | 0x4B, 0x01, 0x01, 0x14, 0x01, [IDm], [PMm], [Sys Code] | -| 0x0E | 0x02 | Unknown | 0x33 | -| 0x12 | 0x0A | Unknown | 0x07, 0xFF, 0x3F, 0x0E, 0xF1, 0xFF, 0x3F, 0x0E, 0xF1 | -| 0x14 | 0x20 | Unknown | a lot, see bpreader.c | -| 0x18 | 0x0D | Unknown | 0x07, 0xDC, 0xF4, 0x3F, 0x11, 0x4D, 0x85, 0x61, 0xF1, 0x26, 0x6A, 0x87 | +| n-1 | (FF - sum of data bytes) & FF if data is present, else FF | Footer +| n | Postamble, Always 00 | */ #pragma pack(push, 1) @@ -64,6 +49,17 @@ struct bpreader_cmd_footer { uint8_t padding; }; +struct bpreader_read_mifare_req { + uint8_t unk0; + uint8_t subcmd; // 0x30 for read, 0x60/61 for write? + uint8_t block; +}; + +struct bpreader_read_mifare_resp_data { + uint8_t padding; + uint8_t block[16]; +}; + struct bpreader_poll_banapass_data { uint8_t card_present; uint8_t unknown1; // 0x01 diff --git a/board/config.c b/board/config.c index 0fad281..a54cee3 100644 --- a/board/config.c +++ b/board/config.c @@ -17,6 +17,7 @@ void bpreader_config_load(struct bpreader_config *cfg, const wchar_t *filename) cfg->enable = GetPrivateProfileIntW(L"reader", L"enable", 1, filename); cfg->port = GetPrivateProfileIntW(L"reader", L"port", 0, filename); + cfg->insert_card = GetPrivateProfileIntW(L"reader", L"insert_card", VK_RETURN, filename); GetPrivateProfileStringW( L"reader", L"access_code", @@ -24,23 +25,11 @@ void bpreader_config_load(struct bpreader_config *cfg, const wchar_t *filename) cfg->access_code, _countof(cfg->access_code), filename); - GetPrivateProfileStringW( - L"reader", - L"chip_id", - L"00000000000000000000000000000000", - cfg->chip_id, - _countof(cfg->chip_id), - filename); HRESULT hr = wstr_to_bytes(cfg->access_code, 20, cfg->access_code_bytes, sizeof(cfg->access_code_bytes)); if (FAILED(hr)) { dprintf("Reader: wstr_to_bytes 1 failed! 0x%lX", hr); } - - hr = wstr_to_bytes(cfg->chip_id, 32, cfg->chip_id_bytes, sizeof(cfg->chip_id_bytes)); - if (FAILED(hr)) { - dprintf("Reader: wstr_to_bytes 2 failed! 0x%lX", hr); - } } void usio_config_load(struct usio_config *cfg, const wchar_t *filename) diff --git a/iccard/aime.c b/iccard/aime.c index 199413a..9957dd3 100644 --- a/iccard/aime.c +++ b/iccard/aime.c @@ -41,6 +41,11 @@ HRESULT aime_card_populate( mifare->sectors[0].blocks[2].bytes[6 + i] = b; } + // Set the card ID, nothing else matters in the first block + mifare->sectors[0].blocks[0].bytes[0] = luid[0]; + mifare->sectors[0].blocks[0].bytes[1] = luid[1]; + mifare->sectors[0].blocks[0].bytes[2] = luid[2]; + mifare->sectors[0].blocks[0].bytes[3] = luid[3]; sprintf_s(accessCode, sizeof accessCode, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", luid[0], luid[1], luid[2], luid[3], luid[4], luid[5], luid[6], luid[7], luid[8], luid[9]); diff --git a/iccard/mifare.h b/iccard/mifare.h index 10dbc34..ca3802a 100644 --- a/iccard/mifare.h +++ b/iccard/mifare.h @@ -2,6 +2,19 @@ #include +enum mifare_cmd { + MIFARE_CMD_AUTH_KEY_A = 0x60, + MIFARE_CMD_AUTH_KEY_B = 0x61, + MIFARE_CMD_PERSONALIZE_UID = 0x40, + MIFARE_CMD_SET_MOD_TYPE = 0x43, + MIFARE_CMD_READ = 0x30, + MIFARE_CMD_WRITE = 0xA0, + MIFARE_CMD_DECREMENT = 0xC0, + MIFARE_CMD_INCREMENT = 0xC1, + MIFARE_CMD_RESTORE = 0xC2, + MIFARE_CMD_TRANSFER = 0xB0, +}; + struct mifare_block { uint8_t bytes[16]; };