分类 硬件技术 下的文章

Proxmark3 Easy 复制4100卡到T5577卡

前言:

最近搬新住处,小区的门禁是用的ID卡,配一张卡30元。可以理解,但还是感觉很贵。想来手里有PM3 Easy,另外还有几张HACKNOWN的双频混合卡,记得它的低频是使用的T5577方案。把吃灰的东西用起来,也复习一下PM3的使用。

实践本文,您可能需要:

  1. Proxmark3 Easy
  2. 待复制的EM4100卡
  3. 空白的T5577卡
  4. 门禁刷卡机,用于验证复制的卡能否正常使用

EM4100卡简介:

EM4100卡工作频率为125KHz,是低频卡。发送数据时采用曼彻斯特编码,比特率为RF/64 。该卡存储64个只读数据位(bit),每个二进制位存储的不是0就是1。起始9个位为9个1,用作表示一次传输的开始。接下来传输10组数据,每组有4位数据+1位偶校验(每组5位中1的个数为偶数个),这个巧妙的设计在进行数据校验的同时确保了发送数据时不会出现连发9个1的情况,从而避免数据发送过程与起始信号冲突。这10组数据中前2组是用于标记版本或厂商,后8组是编号数据。10组数据位的后面跟随的是4位列校验位,最后以0为结束位。如下图所示:

01.jpg

什么是偶校验?所谓的偶校验即指定的一组二进制数据中限定1的个数为偶数,本例中,假如一组数据的数据位为0100(0x4),则目前1的个数为奇数,为了满足偶校验,会在校验位上写1以将1的个数补充到偶数个,这组数据最终就是01001。反之,如果数据位为0101,1的个数已经是偶数,为了满足偶校验,校验位上就写0。

EM4100卡片卡号:

上文中提到的10组数据,每组都编码了一个16进制值。这10个16进制值所构成的就是EM TAG ID这个ID是这张卡存储的所有信息。这也是卡片在读卡过程中发出的实际数据(当热,数据发送时还有发送校验位),因其发射数据时采用的时曼彻斯特编码调制方式,又称其为曼彻斯特内码(Manchester)

需要注意,曼彻斯特内码不在卡面标注ID卡表面通常会印有一串10位10进制数字,该数字为ABA码,它是由EM TAG ID去掉前2位后剩余的用户ID部分转换成10进制后得到的。较大的ID卡表面可能还会印有一个中间由 ,分隔的值,这个是韦根码(wiegand),它是使用ID代码倒数5、6位和后4位分别换算成10进制组成。

假设有一张EM4100卡片的EM TAG ID是:06008148DD 。那么它的ABA码就是:0008472797 [(HEX:008148DD)==>(DEC:0008472797) ];其韦根码为:129,18653 [ (HEX: 81 , HEX:48DD) ==> ( 129 ,18653) ] .

综上,EM TAG ID包含了卡片所有数据,且刷卡时发射的数据也是它,我们复制的新卡自然也应该是发送这些数据。

T5577空白卡简介:

T5577的Page0有8个区块,区块0存储的配置信息,用于配置卡片的工作模式。区块1~7可以存储用户数据,区块7也可以用于存储访问密码。每个区块有33个二进制位。通过把需要发送的数据存储在用户数据区,再通过修改区块0的数据,配置卡片工作方式,以此模拟EM4100卡片。

思路:

为实现目标,首先需要将T5577卡片配置在合适的模式下。曼彻斯特编码、RF/64、ST=0等。经过计算,T5577的Page0:Block0应该配置为:0X00148040。

接下来将EM TAG ID填入上文EM4100卡片简介的图中,计算行列校验位的数值并补齐,以此获得64bit的实际发送数据,将数据转换为16位16进制值,并将其依次写入Block1和Block2。

这样T5577卡片应该就会按照EM4100的方式工作了,在刷卡器上应该会被正常识别。

操作步骤:

实际PM3的命令中提供了更简单的操作方式,有一个命令可以将T5577写成EM4100的工作模式。

在开始之前,我们需要使用hw tune命令来测试天线是否正常。正常情况据说低频天线应该能测到10V以上的电压。但是我的不知是坏了还是怎么,表现如下,但是实际可以正常读写低频卡。

proxmark3> hw tune

