This article is currently an experimental machine translation and may contain errors. If anything is unclear, please refer to the original Chinese version. I am continuously working to improve the translation.
a.k.a. NJU Map Campus Card Clone Solo Run Log
Related data has been anonymized. For reference and learning purposes only.
Instance Introduction (?)
Most existing M1 NFC cards are notoriously insecure — cards without full-sector encryption often have authentication vulnerabilities, allowing offline recovery of all sector keys. Even fully encrypted or non-vulnerable cards can be easily sniffed using tools like Proxmark3 to extract all sector keys and data.
However, SAK20 cards (pure CPU cards) and SAK28 cards (hybrid CPU + M1 emulation) currently lack widely known public vulnerabilities in their CPU components. There’s very little documentation on cracking them, and they’re generally considered unbreakable.
Is that really the case?
Boss of the Instance — [NJU Campus Card]
Phase 1 - The Boring Vulnerable Card
Originally, my battle with NJU’s campus card was supposed to be uneventful: on the first night after arriving at NJU, I pulled out my PN532 and cracked all sector keys in minutes, cloning my campus card effortlessly.
Posted a status update back then
It was a vulnerable, partially encrypted SAK18-type card. Cracking and cloning such cards with a PN532 is trivial — countless tools and tutorials exist online. Despite its unusual 4KB size, all the relevant data resided within the first 1KB, making it easy to write onto any phone with M1 card emulation (or UID/CUID blank cards) and use all functions seamlessly.
And just like that, I entered a carefree life of never needing to carry a physical card…
Phase 2 - Sector Key Calculator
Later one day, Sakiyary asked me to clone his campus card onto his phone. That’s when I discovered that new campus cards issued by NJU since 2022 had switched to SAK28 type.
These cards have both a CPU section and an M1 section, using different protocols. I initially assumed, for compatibility reasons, that data was still stored in the M1 section.
This card had no known vulnerabilities — impossible to crack all sector keys directly with PN532. While Proxmark3 could sniff out the keys, I didn’t have one at the time. So I decided to go for a long-term solution: reverse-engineering the sector key generation algorithm.
Unless you possess superhuman attention and a massive sample set, you can’t reverse the key generation logic with just cards.
So… I obtained a copy of the card reader software through certain unspecified close-range penetration techniques. (Whisper: That was actually the key x)
We already know that before authenticating a sector on an M1 card, only the first 16 bytes are readable — most importantly, the 4-byte UID. Our goal was to find in the reader software how it generates the two 6-byte sector keys (A and B, 12 bytes total) from the 4-byte UID.
NJU’s reader software was a SpringBoot-based Java app bundled with several DLLs. Since it was barely obfuscated, I quickly located the key calculation logic. The actual computation happened inside a DLL — a long chain of hand-crafted bitwise operations involving a so-called “master key.” Fortunately, I found the plaintext key directly logged in the program.
Didn’t even need binary reverse engineering — just call the DLL from a Python script
I also reverse-engineered most of the sector data meanings using simple visual inspection:
Data is quite rich — includes some transaction logs, name, student ID, etc... but obviously useless since everything’s online anyway
At this point, I didn’t even need a PN532 anymore. Any Android phone with NFC and MifareClassicTool could parse and clone the new NJU campus card.
Phase 3 - Final Boss - Pure CPU Part Cracking
I thought I’d fully analyzed NJU’s campus card and the story would end here. This blog post wouldn’t exist — it’d be too boring. But then… during testing, I discovered that NJU actually had a third type of campus card. (Later I realized there were way more than three types if categorized by data content — even cards issued at the same time could differ completely. WTF, NJU, how do you manage this mess?)
I found that some newer campus cards had their M1 sections filled entirely with default FF keys and all sectors empty, yet still worked perfectly.
Only one possibility remained — all data was now stored in the CPU section of the SAK28 card, not using the M1 part at all. This usage is effectively equivalent to a SAK20 pure CPU card.
The Swiss Army Knife of RFID — Proxmark3
Theoretically, I could’ve statically analyzed the communication protocol and keys just by reading the reader code and CPU card documentation. But with limited resources, that would’ve been torture.
We mentioned earlier that SAK08/18/28 cards all follow the ISO/IEC 14443-A standard, operating at 13.56 MHz. Proxmark3 can sniff communication between reader and card and dump it for analysis. (Proxmark3 is the most popular NFC sniffer hardware, offering not just sniffing but many other features and strong open-source support. But you can technically use any 13.56 MHz receiver, even an RTL-SDR to sniff)
So I immediately bought a used Proxmark3 RDV3.0 Easy 512kB (~¥150) based on buying guides ([1] [2]) from a fish market. The seller also threw in some test cards and a suspicious-looking reader software. After checking, I realized the software was only good for automating elevator card cracking and nothing else — we won’t need it here. (If you don’t need GUI tools, some new PM3s are also available cheaply on 1688.)
My PM3 arrived with an ancient firmware version — the version string even had the seller’s Taobao shop name. It couldn’t work properly with open-source tools, so I had to reflash it. When purchasing, always confirm that the PM3 version supports open-source firmware.
After downloading the firmware, no driver is needed on Windows. Just run pm3-flash-bootrom.bat and pm3-flash-fullimage.bat, then you can control the PM3 using the official pm3 CLI tool.

