---
title: "[社課共筆]20251016-這是替身攻擊!悠遊卡背後的 RFID 攻防"
description:
tags:
- 社課
- 共筆
---
:::success
# 這是替身攻擊!悠遊卡背後的 RFID 攻防
**時間:** 2025/10/16(星期四)18:30 ~ 21:00
**地點:** 挺生大樓 A3-200 教室
**簡報:** **[DC上有](https://discord.gg/tTkb4FAx)**
**Slido:** [連結]()
**回饋表單:**[連結](https://forms.gle/UV9WQ1w6B8CfyAh89)

:::
- [Arduino IDE](https://www.arduino.cc/en/software/)
> 請從這裡開始
**小試身手**
```cpp
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
Serial.println("Initialize Arduino program.");
}
int count = 0; // 全域變數
void loop() {
// put your main code here, to run repeatedly:
Serial.print("program is running for ");
Serial.print(count);
Serial.println(" second.");
delay(1000); // 暫停一秒 單位:毫秒(ms)
count = count + 1; // 每次 count 數值加1
}
```
**Arduino 程式基本架構**
```cpp
void setup() {
// put your setup code here, to run once:
}
void loop() {
// put your main code here, to run repeatedly:
}
```

**MFRC-522 程式基本架構**
```cpp
/*
* Typical pin layout used:
* -----------------------------------------------------------------------------
* MFRC522 Arduino Arduino Arduino Arduino
* Reader/PCD Uno/101 Mega Nano v3 Leonardo/Micro
* Signal Pin Pin Pin Pin Pin
* -----------------------------------------------------------------------------
* RST/Reset RST 9 5 D9 RESET/ICSP-5
* SPI SS SDA(SS) 10 53 D10 10
* SPI MOSI MOSI 11 / ICSP-4 51 D11 ICSP-4
* SPI MISO MISO 12 / ICSP-1 50 D12 ICSP-1
* SPI SCK SCK 13 / ICSP-3 52 D13 ICSP-3
*/
#include <SPI.h>
#include <MFRC522.h>
#define RST_PIN 9 // Configurable, see typical pin layout above
#define SS_PIN 10 // Configurable, see typical pin layout above
MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance
void setup() {
Serial.begin(9600); // Initialize serial communications with the PC
while (!Serial); // Do nothing if no serial port is opened
SPI.begin(); // Init SPI bus
mfrc522.PCD_Init(); // Init MFRC522
}
void loop() {
// Reset the loop if no new card present on the sensor/reader.
// This saves the entire process when idle.
if ( ! mfrc522.PICC_IsNewCardPresent()) {
return;
}
// Select one of the cards
if ( ! mfrc522.PICC_ReadCardSerial()) {
return;
}
// TODO ...
}
```
**練習範例程式碼**
```cpp
/*
* Typical pin layout used:
* -----------------------------------------------------------------------------
* MFRC522 Arduino Arduino Arduino Arduino
* Reader/PCD Uno/101 Mega Nano v3 Leonardo/Micro
* Signal Pin Pin Pin Pin Pin
* -----------------------------------------------------------------------------
* RST/Reset RST 9 5 D9 RESET/ICSP-5
* SPI SS SDA(SS) 10 53 D10 10
* SPI MOSI MOSI 11 / ICSP-4 51 D11 ICSP-4
* SPI MISO MISO 12 / ICSP-1 50 D12 ICSP-1
* SPI SCK SCK 13 / ICSP-3 52 D13 ICSP-3
*/
#include <MFRC522.h>
#include <SPI.h>
// Definition
///////////////////////////////////////////////////////////
#define RST_PIN 9 // Configurable, see typical pin layout above
#define SS_PIN 10 // Configurable, see typical pin layout above
// Global Variables
///////////////////////////////////////////////////////////
MFRC522 mfrc522(SS_PIN, RST_PIN); // Create MFRC522 instance
MFRC522::MIFARE_Key key;
MFRC522::StatusCode status;
// Setup
///////////////////////////////////////////////////////////
void setup() {
Serial.begin(9600); // Initialize serial communications with the PC
while (!Serial)
; // Do nothing if no serial port is opened
SPI.begin(); // Init SPI bus
mfrc522.PCD_Init(); // Init MFRC522
for (byte i = 0; i < 6; i++) {
key.keyByte[i] = 0xFF;
}
// 印出讀卡機韌體資訊
// mfrc522.PCD_DumpVersionToSerial();
}
// Loop
///////////////////////////////////////////////////////////
void loop() {
// Reset the loop if no new card present on the sensor/reader.
// This saves the entire process when idle.
if (!mfrc522.PICC_IsNewCardPresent()) {
return;
}
// Select one of the cards
if (!mfrc522.PICC_ReadCardSerial()) {
return;
}
// TODO ...
// 印出卡片資訊
// mfrc522.PICC_DumpDetailsToSerial(&mfrc522.uid);
// 印出卡片所有資料
// mfrc522.PICC_DumpToSerial(&mfrc522.uid);
// 印出 UID
// Serial.print("uid:");
// dump_byte_array(mfrc522.uid.uidByte, mfrc522.uid.size);
// Serial.println();
// 用 key A 驗證 sector 0
// auth_keyA(0, &key);
// 讀取 block 1
// unsigned char block[32] = { 0 };
// read_block(1, block, 32);
// dump_block(1, block);
// 寫入 block 1
// strncpy(block, "Yuto Forever", 16);
// write_block(1, block, 16);
// read_block(1, block, 32);
// hexdump(block, 16);
// 寫入 uid
// byte uid[] = { 0xDE, 0xAD, 0xBE, 0xEF };
// memcpy(block, uid, 4); // uid
// block[4] = bcc0(uid, 4); // bcc0
// block[5] = 0x08; // SAK
// block[6] = 0x04; block[7] = 0x00; // ATQA
// mock factory data
// for(char i = 0, c = 'b'; i < 8; i++, c++)
// block[i + 8] = c;
// 印出欲寫入的資料
// hexdump(block, 16);
// 寫入並印出寫入結果
// write_block(0, block, 16);
// read_block(1, block, 32);
// hexdump(block, 16);
}
// Helper Functions
///////////////////////////////////////////////////////////
/*
* @brief 將 array 的內容以 16 進位印出
*
* @param[out] buffer 要印出的資料
* @param[in] size buffer 的大小
*/
void dump_byte_array(byte* buffer, byte size) {
for (byte i = 0; i < size; i++) {
Serial.print(buffer[i] < 0x10 ? " 0" : " ");
Serial.print(buffer[i], HEX);
}
}
/*
* @brief 將 buffer 的內容 16 進位 + ASCII 印出
*
* @param[out] buffer 要印出的資料
* @param[in] size buffer 的大小
*/
void hexdump(const byte* buffer, size_t size) {
const byte bytes_per_line = 16;
for (size_t offset = 0; offset < size; offset += bytes_per_line) {
if (offset < 0x10)
Serial.print("0");
Serial.print(offset, HEX);
Serial.print(F(": "));
for (byte i = 0; i < bytes_per_line; i++) {
size_t idx = offset + i;
if (i == 8)
Serial.print(" ");
if (idx < size) {
if (buffer[idx] < 0x10)
Serial.print("0");
Serial.print(buffer[idx], HEX);
Serial.print(" ");
} else {
Serial.print(" ");
}
}
Serial.print("| ");
for (byte i = 0; i < bytes_per_line; i++) {
size_t idx = offset + i;
if (idx < size) {
byte c = buffer[idx];
Serial.print(isPrintable(c) ? (char)c : '.');
} else {
Serial.print(" ");
}
}
Serial.println();
}
}
/*
* @brief 讀取卡片中的 block
*
* @param[in] addr 讀取的 block 地址
* @param[out] buffer 讀出來存放的空間
* @param[in] size buffer 的大小
*/
bool read_block(byte addr, byte* buffer, byte size) {
MFRC522::StatusCode status = mfrc522.MIFARE_Read(addr, buffer, &size);
if (status == MFRC522::STATUS_OK)
return true;
Serial.print(F("[-] MIFARE_Read() failed: "));
Serial.println(mfrc522.GetStatusCodeName(status));
return false;
}
/*
* @brief 寫入卡片中的 block
*
* @param[in] addr 讀取的 block 地址
* @param[in] buffer 要寫入的資料
* @param[in] size buffer 的大小
*/
bool write_block(byte addr, byte* buffer, byte size) {
MFRC522::StatusCode status = mfrc522.MIFARE_Write(addr, buffer, size);
if (status == MFRC522::STATUS_OK)
return true;
Serial.print(F("[-] MIFARE_Write() failed: "));
Serial.println(mfrc522.GetStatusCodeName(status));
return false;
}
/*
* @brief 驗證 sector 的 key A
*
* @param[in] sector 要驗證的的 block
* @param[in] key 用來驗證的金鑰
*/
bool auth_keyA(byte sector, MFRC522::MIFARE_Key* key_a) {
Serial.println(F("[i] 驗證 key A..."));
byte trailer = sector * 4 + 3;
status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_A, trailer,
key_a, &(mfrc522.uid));
if (status != MFRC522::STATUS_OK) {
Serial.print(F("[-] PCD_Authenticate() failed: "));
Serial.println(mfrc522.GetStatusCodeName(status));
return false;
}
return true;
}
/*
* @brief 驗證 sector 的 key B
*
* @param[in] sector 要驗證的的 block
* @param[in] key 用來驗證的金鑰
*/
bool auth_keyB(byte sector, MFRC522::MIFARE_Key* key_b) {
Serial.println(F("[i] 驗證 key A..."));
byte trailer = sector * 4 + 3;
status = mfrc522.PCD_Authenticate(MFRC522::PICC_CMD_MF_AUTH_KEY_B, trailer,
key_b, &(mfrc522.uid));
if (status != MFRC522::STATUS_OK) {
Serial.print(F("[-] PCD_Authenticate() failed: "));
Serial.println(mfrc522.GetStatusCodeName(status));
return false;
}
return true;
}
/*
* @brief 傾印 block 的資料
*
* @param[in] addr block 的 地址
* @param[in] buffer block 的資料
*/
void dump_block(byte addr, byte* buffer) {
if (addr < 0x10)
Serial.print("0");
Serial.print(addr);
Serial.print(F(":"));
for (byte i = 0; i < 16; i++) {
if (i == 8)
Serial.print(" ");
Serial.print(buffer[i] < 0x10 ? " 0" : " ");
Serial.print(buffer[i], HEX);
}
Serial.println();
}
/*
* @brief 計算 uid 的校驗碼
*
* @param[in] uid uid 的陣列
* @param[in] size uid 的長度
*/
byte bcc0(byte* uid, byte size) {
byte result = 0;
for (byte i = 0; i < size; i++) {
result ^= uid[i];
}
return result;
}
```
---
# [儲備幹部申請表單](https://forms.gle/FQrHCi4QG4kg6wL28)

---
### 2025 Vibe coding 青年放輕鬆

- **競賽官網:** https://scedux.com/AwX2
- **報名表單:** https://scedux.com/RO3l
## 寒期教育優先區營隊