Measuring antenna characteristics, please wait.........          
# LF antenna:  0.55 V @   125.00 kHz          
# LF antenna:  0.55 V @   134.00 kHz          
# LF optimal:  1.10 V @    46.88 kHz          
# HF antenna: 24.39 V @    13.56 MHz          
# Your LF antenna is unusable.

首先将原始的EM4100卡片防止在PM3的低频天线上,然后使用lf search命令搜索卡片。如果一切顺利,会有类似如下部分提示:

.....
Checking for known tags:

EM410x pattern found:           

EM TAG ID      : 06008148DD          
Unique TAG ID  : **********         

Possible de-scramble patterns 
.....

将EM4100卡片从低频天线上取下,将EM TAG ID记下来,稍后备用。至此,我们已经获取了EM4100卡片的所有数据。

将T5577空白卡放到低频天线上,运行lf em4x em410xwrite <EM TAG ID> 1 64命令,本例中EM TAG ID为:06008148DD,所以命令如下。

lf em4x em410xwrite 06008148DD 1 64

命令执行后,再次执行 lf search命令,若能够回显与之前的EM4100卡片相同之信息,即表示复制成功。考虑兼容性,具体能否使用还是需要到门禁处实际刷卡验证。

不同固件可能某些命令会不完全一样,比如,上文的命令在某个固件中需要使用以格式:

lf em 410xwrite 06008148DD 1

如果需要尝试识别某张卡是不是T5577卡,可以使用lf t55xx detect命令,回显信息类似如下即表明是。

proxmark3> lf t55xx detect
Chip Type  : T55x7          
Modulation : ASK          
Bit Rate   : 5 - RF/64          
Inverted   : No          
Offset     : 33          
Seq. Term. : No          

Block0     : 0x00148040          

Downlink Mode used : default/fixed bit length

使用了上面的lf t55xx detect命令后,可以使用lf t55xx dump命令获取T5577卡中每个块的原始数据。

假设我们需要单独写入某个块,我们可以使用lf t55xx wr <block> <data>的方式写入。以下是将0x00148040写入到块0中。

lf t55xx wr 0 00148040

网上也有人说要把块0写成0x001480E0,也有人说要把块0写成0x00148041,目前我写的是默认的0x00148040,如果不行,大家可以多试一试。如果命令使用过程遇到问题,可以使用help命令获取帮助。

参考:

我用ArduinoProMicro_SSD1351_MLX90614整红外测温计

我用ArduinoProMicro_SSD1351_MLX90614整红外测温计

前言:

最初我想玩屏,于是从某网友手里买了个分辨率128*96的RGB OLED屏,然后尝试通过网友提供的C51示例代码适配到ArduinoProMicro,学习了一下SPI驱动彩屏。然后买了个MLX90614挂上,配合着前面的硬件学习了一下I2C,说起来MLX90614是SMBus协议,和I2C还有点区别。目前程序实现了读写MLX90614,主函数仅实现了隔三秒读取温度显示一次。整个项目的代码已经上传到GitHub,目前的状态只能算是个硬件测试程序,距离实用还差的远。初学者朋友有兴趣的可以Fork玩一下,也欢迎大佬指导改进。

项目地址:

Github:https://github.com/LexsionLee/Thermometer_MLX90614_SSD1351.git

效果图片:

A01.jpg

A02.jpg

硬件:

MCU:ATMEGA32U4
Board:ProMicro (Arduino Leonardo)

OLED Driver IC:SSD1351

OLED Power IC:ASM1117 3V3

温度传感器:MLX90614

引脚使用:

命名 IO口 功能
OLED_CLK D15 SCL
OLED_DIN D16 SDIN
OLED_RES D10 RST
OLED_DC D9 D/C
OLED_CS D8 /CS

CS为 低电平有效

功能 IO口
MLX90614_I2C_SDA D2
MLX90614_I2C_SCL D3

实现:

我选取了硬件SPI的IO口用于驱动屏幕,虽然网友提供的代码是软件模拟SPI。这种选择源于后期使用硬件SPI的可能性的考虑。事实证明,软件模拟的SPI速度太慢,对于这种彩色OLED屏来说,刷屏速度无法接受,能明显看到刷屏动作,体检极差。最终重写了部分不支持C++编译的代码。换用了硬件SPI的方式。这样果然快多了,画面瞬间刷完。

我用取模软件对数字显示字体进行了取模,推荐字体如下:

Lucida Console
MS Gothic
Rockwell
Rockwell Conden

