1
0
mirror of synced 2024-12-18 02:15:52 +01:00

Add files via upload

This commit is contained in:
Sucareto 2021-03-15 22:48:12 +08:00 committed by GitHub
parent 01b48f921b
commit 9810b51c13
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 760 additions and 0 deletions

119
Arduino-Chunithm-Reader.ino Normal file
View File

@ -0,0 +1,119 @@
#include "cmd.h"
void SerialCheck() {
switch (packet_read()) {
case SG_NFC_CMD_RESET:
sg_nfc_cmd_reset();
break;
case SG_NFC_CMD_GET_FW_VERSION:
sg_nfc_cmd_get_fw_version();
break;
case SG_NFC_CMD_GET_HW_VERSION:
sg_nfc_cmd_get_hw_version();
break;
case SG_NFC_CMD_POLL:
sg_nfc_cmd_poll();
break;
case SG_NFC_CMD_MIFARE_READ_BLOCK:
sg_nfc_cmd_mifare_read_block();
break;
case SG_NFC_CMD_FELICA_ENCAP:
sg_nfc_cmd_felica_encap();
break;
case SG_NFC_CMD_MIFARE_AUTHENTICATE:
sg_res_init();
break;
case SG_NFC_CMD_MIFARE_SELECT_TAG:
sg_res_init();
break;
case SG_NFC_CMD_MIFARE_SET_KEY_AIME:
sg_nfc_cmd_mifare_set_key_aime();
break;
case SG_NFC_CMD_MIFARE_SET_KEY_BANA:
sg_res_init();
break;
case SG_NFC_CMD_RADIO_ON:
sg_nfc_cmd_radio_on();
break;
case SG_NFC_CMD_RADIO_OFF:
sg_nfc_cmd_radio_off();
break;
case SG_RGB_CMD_RESET:
sg_led_cmd_reset();
break;
case SG_RGB_CMD_GET_INFO:
sg_led_cmd_get_info();
break;
case SG_RGB_CMD_SET_COLOR:
sg_led_cmd_set_color();
break;
}
}
void setup() {
SerialUSB.begin(38400);
SerialUSB.setTimeout(0);
FastLED.addLeds<WS2812B, DATA_PIN, GRB>(leds, NUM_LEDS);
nfc.begin();
nfc.SAMConfig();
memset(&req, 0, sizeof(req.bytes));
memset(&res, 0, sizeof(res.bytes));
}
void loop() {
SerialCheck();
packet_write();
}
static uint8_t packet_read() {
uint8_t len, r, checksum;
bool escape = false;
while (SerialUSB.available()) {
r = SerialUSB.read();
if (r == 0xE0) {
req.frame_len = 0xFF;
continue;
}
if (req.frame_len == 0xFF) {
req.frame_len = r;
len = 1;
checksum = r;
continue;
}
if (r == 0xD0) {
escape = true;
continue;
}
if (escape) {
r++;
escape = false;
}
if (len == req.frame_len && checksum == r) {
return req.cmd;
}
req.bytes[len++] = r;
checksum += r;
}
return 0;
}
static void packet_write() {
if (res.cmd == 0)
return;
uint8_t checksum = 0;
SerialUSB.write(0xE0);
for (uint8_t i = 0; i < res.frame_len; i++) {
uint8_t w = res.bytes[i];
checksum += w;
if (SerialUSB.availableForWrite() < 2)
return;
if (w == 0xE0 || w == 0xD0) {
SerialUSB.write(0xD0);
SerialUSB.write(--w);
} else {
SerialUSB.write(w);
}
}
SerialUSB.write(checksum);
res.cmd = 0;
}

14
card.txt Normal file
View File

@ -0,0 +1,14 @@
E0 [05] 00 [7D] [42] 00 [C4] //读卡
E0 [19] 00 [7D] [42] 00 13 01 20 10 [ 8 byte IDm ] [ 8 byte PMm ] [ ]
E0 [13] 00 [80] [71] 0E [ 8 byte IDm ] 06 [00] FF FF 01 0F [ ]
E0 [1A] 00 [80] [71] 00 [14] 14 01 [ 8 byte IDm ] [ 8 byte PMm ] 00 00 [ ]
E0 [17] 00 [81] [71] 12 [ 8 byte IDm ] 0A [0C] [ 8 byte IDm ] [ ]
E0 [13] 00 [81] [71] 00 [0D] 0D 0D [ 8 byte IDm ] 01 00 00 [ ]
E0 [18] 00 [82] [71] 13 [ 8 byte IDm ] 0B [A4] [ 8 byte IDm ] 00 [ ]
E0 [11] 00 [82] [71] 00 [0B] 0B A5 [ 8 byte IDm ] 00 [ ]

