mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2024-09-20 15:26:13 +08:00
FIX: a solution for the issue "hf mf esave - always saves 4K"
FIX: a solution for the issue "hf eload, esave, cload, save - filepath variable too short" CHG: minor code clean up. ADD: AES / CRC16 for lua. (and tnp3xx scripts.) ADD: tnp3dump.lua script to dump tnp3xx tags. ADD: tnp3sim.lua script to let PM3 imitate an tnp3xx tag. Needs to be tested live
This commit is contained in:
parent
d91a31f935
commit
b915fda392
|
@ -696,7 +696,7 @@ int CmdFSKdemod(const char *Cmd) //old CmdFSKdemod needs updating
|
|||
|
||||
int lowLen = sizeof (LowTone) / sizeof (int);
|
||||
int highLen = sizeof (HighTone) / sizeof (int);
|
||||
int convLen = (highLen > lowLen) ? highLen : lowLen; //if highlen > lowLen then highlen else lowlen
|
||||
int convLen = (highLen > lowLen) ? highLen : lowLen;
|
||||
uint32_t hi = 0, lo = 0;
|
||||
|
||||
int i, j;
|
||||
|
@ -942,9 +942,16 @@ int CmdTuneSamples(const char *Cmd)
|
|||
|
||||
int CmdLoad(const char *Cmd)
|
||||
{
|
||||
FILE *f = fopen(Cmd, "r");
|
||||
char filename[FILE_PATH_SIZE] = {0x00};
|
||||
int len = 0;
|
||||
|
||||
len = strlen(Cmd);
|
||||
if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE;
|
||||
memcpy(filename, Cmd, len);
|
||||
|
||||
FILE *f = fopen(filename, "r");
|
||||
if (!f) {
|
||||
PrintAndLog("couldn't open '%s'", Cmd);
|
||||
PrintAndLog("couldn't open '%s'", filename);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1250,9 +1257,17 @@ int CmdPlot(const char *Cmd)
|
|||
|
||||
int CmdSave(const char *Cmd)
|
||||
{
|
||||
FILE *f = fopen(Cmd, "w");
|
||||
char filename[FILE_PATH_SIZE] = {0x00};
|
||||
int len = 0;
|
||||
|
||||
len = strlen(Cmd);
|
||||
if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE;
|
||||
memcpy(filename, Cmd, len);
|
||||
|
||||
|
||||
FILE *f = fopen(filename, "w");
|
||||
if(!f) {
|
||||
PrintAndLog("couldn't open '%s'", Cmd);
|
||||
PrintAndLog("couldn't open '%s'", filename);
|
||||
return 0;
|
||||
}
|
||||
int i;
|
||||
|
|
|
@ -47,9 +47,11 @@ int CmdHFTune(const char *Cmd)
|
|||
#define iso14443_CMD_WUPA 0x52
|
||||
#define iso14443_CMD_SELECT 0x93
|
||||
#define iso14443_CMD_SELECT_2 0x95
|
||||
#define iso14443_CMD_SELECT_3 0x97
|
||||
#define iso14443_CMD_REQ 0x26
|
||||
#define iso14443_CMD_READBLOCK 0x30
|
||||
#define iso14443_CMD_WRITEBLOCK 0xA0
|
||||
#define iso14443_CMD_WRITE 0xA2
|
||||
#define iso14443_CMD_INC 0xC0
|
||||
#define iso14443_CMD_DEC 0xC1
|
||||
#define iso14443_CMD_RESTORE 0xC2
|
||||
|
@ -57,6 +59,15 @@ int CmdHFTune(const char *Cmd)
|
|||
#define iso14443_CMD_HALT 0x50
|
||||
#define iso14443_CMD_RATS 0xE0
|
||||
|
||||
#define iso14443_CMD_AUTH_KEYA 0x60
|
||||
#define iso14443_CMD_AUTH_KEYB 0x61
|
||||
|
||||
#define iso14443_CMD_AUTH_STEP1 0x1A
|
||||
#define iso14443_CMD_AUTH_STEP2 0xAA
|
||||
#define iso14443_CMD_AUTH_RESPONSE 0xAF
|
||||
|
||||
#define CHINESE_BACKDOOR_INIT 0x40
|
||||
#define CHINESE_BACKDOOR_STEP2 0x43
|
||||
|
||||
void annotateIso14443a(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize)
|
||||
{
|
||||
|
@ -76,12 +87,22 @@ void annotateIso14443a(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize)
|
|||
case iso14443_CMD_REQ: snprintf(exp,size,"REW"); break;
|
||||
case iso14443_CMD_READBLOCK: snprintf(exp,size,"READBLOCK(%d)",cmd[1]); break;
|
||||
case iso14443_CMD_WRITEBLOCK: snprintf(exp,size,"WRITEBLOCK(%d)",cmd[1]); break;
|
||||
case iso14443_CMD_WRITE: snprintf(exp,size,"WRITE"); break;
|
||||
case iso14443_CMD_INC: snprintf(exp,size,"INC(%d)",cmd[1]); break;
|
||||
case iso14443_CMD_DEC: snprintf(exp,size,"DEC(%d)",cmd[1]); break;
|
||||
case iso14443_CMD_RESTORE: snprintf(exp,size,"RESTORE(%d)",cmd[1]); break;
|
||||
case iso14443_CMD_TRANSFER: snprintf(exp,size,"TRANSFER(%d)",cmd[1]); break;
|
||||
case iso14443_CMD_HALT: snprintf(exp,size,"HALT"); break;
|
||||
case iso14443_CMD_RATS: snprintf(exp,size,"RATS"); break;
|
||||
|
||||
case iso14443_CMD_AUTH_KEYA: snprintf(exp,size,"AUTH KEY A"); break;
|
||||
case iso14443_CMD_AUTH_KEYB: snprintf(exp,size,"AUTH KEY B"); break;
|
||||
case iso14443_CMD_AUTH_STEP1: snprintf(exp,size,"AUTH REQ NONCE"); break;
|
||||
case iso14443_CMD_AUTH_STEP2: snprintf(exp,size,"AUTH STEP 2"); break;
|
||||
case iso14443_CMD_AUTH_RESPONSE: snprintf(exp,size,"AUTH RESPONSE"); break;
|
||||
|
||||
case CHINESE_BACKDOOR_INIT: snprintf(exp,size,"BACKDOOR INIT");break;
|
||||
case CHINESE_BACKDOOR_STEP2: snprintf(exp,size,"BACKDOOR STEP2");break;
|
||||
default: snprintf(exp,size,"?"); break;
|
||||
}
|
||||
return;
|
||||
|
@ -89,7 +110,6 @@ void annotateIso14443a(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize)
|
|||
|
||||
void annotateIclass(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize)
|
||||
{
|
||||
|
||||
if(cmdsize > 1 && cmd[0] == ICLASS_CMD_READ)
|
||||
{
|
||||
snprintf(exp,size,"READ(%d)",cmd[1]);
|
||||
|
@ -112,7 +132,6 @@ void annotateIclass(char *exp, size_t size, uint8_t* cmd, uint8_t cmdsize)
|
|||
}
|
||||
|
||||
|
||||
|
||||
uint16_t printTraceLine(uint16_t tracepos, uint8_t* trace, bool iclass, bool showWaitCycles)
|
||||
{
|
||||
bool isResponse;
|
||||
|
@ -178,8 +197,7 @@ uint16_t printTraceLine(uint16_t tracepos, uint8_t* trace, bool iclass, bool sho
|
|||
// Rough guess that this is a command from the reader
|
||||
// For iClass the command byte is not part of the CRC
|
||||
ComputeCrc14443(CRC_ICLASS, &frame[1], data_len-3, &b1, &b2);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// For other data.. CRC might not be applicable (UPDATE commands etc.)
|
||||
ComputeCrc14443(CRC_ICLASS, frame, data_len-2, &b1, &b2);
|
||||
}
|
||||
|
@ -199,7 +217,6 @@ uint16_t printTraceLine(uint16_t tracepos, uint8_t* trace, bool iclass, bool sho
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
char *crc = crcError ? "!crc" :" ";
|
||||
|
||||
|
@ -207,8 +224,10 @@ uint16_t printTraceLine(uint16_t tracepos, uint8_t* trace, bool iclass, bool sho
|
|||
|
||||
if(!isResponse)
|
||||
{
|
||||
if(iclass) annotateIclass(explanation,sizeof(explanation),frame,data_len);
|
||||
else annotateIso14443a(explanation,sizeof(explanation),frame,data_len);
|
||||
if(iclass)
|
||||
annotateIclass(explanation,sizeof(explanation),frame,data_len);
|
||||
else
|
||||
annotateIso14443a(explanation,sizeof(explanation),frame,data_len);
|
||||
}
|
||||
|
||||
int num_lines = (data_len - 1)/16 + 1;
|
||||
|
|
|
@ -111,7 +111,7 @@ const manufactureName manufactureMapping[] = {
|
|||
// get a product description based on the UID
|
||||
// uid[8] tag uid
|
||||
// returns description of the best match
|
||||
static char* getTagInfo(uint8_t uid) {
|
||||
char* getTagInfo(uint8_t uid) {
|
||||
|
||||
int i, best = -1;
|
||||
int len = sizeof(manufactureMapping) / sizeof(manufactureName);
|
||||
|
@ -168,6 +168,7 @@ int CmdHF14AReader(const char *Cmd)
|
|||
PrintAndLog(" SAK : %02x [%d]", card.sak, resp.arg[0]);
|
||||
|
||||
// Double & triple sized UID, can be mapped to a manufacturer.
|
||||
// HACK: does this apply for Ultralight cards?
|
||||
if ( card.uidlen > 4 ) {
|
||||
PrintAndLog("MANUFACTURER : %s", getTagInfo(card.uid[0]));
|
||||
}
|
||||
|
@ -624,7 +625,7 @@ static void waitCmd(uint8_t iSelect)
|
|||
UsbCommand resp;
|
||||
char *hexout;
|
||||
|
||||
if (WaitForResponseTimeout(CMD_ACK,&resp,1000)) {
|
||||
if (WaitForResponseTimeout(CMD_ACK,&resp,1500)) {
|
||||
recv = resp.d.asBytes;
|
||||
uint8_t iLen = iSelect ? resp.arg[1] : resp.arg[0];
|
||||
PrintAndLog("received %i octets",iLen);
|
||||
|
|
|
@ -20,5 +20,5 @@ int CmdHF14AReader(const char *Cmd);
|
|||
int CmdHF14ASim(const char *Cmd);
|
||||
int CmdHF14ASnoop(const char *Cmd);
|
||||
|
||||
|
||||
char* getTagInfo(uint8_t uid);
|
||||
#endif
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
#include "cmdhf14b.h"
|
||||
#include "cmdmain.h"
|
||||
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
int CmdHF14BDemod(const char *Cmd)
|
||||
|
@ -146,7 +145,7 @@ demodError:
|
|||
|
||||
int CmdHF14BList(const char *Cmd)
|
||||
{
|
||||
uint8_t got[960];
|
||||
uint8_t got[TRACE_BUFFER_SIZE];
|
||||
GetFromBigBuf(got,sizeof(got),0);
|
||||
WaitForResponse(CMD_ACK,NULL);
|
||||
|
||||
|
@ -158,9 +157,8 @@ int CmdHF14BList(const char *Cmd)
|
|||
int prev = -1;
|
||||
|
||||
for(;;) {
|
||||
if(i >= 900) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(i >= TRACE_BUFFER_SIZE) { break; }
|
||||
|
||||
bool isResponse;
|
||||
int timestamp = *((uint32_t *)(got+i));
|
||||
|
@ -177,7 +175,7 @@ int CmdHF14BList(const char *Cmd)
|
|||
if(len > 100) {
|
||||
break;
|
||||
}
|
||||
if(i + len >= 900) {
|
||||
if(i + len >= TRACE_BUFFER_SIZE) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -218,7 +218,24 @@ int CmdLegicRFRead(const char *Cmd)
|
|||
|
||||
int CmdLegicLoad(const char *Cmd)
|
||||
{
|
||||
FILE *f = fopen(Cmd, "r");
|
||||
char filename[FILE_PATH_SIZE] = {0x00};
|
||||
int len = 0;
|
||||
|
||||
if (param_getchar(Cmd, 0) == 'h' || param_getchar(Cmd, 0)== 0x00) {
|
||||
PrintAndLog("It loads datasamples from the file `filename`");
|
||||
PrintAndLog("Usage: hf legic load <file name>");
|
||||
PrintAndLog(" sample: hf legic load filename");
|
||||
return 0;
|
||||
}
|
||||
|
||||
len = strlen(Cmd);
|
||||
if (len > FILE_PATH_SIZE) {
|
||||
PrintAndLog("Filepath too long (was %s bytes), max allowed is %s ", len, FILE_PATH_SIZE);
|
||||
return 0;
|
||||
}
|
||||
memcpy(filename, Cmd, len);
|
||||
|
||||
FILE *f = fopen(filename, "r");
|
||||
if(!f) {
|
||||
PrintAndLog("couldn't open '%s'", Cmd);
|
||||
return -1;
|
||||
|
@ -251,7 +268,7 @@ int CmdLegicSave(const char *Cmd)
|
|||
int requested = 1024;
|
||||
int offset = 0;
|
||||
int delivered = 0;
|
||||
char filename[1024];
|
||||
char filename[FILE_PATH_SIZE];
|
||||
uint8_t got[1024];
|
||||
|
||||
sscanf(Cmd, " %s %i %i", filename, &requested, &offset);
|
||||
|
|
196
client/cmdhfmf.c
196
client/cmdhfmf.c
|
@ -66,8 +66,7 @@ start:
|
|||
if (isOK != 1) return 1;
|
||||
|
||||
// execute original function from util nonce2key
|
||||
if (nonce2key(uid, nt, nr, par_list, ks_list, &r_key))
|
||||
{
|
||||
if (nonce2key(uid, nt, nr, par_list, ks_list, &r_key)) {
|
||||
isOK = 2;
|
||||
PrintAndLog("Key not found (lfsr_common_prefix list is null). Nt=%08x", nt);
|
||||
} else {
|
||||
|
@ -512,6 +511,7 @@ int CmdHF14AMfDump(const char *Cmd)
|
|||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fin);
|
||||
// Read access rights to sectors
|
||||
|
||||
|
@ -629,8 +629,8 @@ int CmdHF14AMfRestore(const char *Cmd)
|
|||
{
|
||||
uint8_t sectorNo,blockNo;
|
||||
uint8_t keyType = 0;
|
||||
uint8_t key[6] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
|
||||
uint8_t bldata[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
uint8_t key[6] = {0xFF};
|
||||
uint8_t bldata[16] = {0x00};
|
||||
uint8_t keyA[40][6];
|
||||
uint8_t keyB[40][6];
|
||||
uint8_t numSectors;
|
||||
|
@ -657,21 +657,14 @@ int CmdHF14AMfRestore(const char *Cmd)
|
|||
return 0;
|
||||
}
|
||||
|
||||
if ((fdump = fopen("dumpdata.bin","rb")) == NULL) {
|
||||
PrintAndLog("Could not find file dumpdata.bin");
|
||||
return 1;
|
||||
}
|
||||
if ((fkeys = fopen("dumpkeys.bin","rb")) == NULL) {
|
||||
PrintAndLog("Could not find file dumpkeys.bin");
|
||||
fclose(fdump);
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (sectorNo = 0; sectorNo < numSectors; sectorNo++) {
|
||||
if (fread(keyA[sectorNo], 1, 6, fkeys) == 0) {
|
||||
PrintAndLog("File reading error (dumpkeys.bin).");
|
||||
fclose(fdump);
|
||||
fclose(fkeys);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
@ -679,13 +672,16 @@ int CmdHF14AMfRestore(const char *Cmd)
|
|||
for (sectorNo = 0; sectorNo < numSectors; sectorNo++) {
|
||||
if (fread(keyB[sectorNo], 1, 6, fkeys) == 0) {
|
||||
PrintAndLog("File reading error (dumpkeys.bin).");
|
||||
fclose(fdump);
|
||||
fclose(fkeys);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fkeys);
|
||||
|
||||
if ((fdump = fopen("dumpdata.bin","rb")) == NULL) {
|
||||
PrintAndLog("Could not find file dumpdata.bin");
|
||||
return 1;
|
||||
}
|
||||
PrintAndLog("Restoring dumpdata.bin to card");
|
||||
|
||||
for (sectorNo = 0; sectorNo < numSectors; sectorNo++) {
|
||||
|
@ -773,11 +769,15 @@ int CmdHF14AMfNested(const char *Cmd)
|
|||
cmdp = param_getchar(Cmd, 0);
|
||||
blockNo = param_get8(Cmd, 1);
|
||||
ctmp = param_getchar(Cmd, 2);
|
||||
|
||||
if (ctmp != 'a' && ctmp != 'A' && ctmp != 'b' && ctmp != 'B') {
|
||||
PrintAndLog("Key type must be A or B");
|
||||
return 1;
|
||||
}
|
||||
if (ctmp != 'A' && ctmp != 'a') keyType = 1;
|
||||
|
||||
if (ctmp != 'A' && ctmp != 'a')
|
||||
keyType = 1;
|
||||
|
||||
if (param_gethex(Cmd, 3, key, 12)) {
|
||||
PrintAndLog("Key must include 12 HEX symbols");
|
||||
return 1;
|
||||
|
@ -791,8 +791,10 @@ int CmdHF14AMfNested(const char *Cmd)
|
|||
PrintAndLog("Target key type must be A or B");
|
||||
return 1;
|
||||
}
|
||||
if (ctmp != 'A' && ctmp != 'a') trgKeyType = 1;
|
||||
if (ctmp != 'A' && ctmp != 'a')
|
||||
trgKeyType = 1;
|
||||
} else {
|
||||
|
||||
switch (cmdp) {
|
||||
case '0': SectorsCnt = 05; break;
|
||||
case '1': SectorsCnt = 16; break;
|
||||
|
@ -869,7 +871,6 @@ int CmdHF14AMfNested(const char *Cmd)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// nested sectors
|
||||
iterations = 0;
|
||||
PrintAndLog("nested...");
|
||||
|
@ -972,7 +973,7 @@ int CmdHF14AMfChk(const char *Cmd)
|
|||
}
|
||||
|
||||
FILE * f;
|
||||
char filename[256]={0};
|
||||
char filename[FILE_PATH_SIZE]={0};
|
||||
char buf[13];
|
||||
uint8_t *keyBlock = NULL, *p;
|
||||
uint8_t stKeyBlock = 20;
|
||||
|
@ -988,7 +989,6 @@ int CmdHF14AMfChk(const char *Cmd)
|
|||
int transferToEml = 0;
|
||||
int createDumpFile = 0;
|
||||
|
||||
|
||||
keyBlock = calloc(stKeyBlock, 6);
|
||||
if (keyBlock == NULL) return 1;
|
||||
|
||||
|
@ -1065,7 +1065,7 @@ int CmdHF14AMfChk(const char *Cmd)
|
|||
keycnt++;
|
||||
} else {
|
||||
// May be a dic file
|
||||
if ( param_getstr(Cmd, 2 + i,filename) > 255 ) {
|
||||
if ( param_getstr(Cmd, 2 + i,filename) >= FILE_PATH_SIZE ) {
|
||||
PrintAndLog("File name too long");
|
||||
free(keyBlock);
|
||||
return 2;
|
||||
|
@ -1346,26 +1346,44 @@ int CmdHF14AMfESet(const char *Cmd)
|
|||
int CmdHF14AMfELoad(const char *Cmd)
|
||||
{
|
||||
FILE * f;
|
||||
char filename[20];
|
||||
char filename[FILE_PATH_SIZE];
|
||||
char *fnameptr = filename;
|
||||
char buf[64];
|
||||
uint8_t buf8[64];
|
||||
int i, len, blockNum;
|
||||
int i, len, blockNum, numBlocks;
|
||||
int nameParamNo = 1;
|
||||
|
||||
memset(filename, 0, sizeof(filename));
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
if (param_getchar(Cmd, 0) == 'h' || param_getchar(Cmd, 0)== 0x00) {
|
||||
char ctmp = param_getchar(Cmd, 0);
|
||||
|
||||
if ( ctmp == 'h' || ctmp == 0x00) {
|
||||
PrintAndLog("It loads emul dump from the file `filename.eml`");
|
||||
PrintAndLog("Usage: hf mf eload <file name w/o `.eml`>");
|
||||
PrintAndLog("Usage: hf mf eload [card memory] <file name w/o `.eml`>");
|
||||
PrintAndLog(" [card memory]: 0 = 320 bytes (Mifare Mini), 1 = 1K (default), 2 = 2K, 4 = 4K");
|
||||
PrintAndLog("");
|
||||
PrintAndLog(" sample: hf mf eload filename");
|
||||
PrintAndLog(" hf mf eload 4 filename");
|
||||
return 0;
|
||||
}
|
||||
|
||||
len = strlen(Cmd);
|
||||
if (len > 14) len = 14;
|
||||
switch (ctmp) {
|
||||
case '0' : numBlocks = 5*4; break;
|
||||
case '1' :
|
||||
case '\0': numBlocks = 16*4; break;
|
||||
case '2' : numBlocks = 32*4; break;
|
||||
case '4' : numBlocks = 256; break;
|
||||
default: {
|
||||
numBlocks = 16*4;
|
||||
nameParamNo = 0;
|
||||
}
|
||||
}
|
||||
|
||||
len = param_getstr(Cmd,nameParamNo,filename);
|
||||
|
||||
if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE;
|
||||
|
||||
memcpy(filename, Cmd, len);
|
||||
fnameptr += len;
|
||||
|
||||
sprintf(fnameptr, ".eml");
|
||||
|
@ -1380,14 +1398,16 @@ int CmdHF14AMfELoad(const char *Cmd)
|
|||
blockNum = 0;
|
||||
while(!feof(f)){
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
if (fgets(buf, sizeof(buf), f) == NULL) {
|
||||
if((blockNum == 16*4) || (blockNum == 32*4 + 8*16)) { // supports both old (1K) and new (4K) .eml files)
|
||||
break;
|
||||
}
|
||||
|
||||
if (blockNum >= numBlocks) break;
|
||||
|
||||
PrintAndLog("File reading error.");
|
||||
fclose(f);
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (strlen(buf) < 32){
|
||||
if(strlen(buf) && feof(f))
|
||||
break;
|
||||
|
@ -1395,6 +1415,7 @@ int CmdHF14AMfELoad(const char *Cmd)
|
|||
fclose(f);
|
||||
return 2;
|
||||
}
|
||||
|
||||
for (i = 0; i < 32; i += 2) {
|
||||
sscanf(&buf[i], "%02x", (unsigned int *)&buf8[i / 2]);
|
||||
}
|
||||
|
@ -1406,12 +1427,12 @@ int CmdHF14AMfELoad(const char *Cmd)
|
|||
}
|
||||
blockNum++;
|
||||
|
||||
if (blockNum >= 32*4 + 8*16) break;
|
||||
if (blockNum >= numBlocks) break;
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
if ((blockNum != 16*4) && (blockNum != 32*4 + 8*16)) {
|
||||
PrintAndLog("File content error. There must be 64 or 256 blocks.");
|
||||
if ((blockNum != numBlocks)) {
|
||||
PrintAndLog("File content error. Got %d must be %d blocks.",blockNum, numBlocks);
|
||||
return 4;
|
||||
}
|
||||
PrintAndLog("Loaded %d blocks from file: %s", blockNum, filename);
|
||||
|
@ -1422,45 +1443,70 @@ int CmdHF14AMfELoad(const char *Cmd)
|
|||
int CmdHF14AMfESave(const char *Cmd)
|
||||
{
|
||||
FILE * f;
|
||||
char filename[20];
|
||||
char filename[FILE_PATH_SIZE];
|
||||
char * fnameptr = filename;
|
||||
uint8_t buf[64];
|
||||
int i, j, len;
|
||||
int i, j, len, numBlocks;
|
||||
int nameParamNo = 1;
|
||||
|
||||
memset(filename, 0, sizeof(filename));
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
||||
if (param_getchar(Cmd, 0) == 'h') {
|
||||
char ctmp = param_getchar(Cmd, 0);
|
||||
|
||||
if ( ctmp == 'h' || ctmp == 'H') {
|
||||
PrintAndLog("It saves emul dump into the file `filename.eml` or `cardID.eml`");
|
||||
PrintAndLog("Usage: hf mf esave [file name w/o `.eml`]");
|
||||
PrintAndLog(" Usage: hf mf esave [card memory] [file name w/o `.eml`]");
|
||||
PrintAndLog(" [card memory]: 0 = 320 bytes (Mifare Mini), 1 = 1K (default), 2 = 2K, 4 = 4K");
|
||||
PrintAndLog("");
|
||||
PrintAndLog(" sample: hf mf esave ");
|
||||
PrintAndLog(" hf mf esave filename");
|
||||
PrintAndLog(" hf mf esave 4");
|
||||
PrintAndLog(" hf mf esave 4 filename");
|
||||
return 0;
|
||||
}
|
||||
|
||||
len = strlen(Cmd);
|
||||
if (len > 14) len = 14;
|
||||
switch (ctmp) {
|
||||
case '0' : numBlocks = 5*4; break;
|
||||
case '1' :
|
||||
case '\0': numBlocks = 16*4; break;
|
||||
case '2' : numBlocks = 32*4; break;
|
||||
case '4' : numBlocks = 256; break;
|
||||
default: {
|
||||
numBlocks = 16*4;
|
||||
nameParamNo = 0;
|
||||
}
|
||||
}
|
||||
|
||||
len = param_getstr(Cmd,nameParamNo,filename);
|
||||
|
||||
if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE;
|
||||
|
||||
// user supplied filename?
|
||||
if (len < 1) {
|
||||
// get filename
|
||||
// get filename (UID from memory)
|
||||
if (mfEmlGetMem(buf, 0, 1)) {
|
||||
PrintAndLog("Cant get block: %d", 0);
|
||||
return 1;
|
||||
PrintAndLog("Can\'t get UID from block: %d", 0);
|
||||
sprintf(filename, "dump.eml");
|
||||
}
|
||||
for (j = 0; j < 7; j++, fnameptr += 2)
|
||||
sprintf(fnameptr, "%02x", buf[j]);
|
||||
sprintf(fnameptr, "%02X", buf[j]);
|
||||
} else {
|
||||
memcpy(filename, Cmd, len);
|
||||
fnameptr += len;
|
||||
}
|
||||
|
||||
// add file extension
|
||||
sprintf(fnameptr, ".eml");
|
||||
|
||||
// open file
|
||||
f = fopen(filename, "w+");
|
||||
|
||||
if ( !f ) {
|
||||
PrintAndLog("Can't open file %s ", filename);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// put hex
|
||||
for (i = 0; i < 32*4 + 8*16; i++) {
|
||||
for (i = 0; i < numBlocks; i++) {
|
||||
if (mfEmlGetMem(buf, i, 1)) {
|
||||
PrintAndLog("Cant get block: %d", i);
|
||||
break;
|
||||
|
@ -1471,7 +1517,7 @@ int CmdHF14AMfESave(const char *Cmd)
|
|||
}
|
||||
fclose(f);
|
||||
|
||||
PrintAndLog("Saved to file: %s", filename);
|
||||
PrintAndLog("Saved %d blocks to file: %s", numBlocks, filename);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1520,13 +1566,34 @@ int CmdHF14AMfECFill(const char *Cmd)
|
|||
int CmdHF14AMfEKeyPrn(const char *Cmd)
|
||||
{
|
||||
int i;
|
||||
uint8_t numSectors;
|
||||
uint8_t data[16];
|
||||
uint64_t keyA, keyB;
|
||||
|
||||
if (param_getchar(Cmd, 0) == 'h') {
|
||||
PrintAndLog("It prints the keys loaded in the emulator memory");
|
||||
PrintAndLog("Usage: hf mf ekeyprn [card memory]");
|
||||
PrintAndLog(" [card memory]: 0 = 320 bytes (Mifare Mini), 1 = 1K (default), 2 = 2K, 4 = 4K");
|
||||
PrintAndLog("");
|
||||
PrintAndLog(" sample: hf mf ekeyprn 1");
|
||||
return 0;
|
||||
}
|
||||
|
||||
char cmdp = param_getchar(Cmd, 0);
|
||||
|
||||
switch (cmdp) {
|
||||
case '0' : numSectors = 5; break;
|
||||
case '1' :
|
||||
case '\0': numSectors = 16; break;
|
||||
case '2' : numSectors = 32; break;
|
||||
case '4' : numSectors = 40; break;
|
||||
default: numSectors = 16;
|
||||
}
|
||||
|
||||
PrintAndLog("|---|----------------|----------------|");
|
||||
PrintAndLog("|sec|key A |key B |");
|
||||
PrintAndLog("|---|----------------|----------------|");
|
||||
for (i = 0; i < 40; i++) {
|
||||
for (i = 0; i < numSectors; i++) {
|
||||
if (mfEmlGetMem(data, FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1, 1)) {
|
||||
PrintAndLog("error get block %d", FirstBlockOfSector(i) + NumBlocksPerSector(i) - 1);
|
||||
break;
|
||||
|
@ -1616,15 +1683,15 @@ int CmdHF14AMfCSetBlk(const char *Cmd)
|
|||
int CmdHF14AMfCLoad(const char *Cmd)
|
||||
{
|
||||
FILE * f;
|
||||
char filename[20];
|
||||
char filename[FILE_PATH_SIZE] = {0x00};
|
||||
char * fnameptr = filename;
|
||||
char buf[64];
|
||||
uint8_t buf8[64];
|
||||
char buf[64] = {0x00};
|
||||
uint8_t buf8[64] = {0x00};
|
||||
uint8_t fillFromEmulator = 0;
|
||||
int i, len, blockNum, flags;
|
||||
|
||||
memset(filename, 0, sizeof(filename));
|
||||
memset(buf, 0, sizeof(buf));
|
||||
// memset(filename, 0, sizeof(filename));
|
||||
// memset(buf, 0, sizeof(buf));
|
||||
|
||||
if (param_getchar(Cmd, 0) == 'h' || param_getchar(Cmd, 0)== 0x00) {
|
||||
PrintAndLog("It loads magic Chinese card (only works with!!!) from the file `filename.eml`");
|
||||
|
@ -1657,7 +1724,7 @@ int CmdHF14AMfCLoad(const char *Cmd)
|
|||
return 0;
|
||||
} else {
|
||||
len = strlen(Cmd);
|
||||
if (len > 14) len = 14;
|
||||
if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE;
|
||||
|
||||
memcpy(filename, Cmd, len);
|
||||
fnameptr += len;
|
||||
|
@ -1702,7 +1769,7 @@ int CmdHF14AMfCLoad(const char *Cmd)
|
|||
}
|
||||
fclose(f);
|
||||
|
||||
if (blockNum != 16 * 4){
|
||||
if (blockNum != 16 * 4 && blockNum != 32 * 4 + 8 * 16){
|
||||
PrintAndLog("File content error. There must be 64 blocks");
|
||||
return 4;
|
||||
}
|
||||
|
@ -1780,14 +1847,14 @@ int CmdHF14AMfCGetSc(const char *Cmd) {
|
|||
int CmdHF14AMfCSave(const char *Cmd) {
|
||||
|
||||
FILE * f;
|
||||
char filename[20];
|
||||
char filename[FILE_PATH_SIZE] = {0x00};
|
||||
char * fnameptr = filename;
|
||||
uint8_t fillFromEmulator = 0;
|
||||
uint8_t buf[64];
|
||||
uint8_t buf[64] = {0x00};
|
||||
int i, j, len, flags;
|
||||
|
||||
memset(filename, 0, sizeof(filename));
|
||||
memset(buf, 0, sizeof(buf));
|
||||
// memset(filename, 0, sizeof(filename));
|
||||
// memset(buf, 0, sizeof(buf));
|
||||
|
||||
if (param_getchar(Cmd, 0) == 'h') {
|
||||
PrintAndLog("It saves `magic Chinese` card dump into the file `filename.eml` or `cardID.eml`");
|
||||
|
@ -1822,7 +1889,7 @@ int CmdHF14AMfCSave(const char *Cmd) {
|
|||
return 0;
|
||||
} else {
|
||||
len = strlen(Cmd);
|
||||
if (len > 14) len = 14;
|
||||
if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE;
|
||||
|
||||
if (len < 1) {
|
||||
// get filename
|
||||
|
@ -1842,6 +1909,11 @@ int CmdHF14AMfCSave(const char *Cmd) {
|
|||
// open file
|
||||
f = fopen(filename, "w+");
|
||||
|
||||
if (f == NULL) {
|
||||
PrintAndLog("File not found or locked.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
// put hex
|
||||
flags = CSETBLOCK_INIT_FIELD + CSETBLOCK_WUPC;
|
||||
for (i = 0; i < 16 * 4; i++) {
|
||||
|
@ -2021,9 +2093,9 @@ static command_t CommandTable[] =
|
|||
{"ecfill", CmdHF14AMfECFill, 0, "Fill simulator memory with help of keys from simulator"},
|
||||
{"ekeyprn", CmdHF14AMfEKeyPrn, 0, "Print keys from simulator memory"},
|
||||
{"csetuid", CmdHF14AMfCSetUID, 0, "Set UID for magic Chinese card"},
|
||||
{"csetblk", CmdHF14AMfCSetBlk, 0, "Write block into magic Chinese card"},
|
||||
{"cgetblk", CmdHF14AMfCGetBlk, 0, "Read block from magic Chinese card"},
|
||||
{"cgetsc", CmdHF14AMfCGetSc, 0, "Read sector from magic Chinese card"},
|
||||
{"csetblk", CmdHF14AMfCSetBlk, 0, "Write block - Magic Chinese card"},
|
||||
{"cgetblk", CmdHF14AMfCGetBlk, 0, "Read block - Magic Chinese card"},
|
||||
{"cgetsc", CmdHF14AMfCGetSc, 0, "Read sector - Magic Chinese card"},
|
||||
{"cload", CmdHF14AMfCLoad, 0, "Load dump into magic Chinese card"},
|
||||
{"csave", CmdHF14AMfCSave, 0, "Save dump from magic Chinese card into file or emulator"},
|
||||
{NULL, NULL, 0, NULL}
|
||||
|
|
|
@ -380,10 +380,8 @@ static void ChkBitstream(const char *str)
|
|||
int i;
|
||||
|
||||
/* convert to bitstream if necessary */
|
||||
for (i = 0; i < (int)(GraphTraceLen / 2); i++)
|
||||
{
|
||||
if (GraphBuffer[i] > 1 || GraphBuffer[i] < 0)
|
||||
{
|
||||
for (i = 0; i < (int)(GraphTraceLen / 2); i++){
|
||||
if (GraphBuffer[i] > 1 || GraphBuffer[i] < 0) {
|
||||
CmdBitstream(str);
|
||||
break;
|
||||
}
|
||||
|
@ -556,11 +554,25 @@ int CmdVchDemod(const char *Cmd)
|
|||
int CmdLFfind(const char *Cmd)
|
||||
{
|
||||
int ans=0;
|
||||
if (!offline){
|
||||
char cmdp = param_getchar(Cmd, 0);
|
||||
|
||||
if (strlen(Cmd) > 1 || cmdp == 'h' || cmdp == 'H') {
|
||||
PrintAndLog("Usage: lf search <0|1>");
|
||||
PrintAndLog(" <use data from Graphbuffer>, if not set, try reading data from tag.");
|
||||
PrintAndLog("");
|
||||
PrintAndLog(" sample: lf search");
|
||||
PrintAndLog(" : lf search 1");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!offline || (cmdp != '1') ){
|
||||
ans=CmdLFRead("");
|
||||
ans=CmdSamples("20000");
|
||||
ans=CmdSamples("20000");
|
||||
} else if (GraphTraceLen < 1000) {
|
||||
PrintAndLog("Data in Graphbuffer was too small.");
|
||||
return 0;
|
||||
}
|
||||
if (GraphTraceLen<1000) return 0;
|
||||
|
||||
PrintAndLog("Checking for known tags:");
|
||||
ans=Cmdaskmandemod("");
|
||||
if (ans>0) return 1;
|
||||
|
|
|
@ -507,12 +507,12 @@ int CmdEM410xWrite(const char *Cmd)
|
|||
|
||||
int CmdReadWord(const char *Cmd)
|
||||
{
|
||||
int Word = 16; //default to invalid word
|
||||
int Word = -1; //default to invalid word
|
||||
UsbCommand c;
|
||||
|
||||
sscanf(Cmd, "%d", &Word);
|
||||
|
||||
if (Word > 15) {
|
||||
if ( (Word > 15) | (Word < 0) ) {
|
||||
PrintAndLog("Word must be between 0 and 15");
|
||||
return 1;
|
||||
}
|
||||
|
@ -530,13 +530,13 @@ int CmdReadWord(const char *Cmd)
|
|||
|
||||
int CmdReadWordPWD(const char *Cmd)
|
||||
{
|
||||
int Word = 16; //default to invalid word
|
||||
int Word = -1; //default to invalid word
|
||||
int Password = 0xFFFFFFFF; //default to blank password
|
||||
UsbCommand c;
|
||||
|
||||
sscanf(Cmd, "%d %x", &Word, &Password);
|
||||
|
||||
if (Word > 15) {
|
||||
if ( (Word > 15) | (Word < 0) ) {
|
||||
PrintAndLog("Word must be between 0 and 15");
|
||||
return 1;
|
||||
}
|
||||
|
@ -565,7 +565,7 @@ int CmdWriteWord(const char *Cmd)
|
|||
return 1;
|
||||
}
|
||||
|
||||
PrintAndLog("Writting word %d with data %08X", Word, Data);
|
||||
PrintAndLog("Writing word %d with data %08X", Word, Data);
|
||||
|
||||
c.cmd = CMD_EM4X_WRITE_WORD;
|
||||
c.d.asBytes[0] = 0x0; //Normal mode
|
||||
|
@ -578,7 +578,7 @@ int CmdWriteWord(const char *Cmd)
|
|||
|
||||
int CmdWriteWordPWD(const char *Cmd)
|
||||
{
|
||||
int Word = 8; //default to invalid word
|
||||
int Word = 16; //default to invalid word
|
||||
int Data = 0xFFFFFFFF; //default to blank data
|
||||
int Password = 0xFFFFFFFF; //default to blank password
|
||||
UsbCommand c;
|
||||
|
@ -590,7 +590,7 @@ int CmdWriteWordPWD(const char *Cmd)
|
|||
return 1;
|
||||
}
|
||||
|
||||
PrintAndLog("Writting word %d with data %08X and password %08X", Word, Data, Password);
|
||||
PrintAndLog("Writing word %d with data %08X and password %08X", Word, Data, Password);
|
||||
|
||||
c.cmd = CMD_EM4X_WRITE_WORD;
|
||||
c.d.asBytes[0] = 0x1; //Password mode
|
||||
|
@ -601,8 +601,6 @@ int CmdWriteWordPWD(const char *Cmd)
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static command_t CommandTable[] =
|
||||
{
|
||||
{"help", CmdHelp, 1, "This help"},
|
||||
|
|
|
@ -29,7 +29,7 @@ size_t nbytes(size_t nbits) {
|
|||
|
||||
int CmdLFHitagList(const char *Cmd)
|
||||
{
|
||||
uint8_t got[3000];
|
||||
uint8_t got[TRACE_BUFFER_SIZE];
|
||||
GetFromBigBuf(got,sizeof(got),0);
|
||||
WaitForResponse(CMD_ACK,NULL);
|
||||
|
||||
|
@ -39,11 +39,25 @@ int CmdLFHitagList(const char *Cmd)
|
|||
|
||||
int i = 0;
|
||||
int prev = -1;
|
||||
int len = strlen(Cmd);
|
||||
|
||||
char filename[FILE_PATH_SIZE] = { 0x00 };
|
||||
FILE* pf = NULL;
|
||||
|
||||
if (len > FILE_PATH_SIZE)
|
||||
len = FILE_PATH_SIZE;
|
||||
memcpy(filename, Cmd, len);
|
||||
|
||||
if (strlen(filename) > 0) {
|
||||
if ((pf = fopen(filename,"wb")) == NULL) {
|
||||
PrintAndLog("Error: Could not open file [%s]",filename);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
if(i >= 1900) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(i >= TRACE_BUFFER_SIZE) { break; }
|
||||
|
||||
bool isResponse;
|
||||
int timestamp = *((uint32_t *)(got+i));
|
||||
|
@ -68,9 +82,7 @@ int CmdLFHitagList(const char *Cmd)
|
|||
if (len > 100) {
|
||||
break;
|
||||
}
|
||||
if (i + len >= 1900) {
|
||||
break;
|
||||
}
|
||||
if (i + len >= TRACE_BUFFER_SIZE) { break;}
|
||||
|
||||
uint8_t *frame = (got+i+9);
|
||||
|
||||
|
@ -103,18 +115,22 @@ int CmdLFHitagList(const char *Cmd)
|
|||
line);
|
||||
|
||||
|
||||
// if (pf) {
|
||||
// fprintf(pf," +%7d: %3d: %s %s\n",
|
||||
// (prev < 0 ? 0 : (timestamp - prev)),
|
||||
// bits,
|
||||
// (isResponse ? "TAG" : " "),
|
||||
// line);
|
||||
// }
|
||||
if (pf) {
|
||||
fprintf(pf," +%7d: %3d: %s %s\n",
|
||||
(prev < 0 ? 0 : (timestamp - prev)),
|
||||
bits,
|
||||
(isResponse ? "TAG" : " "),
|
||||
line);
|
||||
}
|
||||
|
||||
prev = timestamp;
|
||||
i += (len + 9);
|
||||
}
|
||||
|
||||
if (pf) {
|
||||
fclose(pf);
|
||||
PrintAndLog("Recorded activity succesfully written to file: %s", filename);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -126,12 +142,14 @@ int CmdLFHitagSnoop(const char *Cmd) {
|
|||
}
|
||||
|
||||
int CmdLFHitagSim(const char *Cmd) {
|
||||
|
||||
UsbCommand c = {CMD_SIMULATE_HITAG};
|
||||
char filename[256] = { 0x00 };
|
||||
char filename[FILE_PATH_SIZE] = { 0x00 };
|
||||
FILE* pf;
|
||||
bool tag_mem_supplied;
|
||||
|
||||
param_getstr(Cmd,0,filename);
|
||||
int len = strlen(Cmd);
|
||||
if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE;
|
||||
memcpy(filename, Cmd, len);
|
||||
|
||||
if (strlen(filename) > 0) {
|
||||
if ((pf = fopen(filename,"rb+")) == NULL) {
|
||||
|
@ -227,9 +245,9 @@ int CmdLFHitagReader(const char *Cmd) {
|
|||
static command_t CommandTable[] =
|
||||
{
|
||||
{"help", CmdHelp, 1, "This help"},
|
||||
{"list", CmdLFHitagList, 1, "List Hitag trace history"},
|
||||
{"list", CmdLFHitagList, 1, "<outfile> List Hitag trace history"},
|
||||
{"reader", CmdLFHitagReader, 1, "Act like a Hitag Reader"},
|
||||
{"sim", CmdLFHitagSim, 1, "Simulate Hitag transponder"},
|
||||
{"sim", CmdLFHitagSim, 1, "<infile> Simulate Hitag transponder"},
|
||||
{"snoop", CmdLFHitagSnoop, 1, "Eavesdrop Hitag communication"},
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
|
|
@ -132,9 +132,11 @@ int getCommand(UsbCommand* response)
|
|||
bool WaitForResponseTimeout(uint32_t cmd, UsbCommand* response, size_t ms_timeout) {
|
||||
|
||||
UsbCommand resp;
|
||||
|
||||
if (response == NULL)
|
||||
response = &resp;
|
||||
|
||||
|
||||
// Wait until the command is received
|
||||
for(size_t dm_seconds=0; dm_seconds < ms_timeout/10; dm_seconds++) {
|
||||
|
||||
|
|
|
@ -52,11 +52,8 @@ void ReceiveCommand(UsbCommand* rxcmd) {
|
|||
while (true) {
|
||||
rxlen = sizeof(UsbCommand) - (prx-prxcmd);
|
||||
if (uart_receive(sp,prx,&rxlen)) {
|
||||
// printf("received [%zd] bytes\n",rxlen);
|
||||
prx += rxlen;
|
||||
if ((prx-prxcmd) >= sizeof(UsbCommand)) {
|
||||
// printf("received: ");
|
||||
// cmd_debug(rxcmd);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -104,8 +104,11 @@ local _commands = {
|
|||
CMD_MIFARE_EML_MEMSET = 0x0602,
|
||||
CMD_MIFARE_EML_MEMGET = 0x0603,
|
||||
CMD_MIFARE_EML_CARDLOAD = 0x0604,
|
||||
CMD_MIFARE_EML_CSETBLOCK = 0x0605,
|
||||
CMD_MIFARE_EML_CGETBLOCK = 0x0606,
|
||||
|
||||
--// magic chinese card commands
|
||||
CMD_MIFARE_CSETBLOCK = 0x0605,
|
||||
CMD_MIFARE_CGETBLOCK = 0x0606,
|
||||
CMD_MIFARE_CIDENT = 0x0607,
|
||||
|
||||
CMD_SIMULATE_MIFARE_CARD = 0x0610,
|
||||
|
||||
|
|
|
@ -33,9 +33,86 @@ local Utils =
|
|||
|
||||
return answer
|
||||
end,
|
||||
|
||||
------------ FILE READING
|
||||
ReadDumpFile = function (filename)
|
||||
|
||||
if filename == nil then
|
||||
return nil, 'Filename is empty'
|
||||
end
|
||||
if #filename == 0 then
|
||||
return nil, 'Filename length is zero'
|
||||
end
|
||||
|
||||
infile = io.open(filename, "rb")
|
||||
if infile == nil then
|
||||
return nil, string.format("Could not read file %s",filename)
|
||||
end
|
||||
local t = infile:read("*all")
|
||||
len = string.len(t)
|
||||
local _,hex = bin.unpack(("H%d"):format(len),t)
|
||||
io.close(infile)
|
||||
return hex
|
||||
end,
|
||||
|
||||
------------ string split function
|
||||
Split = function( inSplitPattern, outResults )
|
||||
if not outResults then
|
||||
outResults = {}
|
||||
end
|
||||
local start = 1
|
||||
local splitStart, splitEnd = string.find( self, inSplitPattern, start )
|
||||
while splitStart do
|
||||
table.insert( outResults, string.sub( self, start, splitStart-1 ) )
|
||||
start = splitEnd + 1
|
||||
splitStart, splitEnd = string.find( self, inSplitPattern, start )
|
||||
end
|
||||
table.insert( outResults, string.sub( self, start ) )
|
||||
return outResults
|
||||
end,
|
||||
|
||||
------------ CRC-16 ccitt checksums
|
||||
|
||||
-- Takes a hex string and calculates a crc16
|
||||
Crc16 = function(s)
|
||||
if s == nil then return nil end
|
||||
if #s == 0 then return nil end
|
||||
if type(s) == 'string' then
|
||||
local utils = require('utils')
|
||||
local asc = utils.ConvertHexToAscii(s)
|
||||
local hash = core.crc16(asc)
|
||||
return hash
|
||||
end
|
||||
return nil
|
||||
end,
|
||||
|
||||
-- input parameter is a string
|
||||
-- Swaps the endianess and returns a number,
|
||||
-- IE: 'cd7a' -> '7acd' -> 0x7acd
|
||||
SwapEndianness = function(s, len)
|
||||
if s == nil then return nil end
|
||||
if #s == 0 then return '' end
|
||||
if type(s) ~= 'string' then return nil end
|
||||
|
||||
local retval = 0
|
||||
if len == 16 then
|
||||
local t = s:sub(3,4)..s:sub(1,2)
|
||||
retval = tonumber(t,16)
|
||||
elseif len == 24 then
|
||||
local t = s:sub(5,6)..s:sub(3,4)..s:sub(1,2)
|
||||
retval = tonumber(t,16)
|
||||
elseif len == 32 then
|
||||
local t = s:sub(7,8)..s:sub(5,6)..s:sub(3,4)..s:sub(1,2)
|
||||
retval = tonumber(t,16)
|
||||
end
|
||||
return retval
|
||||
end,
|
||||
|
||||
------------ CONVERSIONS
|
||||
|
||||
--
|
||||
-- Converts DECIMAL to HEX
|
||||
ConvertDec2Hex = function(IN)
|
||||
ConvertDecToHex = function(IN)
|
||||
local B,K,OUT,I,D=16,"0123456789ABCDEF","",0
|
||||
while IN>0 do
|
||||
I=I+1
|
||||
|
@ -46,12 +123,100 @@ local Utils =
|
|||
end,
|
||||
---
|
||||
-- Convert Byte array to string of hex
|
||||
ConvertBytes2String = function(bytes)
|
||||
s = {}
|
||||
ConvertBytesToHex = function(bytes)
|
||||
if #bytes == 0 then
|
||||
return ''
|
||||
end
|
||||
local s={}
|
||||
for i = 1, #(bytes) do
|
||||
s[i] = string.format("%02X",bytes[i])
|
||||
end
|
||||
return table.concat(s)
|
||||
end,
|
||||
-- Convert byte array to string with ascii
|
||||
ConvertBytesToAscii = function(bytes)
|
||||
if #bytes == 0 then
|
||||
return ''
|
||||
end
|
||||
local s={}
|
||||
for i = 1, #(bytes) do
|
||||
s[i] = string.char(bytes[i])
|
||||
end
|
||||
return table.concat(s)
|
||||
end,
|
||||
ConvertHexToBytes = function(s)
|
||||
local t={}
|
||||
if s == nil then return t end
|
||||
if #s == 0 then return t end
|
||||
for k in s:gmatch"(%x%x)" do
|
||||
table.insert(t,tonumber(k,16))
|
||||
end
|
||||
return t
|
||||
end,
|
||||
ConvertAsciiToBytes = function(s)
|
||||
local t={}
|
||||
if s == nil then return t end
|
||||
if #s == 0 then return t end
|
||||
|
||||
for k in s:gmatch"(.)" do
|
||||
table.insert(t, string.byte(k))
|
||||
end
|
||||
return t
|
||||
end,
|
||||
ConvertHexToAscii = function(s)
|
||||
local t={}
|
||||
if s == nil then return t end
|
||||
if #s == 0 then return t end
|
||||
for k in s:gmatch"(%x%x)" do
|
||||
table.insert(t, string.char(tonumber(k,16)))
|
||||
end
|
||||
return table.concat(t)
|
||||
end,
|
||||
|
||||
-- function convertStringToBytes(str)
|
||||
-- local bytes = {}
|
||||
-- local strLength = string.len(str)
|
||||
-- for i=1,strLength do
|
||||
-- table.insert(bytes, string.byte(str, i))
|
||||
-- end
|
||||
|
||||
-- return bytes
|
||||
-- end
|
||||
|
||||
-- function convertBytesToString(bytes)
|
||||
-- local bytesLength = table.getn(bytes)
|
||||
-- local str = ""
|
||||
-- for i=1,bytesLength do
|
||||
-- str = str .. string.char(bytes[i])
|
||||
-- end
|
||||
|
||||
-- return str
|
||||
-- end
|
||||
|
||||
-- function convertHexStringToBytes(str)
|
||||
-- local bytes = {}
|
||||
-- local strLength = string.len(str)
|
||||
-- for k=2,strLength,2 do
|
||||
-- local hexString = "0x" .. string.sub(str, (k - 1), k)
|
||||
-- table.insert(bytes, hex.to_dec(hexString))
|
||||
-- end
|
||||
|
||||
-- return bytes
|
||||
-- end
|
||||
|
||||
-- function convertBytesToHexString(bytes)
|
||||
-- local str = ""
|
||||
-- local bytesLength = table.getn(bytes)
|
||||
-- for i=1,bytesLength do
|
||||
-- local hexString = string.sub(hex.to_hex(bytes[i]), 3)
|
||||
-- if string.len(hexString) == 1 then
|
||||
-- hexString = "0" .. hexString
|
||||
-- end
|
||||
-- str = str .. hexString
|
||||
-- end
|
||||
|
||||
-- return str
|
||||
-- end
|
||||
|
||||
}
|
||||
return Utils
|
|
@ -16,7 +16,7 @@
|
|||
#include <unistd.h>
|
||||
#include <readline/readline.h>
|
||||
#include <readline/history.h>
|
||||
//#include "proxusb.h"
|
||||
|
||||
#include "proxmark3.h"
|
||||
#include "proxgui.h"
|
||||
#include "cmdmain.h"
|
||||
|
|
|
@ -18,6 +18,8 @@
|
|||
#include "util.h"
|
||||
#include "nonce2key/nonce2key.h"
|
||||
#include "../common/iso15693tools.h"
|
||||
#include <openssl/aes.h>
|
||||
#include "../common/crc16.h"
|
||||
/**
|
||||
* The following params expected:
|
||||
* UsbCommand c
|
||||
|
@ -224,6 +226,54 @@ static int l_iso15693_crc(lua_State *L)
|
|||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
Simple AES 128 cbc hook up to OpenSSL.
|
||||
params: key, input
|
||||
*/
|
||||
static int l_aes(lua_State *L)
|
||||
{
|
||||
//Check number of arguments
|
||||
int i;
|
||||
size_t size;
|
||||
const char *p_key = luaL_checklstring(L, 1, &size);
|
||||
if(size != 32) return returnToLuaWithError(L,"Wrong size of key, got %d bytes, expected 32", (int) size);
|
||||
|
||||
const char *p_encTxt = luaL_checklstring(L, 2, &size);
|
||||
|
||||
unsigned char indata[AES_BLOCK_SIZE] = {0x00};
|
||||
unsigned char outdata[AES_BLOCK_SIZE] = {0x00};
|
||||
unsigned char aes_key[AES_BLOCK_SIZE] = {0x00};
|
||||
unsigned char iv[AES_BLOCK_SIZE] = {0x00};
|
||||
|
||||
// convert key to bytearray
|
||||
for (i = 0; i < 32; i += 2) {
|
||||
sscanf(&p_encTxt[i], "%02x", (unsigned int *)&indata[i / 2]);
|
||||
}
|
||||
|
||||
// convert input to bytearray
|
||||
for (i = 0; i < 32; i += 2) {
|
||||
sscanf(&p_key[i], "%02x", (unsigned int *)&aes_key[i / 2]);
|
||||
}
|
||||
|
||||
AES_KEY key;
|
||||
AES_set_decrypt_key(aes_key, 128, &key);
|
||||
AES_cbc_encrypt(indata, outdata, sizeof(indata), &key, iv, AES_DECRYPT);
|
||||
|
||||
//Push decrypted array as a string
|
||||
lua_pushlstring(L,(const char *)&outdata, sizeof(outdata));
|
||||
return 1;// return 1 to signal one return value
|
||||
}
|
||||
|
||||
static int l_crc16(lua_State *L)
|
||||
{
|
||||
size_t size;
|
||||
const char *p_str = luaL_checklstring(L, 1, &size);
|
||||
|
||||
uint16_t retval = crc16_ccitt( (uint8_t*) p_str, size);
|
||||
lua_pushinteger(L, (int) retval);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Sets the lua path to include "./lualibs/?.lua", in order for a script to be
|
||||
* able to do "require('foobar')" if foobar.lua is within lualibs folder.
|
||||
|
@ -261,6 +311,8 @@ int set_pm3_libraries(lua_State *L)
|
|||
{"clearCommandBuffer", l_clearCommandBuffer},
|
||||
{"console", l_CmdConsole},
|
||||
{"iso15693_crc", l_iso15693_crc},
|
||||
{"aes", l_aes},
|
||||
{"crc16", l_crc16},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
|
272
client/scripts/tnp3dump.lua
Normal file
272
client/scripts/tnp3dump.lua
Normal file
|
@ -0,0 +1,272 @@
|
|||
local cmds = require('commands')
|
||||
local getopt = require('getopt')
|
||||
local bin = require('bin')
|
||||
local lib14a = require('read14a')
|
||||
local utils = require('utils')
|
||||
local md5 = require('md5')
|
||||
local dumplib = require('html_dumplib')
|
||||
local toyNames = require('default_toys')
|
||||
|
||||
example =[[
|
||||
1. script run tnp3dump
|
||||
2. script run tnp3dump -n
|
||||
3. script run tnp3dump -k aabbccddeeff
|
||||
4. script run tnp3dump -k aabbccddeeff -n
|
||||
5. script run tnp3dump -o myfile
|
||||
6. script run tnp3dump -n -o myfile
|
||||
7. script run tnp3dump -k aabbccddeeff -n -o myfile
|
||||
]]
|
||||
author = "Iceman"
|
||||
usage = "script run tnp3dump -k <key> -n -o <filename>"
|
||||
desc =[[
|
||||
This script will try to dump the contents of a Mifare TNP3xxx card.
|
||||
It will need a valid KeyA in order to find the other keys and decode the card.
|
||||
Arguments:
|
||||
-h : this help
|
||||
-k <key> : Sector 0 Key A.
|
||||
-n : Use the nested cmd to find all keys
|
||||
-o : filename for the saved dumps
|
||||
]]
|
||||
|
||||
local HASHCONSTANT = '20436F707972696768742028432920323031302041637469766973696F6E2E20416C6C205269676874732052657365727665642E20'
|
||||
|
||||
local TIMEOUT = 2000 -- Shouldn't take longer than 2 seconds
|
||||
local DEBUG = false -- the debug flag
|
||||
local numBlocks = 64
|
||||
local numSectors = 16
|
||||
---
|
||||
-- A debug printout-function
|
||||
function dbg(args)
|
||||
if not DEBUG then
|
||||
return
|
||||
end
|
||||
|
||||
if type(args) == "table" then
|
||||
local i = 1
|
||||
while result[i] do
|
||||
dbg(result[i])
|
||||
i = i+1
|
||||
end
|
||||
else
|
||||
print("###", args)
|
||||
end
|
||||
end
|
||||
---
|
||||
-- This is only meant to be used when errors occur
|
||||
function oops(err)
|
||||
print("ERROR: ",err)
|
||||
end
|
||||
---
|
||||
-- Usage help
|
||||
function help()
|
||||
print(desc)
|
||||
print("Example usage")
|
||||
print(example)
|
||||
end
|
||||
--
|
||||
-- Exit message
|
||||
function ExitMsg(msg)
|
||||
print( string.rep('--',20) )
|
||||
print( string.rep('--',20) )
|
||||
print(msg)
|
||||
print()
|
||||
end
|
||||
|
||||
local function readdumpkeys(infile)
|
||||
t = infile:read("*all")
|
||||
len = string.len(t)
|
||||
local len,hex = bin.unpack(("H%d"):format(len),t)
|
||||
return hex
|
||||
end
|
||||
|
||||
local function waitCmd()
|
||||
local response = core.WaitForResponseTimeout(cmds.CMD_ACK,TIMEOUT)
|
||||
if response then
|
||||
local count,cmd,arg0 = bin.unpack('LL',response)
|
||||
if(arg0==1) then
|
||||
local count,arg1,arg2,data = bin.unpack('LLH511',response,count)
|
||||
return data:sub(1,32)
|
||||
else
|
||||
return nil, "Couldn't read block.."
|
||||
end
|
||||
end
|
||||
return nil, "No response from device"
|
||||
end
|
||||
|
||||
local function computeCrc16(s)
|
||||
local hash = core.crc16(utils.ConvertHexToAscii(s))
|
||||
return hash
|
||||
end
|
||||
|
||||
local function reverseCrcBytes(crc)
|
||||
crc2 = crc:sub(3,4)..crc:sub(1,2)
|
||||
return tonumber(crc2,16)
|
||||
end
|
||||
|
||||
local function main(args)
|
||||
|
||||
print( string.rep('--',20) )
|
||||
print( string.rep('--',20) )
|
||||
|
||||
local keyA
|
||||
local cmd
|
||||
local err
|
||||
local useNested = false
|
||||
local cmdReadBlockString = 'hf mf rdbl %d A %s'
|
||||
local input = "dumpkeys.bin"
|
||||
local outputTemplate = os.date("toydump_%Y-%m-%d_%H%M%S");
|
||||
|
||||
-- Arguments for the script
|
||||
for o, a in getopt.getopt(args, 'hk:no:') do
|
||||
if o == "h" then return help() end
|
||||
if o == "k" then keyA = a end
|
||||
if o == "n" then useNested = true end
|
||||
if o == "o" then outputTemplate = a end
|
||||
end
|
||||
|
||||
-- validate input args.
|
||||
keyA = keyA or '4b0b20107ccb'
|
||||
if #(keyA) ~= 12 then
|
||||
return oops( string.format('Wrong length of write key (was %d) expected 12', #keyA))
|
||||
end
|
||||
|
||||
-- Turn off Debug
|
||||
local cmdSetDbgOff = "hf mf dbg 0"
|
||||
core.console( cmdSetDbgOff)
|
||||
|
||||
result, err = lib14a.read1443a(false)
|
||||
if not result then
|
||||
return oops(err)
|
||||
end
|
||||
|
||||
core.clearCommandBuffer()
|
||||
|
||||
if 0x01 ~= result.sak then -- NXP MIFARE TNP3xxx
|
||||
return oops('This is not a TNP3xxx tag. aborting.')
|
||||
end
|
||||
|
||||
-- Show tag info
|
||||
print((' Found tag : %s'):format(result.name))
|
||||
print(('Using keyA : %s'):format(keyA))
|
||||
|
||||
--Trying to find the other keys
|
||||
if useNested then
|
||||
core.console( ('hf mf nested 1 0 A %s d'):format(keyA) )
|
||||
end
|
||||
|
||||
core.clearCommandBuffer()
|
||||
|
||||
-- Loading keyfile
|
||||
print('Loading dumpkeys.bin')
|
||||
local hex, err = utils.ReadDumpFile(input)
|
||||
if not hex then
|
||||
return oops(err)
|
||||
end
|
||||
|
||||
local akeys = hex:sub(0,12*16)
|
||||
|
||||
-- Read block 0
|
||||
cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = 0,arg2 = 0,arg3 = 0, data = keyA}
|
||||
err = core.SendCommand(cmd:getBytes())
|
||||
if err then return oops(err) end
|
||||
local block0, err = waitCmd()
|
||||
if err then return oops(err) end
|
||||
|
||||
-- Read block 1
|
||||
cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = 1,arg2 = 0,arg3 = 0, data = keyA}
|
||||
err = core.SendCommand(cmd:getBytes())
|
||||
if err then return oops(err) end
|
||||
local block1, err = waitCmd()
|
||||
if err then return oops(err) end
|
||||
|
||||
local key
|
||||
local pos = 0
|
||||
local blockNo
|
||||
local blocks = {}
|
||||
|
||||
print('Reading card data')
|
||||
core.clearCommandBuffer()
|
||||
|
||||
-- main loop
|
||||
io.write('Decrypting blocks > ')
|
||||
for blockNo = 0, numBlocks-1, 1 do
|
||||
|
||||
if core.ukbhit() then
|
||||
print("aborted by user")
|
||||
break
|
||||
end
|
||||
|
||||
pos = (math.floor( blockNo / 4 ) * 12)+1
|
||||
key = akeys:sub(pos, pos + 11 )
|
||||
cmd = Command:new{cmd = cmds.CMD_MIFARE_READBL, arg1 = blockNo ,arg2 = 0,arg3 = 0, data = key}
|
||||
local err = core.SendCommand(cmd:getBytes())
|
||||
if err then return oops(err) end
|
||||
local blockdata, err = waitCmd()
|
||||
if err then return oops(err) end
|
||||
|
||||
if blockNo%4 ~= 3 then
|
||||
if blockNo < 8 then
|
||||
-- Block 0-7 not encrypted
|
||||
blocks[blockNo+1] = ('%02d :: %s'):format(blockNo,blockdata)
|
||||
else
|
||||
local base = ('%s%s%02x%s'):format(block0, block1, blockNo, HASHCONSTANT)
|
||||
local baseStr = utils.ConvertHexToAscii(base)
|
||||
local md5hash = md5.sumhexa(baseStr)
|
||||
local aestest = core.aes(md5hash, blockdata)
|
||||
|
||||
local hex = utils.ConvertAsciiToBytes(aestest)
|
||||
hex = utils.ConvertBytesToHex(hex)
|
||||
|
||||
-- blocks with zero not encrypted.
|
||||
if string.find(blockdata, '^0+$') then
|
||||
blocks[blockNo+1] = ('%02d :: %s'):format(blockNo,blockdata)
|
||||
else
|
||||
blocks[blockNo+1] = ('%02d :: %s'):format(blockNo,hex)
|
||||
io.write( blockNo..',')
|
||||
end
|
||||
end
|
||||
else
|
||||
-- Sectorblocks, not encrypted
|
||||
blocks[blockNo+1] = ('%02d :: %s%s'):format(blockNo,key,blockdata:sub(13,32))
|
||||
end
|
||||
end
|
||||
io.write('\n')
|
||||
|
||||
core.clearCommandBuffer()
|
||||
|
||||
-- Print results
|
||||
local bindata = {}
|
||||
local emldata = ''
|
||||
|
||||
for _,s in pairs(blocks) do
|
||||
local slice = s:sub(8,#s)
|
||||
local str = utils.ConvertBytesToAscii(
|
||||
utils.ConvertHexToBytes(slice)
|
||||
)
|
||||
emldata = emldata..slice..'\n'
|
||||
for c in (str):gmatch('.') do
|
||||
bindata[#bindata+1] = c
|
||||
end
|
||||
end
|
||||
|
||||
-- Write dump to files
|
||||
if not DEBUG then
|
||||
local foo = dumplib.SaveAsBinary(bindata, outputTemplate..'.bin')
|
||||
print(("Wrote a BIN dump to the file %s"):format(foo))
|
||||
local bar = dumplib.SaveAsText(emldata, outputTemplate..'.eml')
|
||||
print(("Wrote a EML dump to the file %s"):format(bar))
|
||||
end
|
||||
|
||||
local uid = block0:sub(1,8)
|
||||
local itemtype = block1:sub(1,4)
|
||||
local cardid = block1:sub(9,24)
|
||||
|
||||
-- Show info
|
||||
print( string.rep('--',20) )
|
||||
print( (' ITEM TYPE : 0x%s - %s'):format(itemtype, toyNames[itemtype]) )
|
||||
print( (' UID : 0x%s'):format(uid) )
|
||||
print( (' CARDID : 0x%s'):format(cardid ) )
|
||||
print( string.rep('--',20) )
|
||||
|
||||
end
|
||||
main(args)
|
355
client/scripts/tnp3sim.lua
Normal file
355
client/scripts/tnp3sim.lua
Normal file
|
@ -0,0 +1,355 @@
|
|||
local cmds = require('commands')
|
||||
local getopt = require('getopt')
|
||||
local bin = require('bin')
|
||||
local lib14a = require('read14a')
|
||||
local utils = require('utils')
|
||||
local md5 = require('md5')
|
||||
local toyNames = require('default_toys')
|
||||
|
||||
example =[[
|
||||
1. script run tnp3sim
|
||||
2. script run tnp3sim -m
|
||||
3. script run tnp3sim -m -i myfile
|
||||
]]
|
||||
author = "Iceman"
|
||||
usage = "script run tnp3sim -h -m -i <filename>"
|
||||
desc =[[
|
||||
This script will try to load a binary datadump of a Mifare TNP3xxx card.
|
||||
It vill try to validate all checksums and view some information stored in the dump
|
||||
For an experimental mode, it tries to manipulate some data.
|
||||
At last it sends all data to the PM3 device memory where it can be used in the command "hf mf sim"
|
||||
|
||||
Arguments:
|
||||
-h : this help
|
||||
-m : Maxed out items (experimental)
|
||||
-i : filename for the datadump to read (bin)
|
||||
]]
|
||||
|
||||
local TIMEOUT = 2000 -- Shouldn't take longer than 2 seconds
|
||||
local DEBUG = true -- the debug flag
|
||||
---
|
||||
-- A debug printout-function
|
||||
function dbg(args)
|
||||
if not DEBUG then
|
||||
return
|
||||
end
|
||||
|
||||
if type(args) == "table" then
|
||||
local i = 1
|
||||
while result[i] do
|
||||
dbg(result[i])
|
||||
i = i+1
|
||||
end
|
||||
else
|
||||
print("###", args)
|
||||
end
|
||||
end
|
||||
---
|
||||
-- This is only meant to be used when errors occur
|
||||
function oops(err)
|
||||
print("ERROR: ",err)
|
||||
end
|
||||
---
|
||||
-- Usage help
|
||||
function help()
|
||||
print(desc)
|
||||
print("Example usage")
|
||||
print(example)
|
||||
end
|
||||
--
|
||||
-- Exit message
|
||||
function ExitMsg(msg)
|
||||
print( string.rep('--',20) )
|
||||
print( string.rep('--',20) )
|
||||
print(msg)
|
||||
print()
|
||||
end
|
||||
|
||||
|
||||
local function writedumpfile(infile)
|
||||
t = infile:read("*all")
|
||||
len = string.len(t)
|
||||
local len,hex = bin.unpack(("H%d"):format(len),t)
|
||||
return hex
|
||||
end
|
||||
-- blocks with data
|
||||
-- there are two dataareas, in block 8 or block 36, ( 1==8 ,
|
||||
-- checksum type = 0, 1, 2, 3
|
||||
local function GetCheckSum(blocks, dataarea, chksumtype)
|
||||
|
||||
local crc
|
||||
local area = 36
|
||||
if dataarea == 1 then
|
||||
area = 8
|
||||
end
|
||||
|
||||
if chksumtype == 0 then
|
||||
crc = blocks[1]:sub(29,32)
|
||||
elseif chksumtype == 1 then
|
||||
crc = blocks[area]:sub(29,32)
|
||||
elseif chksumtype == 2 then
|
||||
crc = blocks[area]:sub(25,28)
|
||||
elseif chksumtype == 3 then
|
||||
crc = blocks[area]:sub(21,24)
|
||||
end
|
||||
return utils.SwapEndianness(crc,16)
|
||||
end
|
||||
|
||||
local function SetCheckSum(blocks, chksumtype)
|
||||
|
||||
if blocks == nil then return nil, 'Argument \"blocks\" nil' end
|
||||
local newcrc
|
||||
local area1 = 8
|
||||
local area2 = 36
|
||||
|
||||
if chksumtype == 0 then
|
||||
newcrc = ('%04X'):format(CalcCheckSum(blocks,1,0))
|
||||
blocks[1] = blocks[1]:sub(1,28)..newcrc:sub(3,4)..newcrc:sub(1,2)
|
||||
elseif chksumtype == 1 then
|
||||
newcrc = ('%04X'):format(CalcCheckSum(blocks,1,1))
|
||||
blocks[area1] = blocks[area1]:sub(1,28)..newcrc:sub(3,4)..newcrc:sub(1,2)
|
||||
newcrc = ('%04X'):format(CalcCheckSum(blocks,2,1))
|
||||
blocks[area2] = blocks[area2]:sub(1,28)..newcrc:sub(3,4)..newcrc:sub(1,2)
|
||||
elseif chksumtype == 2 then
|
||||
newcrc = ('%04X'):format(CalcCheckSum(blocks,1,2))
|
||||
blocks[area1] = blocks[area1]:sub(1,24)..newcrc:sub(3,4)..newcrc:sub(1,2)..blocks[area1]:sub(29,32)
|
||||
newcrc = ('%04X'):format(CalcCheckSum(blocks,2,2))
|
||||
blocks[area2] = blocks[area2]:sub(1,24)..newcrc:sub(3,4)..newcrc:sub(1,2)..blocks[area2]:sub(29,32)
|
||||
elseif chksumtype == 3 then
|
||||
newcrc = ('%04X'):format(CalcCheckSum(blocks,1,3))
|
||||
blocks[area1] = blocks[area1]:sub(1,20)..newcrc:sub(3,4)..newcrc:sub(1,2)..blocks[area1]:sub(25,32)
|
||||
newcrc = ('%04X'):format(CalcCheckSum(blocks,2,3))
|
||||
blocks[area2] = blocks[area2]:sub(1,20)..newcrc:sub(3,4)..newcrc:sub(1,2)..blocks[area2]:sub(25,32)
|
||||
end
|
||||
end
|
||||
|
||||
function CalcCheckSum(blocks, dataarea, chksumtype)
|
||||
local area = 36
|
||||
if dataarea == 1 then
|
||||
area = 8
|
||||
end
|
||||
|
||||
if chksumtype == 0 then
|
||||
data = blocks[0]..blocks[1]:sub(1,28)
|
||||
elseif chksumtype == 1 then
|
||||
data = blocks[area]:sub(1,28)..'0500'
|
||||
elseif chksumtype == 2 then
|
||||
data = blocks[area+1]..blocks[area+2]..blocks[area+4]
|
||||
elseif chksumtype == 3 then
|
||||
data = blocks[area+5]..blocks[area+6]..blocks[area+8]..string.rep('00',0xe0)
|
||||
end
|
||||
return utils.Crc16(data)
|
||||
end
|
||||
|
||||
local function ValidateCheckSums(blocks)
|
||||
|
||||
local isOk, crc, calc
|
||||
-- Checksum Type 0
|
||||
crc = GetCheckSum(blocks,1,0)
|
||||
calc = CalcCheckSum(blocks, 1, 0)
|
||||
if crc == calc then isOk='Ok' else isOk = 'Error' end
|
||||
io.write( ('TYPE 0 : %04x = %04x -- %s\n'):format(crc,calc,isOk))
|
||||
|
||||
-- Checksum Type 1 (DATAAREAHEADER 1)
|
||||
crc = GetCheckSum(blocks,1,1)
|
||||
calc = CalcCheckSum(blocks,1,1)
|
||||
if crc == calc then isOk='Ok' else isOk = 'Error' end
|
||||
io.write( ('TYPE 1 area 1: %04x = %04x -- %s\n'):format(crc,calc,isOk))
|
||||
|
||||
-- Checksum Type 1 (DATAAREAHEADER 2)
|
||||
crc = GetCheckSum(blocks,2,1)
|
||||
calc = CalcCheckSum(blocks,2,1)
|
||||
if crc == calc then isOk='Ok' else isOk = 'Error' end
|
||||
io.write( ('TYPE 1 area 2: %04x = %04x -- %s\n'):format(crc,calc,isOk))
|
||||
|
||||
-- Checksum Type 2 (DATAAREA 1)
|
||||
crc = GetCheckSum(blocks,1,2)
|
||||
calc = CalcCheckSum(blocks,1,2)
|
||||
if crc == calc then isOk='Ok' else isOk = 'Error' end
|
||||
io.write( ('TYPE 2 area 1: %04x = %04x -- %s\n'):format(crc,calc,isOk))
|
||||
|
||||
-- Checksum Type 2 (DATAAREA 2)
|
||||
crc = GetCheckSum(blocks,2,2)
|
||||
calc = CalcCheckSum(blocks,2,2)
|
||||
if crc == calc then isOk='Ok' else isOk = 'Error' end
|
||||
io.write( ('TYPE 2 area 2: %04x = %04x -- %s\n'):format(crc,calc,isOk))
|
||||
|
||||
-- Checksum Type 3 (DATAAREA 1)
|
||||
crc = GetCheckSum(blocks,1,3)
|
||||
calc = CalcCheckSum(blocks,1,3)
|
||||
if crc == calc then isOk='Ok' else isOk = 'Error' end
|
||||
io.write( ('TYPE 3 area 1: %04x = %04x -- %s\n'):format(crc,calc,isOk))
|
||||
|
||||
-- Checksum Type 3 (DATAAREA 2)
|
||||
crc = GetCheckSum(blocks,2,3)
|
||||
calc = CalcCheckSum(blocks,2,3)
|
||||
if crc == calc then isOk='Ok' else isOk = 'Error' end
|
||||
io.write( ('TYPE 3 area 2: %04x = %04x -- %s\n'):format(crc,calc,isOk))
|
||||
end
|
||||
|
||||
|
||||
local function LoadEmulator(blocks)
|
||||
local HASHCONSTANT = '20436F707972696768742028432920323031302041637469766973696F6E2E20416C6C205269676874732052657365727665642E20'
|
||||
local cmd
|
||||
local blockdata
|
||||
for _,b in pairs(blocks) do
|
||||
|
||||
blockdata = b
|
||||
|
||||
if _%4 ~= 3 then
|
||||
if (_ >= 8 and _<=21) or (_ >= 36 and _<=49) then
|
||||
local base = ('%s%s%02x%s'):format(blocks[0], blocks[1], _ , HASHCONSTANT)
|
||||
local baseStr = utils.ConvertHexToAscii(base)
|
||||
local key = md5.sumhexa(baseStr)
|
||||
local enc = core.aes(key, blockdata)
|
||||
local hex = utils.ConvertAsciiToBytes(enc)
|
||||
hex = utils.ConvertBytesToHex(hex)
|
||||
|
||||
blockdata = hex
|
||||
io.write( _..',')
|
||||
end
|
||||
end
|
||||
|
||||
cmd = Command:new{cmd = cmds.CMD_MIFARE_EML_MEMSET, arg1 = _ ,arg2 = 1,arg3 = 0, data = blockdata}
|
||||
local err = core.SendCommand(cmd:getBytes())
|
||||
if err then
|
||||
return err
|
||||
end
|
||||
end
|
||||
io.write('\n')
|
||||
end
|
||||
|
||||
local function main(args)
|
||||
|
||||
print( string.rep('--',20) )
|
||||
print( string.rep('--',20) )
|
||||
|
||||
local result, err, hex
|
||||
local maxed = false
|
||||
local inputTemplate = "dumpdata.bin"
|
||||
local outputTemplate = os.date("toydump_%Y-%m-%d_%H%M");
|
||||
|
||||
-- Arguments for the script
|
||||
for o, a in getopt.getopt(args, 'hmi:o:') do
|
||||
if o == "h" then return help() end
|
||||
if o == "m" then maxed = true end
|
||||
if o == "o" then outputTemplate = a end
|
||||
if o == "i" then inputTemplate = a end
|
||||
end
|
||||
|
||||
-- Turn off Debug
|
||||
local cmdSetDbgOff = "hf mf dbg 0"
|
||||
core.console( cmdSetDbgOff)
|
||||
|
||||
-- Look for tag present on reader,
|
||||
result, err = lib14a.read1443a(false)
|
||||
if not result then return oops(err) end
|
||||
|
||||
core.clearCommandBuffer()
|
||||
|
||||
if 0x01 ~= result.sak then -- NXP MIFARE TNP3xxx
|
||||
return oops('This is not a TNP3xxx tag. aborting.')
|
||||
end
|
||||
|
||||
-- Show tag info
|
||||
print((' Found tag : %s'):format(result.name))
|
||||
|
||||
-- Load dump.bin file
|
||||
print( (' Load data from %s'):format(inputTemplate))
|
||||
hex, err = utils.ReadDumpFile(inputTemplate)
|
||||
if not hex then return oops(err) end
|
||||
|
||||
local blocks = {}
|
||||
local blockindex = 0
|
||||
for i = 1, #hex, 32 do
|
||||
blocks[blockindex] = hex:sub(i,i+31)
|
||||
blockindex = blockindex + 1
|
||||
end
|
||||
|
||||
if DEBUG then
|
||||
print('Validating checksums in the loaded datadump')
|
||||
ValidateCheckSums(blocks)
|
||||
end
|
||||
|
||||
--
|
||||
print( string.rep('--',20) )
|
||||
print(' Gathering info')
|
||||
local uid = blocks[0]:sub(1,8)
|
||||
local itemtype = blocks[1]:sub(1,4)
|
||||
local cardid = blocks[1]:sub(9,24)
|
||||
|
||||
-- Show info
|
||||
print( string.rep('--',20) )
|
||||
print( (' ITEM TYPE : 0x%s - %s'):format(itemtype, toyNames[itemtype]) )
|
||||
print( (' UID : 0x%s'):format(uid) )
|
||||
print( (' CARDID : 0x%s'):format(cardid ) )
|
||||
print( string.rep('--',20) )
|
||||
|
||||
-- lets do something.
|
||||
--
|
||||
local experience = blocks[8]:sub(1,6)
|
||||
print(('Experience : %d'):format(utils.SwapEndianness(experience,24)))
|
||||
local money = blocks[8]:sub(7,10)
|
||||
print(('Money : %d'):format(utils.SwapEndianness(money,16)))
|
||||
local fairy = blocks[9]:sub(1,8)
|
||||
--FD0F = Left, FF0F = Right
|
||||
local path = 'not choosen'
|
||||
if fairy:sub(2,2) == 'D' then
|
||||
path = 'Left'
|
||||
elseif fairy:sub(2,2) == 'F' then
|
||||
path = 'Right'
|
||||
end
|
||||
print(('Fairy : %d [Path: %s] '):format(utils.SwapEndianness(fairy,24),path))
|
||||
|
||||
local hat = blocks[9]:sub(8,11)
|
||||
print(('Hat : %d'):format(utils.SwapEndianness(hat,16)))
|
||||
|
||||
--0x0D 0x29 0x0A 0x02 16-bit hero points value. Maximum 100.
|
||||
local heropoints = blocks[13]:sub(20,23)
|
||||
print(('Hero points : %d'):format(utils.SwapEndianness(heropoints,16)))
|
||||
|
||||
--0x10 0x2C 0x0C 0x04 32 bit flag value indicating heroic challenges completed.
|
||||
local challenges = blocks[16]:sub(25,32)
|
||||
print(('Finished hero challenges : %d'):format(utils.SwapEndianness(challenges,32)))
|
||||
|
||||
if maxed then
|
||||
print('Lets try to max out some values')
|
||||
-- max out money, experience
|
||||
--print (blocks[8])
|
||||
blocks[8] = 'FFFFFF'..'FFFF'..blocks[8]:sub(11,32)
|
||||
blocks[36] = 'FFFFFF'..'FFFF'..blocks[36]:sub(11,32)
|
||||
--print (blocks[8])
|
||||
|
||||
-- max out hero challenges
|
||||
--print (blocks[16])
|
||||
blocks[16] = blocks[16]:sub(1,24)..'FFFFFFFF'
|
||||
blocks[44] = blocks[44]:sub(1,24)..'FFFFFFFF'
|
||||
--print (blocks[16])
|
||||
|
||||
-- max out heropoints
|
||||
--print (blocks[13])
|
||||
blocks[13] = blocks[13]:sub(1,19)..'0064'..blocks[13]:sub(24,32)
|
||||
blocks[41] = blocks[41]:sub(1,19)..'0064'..blocks[41]:sub(24,32)
|
||||
--print (blocks[13])
|
||||
|
||||
-- Update Checksums
|
||||
print('Updating all checksums')
|
||||
SetCheckSum(blocks, 3)
|
||||
SetCheckSum(blocks, 2)
|
||||
SetCheckSum(blocks, 1)
|
||||
SetCheckSum(blocks, 0)
|
||||
|
||||
print('Validating all checksums')
|
||||
ValidateCheckSums(blocks)
|
||||
end
|
||||
|
||||
--Load dumpdata to emulator memory
|
||||
if DEBUG then
|
||||
print('Sending dumpdata to emulator memory')
|
||||
err = LoadEmulator(blocks)
|
||||
if err then return oops(err) end
|
||||
core.clearCommandBuffer()
|
||||
print('The simulation is now prepared.\n --> run \"hf mf sim 5 '..uid..'\" <--')
|
||||
end
|
||||
end
|
||||
main(args)
|
|
@ -46,12 +46,18 @@ int ukbhit(void) {
|
|||
#endif
|
||||
|
||||
// log files functions
|
||||
void AddLogLine(char *fileName, char *extData, char *c) {
|
||||
void AddLogLine(char *file, char *extData, char *c) {
|
||||
FILE *fLog = NULL;
|
||||
char filename[FILE_PATH_SIZE] = {0x00};
|
||||
int len = 0;
|
||||
|
||||
fLog = fopen(fileName, "a");
|
||||
len = strlen(file);
|
||||
if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE;
|
||||
memcpy(filename, file, len);
|
||||
|
||||
fLog = fopen(filename, "a");
|
||||
if (!fLog) {
|
||||
printf("Could not append log file %s", fileName);
|
||||
printf("Could not append log file %s", filename);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -103,11 +109,13 @@ void print_hex(const uint8_t * data, const size_t len)
|
|||
}
|
||||
|
||||
char * sprint_hex(const uint8_t * data, const size_t len) {
|
||||
|
||||
int maxLen = ( len > 1024/3) ? 1024/3 : len;
|
||||
static char buf[1024];
|
||||
char * tmp = buf;
|
||||
size_t i;
|
||||
|
||||
for (i=0; i < len && i < 1024/3; i++, tmp += 3)
|
||||
for (i=0; i < maxLen; ++i, tmp += 3)
|
||||
sprintf(tmp, "%02x ", data[i]);
|
||||
|
||||
return buf;
|
||||
|
|
Loading…
Reference in a new issue