Sniffing Communication
Enter hf 14a sniff in the command line to start sniffing. Place the card on the PM3 reader area, then stick both the card and PM3 onto the reader to swipe. Press the side button to stop sniffing. Use hf 14a list to view captured data.
Successfully sniffed communication with valid CRC (occasionally I got CRC errors or missing data — just retry a few times)
How do we analyze the captured data? You know NJU (and its outsourcing vendor) definitely didn’t invent their own NFC card from scratch. Use auto or hf mf info to identify card type and manufacturer:
1 | [usb] pm3 --> hf mf info |
The latter directly identified this SAK28 card as Fudan FM1208-10. A quick Google search leads to Fudan Microelectronics’ official page, and we could’ve downloaded the product manual directly — except the download link on their website is broken. But with some digging online, it’s not hard to find the public documentation. I’ve also uploaded a copy here.
CPU Card Structure
In fact, most cards colloquially called “CPU cards” in China are likely Fudan Microelectronics’ FM1208 or similar models (searching “cpu卡” on Taobao only yields these). So the conclusions in this section apply to most cards marketed as “CPU cards” today.
According to the document, Chapter 4 “FMCOS File Structure”, this type of card uses a tree-like file system instead of M1’s sector-based storage:
The basic file system of FMCOS IC cards consists of a Master File (MF), Directory Files (DF), and Elementary Files (EF). The MF is unique in the card. Under the MF, there can be multiple DFs and EFs. A DF can contain multiple EFs and sub-DFs. We call a DF with subdirectories a DDF, and one without a DF.
From the terminal’s perspective, payment-related data is organized in a tree structure accessible via directories. Each branch represents an Application Data File (ADF). An ADF serves as an entry point to one or more EFs. An ADF and its associated data reside on the same branch of the tree.
…(more detailed descriptions follow — check the document yourself)
The card’s internal structure is roughly: MF as the root, DF as folders, EF as files. EFs come in types: binary files, record files (binary lists), wallet files, key files, etc.
Each file has access control. Each directory has a KEY file storing several keys. The reader must know these keys and complete a challenge-response authentication to elevate privileges and unlock further operations in that directory. (See Chapter 5: “FMCOS Unique Security System”)
File identifiers are 2-byte codes used to locate files. You can select a file by its identifier. The MF’s identifier is 3F00, default name 1PAY.SYS.DDF01. All files can be selected via SELECT command using their identifier. DFs can also be selected by name.
Each file or directory has a 2-byte ID for selection. Folders can also be selected using variable-length byte strings as names.
Additionally, communication can optionally be protected with MAC (message authentication) or DES/3DES encryption to prevent tampering or eavesdropping.
NJU’s card only uses binary and record files, so we won’t dive deeper. Other types are well-documented (e.g., wallet files have complex read/write rules).
Analyzing NJU’s CPU Card
With basic knowledge of the card, documentation, and captured data, we can finally begin analyzing.
Let’s look at a captured communication session during a dorm hot water purchase (Parsing by hand against the doc was exhausting… should’ve written a script from the start):
1 | # First two bytes are protocol header, last two are CRC; middle is actual APDU content |
At first glance, this was headache-inducing. It’s an online transaction — why so many reads and writes across three different files? The data made no obvious sense. The selected directory had a mysterious name D156000001BDF0CACBB4EFD6A7B8B6.
But here’s the good news: no authentication happened before reading files, meaning these three files require no permission to read. Also, communication wasn’t encrypted — all plaintext data was captured.
Since we’ve already found three unprotected files, I decided to explore what data exists on the card.
Although we lack a ready-made upper-layer program for FM1208, PM3’s hf 14a apdu command allows sending raw 16-bit APDU payloads to the card and receiving responses. This card follows the APDU format defined in ISO/IEC 7816-4, so we can directly use PM3 CLI to send commands and observe behavior.
1 | # Try sending SELECT MF — card responds successfully. Now we can emulate the reader! |
Once we can interact directly with the card, we can actively explore its contents. As mentioned, we can select files by name or 2-byte ID. But FM1208 doesn’t support listing files. So I wrote a script to brute-force all file IDs from 0x0000 to 0xFFFF and map the folder structure.
Brute-forcing one directory level takes about 20–30 minutes — not too slow, considering the card’s total storage is under 8KB. No need to worry about missing files.
I also tried reading content via READ commands to determine file types and did some basic analysis as follows.
1 | 3F00 (root, name 1PAY.SYS.DDF01) |
Considering how chaotic most of NJU’s internal systems are, I decided not to obsess over each data field’s meaning. The old M1 card had tons of data, but testing showed only 4-byte UID + 6-byte sector key + 3 extra bytes were needed for full functionality. The rest? Pure fluff — could be gone and no one would notice.
Now we’ve mostly extracted the card’s content. We know via sniffing that unreadable parts aren’t essential for normal transactions. And since it’s an online card, tampering is pointless. So let’s think about cloning.
Cloning and Emulation
To clone an M1 card, we need a backdoored UID/CUID card to write UID and sectors. For CPU cards, since normal FM1208 UID can’t be changed, we also need such a “backdoor” card.
Search Taobao for CPU复制卡/TID卡/SID卡 to find such cards and配套 software (e.g. this one and this one). According to sellers, we can use special software to freely modify directory structure and UID. Just match the original card’s structure and UID — and voilà, the card is cloned.
But… replacing a lost NJU campus card costs only ¥20, while clone cards sell for ¥40. I’d rather just go report it lost.
Let’s try emulating with PM3 first. PM3 doesn’t natively support FM1208 commands, so we need to hack the firmware. PM3 has FPGA and ARM chips. After reading the code, I found it currently returns 90 00 for all emulated card responses. We just need to patch the relevant code to return the same responses as the sniffed card. (Thankfully we only need to modify ARM-side C code — I really don’t know Verilog.)
After flashing the DIY firmware, run hf 14a sim -t 11 — emulation succeeds:
Cloned a classmate’s card and showed off in front of them (x)
Earlier I said “not obsessing over data meaning” — and now it’s proven right. I found that only responding correctly to SELECT DF03 was necessary. All other requests could return empty 90 00 success responses, and the emulated card still worked perfectly. The patch code? Just a few lines.
Another classic NJU pile of spaghetti code with over-engineered, dysfunctional design.
Also, since the reader lacks card authentication and can’t distinguish real from emulated cards, we can obviously modify data during emulation — effectively allowing arbitrary card data modification. This also provides a handy tool for further reverse engineering — change a mysterious value, observe system behavior, and reverse its purpose.
Finally, our ultimate goal: can we emulate this card on an Android phone and use the phone as a card?
Android has supported HCE (Host Card Emulation) since 4.4. Interestingly, while it doesn’t support M1, it does support ISO 7816-4 and ISO 14443-4 — exactly what FM1208 uses. I even found a GitHub repo that emulates FM1208 via HCE, and successfully read the phone-emulated card with PM3. But it didn’t work on NJU’s readers.
After two hours of research and experiments, digging through Android source code, I found two final issues:
- Android HCE’s UID doesn’t match the original card — some readers reject it.
- Android HCE requires the first SELECT command to be SELECT_AID (
00A404by name), but NJU’s reader sends SELECT MF (00A400) first. Android returns an error, and the reader aborts.
I tried hooking onHostEmulationData in NfcNci, but found the 00A400 command never reaches host emulation logic — it fails earlier in NfcService. Native-level hooks are harder and hardware-dependent. I was about to give up — then I stumbled upon nfcgate.
After testing on my Sony Xperia 5 II, I found it implements native-level hooks, solving both UID modification and SELECT MF interception. It even supports relaying NFC communication over the network.
With minor modifications to nfcgate’s code, we can receive APDUs from the reader directly in Java, craft responses, and achieve emulation on par with PM3 — perfectly enabling phone-based campus card usage.
Running modified nfcgate — PM3 reads identical data to original card, and SELECT responses can be customized
Since my phone was too thick to fit into the dorm reader slot, I tested on another terminal that required slightly more commands to work:
Android-emulated card fully recognized. Phone logs show reader requests
Considering phones offer vastly more storage and processing power than PM3, and the card has no read password, one could even build an app that, upon tapping any NJU campus card, reads and saves its data (or transmits over network), then emulates it — no extra hardware needed.
But I personally have no need for CPU card emulation on phone (my old card is still M1), and I’m about to graduate anyway. So I’ll leave this idea here for future tinkerers.
Instance Summary (x)
Fudan Microelectronics’ FM1208 CPU card currently has no public vulnerabilities, but that doesn’t mean it’s secure — nor do vendor implementations.
NJU’s campus card is a classic failure case:
- File permissions set to readable without authentication
- All readers lack encryption and MAC
- Readers lack card authentication
With all these flaws stacked, CPU card data is as freely readable, copyable, and modifiable as M1 cards. NJU even managed to make the more expensive CPU card less secure than the old M1 — M1 at least required a PN532 and ~10 minutes to crack sector keys, while any NFC-enabled Android phone can read CPU card data instantly.
If I’d had more experience earlier, I could’ve done the entire crack using just a PN532 or Android phone.
Moreover, the FM1208 protocol itself has clear security flaws. Beyond the manual’s encouragement — “high security comes at the cost of speed and implementation complexity, so higher security isn’t always better” — even if developers enable all security features (3DES keys, line encryption, MAC, internal/external authentication), the card still can’t resist sophisticated MITM or replay attacks.
Imagine this attack: I act as a man-in-the-middle, forwarding communication between card and reader. When the reader completes external authentication, I pause forwarding — now I have a card in authenticated state, free to send privileged commands.
Or: if a reader sends commands in a fixed pattern, I can sniff the communication, record it, and replay it via an emulated card to clone it.
Not to mention the card’s MAC only supports DES, not 3DES. If the developer didn’t use 3DES for line encryption, sniffed communication can be brute-forced. In 2025, a single RTX 4090 can search at 146.6 GH/s — exhausting the 56-bit DES key space in under 5 days.
Even if this card never reveals new vulnerabilities — despite its vague, inconsistent documentation and frequent mismatches between specs and actual behavior — its pile of design flaws will keep future developers busy for a long time.
Phew… long blog post. Finally done. Satisfies my curiosity about the legendary “CPU card.” Not that impressive — the magic is gone.
All code used is in the FM1208_scripts repo. All public data comes from a real but already reported-lost NJU campus card. Demo videos use another valid card. Please avoid exposing data from active campus cards to prevent misuse.
This article is licensed under the CC BY-NC-SA 4.0 license.
Author: lyc8503, Article link: https://blog.lyc8503.net/en/post/reverse-nju-cpu-card/
If this article was helpful or interesting to you, consider buy me a coffee¬_¬
Feel free to comment in English below o/