一张水卡的数据解析及利用

您所在的位置:网站首页 nfc读ic卡号 一张水卡的数据解析及利用

一张水卡的数据解析及利用

2023-06-15 06:36| 来源: 网络整理| 查看: 265

解析密钥 & 读取数据

使用 M1T 解析出 IC 卡的 Key B 为 A9 DE 7F 3C EB 1F。 读取数据进行分析,以下是该卡的第 10 和 11 扇区以及 0 扇区的块 0,除此之外的扇区数据均为空。

Section 0 Block 0: 5E E1 6E A4 75 08 04 00 01 DD 54 AF A4 43 D6 1D Section 10 Block 0: 23 0A 01 00 09 F5 00 D6 02 00 5E 00 00 5E 00 62 Block 1: 1B F5 03 EE 04 0A AA 00 A0 01 83 1B 00 9E 00 84 Block 2: 23 0A 01 00 09 F5 00 D6 02 00 5E 00 00 5E 00 62 Block 3: 0A A1 1E 91 5B 81 7F 07 88 69 A9 DE 7F 3C EB 1F Section 11 Block 0: C1 3E 12 2C 00 C1 00 00 00 00 06 00 00 06 00 B6 Block 1: 1B F5 03 EE 04 0A AA 00 A0 01 83 1B 00 9E 00 84 Block 2: C1 3E 12 2C 00 C1 00 00 00 00 06 00 00 06 00 B6 Block 3: 0B A1 1E 91 5B 81 7F 07 88 69 A9 DE 7F 3C EB 1F 分析数据

通过观察发现,这些扇区的 Key A 并不相同,而 Key B 为固定值;并且第 10 扇区和第 11 扇区中块 0 和块 2 的数据相同。 通过多次刷卡发现,第 10 扇区会被刷卡机修改,而第 11 扇区未被使用。 接下来的分析重点将放在 Key A 和第 10 扇区上。

Key A 的分析

通过观察发现 Key A 的结构如下:

0A A1 1E 91 5B 81

数据位作用计算0A扇区号0AA1 1E 91 5B取反 UID~5E ~E1 ~6E ~A481固定值81 块 0 的分析

通过多次比对数据改动和刷卡机显示的数额,猜测出一些数据位的作用如下:

23 0A 01 00 09 F5 00 D6 02 00 5E 00 00 5E 00 62

数据位作用计算23异或校验0A ^ 01 ^ 00 ^ 09 ^ F5 ^ 00 ^ D6 ^ 02 ^ 00 ^ 5E ^ 00 ^ 00 ^ 5E ^ 000A和校验01 + 00 + 0901 00剩余数额0.01CNY * 100F5和取反校验~ (01 + 00 + 09)D6 02上次使用数额7.26CNY * 1005E使用次数62和取反校验~ (0A + 01 + 00 + 09 + F5 + 00 + D6 + 02 + 00 + 5E + 00 + 00 + 5E + 00)

黑色标注的数据猜测为无实际作用的数据。

块 1 的分析

这里的数据是固定的,不知道用途,但可以猜测出第一位和最后一位为校验位:

1B F5 03 EE 04 0A AA 00 A0 01 83 1B 00 9E 00 84

数据位作用计算1B异或校验F5 ^ 03 ^ EE ^ 04 ^ 0A ^ AA ^ 00 ^ A0 ^ 01 ^ 83 ^ 1B ^ 00 ^ 9E ^ 0084和取反校验~ (F5 + 03 + EE + 04 + 0A + AA + 00 + A0 + 01 + 83 + 1B + 00 + 9E + 00)

通过比对,尝试将不同的数据位置零后也可以正常使用。

利用

先构建 M1 卡的结构

// M1Card.h #pragma once #include typedef struct KEY_TAG { uint8_t KeyA[6]; uint8_t AccessBits[4]; uint8_t KeyB[6]; } KEY, *PKEY; typedef struct SECTOR_TAG { uint8_t Data0[16]; uint8_t Data1[16]; uint8_t Data2[16]; KEY Key; } SECTOR, *PSECTOR;

然后构建解析出的水卡的结构

// MyCard.h #pragma once #include #include "M1Card.h" typedef struct CARDDATA_TAG { uint8_t OverallXorCheck; uint8_t NumberSumCheck; union { uint16_t Number; struct { uint8_t NumberByte01; uint8_t NumberByte02; }; }; uint8_t Padding1Byte01; uint8_t NumberSumXorCheck; uint8_t Padding5Bytes[5]; uint8_t UsageCountAddNum; uint8_t Padding1Byte02; uint8_t UsageCountSumCheck; uint8_t Padding1Byte03; uint8_t OverallSumXorCheck; } CARDDATA, *PCARDDATA; typedef struct KEYA_TAG { uint8_t Index; uint8_t UIDCheck[4]; uint8_t Padding1Byte; } KEYA, *PKEYA; void MyCard_SetCard(PSECTOR pSectorArray, uint8_t* pUIDBuffer, int number);

最后写出利用函数

// MyCard.c #include "M1Card.h" #include "MyCard.h" #include uint8_t gAcs[4] = { 0x7F, 0x07, 0x88, 0x69 }; uint8_t gKeyB[6] = { 0xA9, 0xDE, 0x7F, 0x3C, 0xEB, 0x1F }; uint8_t gIdData[16] = { 0x1D, 0xF5, 0x03, 0xEE, 0x04, 0x0A, 0xAA, 0x00, 0xA0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xC0 }; void MyCard_SetUIDFromUID(PSECTOR pSectorArray, uint8_t* pUIDBuffer) { uint8_t check = 0; for (int i = 0; i for (int i = 0; i pKeyA->UIDCheck[i] = ~pUIDBuffer[i]; } } } void MyCard_SetDataSector(PSECTOR pSectorArray, int number) { PCARDDATA pData = (PCARDDATA)(pSectorArray + 10)->Data0; memset(pData, 0, 16); pData->Number = number; pData->NumberSumCheck = pData->NumberByte01 + pData->NumberByte02 + pData->Padding1Byte01; pData->NumberSumXorCheck = ~pData->NumberSumCheck; // pData->UsageCountAddNum = pData->UsageCountSumCheck = 0x00; int sum = 0; for (int i = 1; i memcpy_s((pSectorArray + 10)->Data1, 16, gIdData, 16); } void MyCard_SetCard(PSECTOR pSectorArray, uint8_t* pUIDBuffer, int number) { MyCard_SetUIDFromUID(pSectorArray, pUIDBuffer); MyCard_SetKeyFromUID(pSectorArray, pUIDBuffer); MyCard_SetDataIDSector(pSectorArray); MyCard_SetDataSector(pSectorArray, number); } 写在结尾 ⚠ 本篇文章仅供参考,请勿用于非法用途!⚠⚠⚠


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3