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:
iceman1001 2015-01-07 22:00:29 +01:00
parent d91a31f935
commit b915fda392
19 changed files with 1137 additions and 133 deletions

View file

@ -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;

View file

@ -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;

View file

@ -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);

View file

@ -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

View file

@ -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;
}

View file

@ -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);

View file

@ -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}

View file

@ -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;

View file

@ -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"},

View file

@ -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}
};

View file

@ -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++) {

View file

@ -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;
}
}

View file

@ -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,

View file

@ -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

View file

@ -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"

View file

@ -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
View 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
View 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)

View file

@ -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;