I2C软件模拟部分,分别对通信协议中基础的片段进行了模拟,然后分层次拼接实现具体的读写功能。与某些I2C通信不同,这个SMBus协议中传输了一位PEC数据,用来校验传输的数据是否正确。我们读取时可以忽略,但是尝试写入时必然要发送PEC的。PEC的值是用本次读写操作中所有数据连在一起通过CRC-8校验得出的。比如写EEPROM时发送的PEC是由从机地址、欲写入的寄存器地址、数据低8位、数据高8位这些数据经过CRC-8校验得出。具体算法没弄懂,索性抄了网友的PEC生成函数,在PC上写了个临时程序验证OK,就这样用了。

手册(Datasheet)中给出的各种地址是需要拼上一个所谓的Opcode的,RAM部分的拼的是0,EEPROM拼的是001X XXXX。具体参考8.4.5. Commands。

EEPROM地址EMISS包含发射率参数(工厂默认1.0=0x FFFF),这是个16位数值。计算公式为:Emissivity = dec2hex[ round( 65535 x ε) ],其实就是65535乘以发射率(范围0.1~1.0),然后得出的结果转换为16进制值。修改EMISS需要先向该地址写0x0000,然后再将新的值写入。

实时的红外测温数据从TOBJ中读出,数据格式为4位16进制值,最高位为错误标记位。我使用的版本只有TOBJ1,所以我程序中读取的TOBJ1的数据。该数据乘以0.02得出的值即为当前红外传感器测得的绝对温度,即开氏温度。众所周知,此温度减去273.15即为摄氏温度。传感器量程能报告的最高温度为382.19℃(0x7FFF),如果报告数据最高位(MSB)为1(0x8XXX)则表示数据有错误,程序上需要做对应处理(目前程序中没有对此做处理)。另外我们可以从TA中读出传感器本身的当前温度数据(线性输出极限范围-38.2~+125℃),处理方式同上。

最后我们将得到的温度数据输出到屏幕上显示即可。

踩坑记录:

因为博主技术太菜,所以会遇到一些低级错误,记下来防止再犯错误!

In function XXX :XXX.cpp:XXXXX :"undefined reference to XXX"

Arduino(AVR) 使用的是C++语言,它使用的编译器是g++ 。在编译时,.ino文件会被改成.cpp,作为C++文件编译。我们认为C++是C的超集,如此看来,我们使用C的语法来写程序应当是可行的。但如果我们的项目由多个.c和.h文件构成且其他.c与.h文件中有函数在.ino文件中调用时,即c文件和cpp文件混编的情况,编译器便会报错。编译器会报告ino文件中调用的函数没有定义,即:In function XXX :XXX.cpp:XXXXX :"undefined reference to XXX" 。具体什么原因,这里不详细展开。这种情况,在合适位置加上extern "C"即可。具体如下:

#ifndef _XXX_H_
#define _XXX_H_

#ifdef __cplusplus
extern "C" {
#endif

void afunctionA(void);
void afunctionB(void);

#ifdef __cplusplus
}
#endif

error: old-style parameter declarations in prototyped function definition

编译项目的时候,提示“old-style parameter declarations in prototyped function definition”。看函数写的也没啥问题,这个项目之前是能够编译通过的,今天改了几段代码,增加了几个函数,然后编译才出现的错误。百度搜索了一下,居然是头文件中这个函数声明时少打了个分号!!!

unknown type name 'class'; did you mean 'labs'

Arduino编译时遇到unknown type name 'class'; did you mean 'labs'这个错误,一番查资料才明白,C++和C混编导致此问题。C文件中调用了C++的函数,而C文件编译时调用的C编译器不支持C++中的类。一般可以把.c文件重命名为.cpp解决。但需要处理C文件中不符合C++语言的代码。

#error: duplicate 'unsigned'

在将C文件更名为.cpp文件后编译出现此错误,是因为 #define u8 unsigned char 造成的。这是写C51时的宏定义习惯,大家都知道,这么写就不需要每次都写那么长的一串了。百度搜索了一下,据说在C++编译器中这种写法不规范,应当使用 typedef unsigned char u8; 来定义类型。我也不知道他说的是否准确、严谨,但是我尝试使用typedef的方式替代之前的写法,再次尝试编译果然可以了。题外话,Arduino的代码库中已经有定义了u16类型,我自己写的就把u16写成了uu16来规避这个问题。