STM32F103+RTT从零开始(三)—— S50门禁卡复制
近期因為各種原因,重新租了個房子住,小區外面有門禁系統,樓下也有個門禁系統。房東只給了一套門禁卡,而我家人也需要門禁卡,所以我就去小區物業那里補卡,結果小區物業那里只能補小區的門禁卡,樓下的門禁卡需要在另外個地方補。物業工作人員給說了下地方,我找了下沒找到,又想起了我一年前買了個RFID模塊和十幾個空白門禁卡,還沒開封。又正好時值國慶,空閑時間比較多,不如自己來復制吧。
基礎知識
一兩個月前,我寫了兩篇STM32F103+RTT的入門博客。那兩篇是非常基礎的,到這里直接就是復制門禁卡,看起來好像不是循序漸進。不過也是沒法子,畢竟現在從事的工作和這些完全不沾邊,工作又忙,所以沒太多時間來一步一步學習并且寫博客,只能玩到哪是哪了。
先看了下門禁卡的分類和一些基礎資料,了解到我新租住的房子所在的小區用的門禁卡是S50類型的。它具有16個 扇區,每個扇區具有四個Block,分別為0、1、2、3,每個Block可以存儲16字節的數據。其中每個扇區的Block3存儲的為6字節A密碼+4字節控制位+6字節B密碼。另外第一扇區的Block0存儲的為卡號以及廠商的基本信息。卡就是下面的這個鬼樣子:
一般來說,第一扇區的Block0下內容是不能更改的,我原以為小區門禁卡是通過其他扇區的數據來做驗證的,后面寫好了讀數據的代碼,發現從門禁卡中從數據塊中讀取的數據都是0,只有密碼區、控制區及ID下第一扇區的Block0中有數據。所以我們的那個小區中的門禁卡應該是通過卡的第一扇區的Block0中的信息來驗證的。也就是說我們要做的是復制整個卡,包括第一扇區的Block0。
要復制第一扇區的Block0,普通的IC卡就不行了,我之前買的卡就是普通的IC卡,鼓搗了很久,一直以為是程序寫的有問題,后來才發現是卡不行。沒辦法,只能重新買卡了。
選卡也要選擇合適的卡,查了下資料,能夠修改第一扇區Block0的兼容S50類型的卡,有UID卡(可以使用后門指令無限制重復修改第一扇區Block0,會響應后門指令)、CUID卡(可以使用后門指令無限制重復修改第一扇區的Block0,不會響應后門指令)、FUID卡(使用普通指令,只能修改一次第一扇區的Block0)等。根據上面的說明,可以知道,UID卡可以無限制修改,但是由于會響應后門指令,所以如果門禁系統有檢測后門指令并且禁用,那就不能用了。CUID不響應后門指令,但是由于可以用后面指令修改,門禁系統如果先去修改一下,確認不能修改,再進行門禁驗證,那么CUID的卡就也不能用了。FUID顯然是最保險的,但是從價格來說,FUID(2.2元) > CUID(1.3元) > UID(0.78元)。
所以我先試了下房東給的門禁卡,發現它是可以被修改的,而且也會響應后門指令,那么考慮性價比,當然是買UID卡了。10塊錢13個還包郵,加上8塊錢不到的一個RFID-RC522,一共18塊錢(PS : 物業那里20塊錢一個門禁卡,真坑)。
門禁卡復制實現
上面提到修改門禁卡第一扇區Block0是需要使用后門指令的,直接按照普通的寫數據的方式進行修改,是無法修改的。既然主要目的是復制門禁卡,懶得重復去造輪子了。我之前買的RFID-RC522模塊,使用的是SPI的通信模式,淘寶上搜索,應該很多都是這樣的,如下圖所示:
對,買的就是這樣沒焊腳的,然后我又買了個電烙鐵套裝。。。
然后上位機還是使用之前的那個STM32F103C8T6。
RC522驅動程序
然后再網上找了下STM32F103下RC522的驅動程序,并增加利用后門指令寫第一扇區block0的代碼如下:
驅動頭文件rc522.h
驅動實現rc522.c
#include "rc522.h" #include "stm32f10x_gpio.h"#define MAXRLEN 18 void PcdInit() {GPIO_InitTypeDef GPIO_InitStructure;/* Enable the GPIO Clock */RCC_APB2PeriphClockCmd(MF522_RST_CLK, ENABLE);/* Configure the GPIO pin */GPIO_InitStructure.GPIO_Pin = MF522_RST_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;GPIO_Init(MF522_RST_PORT, &GPIO_InitStructure);/* Enable the GPIO Clock */RCC_APB2PeriphClockCmd(MF522_MISO_CLK, ENABLE);/* Configure the GPIO pin */GPIO_InitStructure.GPIO_Pin = MF522_MISO_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;GPIO_Init(MF522_MISO_PORT, &GPIO_InitStructure);/* Enable the GPIO Clock */RCC_APB2PeriphClockCmd(MF522_MOSI_CLK, ENABLE);/* Configure the GPIO pin */GPIO_InitStructure.GPIO_Pin = MF522_MOSI_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;GPIO_Init(MF522_MOSI_PORT, &GPIO_InitStructure);/* Enable the GPIO Clock */RCC_APB2PeriphClockCmd(MF522_SCK_CLK, ENABLE);/* Configure the GPIO pin */GPIO_InitStructure.GPIO_Pin = MF522_SCK_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;GPIO_Init(MF522_SCK_PORT, &GPIO_InitStructure);/* Enable the GPIO Clock */RCC_APB2PeriphClockCmd(MF522_NSS_CLK, ENABLE);/* Configure the GPIO pin */GPIO_InitStructure.GPIO_Pin = MF522_NSS_PIN;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;GPIO_Init(MF522_NSS_PORT, &GPIO_InitStructure); }char PcdRequest(unsigned char req_code,unsigned char *pTagType) {char status; unsigned int unLen;unsigned char ucComMF522Buf[MAXRLEN]; ClearBitMask(Status2Reg,0x08);WriteRawRC(BitFramingReg,0x07);SetBitMask(TxControlReg,0x03);ucComMF522Buf[0] = req_code;status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,1,ucComMF522Buf,&unLen); // if(status == MI_OK ) // { LED_GREEN =0 ;} // else {LED_GREEN =1 ;}if ((status == MI_OK) && (unLen == 0x10)){ *pTagType = ucComMF522Buf[0];*(pTagType+1) = ucComMF522Buf[1];}else{ status = MI_ERR; }return status; }char PcdAnticoll(unsigned char *pSnr) {char status;unsigned char i,snr_check=0;unsigned int unLen;unsigned char ucComMF522Buf[MAXRLEN]; ClearBitMask(Status2Reg,0x08);WriteRawRC(BitFramingReg,0x00);ClearBitMask(CollReg,0x80);ucComMF522Buf[0] = PICC_ANTICOLL1;ucComMF522Buf[1] = 0x20;status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,2,ucComMF522Buf,&unLen);if (status == MI_OK){for (i=0; i<4; i++){ *(pSnr+i) = ucComMF522Buf[i];snr_check ^= ucComMF522Buf[i];}if (snr_check != ucComMF522Buf[i]){ status = MI_ERR; }}SetBitMask(CollReg,0x80);return status; }char PcdSelect(unsigned char *pSnr) {char status;unsigned char i;unsigned int unLen;unsigned char ucComMF522Buf[MAXRLEN]; ucComMF522Buf[0] = PICC_ANTICOLL1;ucComMF522Buf[1] = 0x70;ucComMF522Buf[6] = 0;for (i=0; i<4; i++){ucComMF522Buf[i+2] = *(pSnr+i);ucComMF522Buf[6] ^= *(pSnr+i);}CalulateCRC(ucComMF522Buf,7,&ucComMF522Buf[7]);ClearBitMask(Status2Reg,0x08);status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,9,ucComMF522Buf,&unLen);if ((status == MI_OK) && (unLen == 0x18)){ status = MI_OK; }else{ status = MI_ERR; }return status; }char PcdAuthState(unsigned char auth_mode,unsigned char addr,unsigned char *pKey,unsigned char *pSnr) {char status;unsigned int unLen;unsigned char i,ucComMF522Buf[MAXRLEN]; ucComMF522Buf[0] = auth_mode;ucComMF522Buf[1] = addr;for (i=0; i<6; i++){ ucComMF522Buf[i+2] = *(pKey+i); }for (i=0; i<6; i++){ ucComMF522Buf[i+8] = *(pSnr+i); }// memcpy(&ucComMF522Buf[2], pKey, 6); // memcpy(&ucComMF522Buf[8], pSnr, 4); status = PcdComMF522(PCD_AUTHENT,ucComMF522Buf,12,ucComMF522Buf,&unLen);if ((status != MI_OK) || (!(ReadRawRC(Status2Reg) & 0x08))){ status = MI_ERR; }return status; }char PcdRead(unsigned char addr,unsigned char *pData) {char status;unsigned int unLen;unsigned char i,ucComMF522Buf[MAXRLEN]; ucComMF522Buf[0] = PICC_READ;ucComMF522Buf[1] = addr;CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);if ((status == MI_OK) && (unLen == 0x90))// { memcpy(pData, ucComMF522Buf, 16); }{for (i=0; i<16; i++){ *(pData+i) = ucComMF522Buf[i]; }}else{ status = MI_ERR; }return status; }char PcdWrite(unsigned char addr,unsigned char *pData) {char status;unsigned int unLen;unsigned char i,ucComMF522Buf[MAXRLEN]; ucComMF522Buf[0] = PICC_WRITE;ucComMF522Buf[1] = addr;CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A)){ status = MI_ERR; }if (status == MI_OK){//memcpy(ucComMF522Buf, pData, 16);for (i=0; i<16; i++){ ucComMF522Buf[i] = *(pData+i); }CalulateCRC(ucComMF522Buf,16,&ucComMF522Buf[16]);status = PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,18,ucComMF522Buf,&unLen);if ((status != MI_OK) || (unLen != 4) || ((ucComMF522Buf[0] & 0x0F) != 0x0A)){ status = MI_ERR; }}return status; }//這個是寫第一扇區Block0的代碼 char PcdSpicelWrite(unsigned char *pData) {char status;unsigned int unLen;unsigned char i,ucComMF522Buf[MAXRLEN]; //需要使用以下步驟開啟后門PcdHalt();WriteRawRC(BitFramingReg, 0x07);//WriteRawRC(CommandReg, 0x40);ucComMF522Buf[0] = 0x40;PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,1,ucComMF522Buf,&unLen);WriteRawRC(BitFramingReg, 0x00);ucComMF522Buf[0] = 0x43;PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,1,ucComMF522Buf,&unLen);return PcdWrite(0, pData); }char PcdHalt(void) {unsigned int unLen;unsigned char ucComMF522Buf[MAXRLEN]; ucComMF522Buf[0] = PICC_HALT;ucComMF522Buf[1] = 0;CalulateCRC(ucComMF522Buf,2,&ucComMF522Buf[2]);PcdComMF522(PCD_TRANSCEIVE,ucComMF522Buf,4,ucComMF522Buf,&unLen);return MI_OK; }//?MF522??CRC16?? void CalulateCRC(unsigned char *pIndata,unsigned char len,unsigned char *pOutData) {unsigned char i,n;ClearBitMask(DivIrqReg,0x04);WriteRawRC(CommandReg,PCD_IDLE);SetBitMask(FIFOLevelReg,0x80);for (i=0; i<len; i++){ WriteRawRC(FIFODataReg, *(pIndata+i)); }WriteRawRC(CommandReg, PCD_CALCCRC);i = 0xFF;do {n = ReadRawRC(DivIrqReg);i--;}while ((i!=0) && !(n&0x04));pOutData[0] = ReadRawRC(CRCResultRegL);pOutData[1] = ReadRawRC(CRCResultRegM); }char PcdReset(void) {RST_H;delay_10ms(1);RST_L;delay_10ms(1);RST_H;delay_10ms(10);if(ReadRawRC(0x02) == 0x80){}WriteRawRC(CommandReg,PCD_RESETPHASE);WriteRawRC(ModeReg,0x3D); WriteRawRC(TReloadRegL,30); WriteRawRC(TReloadRegH,0);WriteRawRC(TModeReg,0x8D);WriteRawRC(TPrescalerReg,0x3E);WriteRawRC(TxAutoReg,0x40); return MI_OK; }char M500PcdConfigISOType(unsigned char type) {if (type == 'A'){ ClearBitMask(Status2Reg,0x08);WriteRawRC(ModeReg,0x3D);//3FWriteRawRC(RxSelReg,0x86);//84WriteRawRC(RFCfgReg,0x7F); //4FWriteRawRC(TReloadRegL,30);//tmoLength);// TReloadVal = 'h6a =tmoLength(dec) WriteRawRC(TReloadRegH,0);WriteRawRC(TModeReg,0x8D);WriteRawRC(TPrescalerReg,0x3E);delay_10ms(1);PcdAntennaOn();}else{ return (char)-1; }return MI_OK; }unsigned char ReadRawRC(unsigned char Address) {unsigned char i, ucAddr;unsigned char ucResult=0;NSS_L;ucAddr = ((Address<<1)&0x7E)|0x80;for(i=8;i>0;i--){SCK_L;if(ucAddr&0x80)MOSI_H;elseMOSI_L;SCK_H;ucAddr <<= 1;}for(i=8;i>0;i--){SCK_L;ucResult <<= 1;SCK_H;if(READ_MISO == 1)ucResult |= 1;}NSS_H;SCK_H;return ucResult; }void WriteRawRC(unsigned char Address, unsigned char value) { unsigned char i, ucAddr;SCK_L;NSS_L;ucAddr = ((Address<<1)&0x7E);for(i=8;i>0;i--){if(ucAddr&0x80)MOSI_H;elseMOSI_L;SCK_H;ucAddr <<= 1;SCK_L;}for(i=8;i>0;i--){if(value&0x80)MOSI_H;elseMOSI_L;SCK_H;value <<= 1;SCK_L;}NSS_H;SCK_H; }void SetBitMask(unsigned char reg,unsigned char mask) {char tmp = 0x0;tmp = ReadRawRC(reg);WriteRawRC(reg,tmp | mask); // set bit mask }void ClearBitMask(unsigned char reg,unsigned char mask) {char tmp = 0x0;tmp = ReadRawRC(reg);WriteRawRC(reg, tmp & ~mask); // clear bit mask } char PcdComMF522(unsigned char Command, unsigned char *pInData, unsigned char InLenByte,unsigned char *pOutData, unsigned int *pOutLenBit) {char status = MI_ERR;unsigned char irqEn = 0x00;unsigned char waitFor = 0x00;unsigned char lastBits;unsigned char n;unsigned int i;switch (Command){case PCD_AUTHENT:irqEn = 0x12;waitFor = 0x10;break;case PCD_TRANSCEIVE:case PCD_SPECIAL_COPY:irqEn = 0x77;waitFor = 0x30;break;default:break;}WriteRawRC(ComIEnReg,irqEn|0x80);ClearBitMask(ComIrqReg,0x80);WriteRawRC(CommandReg,PCD_IDLE);SetBitMask(FIFOLevelReg,0x80);for (i=0; i<InLenByte; i++){ WriteRawRC(FIFODataReg, pInData[i]); }WriteRawRC(CommandReg, Command);if (Command == PCD_TRANSCEIVE){ SetBitMask(BitFramingReg,0x80); }i = 2000;do {n = ReadRawRC(ComIrqReg);i--;}while ((i!=0) && !(n&0x01) && !(n&waitFor));ClearBitMask(BitFramingReg,0x80);if (i!=0){ if(!(ReadRawRC(ErrorReg)&0x1B)){status = MI_OK;if (n & irqEn & 0x01){ status = MI_NOTAGERR; }if (Command == PCD_TRANSCEIVE){n = ReadRawRC(FIFOLevelReg);lastBits = ReadRawRC(ControlReg) & 0x07;if (lastBits){ *pOutLenBit = (n-1)*8 + lastBits; }else{ *pOutLenBit = n*8; }if (n == 0){ n = 1; }if (n > MAXRLEN){ n = MAXRLEN; }for (i=0; i<n; i++){ pOutData[i] = ReadRawRC(FIFODataReg); }}}else{ status = MI_ERR; }}SetBitMask(ControlReg,0x80); // stop timer nowWriteRawRC(CommandReg,PCD_IDLE); return status; }void PcdAntennaOn() {unsigned char i;i = ReadRawRC(TxControlReg);if (!(i & 0x03)){SetBitMask(TxControlReg, 0x03);} }void PcdAntennaOff() {ClearBitMask(TxControlReg, 0x03); }void WaitCardOff(void) {char status;unsigned char TagType[2];while(1){status = PcdRequest(REQ_ALL, TagType);if(status){status = PcdRequest(REQ_ALL, TagType);if(status){status = PcdRequest(REQ_ALL, TagType);if(status){return;}}}delay_10ms(10);} }void delay_10ms(unsigned int _10ms) {unsigned int i, j;for(i=0; i<_10ms; i++){for(j=0; j<60000; j++);} }后門代碼實現依據來源于這篇博客,RC522驅動代碼來源于這篇博客,在此表示感謝。
主要控制邏輯
按照之前點亮LED的經驗,我們使用RTthread來進行進行門禁卡的檢測和復制。主要代碼如下:
復制代碼被注釋了,我們先使用檢測并讀取的代碼,讀取出原卡的內容,然后把讀取內容記錄下來,復制到新卡上去。正確的做法應該是使用完整邏輯來實現這個流程,這里為了方便,直接手動記錄,然后修改代碼重新編譯來進行卡的復制,有興趣有需要的朋友可在此基礎上自行補充完成。
工程源碼
工程源碼掛載在CSDN下載頻道,攢點下載分備用。歡迎轉載,轉載博客請注明出處湖廣午王的博客。
總結
以上是生活随笔為你收集整理的STM32F103+RTT从零开始(三)—— S50门禁卡复制的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 选项卡怎么实现切换效果
- 下一篇: raid卡缓存对硬盘性能_可能是最简单的