|
|
@ -135,13 +135,13 @@ void Mifare::chk()
|
|
|
|
data = reMatch.captured().toUpper();
|
|
|
|
data = reMatch.captured().toUpper();
|
|
|
|
offset += data.length();
|
|
|
|
offset += data.length();
|
|
|
|
QStringList cells = data.remove(" ").split("|");
|
|
|
|
QStringList cells = data.remove(" ").split("|");
|
|
|
|
if(!cells.at(2).contains("?"))
|
|
|
|
if(!cells[2].contains("?"))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
keyAList->replace(i, cells.at(2));
|
|
|
|
keyAList->replace(i, cells[2]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(!cells.at(3).contains("?"))
|
|
|
|
if(!cells[3].contains("?"))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
keyBList->replace(i, cells.at(3));
|
|
|
|
keyBList->replace(i, cells[3]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -157,13 +157,13 @@ void Mifare::chk()
|
|
|
|
data = reMatch.captured().toUpper();
|
|
|
|
data = reMatch.captured().toUpper();
|
|
|
|
offset += data.length();
|
|
|
|
offset += data.length();
|
|
|
|
QStringList cells = data.remove(" ").split("|");
|
|
|
|
QStringList cells = data.remove(" ").split("|");
|
|
|
|
if(cells.at(3) == "1")
|
|
|
|
if(cells[3] == "1")
|
|
|
|
{
|
|
|
|
{
|
|
|
|
keyAList->replace(i, cells.at(2));
|
|
|
|
keyAList->replace(i, cells[2]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(cells.at(5) == "1")
|
|
|
|
if(cells[5] == "1")
|
|
|
|
{
|
|
|
|
{
|
|
|
|
keyBList->replace(i, cells.at(4));
|
|
|
|
keyBList->replace(i, cells[4]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -229,13 +229,13 @@ void Mifare::nested()
|
|
|
|
data = reMatch.captured().toUpper();
|
|
|
|
data = reMatch.captured().toUpper();
|
|
|
|
offset += data.length();
|
|
|
|
offset += data.length();
|
|
|
|
QStringList cells = data.remove(" ").split("|");
|
|
|
|
QStringList cells = data.remove(" ").split("|");
|
|
|
|
if(cells.at(3) == "1")
|
|
|
|
if(cells[3] == "1")
|
|
|
|
{
|
|
|
|
{
|
|
|
|
keyAList->replace(i, cells.at(2));
|
|
|
|
keyAList->replace(i, cells[2]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(cells.at(5) == "1")
|
|
|
|
if(cells[5] == "1")
|
|
|
|
{
|
|
|
|
{
|
|
|
|
keyBList->replace(i, cells.at(4));
|
|
|
|
keyBList->replace(i, cells[4]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -327,6 +327,10 @@ QStringList Mifare::_readsec(int sectorId, KeyType keyType, const QString& key,
|
|
|
|
QRegularExpressionMatch reMatch;
|
|
|
|
QRegularExpressionMatch reMatch;
|
|
|
|
int offset = 0;
|
|
|
|
int offset = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for(int i = 0; i < cardType.blk[sectorId]; i++)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
data.append("");
|
|
|
|
|
|
|
|
}
|
|
|
|
if(!data_isKeyValid(key))
|
|
|
|
if(!data_isKeyValid(key))
|
|
|
|
{
|
|
|
|
{
|
|
|
|
return data;
|
|
|
|
return data;
|
|
|
@ -334,6 +338,7 @@ QStringList Mifare::_readsec(int sectorId, KeyType keyType, const QString& key,
|
|
|
|
|
|
|
|
|
|
|
|
if(util->getClientType() == Util::CLIENTTYPE_OFFICIAL || util->getClientType() == Util::CLIENTTYPE_ICEMAN)
|
|
|
|
if(util->getClientType() == Util::CLIENTTYPE_OFFICIAL || util->getClientType() == Util::CLIENTTYPE_ICEMAN)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
// try to read all blocks together
|
|
|
|
result = util->execCMDWithOutput(
|
|
|
|
result = util->execCMDWithOutput(
|
|
|
|
"hf mf rdsc "
|
|
|
|
"hf mf rdsc "
|
|
|
|
+ QString::number(sectorId)
|
|
|
|
+ QString::number(sectorId)
|
|
|
@ -354,9 +359,39 @@ QStringList Mifare::_readsec(int sectorId, KeyType keyType, const QString& key,
|
|
|
|
tmp = reMatch.captured().toUpper();
|
|
|
|
tmp = reMatch.captured().toUpper();
|
|
|
|
offset += tmp.length();
|
|
|
|
offset += tmp.length();
|
|
|
|
tmp.remove(" ");
|
|
|
|
tmp.remove(" ");
|
|
|
|
data.append(tmp);
|
|
|
|
data[i] = tmp;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
// if failed, try to read them seperately.
|
|
|
|
|
|
|
|
// (when one of the block cannot be read, the rdsc will return nothing, so you need to read the rest of blocks manually)
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
for(int i = 0; i < cardType.blk[sectorId]; i++)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
data[i] = _readblk(cardType.blks[sectorId] + i, keyType, key, waitTime);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//process trailer(like _readblk())
|
|
|
|
|
|
|
|
QString trailer = data[cardType.blk[sectorId] - 1];
|
|
|
|
|
|
|
|
if(trailer != "")
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
if(keyType == KEY_A) // in this case, the Access Bits is always accessible
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
trailer.replace(0, 12, key);
|
|
|
|
|
|
|
|
QList<quint8> ACBits = data_getACBits(trailer.mid(12, 8));
|
|
|
|
|
|
|
|
if(ACBits[3] == 2 || ACBits[3] == 3 || ACBits[3] == 5 || ACBits[3] == 6 || ACBits[3] == 7) // in these cases, the KeyB cannot be read by KeyA
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
trailer.replace(20, 12, "????????????");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
else if(keyType == KEY_B)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
trailer.replace(20, 12, key);;
|
|
|
|
|
|
|
|
trailer.replace(0, 12, "????????????"); // fill the keyA part with ?
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
data[cardType.blk[sectorId] - 1] = trailer;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return data;
|
|
|
|
return data;
|
|
|
@ -377,94 +412,61 @@ void Mifare::read()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Mifare::readAll() // note:cannot handle some situations(special trailer block)
|
|
|
|
void Mifare::readAll()
|
|
|
|
{
|
|
|
|
{
|
|
|
|
QStringList data;
|
|
|
|
QStringList data, dataA, dataB;
|
|
|
|
QString result;
|
|
|
|
QString trailerA, trailerB;
|
|
|
|
bool isKeyAValid;
|
|
|
|
|
|
|
|
bool isKeyBValid;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
QString tmp;
|
|
|
|
|
|
|
|
for(int i = 0; i < cardType.sector_size; i++)
|
|
|
|
for(int i = 0; i < cardType.sector_size; i++)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
result = "";
|
|
|
|
|
|
|
|
isKeyAValid = false;
|
|
|
|
|
|
|
|
isKeyBValid = false;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// check keys and read the first block of each sector
|
|
|
|
|
|
|
|
data = _readsec(i, Mifare::KEY_A, keyAList->at(i));
|
|
|
|
|
|
|
|
if(data.size() > 0)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
isKeyAValid = true;
|
|
|
|
|
|
|
|
for(int j = 0; j < cardType.blk[i]; j++)
|
|
|
|
for(int j = 0; j < cardType.blk[i]; j++)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
dataList->replace(cardType.blks[i] + j, data[j]);
|
|
|
|
// dataA is always filled with "" because of the _readsec()
|
|
|
|
data_syncWithDataWidget(false, cardType.blks[i] + j);
|
|
|
|
data.append("");
|
|
|
|
}
|
|
|
|
dataB.append("");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
data.clear();
|
|
|
|
dataA = _readsec(i, Mifare::KEY_A, keyAList->at(i));
|
|
|
|
data = _readsec(i, Mifare::KEY_B, keyBList->at(i));
|
|
|
|
if(dataA.contains("") || dataA[cardType.blk[i] - 1].right(12) == "????????????")
|
|
|
|
if(data.size() > 0)
|
|
|
|
dataB = _readsec(i, Mifare::KEY_B, keyBList->at(i));
|
|
|
|
{
|
|
|
|
|
|
|
|
isKeyBValid = true;
|
|
|
|
|
|
|
|
for(int j = 0; j < cardType.blk[i]; j++)
|
|
|
|
for(int j = 0; j < cardType.blk[i]; j++)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
dataList->replace(cardType.blks[i] + j, data[j]);
|
|
|
|
if(dataA[j] != "")
|
|
|
|
data_syncWithDataWidget(false, cardType.blks[i] + j);
|
|
|
|
data[j] = dataA[j];
|
|
|
|
}
|
|
|
|
else
|
|
|
|
|
|
|
|
data[j] = dataB[j];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// check keys and read the first block of each sector
|
|
|
|
// process trailer block seperately
|
|
|
|
|
|
|
|
trailerA = dataA[cardType.blk[i] - 1];
|
|
|
|
if(isKeyAValid || isKeyBValid)
|
|
|
|
trailerB = dataB[cardType.blk[i] - 1];
|
|
|
|
|
|
|
|
if(trailerA != "" && trailerB != "")
|
|
|
|
{
|
|
|
|
{
|
|
|
|
|
|
|
|
QString ACbits = trailerA.mid(12, 8);
|
|
|
|
// fill the MF_dataWidget with the known valid key
|
|
|
|
QString key_A = trailerA.left(12);
|
|
|
|
//
|
|
|
|
QString key_B = trailerA.at(31) != '?' ? trailerA.right(12) : trailerB.right(12);
|
|
|
|
// check whether the MF_dataWidget contains the valid key,
|
|
|
|
data[cardType.blk[i] - 1] = key_A + ACbits + key_B;
|
|
|
|
// and fill MF_keyWidget(when you only have KeyA but the ReadBlock output
|
|
|
|
|
|
|
|
// contains the KeyB)
|
|
|
|
|
|
|
|
//
|
|
|
|
|
|
|
|
// the structure is not symmetric, since you cannot get KeyA from output
|
|
|
|
|
|
|
|
// this program will only process the provided KeyA(in MF_keyWidget)
|
|
|
|
|
|
|
|
result = dataList->at(cardType.blks[i] + cardType.blk[i] - 1);
|
|
|
|
|
|
|
|
if(isKeyAValid)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
result.replace(0, 12, keyAList->at(i));
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
result = result.replace(0, 12, "????????????");
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
dataList->replace(cardType.blks[i] + cardType.blk[i] - 1, result);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if(isKeyBValid)
|
|
|
|
for(int j = 0; j < cardType.blk[i]; j++)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
result.replace(20, 12, keyBList->at(i));
|
|
|
|
dataList->replace(cardType.blks[i] + j, data[j]);
|
|
|
|
dataList->replace(cardType.blks[i] + cardType.blk[i] - 1, result);
|
|
|
|
data_syncWithDataWidget(false, cardType.blks[i] + j);
|
|
|
|
data_syncWithDataWidget(false, cardType.blks[i] + cardType.blk[i] - 1);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else // now isKeyAValid == true, the output might contains the KeyB
|
|
|
|
|
|
|
|
{
|
|
|
|
// data widget has been updated, so this is just a temporary varient.
|
|
|
|
QString tmpKey =
|
|
|
|
if(data[cardType.blk[i] - 1] == "")
|
|
|
|
dataList->at(cardType.blks[i] + cardType.blk[i] - 1).right(12);
|
|
|
|
data[cardType.blk[i] - 1] = "????????????????????????????????";
|
|
|
|
result = _readblk(cardType.blks[i] + cardType.blk[i] - 1, Mifare::KEY_B, tmpKey);
|
|
|
|
|
|
|
|
if(result != "")
|
|
|
|
// doesn't replace the existing key.
|
|
|
|
{
|
|
|
|
if(keyAList->at(i) == "" || keyAList->at(i) == "????????????")
|
|
|
|
keyBList->replace(i, tmpKey);
|
|
|
|
keyAList->replace(i, data[cardType.blk[i] - 1].left(12));
|
|
|
|
|
|
|
|
if(keyBList->at(i) == "" || keyBList->at(i) == "????????????")
|
|
|
|
|
|
|
|
keyBList->replace(i, data[cardType.blk[i] - 1].right(12));
|
|
|
|
|
|
|
|
data_syncWithKeyWidget(false, i, KEY_A);
|
|
|
|
data_syncWithKeyWidget(false, i, KEY_B);
|
|
|
|
data_syncWithKeyWidget(false, i, KEY_B);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
result = dataList->at(cardType.blks[i] + cardType.blk[i] - 1);
|
|
|
|
|
|
|
|
result = result.replace(20, 12, "????????????");
|
|
|
|
|
|
|
|
dataList->replace(cardType.blks[i] + cardType.blk[i] - 1, result);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
data_syncWithDataWidget(false, cardType.blks[i] + cardType.blk[i] - 1);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Mifare::write()
|
|
|
|
void Mifare::write()
|
|
|
|