BIN
chunihook.dll Normal file

Binary file not shown.

239
cmd.h Normal file
View File

@ -0,0 +1,239 @@
#include "FastLED.h"
#define NUM_LEDS 6
#define DATA_PIN A3
#define BRI 50
CRGB leds[NUM_LEDS];
#include "Adafruit_PN532.h"
#define PN532_IRQ (4)
Adafruit_PN532 nfc(PN532_IRQ, 16);
boolean readerDisabled = false;
uint8_t AimeKey[6];
uint8_t MifareKey[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
enum {
SG_NFC_CMD_GET_FW_VERSION = 0x30,//获取FW版本
SG_NFC_CMD_GET_HW_VERSION = 0x32,//获取HW版本
SG_NFC_CMD_RADIO_ON = 0x40,//打开读卡器天线
SG_NFC_CMD_RADIO_OFF = 0x41,//关闭读卡器天线
SG_NFC_CMD_POLL = 0x42,//发送卡号
SG_NFC_CMD_MIFARE_SELECT_TAG = 0x43,
SG_NFC_CMD_MIFARE_SET_KEY_BANA = 0x50,
SG_NFC_CMD_MIFARE_READ_BLOCK = 0x52,
SG_NFC_CMD_MIFARE_SET_KEY_AIME = 0x54,
SG_NFC_CMD_MIFARE_AUTHENTICATE = 0x55,
SG_NFC_CMD_RESET = 0x62,//重置读卡器
SG_NFC_CMD_FELICA_ENCAP = 0x71,
SG_RGB_CMD_SET_COLOR = 0x81,//LED颜色设置
SG_RGB_CMD_RESET = 0xF5,//LED重置
SG_RGB_CMD_GET_INFO = 0xF0,//LED信息获取
FELICA_CMD_POLL = 0x00,//ENCAP用
FELICA_CMD_GET_SYSTEM_CODE = 0x0c,
FELICA_CMD_NDA_A4 = 0xa4,
};
typedef union packet_req {
uint8_t bytes[256];
struct {
uint8_t frame_len;
uint8_t addr;
uint8_t seq_no;
uint8_t cmd;
uint8_t payload_len;
union {
uint8_t key[6];// sg_nfc_req_mifare_set_key
struct {// sg_nfc_cmd_mifare_read_block
uint8_t uid[4];
uint8_t block_no;
};
struct {// sg_nfc_req_felica_encap
uint8_t IDm[8];
uint8_t encap_len;
uint8_t code;
uint8_t felica_payload[241];
};
uint8_t color_payload[3];//sg_led_req_set_color
};
};
} packet_req_t;
typedef union packet_res {
uint8_t bytes[256];
struct {
uint8_t frame_len;
uint8_t addr;
uint8_t seq_no;
uint8_t cmd;
uint8_t status;
uint8_t payload_len;
union {
char version[23];// sg_nfc_res_get_fw_version,sg_nfc_res_get_hw_version
struct {// sg_nfc_res_poll
uint8_t count;
uint8_t type;
uint8_t id_len;
union {
uint8_t uid[4];
uint8_t IDPM[16];
};
};
uint8_t block[16];// sg_nfc_res_mifare_read_block
struct {// sg_nfc_res_felica_encap
uint8_t encap_len;
uint8_t code;
uint8_t IDm[8];
union {
struct {
uint8_t PMm[8];
uint8_t system_code[2];
};
uint8_t felica_payload[241];
};
};
uint8_t reset_payload; //sg_led_res_reset
uint8_t info_payload[9]; //sg_led_res_get_info
};
};
} packet_res_t;
static packet_req_t req;
static packet_res_t res;
static void sg_res_init(uint8_t payload_len = 0) { //初始化模板
res.frame_len = 6 + payload_len;
res.addr = req.addr;
res.seq_no = req.seq_no;
res.cmd = req.cmd;
res.status = 0;
res.payload_len = payload_len;
}
static void sg_nfc_cmd_reset() {//重置读卡器
sg_res_init();
res.status = 3;
readerDisabled = true;
}
static void sg_nfc_cmd_get_fw_version() {
sg_res_init(sizeof(res.version));
memcpy(res.version, "TN32MSEC003S F/W Ver1.2E", sizeof(res.version));
}
static void sg_nfc_cmd_get_hw_version() {
sg_res_init(sizeof(res.version));
memcpy(res.version, "TN32MSEC003S H/W Ver3.0J", sizeof(res.version));
}
static void sg_nfc_cmd_mifare_set_key_aime() {
sg_res_init();
memcpy(req.key, AimeKey, sizeof(AimeKey));
}
static void sg_led_cmd_reset() {
sg_res_init(sizeof(res.reset_payload));
res.reset_payload = 0;
fill_solid(leds, NUM_LEDS, 0x000000);
FastLED[0].show(leds, NUM_LEDS, BRI);
}
static void sg_led_cmd_get_info() {
sg_res_init(sizeof(res.info_payload));
static uint8_t info[] = {'1', '5', '0', '8', '4', 0xFF, 0x10, 0x00, 0x12};
memcpy(res.info_payload, info, 9);
}
static void sg_led_cmd_set_color() {
uint8_t r = req.color_payload[0];
uint8_t g = req.color_payload[1];
uint8_t b = req.color_payload[2];
fill_solid(leds, NUM_LEDS, CRGB(r, g, b));
FastLED[0].show(leds, NUM_LEDS, BRI);
}
static void sg_nfc_cmd_radio_on() {
sg_res_init();
if (!readerDisabled) {
return;
}
nfc.startPassiveTargetIDDetection(PN532_MIFARE_ISO14443A);
readerDisabled = false;
}
static void sg_nfc_cmd_radio_off() {
sg_res_init();
readerDisabled = true;
}
static void sg_nfc_cmd_poll() { //卡号发送
uint8_t uid[4];
uint8_t t;
//读aime实验性
nfc.startPassiveTargetIDDetection(PN532_MIFARE_ISO14443A);
delay(10);
if (!digitalRead(PN532_IRQ)) {
nfc.readDetectedPassiveTargetID(uid, &t);
if (nfc.mifareclassic_AuthenticateBlock(uid, t, 1, MIFARE_CMD_AUTH_B, AimeKey)) { //aime
res.type = 0x10;
res.id_len = t;
memcpy(res.uid, uid, t);//默认ID为0x01020304
sg_res_init(7);
res.count = 1;
return;
}
}
//读普通mifare当作felica
nfc.startPassiveTargetIDDetection(PN532_MIFARE_ISO14443A);
delay(10);
if (!digitalRead(PN532_IRQ)) {
nfc.readDetectedPassiveTargetID(uid, &t);
if (nfc.mifareclassic_AuthenticateBlock(uid, t, 1, MIFARE_CMD_AUTH_A, MifareKey)) {
if (nfc.mifareclassic_ReadDataBlock(1, res.IDPM)) {//此处略过了IDm和PMm的分别读取
res.type = 0x20;
res.id_len = sizeof(res.IDPM);
sg_res_init(19);//count,type,id_len,IDm,PMm
res.count = 1;
return;
}
}
}
sg_res_init(1);
res.count = 0;
}
static void sg_nfc_cmd_mifare_read_block() {
if (req.block_no > 3)
return;
sg_res_init(sizeof(res.block));
if (nfc.mifareclassic_AuthenticateBlock(req.uid, 4, req.block_no, MIFARE_CMD_AUTH_B, AimeKey)) {
if (nfc.mifareclassic_ReadDataBlock(req.block_no, res.block)) {
return;
}
}
sg_res_init();
}
static void sg_nfc_cmd_felica_encap() {
uint8_t code = req.code;
res.code = code + 1;
memcpy(res.IDm, req.IDm, sizeof(req.IDm));
switch (code) {
case FELICA_CMD_POLL:
sg_res_init(0x14);
res.system_code[0] = 0x00;
res.system_code[1] = 0x00;
break;
case FELICA_CMD_GET_SYSTEM_CODE:
sg_res_init(0x0D);
res.felica_payload[0] = 0x01;
res.felica_payload[1] = 0x00;
res.felica_payload[2] = 0x00;
break;
case FELICA_CMD_NDA_A4:
sg_res_init(0x0B);
res.felica_payload[0] = 0x00;
break;
}
res.encap_len = res.payload_len;
}

244
nfc.txt Normal file
View File

@ -0,0 +1,244 @@
N.B. Quoted strings are NOT NUL-terminated unless otherwise noted.
Useful reading: https://www.nxp.com/docs/en/data-sheet/MF1S50YYX_V1.pdf
(AiMe branded cards are Mifare Classic cards. Other technologies exist though)
Summary
-------
Hardware:
Assembly connector:
5V Host in
Tx;Rx;GND Host RS232 in
Tx;Rx;GND Daisy-chain out
Main board (probably LED controller):
Silk "837-15084"
CN1: Host 5V power in, ?V NFC-sub power out
CN2: Host RS232 Tx;Rx;GND in, NFC-sub Tx;Rx out
CN3: LED-Sub power and data(?) out
DIPSW1: Set to hex nibble 8.
Contains ADM3222 RS232 transceiver IC
Contains ATMega32 MCU
NFC subboard:
Sticker: Model "TN32MSEC003S"
CN1: ?V power and Tx;Rx;GND in, Tx;Rx;GND ass'y CN daisy out.
DIPSW1: Set to hex nibble 0.
Contains ATmega168 MCU
Contains ADM3202A RS232 transceiver IC
Contains shielded RF circuit
Entire non-ground-plane PCB area is visible through the chassis
torx screws lol
LED subboard:
Silk: "837-15120"
CN1: ?V power and Tx;Rx;GND in.
Five RGB LEDs and a bunch of resistors
No visible logic ICs..?
No DIPSW.
JVS framing:
E0 sync
D0 escape (+1 to unescape)
Checksum is sum of bytes after unescaping
Frame header:
Frame length (including length byte itself)
Address
Sequence no, hopefully loops before hitting esc byte...
Command byte
Bus addressing:
Low nibble set using DIPSWs
High nibble ???
Daisy chaining mechanism unknown (RS232 wires probably multi-tap)
Startup
-------
Addr 00 Command 62:
Req:
00 Payload length
Resp:
00 Status byte
00 Payload length
Description:
Unknown. Reset?
Addr 00 Command 30:
Req:
00 Payload length
Resp:
00 Status byte
17 Payload length
.. "TN32MSEC003S F/W Ver1.2E"
Description:
Get firmware version
Addr 00 Command 32:
Req:
00 Payload length
Resp:
00 Status byte
17 Payload length
.. "TN32MSEC003S H/W Ver3.0J"
Description:
Get hardware version
Addr 08 Command f5:
Req:
00 Payload length
Resp:
00 Status byte
00 Payload length
Description:
LED sub-board reset.
Won't accept LED commands until you do this.
Addr 08 Command f0:
Req:
00 Payload length
Resp:
00 Status byte
09 Payload length
.. "15084" (part nr for LED board)
FF ??
11 ??
00 ??
12 ??
Description:
Get board "info"
Addr 00 Command 54:
Req:
06 Payload length
57 'W'
43 'C'
43 'C'
46 'F'
76 'v'
32 '2'
Resp:
00 Status byte?
00 ??
Description:
Set Mifare KeyA.
"WCCF" might refer this this SEGA arcade game:
https://en.wikipedia.org/wiki/World_Club_Champion_Football
It's quite old and has AiMe readers, maybe where they first appeared?
Addr 00 Command 50:
Req:
06 Payload length
60 ??
90 ??
D0 ?? (This is escaped of course)
06 ??
32 ??
F5 ??
Resp:
00 Status byte
00 Payload length
Description:
Possibly Mifare KeyB.
Polling
-------
Addr 00 Command 40:
Req:
01 Payload length
03 ??
Resp:
00 Status byte
00 Payload length
Description:
Poll some other NFC technology?
Addr 00 Command 42:
Req:
00 Payload length
Resp if no MiFare card:
00 Status byte
01 Payload length
00 (represents nothing i guess)
Resp if MiFare card:
00 Status byte?
07 Payload length
01 Chunk length?
10 ?? Block size maybe?
04 Chunk length?
.. Mifare UID, four bytes.
Description:
Check for Mifare card presence?
Addr 00 Command 41:
Req:
00 Payload length
Resp:
00 Status byte
00 Payload length
Description:
Unknown. Poll some other NFC technology?
Card read
---------
Addr 00 Command 43:
Req:
04 Payload length
.. Mifare UID, four bytes.
Resp:
00 Status byte
00 Payload length
Description:
Select MiFare by UID?
Addr 00 Command 55:
Req:
05 Payload length
.. Mifare UID, four bytes.
03 ??
Resp:
00 Status byte
00 Payload length
Description:
Unknown.
Block 3 on a Mifare sector contains keys and an access control list.
It is generally not accessed directly (unless being provisioned?)
Addr 00 Command 52:
Req:
05 Payload length
.. Mifare UID, four bytes.
.. Block number, 1 or 2.
Resp for Block 1:
00 Status byte
10 Payload length (1 block)
.. "SBSD"
00 00 00 00
00 00 00 00
00 4E C6 22
Resp for Block 2:
00 Status byte
10 Payload length (1 block)
.. 00 00 00 00 00 00 xx xx
xx xx xx xx xx xx xx xx
Description:
Probably reads blocks 1 and 2 from Mifare sector 0.
Block 0 contains the "vendor information" and UID.
Block 1 contents are unknown, probably AiMe DB info.
Block 2 last 10 bytes hex are printed on the card ("local unique id").
(Block 3 contains encryption keys so is not allowed to be read)
LED
---
Addr 08 Command 81:
Req:
03 Payload length
ff Red intensity
ff Green intensity
ff Blue intensity
Resp:
None! Command is not acknowledged
Description:
Set LED color

144
sg-cmd.c Normal file
View File

@ -0,0 +1,144 @@
#include <assert.h>
#include "board/sg-cmd.h"
#include "board/sg-frame.h"
#include "hook/iobuf.h"
#include "util/dprintf.h"
union sg_req_any {
struct sg_req_header req;
uint8_t bytes[256];
};
union sg_res_any {
struct sg_res_header res;
uint8_t bytes[256];
};
static HRESULT sg_req_validate(const void *ptr, size_t nbytes);
static void sg_res_error(
struct sg_res_header *res,
const struct sg_req_header *req);
static HRESULT sg_req_validate(const void *ptr, size_t nbytes)
{
const struct sg_req_header *req;
size_t payload_len;
assert(ptr != NULL);
if (nbytes < sizeof(*req)) {
dprintf("SG Cmd: Request header truncated\n");
return E_FAIL;
}
req = ptr;
if (req->hdr.frame_len != nbytes) {
dprintf("SG Cmd: Frame length mismatch: got %i exp %i\n",
req->hdr.frame_len,
(int) nbytes);
return E_FAIL;
}
payload_len = req->hdr.frame_len - sizeof(*req);
if (req->payload_len != payload_len) {
dprintf("SG Cmd: Payload length mismatch: got %i exp %i\n",
req->payload_len,
(int) payload_len);
return E_FAIL;
}
return S_OK;
}
void sg_req_transact(
struct iobuf *res_frame,
const uint8_t *req_bytes,
size_t req_nbytes,
sg_dispatch_fn_t dispatch,
void *ctx)
{
printf("req: ");
for (uint8_t i = 0; i < req_nbytes; i++)
printf("%02X ", req_bytes[i]);
printf("\n");
struct iobuf req_span;
union sg_req_any req;
union sg_res_any res;
HRESULT hr;
assert(res_frame != NULL);
assert(req_bytes != NULL);
assert(dispatch != NULL);
req_span.bytes = req.bytes;
req_span.nbytes = sizeof(req.bytes);
req_span.pos = 0;
hr = sg_frame_decode(&req_span, req_bytes, req_nbytes);
if (FAILED(hr)) {
return;
}
hr = sg_req_validate(req.bytes, req_span.pos);
if (FAILED(hr)) {
return;
}
hr = dispatch(ctx, &req, &res);
if (hr != S_FALSE) {
if (FAILED(hr)) {
sg_res_error(&res.res, &req.req);
}
sg_frame_encode(res_frame, res.bytes, res.res.hdr.frame_len);
printf("res: ");
for (uint8_t i = 0; i < res_frame->pos; i++)
printf("%02X ", res_frame->bytes[i]);
printf("\n");
}
}
void sg_res_init(
struct sg_res_header *res,
const struct sg_req_header *req,
size_t payload_len)
{
assert(res != NULL);
assert(req != NULL);
res->hdr.frame_len = sizeof(*res) + payload_len;
res->hdr.addr = req->hdr.addr;
res->hdr.seq_no = req->hdr.seq_no;
res->hdr.cmd = req->hdr.cmd;
res->status = 0;
res->payload_len = payload_len;
}
static void sg_res_error(
struct sg_res_header *res,
const struct sg_req_header *req)
{
assert(res != NULL);
assert(req != NULL);
res->hdr.frame_len = sizeof(*res);
res->hdr.addr = req->hdr.addr;
res->hdr.seq_no = req->hdr.seq_no;
res->hdr.cmd = req->hdr.cmd;
res->status = 1;
res->payload_len = 0;
}