---
# System prepended metadata

title: '[社課共筆]20251016-這是替身攻擊！悠遊卡背後的 RFID 攻防'
tags: [共筆, 社課]

---

---
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)
![qr.ioi.tw](https://hackmd.io/_uploads/B1PDj-CTxl.png =100x)
:::

- [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:

}
```
![螢幕擷取畫面 2025-10-16 201441](https://hackmd.io/_uploads/ByQaWDR6gx.png)

**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)
![250916135334](https://hackmd.io/_uploads/S1pDkwRpee.jpg =1000%x)

---

### 2025 Vibe coding 青年放輕鬆 

![(EDM) 2025 Vibe Coding青年放輕松](https://hackmd.io/_uploads/B1irxPR6lx.jpg)

- **競賽官網：** https://scedux.com/AwX2
- **報名表單：** https://scedux.com/RO3l

## 寒期教育優先區營隊
![寒期教育優先區](https://hackmd.io/_uploads/HkB-mhMnll.png)