diff --git a/CHANGELOG.md b/CHANGELOG.md index e3db619fd..f7dc5d6a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file. This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... ## [unreleased][unreleased] + - Chg history and logfile are now saved into $HOME/.proxmark3/ (@doegox) - Chg optimization of iclass mac calculations on deviceside (@pwpiwi) - Add 'hf mf autopwn' - Autopwn function for Mifare Classic, extract all keys and dump card memory (@matthiaskonrath) - Add Lua paths: look for scripts also in ~/.proxmark/lua{scripts,libs} and /usr/local/share/proxmark3/lua{scripts,libs} (@doegox) diff --git a/appveyor.yml b/appveyor.yml index a0c261b2b..a0a4b18a9 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -76,10 +76,64 @@ clone_script: Write-Host "Update msys2 packages..." -NoNewLine $env:Path = "C:\ProxSpace\msys2\usr\bin;C:\ProxSpace\msys2\mingw32\bin;C:\ProxSpace\gcc-arm-none-eabi\bin;$env:Path" + + Function ExecUpdate($Name, $Cmd, $ErrorLine) { - C:\ProxSpace\msys2\msys2_shell.cmd -mingw32 -defterm -no-start /dev/null 1> msys1.txt 2>&1 + #--- begin Job + + $Job = Start-Job -Name "$Name" -ScriptBlock { + $env:Path = "C:\ProxSpace\msys\bin;$env:Path" + Set-Location $using:PWD - C:\ProxSpace\msys2\msys2_shell.cmd -mingw32 -defterm -no-start /dev/null 1> msys1.txt 2>&1 + $sb=[scriptblock]::Create("$using:Cmd") + #execute scriptblock + $Cond=&$sb + + return $Cond + } + + #--- end Job + + $JobTime=[System.Environment]::TickCount + while($true) { + Receive-Job -Job $Job -Keep -OutVariable Res 2>&1 6>&1 | Out-Null + + if ($Res -is "String" -and $Res -like "*$ErrorLine*"){ + Write-host "Exit by stop phrase" + break + } + + if ($Res -is [Object]){ + [bool]$needexit = $false + ForEach($line in $Res){ + if ($line -like "*$ErrorLine*"){ + Write-host "Exit by stop phrase [obj]" + $needexit = $true + break + } + } + if ($needexit) { + break + } + } + + if(Wait-Job $Job -Timeout 5){ + Write-host "Exit by end job" + break + } + + if ([System.Environment]::TickCount-$JobTime -gt 600000) { + Write-host "Exit by timeout" + break + } + } + + Remove-Job -Force $Job + } + + ExecUpdate "update1" "C:\ProxSpace\msys2\msys2_shell.cmd -mingw32 -defterm -no-start /dev/null" "terminate?MSYS2" + + ExecUpdate "update2" "C:\ProxSpace\msys2\msys2_shell.cmd -mingw32 -defterm -no-start /dev/null" "terminate?MSYS2" Write-Host "[ OK ]" -ForegroundColor Green install: diff --git a/armsrc/appmain.c b/armsrc/appmain.c index b593c826b..13aa6bc84 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -1134,7 +1134,8 @@ static void PacketReceived(PacketCommandNG *packet) { break; } case CMD_HF_MIFARE_EML_LOAD: { - MifareECardLoad(packet->oldarg[0], packet->oldarg[1]); + mfc_eload_t *payload = (mfc_eload_t *) packet->data.asBytes; + MifareECardLoadExt(payload->sectorcnt, payload->keytype); break; } // Work with "magic Chinese" card diff --git a/armsrc/iclass.c b/armsrc/iclass.c index c8504e5ed..b550158cc 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -55,7 +55,13 @@ #include "protocols.h" #include "ticks.h" -static int timeout = 4096; +static int g_wait = 300; +static int timeout = 2900; +static uint32_t time_rdr = 0; +static uint32_t time_delta = 0; +static uint32_t time_delta_wait = 0; +static uint32_t time_response = 0; + static int SendIClassAnswer(uint8_t *resp, int respLen, uint16_t delay); int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf); @@ -151,7 +157,7 @@ typedef struct { static tUartIc Uart; static void OnError(uint8_t reason) { - reply_old(CMD_ACK, 0, reason, 0, 0, 0); + reply_mix(CMD_ACK, 0, reason, 0, 0, 0); switch_off(); } @@ -160,10 +166,12 @@ static void uart_reset(void) { Uart.synced = false; Uart.frame = false; } + static void uart_init(uint8_t *data) { Uart.buf = data; uart_reset(); } + static void uart_bit(uint8_t bit) { static uint8_t buf = 0xff; static uint8_t n_buf; @@ -1427,7 +1435,6 @@ int doIClassSimulation(int simulationMode, uint8_t *reader_mac_buf) { uint32_t time_0 = GetCountSspClk(); uint32_t t2r_stime = 0, t2r_etime = 0; uint32_t r2t_stime, r2t_etime = 0; - LED_A_ON(); bool buttonPressed = false; @@ -1717,6 +1724,8 @@ static void TransmitIClassCommand(const uint8_t *cmd, int len, int *samples, int bool firstpart = true; uint8_t sendbyte; + time_rdr = 0; + FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); AT91C_BASE_SSC->SSC_THR = 0x00; @@ -1755,6 +1764,8 @@ static void TransmitIClassCommand(const uint8_t *cmd, int len, int *samples, int } } + time_rdr = GetCountSspClk(); + if (samples) { if (wait) *samples = (c + *wait) << 3; @@ -1827,7 +1838,7 @@ void ReaderTransmitIClass(uint8_t *frame, int len) { // If a response is captured return TRUE // If it takes too long return FALSE //----------------------------------------------------------------------------- -static int GetIClassAnswer(uint8_t *receivedResponse, int maxLen, int *samples, int *elapsed) { +static int GetIClassAnswer(uint8_t *receivedResponse, int maxLen, int *samples, int *wait) { // buffer needs to be 512 bytes // maxLen is not used... @@ -1837,13 +1848,16 @@ static int GetIClassAnswer(uint8_t *receivedResponse, int maxLen, int *samples, // Setup UART/DEMOD to receive DemodIcInit(receivedResponse); - if (elapsed) *elapsed = 0; - // Set FPGA mode to "reader listen mode", no modulation (listen // only, since we are receiving, not transmitting). FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_LISTEN); - SpinDelayUs(320); //310 Tout= 330us (iso15603-2) (330/21.3) take consideration for clock increments. + time_delta = GetCountSspClk() - time_rdr; + + SpinDelayUs(g_wait); //310 Tout= 330us (iso15603-2) (330/21.3) take consideration for clock increments. + time_delta_wait = GetCountSspClk() - time_rdr - time_delta; + + uint32_t foo = GetCountSspClk(); // clear RXRDY: uint8_t b = (uint8_t)AT91C_BASE_SSC->SSC_RHR; (void)b; @@ -1861,15 +1875,16 @@ static int GetIClassAnswer(uint8_t *receivedResponse, int maxLen, int *samples, } // keep tx buffer in a defined state anyway. +/* if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) { AT91C_BASE_SSC->SSC_THR = 0x00; - // To make use of exact timing of next command from reader!! - if (elapsed)(*elapsed)++; } - +*/ // Wait for byte be become available in rx holding register if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) { - if (c >= timeout) return false; + + if ( GetCountSspClk() - foo > timeout) return false; +// if (c >= timeout) return false; c++; @@ -1881,25 +1896,28 @@ static int GetIClassAnswer(uint8_t *receivedResponse, int maxLen, int *samples, if (ManchesterDecoding_iclass(b & 0x0f)) { if (samples) *samples = c << 3; + + time_response = GetCountSspClk() - foo; return true; } } } + return false; } int ReaderReceiveIClass(uint8_t *receivedAnswer) { int samples = 0; - if (!GetIClassAnswer(receivedAnswer, 0, &samples, NULL)) - return false; + if (GetIClassAnswer(receivedAnswer, 0, &samples, NULL) == false) + return 0; rsamples += samples; LogTrace(receivedAnswer, Demod.len, rsamples, rsamples, NULL, false); if (samples == 0) - return false; + return 0; return Demod.len; } @@ -1924,7 +1942,7 @@ void setupIclassReader() { // Now give it time to spin up. // Signal field is on with the appropriate LED FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_READER_MOD); - SpinDelay(300); + SpinDelay(500); StartCountSspClk(); @@ -1936,13 +1954,20 @@ bool sendCmdGetResponseWithRetries(uint8_t *command, size_t cmdsize, uint8_t *re ReaderTransmitIClass(command, cmdsize); + //iceman - if received size is bigger than expected, we smash the stack here // since its called with fixed sized arrays + + // update/write commadn takes 4ms to 15ms before responding + if ( command[0] == ICLASS_CMD_UPDATE ) + g_wait = 15000; + uint8_t got_n = ReaderReceiveIClass(resp); // 0xBB is the internal debug separator byte.. if (expected_size != got_n || (resp[0] == 0xBB || resp[7] == 0xBB || resp[2] == 0xBB)) { //try again + SpinDelayUs(400); continue; } @@ -2396,8 +2421,6 @@ void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain) { if (isOK) goto out; - SpinDelayUs(400); //iClass (iso15693-2) should timeout after 330us. - // Auth Sequence MUST begin with reading e-purse. (block2) // Card selected, now read e-purse (cc) (block2) (only 8 bytes no CRC) ReaderTransmitIClass(readcheck_cc, sizeof(readcheck_cc)); diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index 63cf1128d..17570e680 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -1342,8 +1342,6 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da for (uint16_t i = s_point; i < keyCount; ++i) { - //if ( i % 100 == 0) Dbprintf("ChkKeys_fast: sector %d | checking %d | %d found | s_point %d", s, i, foundkeys, s_point); - // Allow button press / usb cmd to interrupt device if (BUTTON_PRESS() && !data_available()) { goto OUT; @@ -1525,6 +1523,33 @@ OUT: FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); BigBuf_free(); BigBuf_Clear_ext(false); + + // special trick ecfill + if (use_flashmem && foundkeys == allkeys) { + + uint8_t block[16] = {0}; + for (int i = 0; i < sectorcnt; i++) { + + uint8_t blockno; + if (i < 32) { + blockno = (i * 4) ^ 0x3; + } else { + blockno = (32 * 4 + (i - 32) * 16) ^ 0xF; + } + // get ST + emlGetMem(block, blockno, 1); + + memcpy(block, k_sector[i].keyA, 6); + memcpy(block + 10, k_sector[i].keyB, 6); + + emlSetMem_xt(block, blockno, 1, sizeof(block)); + } + int oldbg = DBGLEVEL; + DBGLEVEL = DBG_NONE; + MifareECardLoad(sectorcnt, 0); + MifareECardLoad(sectorcnt, 1); + DBGLEVEL = oldbg; + } } else { // partial/none keys found reply_mix(CMD_ACK, foundkeys, 0, 0, 0, 0); @@ -1669,10 +1694,15 @@ void MifareEMemGet(uint8_t blockno, uint8_t blockcnt) { // Load a card into the emulator memory // //----------------------------------------------------------------------------- -int MifareECardLoad(uint32_t arg0, uint32_t arg1) { +int MifareECardLoadExt(uint8_t numSectors, uint8_t keyType) { + int retval = MifareECardLoad(numSectors, keyType); + reply_ng(CMD_HF_MIFARE_EML_LOAD, retval, NULL, 0); + return retval; +} + +int MifareECardLoad(uint8_t numSectors, uint8_t keyType) { + uint32_t cuid = 0; - uint8_t numSectors = arg0; - uint8_t keyType = arg1; struct Crypto1State mpcs = {0, 0}; struct Crypto1State *pcs; pcs = &mpcs; @@ -1683,42 +1713,40 @@ int MifareECardLoad(uint32_t arg0, uint32_t arg1) { uint8_t uid[10] = {0x00}; LED_A_ON(); - LED_B_OFF(); - LED_C_OFF(); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); clear_trace(); set_tracing(true); - bool isOK = true; + int retval; if (!iso14443a_select_card(uid, NULL, &cuid, true, 0, true)) { - isOK = false; - if (DBGLEVEL >= 1) Dbprintf("Can't select card"); + retval = PM3_ESOFT; + if (DBGLEVEL > DBG_ERROR) Dbprintf("Can't select card"); + goto out; } - for (uint8_t sectorNo = 0; isOK && sectorNo < numSectors; sectorNo++) { + for (uint8_t sectorNo = 0; sectorNo < numSectors; sectorNo++) { uint64_t ui64Key = emlGetKey(sectorNo, keyType); if (sectorNo == 0) { - if (isOK && mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_FIRST)) { - if (DBGLEVEL >= 1) Dbprintf("Sector[%2d]. Auth error", sectorNo); + if (mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_FIRST)) { + if (DBGLEVEL > DBG_ERROR) Dbprintf("Sector[%2d]. Auth error", sectorNo); break; } } else { - if (isOK && mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_NESTED)) { - isOK = false; - if (DBGLEVEL >= 1) Dbprintf("Sector[%2d]. Auth nested error", sectorNo); - break; + if (mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keyType, ui64Key, AUTH_NESTED)) { + retval = PM3_ESOFT; + if (DBGLEVEL > DBG_ERROR) Dbprintf("Sector[%2d]. Auth nested error", sectorNo); + goto out; } } - for (uint8_t blockNo = 0; isOK && blockNo < NumBlocksPerSector(sectorNo); blockNo++) { - if (isOK && mifare_classic_readblock(pcs, cuid, FirstBlockOfSector(sectorNo) + blockNo, dataoutbuf)) { - isOK = false; - if (DBGLEVEL >= 1) Dbprintf("Error reading sector %2d block %2d", sectorNo, blockNo); + for (uint8_t blockNo = 0; blockNo < NumBlocksPerSector(sectorNo); blockNo++) { + if (mifare_classic_readblock(pcs, cuid, FirstBlockOfSector(sectorNo) + blockNo, dataoutbuf)) { + retval = PM3_ESOFT; + if (DBGLEVEL > DBG_ERROR) Dbprintf("Error reading sector %2d block %2d", sectorNo, blockNo); break; } - if (isOK) { if (blockNo < NumBlocksPerSector(sectorNo) - 1) { emlSetMem(dataoutbuf, FirstBlockOfSector(sectorNo) + blockNo, 1); } else { // sector trailer, keep the keys, set only the AC @@ -1729,22 +1757,19 @@ int MifareECardLoad(uint32_t arg0, uint32_t arg1) { } } - } - - if (mifare_classic_halt(pcs, cuid)) - if (DBGLEVEL >= 1) + if (mifare_classic_halt(pcs, cuid)) { + if (DBGLEVEL > DBG_ERROR) Dbprintf("Halt error"); + } - // ----------------------------- crypto1 destroy + if (DBGLEVEL >= DBG_INFO) DbpString("Emulator fill sectors finished"); + +out: crypto1_destroy(pcs); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LEDsoff(); - - if (DBGLEVEL >= 2) DbpString("EMUL FILL SECTORS FINISHED"); - set_tracing(false); - return (isOK) ? PM3_SUCCESS : PM3_EUNDEF; + return retval; } diff --git a/armsrc/mifarecmd.h b/armsrc/mifarecmd.h index 445b04130..d563e37a8 100644 --- a/armsrc/mifarecmd.h +++ b/armsrc/mifarecmd.h @@ -31,7 +31,8 @@ void MifareChkKeys_fast(uint32_t arg0, uint32_t arg1, uint32_t arg2, uint8_t *da void MifareEMemClr(void); void MifareEMemSet(uint8_t blockno, uint8_t blockcnt, uint8_t blockwidth, uint8_t *datain); void MifareEMemGet(uint8_t blockno, uint8_t blockcnt); -int MifareECardLoad(uint32_t arg0, uint32_t arg1); +int MifareECardLoad(uint8_t sectorcnt, uint8_t keytype); +int MifareECardLoadExt(uint8_t numSectors, uint8_t keyType); void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint8_t *datain); // Work with "magic Chinese" card void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint8_t *datain); diff --git a/client/Makefile b/client/Makefile index d9e43d445..fc7fa520b 100644 --- a/client/Makefile +++ b/client/Makefile @@ -73,7 +73,7 @@ ifneq (,$(PM3_SHARE_PATH)) PM3CFLAGS += -DPM3_SHARE_PATH=\"$(PM3_SHARE_PATH)\" endif ifneq (,$(findstring MINGW,$(platform))) - PM3CFLAGS += -mno-ms-bitfields + PM3CFLAGS += -mno-ms-bitfields -fexec-charset=cp850 endif CXXFLAGS ?= -Wall -Werror -O3 PM3CXXFLAGS = $(CXXFLAGS) -I../include diff --git a/client/cmdhfmf.c b/client/cmdhfmf.c index aed756278..7a1d2f4b2 100644 --- a/client/cmdhfmf.c +++ b/client/cmdhfmf.c @@ -751,12 +751,56 @@ static uint8_t NumBlocksPerSector(uint8_t sectorNo) { return 16; } } + static uint8_t GetSectorFromBlockNo(uint8_t blockNo) { if (blockNo < 128) return blockNo / 4; else return 32 + ((128 - blockNo) / 16); } + +static char GetFormatFromSector(uint8_t sectorNo) { + switch (sectorNo) { + case MIFARE_MINI_MAXSECTOR: + return '0'; + case MIFARE_1K_MAXSECTOR: + return '1'; + case MIFARE_2K_MAXSECTOR: + return '2'; + case MIFARE_4K_MAXSECTOR: + return '4'; + default : + return ' '; + } +} + +static int FastDumpWithEcFill(uint8_t numsectors){ + PacketResponseNG resp; + + mfc_eload_t payload; + payload.sectorcnt = numsectors; + payload.keytype = 0; + + // ecfill key A + clearCommandBuffer(); + SendCommandNG(CMD_HF_MIFARE_EML_LOAD, (uint8_t *)&payload, sizeof(payload)); + + int res = WaitForResponseTimeout(CMD_HF_MIFARE_EML_LOAD, &resp, 2000); + if ( res != PM3_SUCCESS) { + } + + // ecfill key B + payload.keytype = 1; + + clearCommandBuffer(); + SendCommandNG(CMD_HF_MIFARE_EML_LOAD, (uint8_t *)&payload, sizeof(payload)); + res = WaitForResponseTimeout(CMD_HF_MIFARE_EML_LOAD, &resp, 2000); + if ( res != PM3_SUCCESS) { + + } + return PM3_SUCCESS; +} + static int CmdHF14AMfDump(const char *Cmd) { uint64_t t1 = msclock(); @@ -1242,7 +1286,12 @@ static int CmdHF14AMfNested(const char *Cmd) { } PrintAndLogEx(SUCCESS, "Testing known keys. Sector count=%d", SectorsCnt); - mfCheckKeys_fast(SectorsCnt, true, true, 1, ARRAYLEN(g_mifare_default_keys) + 1, keyBlock, e_sector, false); + int res = mfCheckKeys_fast(SectorsCnt, true, true, 1, ARRAYLEN(g_mifare_default_keys) + 1, keyBlock, e_sector, false); + if ( res == PM3_SUCCESS ) { + // all keys found + PrintAndLogEx(SUCCESS, "Fast check found all keys"); + goto jumptoend; + } uint64_t t2 = msclock() - t1; PrintAndLogEx(SUCCESS, "Time to check %d known keys: %.0f seconds\n", ARRAYLEN(g_mifare_default_keys), (float)t2 / 1000.0); @@ -1329,6 +1378,7 @@ static int CmdHF14AMfNested(const char *Cmd) { } } +jumptoend: //print them printKeyTable(SectorsCnt, e_sector); @@ -1612,56 +1662,69 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { bool legacy_mfchk = false; bool prng_type = false; bool verbose = false; + bool has_filename = false; + bool errors = false; // Parse the options given by the user - ctmp = tolower(param_getchar(Cmd, 0)); - while ((ctmp = param_getchar(Cmd, cmdp))) { + while ( (ctmp = param_getchar(Cmd, cmdp)) && !errors ) { switch (tolower(ctmp)) { case 'h': return usage_hf14_autopwn(); case 'f': if (param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE) >= FILE_PATH_SIZE) { PrintAndLogEx(FAILED, "Filename too long"); + errors = true; + } else { + has_filename = true; } - cmdp ++; + cmdp += 2; break; case 'l': legacy_mfchk = true; + cmdp++; break; case 'v': verbose = true; + cmdp++; break; case '*': // Get the number of sectors sectors_cnt = NumOfSectors(param_getchar(Cmd, cmdp + 1)); block_cnt = NumOfBlocks(param_getchar(Cmd, cmdp + 1)); - cmdp ++; + cmdp += 2; break; case 'k': // Get the known block number if (param_getchar(Cmd, cmdp + 1) == 0x00) { - PrintAndLogEx(WARNING, "Sector number is missing"); - return PM3_EINVARG; + errors = true; + break; } + blockNo = param_get8(Cmd, cmdp + 1); + // Get the knonwn block type ctmp = tolower(param_getchar(Cmd, cmdp + 2)); if (ctmp != 'a' && ctmp != 'b') { PrintAndLogEx(WARNING, "Key type must be A or B"); - return PM3_EINVARG; + errors = true; + break; } + if (ctmp != 'a') { keyType = 1; } + // Get the known block key if (param_gethex(Cmd, cmdp + 3, key, 12)) { PrintAndLogEx(WARNING, "Key must include 12 HEX symbols"); + errors = true; return PM3_EINVARG; } know_target_key = true; cmdp += 3; case 's': slow = true; + cmdp++; break; case 'i': SetSIMDInstr(SIMD_AUTO); @@ -1695,7 +1758,10 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { PrintAndLogEx(WARNING, "Unknown parameter '%c'\n", ctmp); return usage_hf14_autopwn(); } - cmdp++; + } + + if ( errors ) { + return usage_hf14_autopwn(); } // Create the key storage stucture @@ -1732,19 +1798,20 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { // check the user supplied key if (know_target_key == false) - PrintAndLogEx(WARNING, "No known key was supplied, key recovery might fail"); + PrintAndLogEx(WARNING, "no known key was supplied, key recovery might fail"); else { - if (verbose) PrintAndLogEx(INFO, _YELLOW_("======================= START KNOWN KEY ATTACK =======================")); + if (verbose) { + PrintAndLogEx(INFO, _YELLOW_("======================= START KNOWN KEY ATTACK =======================")); + } if (mfCheckKeys(FirstBlockOfSector(blockNo), keyType, true, 1, key, &key64) == PM3_SUCCESS) { - PrintAndLogEx(INFO, "Using valid key: sector: %3d key type: %c key: " _YELLOW_("%s") "(used for nested / hardnested attack)", + PrintAndLogEx(INFO, "target sector:%3u key type: %c -- using valid key [ " _YELLOW_("%s") "] (used for nested / hardnested attack)", blockNo, keyType ? 'B' : 'A', sprint_hex(key, sizeof(key)) ); // Store the key for the nested / hardnested attack (if supplied by the user) - e_sector[blockNo].Key[keyType] = bytes_to_num(key, 6); - e_sector[blockNo].foundKey[keyType] = 'U'; + e_sector[blockNo].Key[keyType] = key64; } else { know_target_key = false; PrintAndLogEx(FAILED, "Key is wrong. Can't authenticate to sector:"_RED_("%3d") " key type: "_RED_("%c") " key: " _RED_("%s"), @@ -1752,8 +1819,9 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { keyType ? 'B' : 'A', sprint_hex(key, sizeof(key)) ); - PrintAndLogEx(WARNING, "Falling back to dictionary"); + PrintAndLogEx(WARNING, "falling back to dictionary"); } + // Check if the user supplied key is used by other sectors for (int i = 0; i < sectors_cnt; i++) { for (int j = 0; j < 2; j++) { @@ -1768,13 +1836,13 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { know_target_key = true; blockNo = i; keyType = j; - PrintAndLogEx(SUCCESS, "Found valid key: sector: %3d key type: %c key: " _YELLOW_("%s") "(used for nested / hardnested attack)", + PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [ " _YELLOW_("%s") "] (used for nested / hardnested attack)", i, j ? 'B' : 'A', sprint_hex(key, sizeof(key)) ); } else { - PrintAndLogEx(SUCCESS, "Found valid key: sector: %3d key type: %c key: " _YELLOW_("%s"), + PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [ " _YELLOW_("%s") "]", i, j ? 'B' : 'A', sprint_hex(key, sizeof(key)) @@ -1787,16 +1855,21 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { if (verbose) PrintAndLogEx(INFO, _YELLOW_("======================= STOP KNOWN KEY ATTACK =======================")); } + bool load_success = true; // Load the dictionary - if (strlen(filename) != 0) { + if (has_filename) { int res = loadFileDICTIONARY_safe(filename, (void**) &keyBlock, 6, &key_cnt); - if (res != PM3_SUCCESS || key_cnt <= 0 || keyBlock == NULL) { + if (res != PM3_SUCCESS || key_cnt == 0 || keyBlock == NULL) { PrintAndLogEx(FAILED, "An error occurred while loading the dictionary! (we will use the default keys now)"); - if (keyBlock != NULL) free(keyBlock); - goto useDefaultKeys; + if (keyBlock != NULL) + free(keyBlock); + + load_success = false; } - } else { -useDefaultKeys: + + } + + if ( has_filename == false || load_success == false ) { keyBlock = calloc(ARRAYLEN(g_mifare_default_keys), 6); if (keyBlock == NULL) { free(e_sector); @@ -1807,6 +1880,7 @@ useDefaultKeys: num_to_bytes(g_mifare_default_keys[cnt], 6, keyBlock + cnt * 6); } key_cnt = ARRAYLEN(g_mifare_default_keys); + PrintAndLogEx(SUCCESS, "loaded " _GREEN_("%2d") "keys from hardcoded default array", key_cnt); } // Use the dictionary to find sector keys on the card @@ -1833,10 +1907,12 @@ useDefaultKeys: printf("\n"); fflush(stdout); } else { + int chunksize = key_cnt > (PM3_CMD_DATA_SIZE / 6) ? (PM3_CMD_DATA_SIZE / 6) : key_cnt; bool firstChunk = true, lastChunk = false; + for (uint8_t strategy = 1; strategy < 3; strategy++) { - PrintAndLogEx(INFO, "Running strategy %u", strategy); + PrintAndLogEx(INFO, "running strategy %u", strategy); // main keychunk loop for (int i = 0; i < key_cnt; i += chunksize) { @@ -1855,7 +1931,7 @@ useDefaultKeys: if (firstChunk) firstChunk = false; // all keys, aborted - if (res == 0 || res == 2) { + if (res == PM3_SUCCESS) { i = key_cnt; strategy = 3; break; // Exit the loop @@ -1875,20 +1951,19 @@ useDefaultKeys: e_sector[i].foundKey[j] = 'D'; num_to_bytes(e_sector[i].Key[j], 6, tmp_key); - // Store valid credentials for the nested / hardnested attack if none exist if (know_target_key == false) { num_to_bytes(e_sector[i].Key[j], 6, key); know_target_key = true; blockNo = i; keyType = j; - PrintAndLogEx(SUCCESS, "Found valid key: sector: %3d key type: %c key: " _YELLOW_("%s") "(used for nested / hardnested attack)", + PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [ " _YELLOW_("%s") "] (used for nested / hardnested attack)", i, j ? 'B' : 'A', sprint_hex(tmp_key, sizeof(tmp_key)) ); } else { - PrintAndLogEx(SUCCESS, "Found valid key: sector: %3d key type: %c key: " _YELLOW_("%s"), + PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [ " _YELLOW_("%s") "]", i, j ? 'B' : 'A', sprint_hex(tmp_key, sizeof(tmp_key)) @@ -1926,21 +2001,11 @@ useDefaultKeys: PrintAndLogEx(SUCCESS, "\nFound valid key: %012" PRIx64 "\n", key64); break; } - num_to_bytes(key64, 6, key); - // Check if the darkside key is valid - if (mfCheckKeys(FirstBlockOfSector(blockNo), keyType, true, 1, key, &key64) != PM3_SUCCESS) { - PrintAndLogEx(FAILED, "The key generated by the darkside attack is not valid!" - _RED_("%3d") " key type: "_RED_("%c") " key: " _RED_("%s"), - blockNo, - keyType ? 'B' : 'A', - sprint_hex(key, sizeof(key)) - ); - goto noValidKeyFound; - } + // Store the keys - e_sector[blockNo].Key[keyType] = bytes_to_num(key, 6); + e_sector[blockNo].Key[keyType] = key64; e_sector[blockNo].foundKey[keyType] = 'S'; - PrintAndLogEx(SUCCESS, "Found valid key: sector: %3d key type: %c key: " _YELLOW_("%s") "(used for nested / hardnested attack)", + PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [ " _YELLOW_("%s") "] (used for nested / hardnested attack)", blockNo, keyType ? 'B' : 'A', sprint_hex(key, sizeof(key)) @@ -1953,6 +2018,7 @@ noValidKeyFound: return PM3_ESOFT; } } + free(keyBlock); // Clear the needed variables num_to_bytes(0, 6, tmp_key); @@ -1979,7 +2045,7 @@ noValidKeyFound: if (mfCheckKeys(FirstBlockOfSector(i), j, true, 1, tmp_key, &key64) == PM3_SUCCESS) { e_sector[i].Key[j] = bytes_to_num(tmp_key, 6); e_sector[i].foundKey[j] = 'R'; - PrintAndLogEx(SUCCESS, "Found valid key: sector: %3d key type: %c key: " _YELLOW_("%s"), + PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [ " _YELLOW_("%s") "]", i, j ? 'B' : 'A', sprint_hex(tmp_key, sizeof(tmp_key)) @@ -1995,7 +2061,7 @@ noValidKeyFound: if (e_sector[current_sector_i].foundKey[0] && !e_sector[current_sector_i].foundKey[1]) { if (verbose) { PrintAndLogEx(INFO, _YELLOW_("======================= START READ B KEY ATTACK =======================")); - PrintAndLogEx(INFO, "Reading B key: sector: %3d key type: %c", + PrintAndLogEx(INFO, "reading B key: sector: %3d key type: %c", current_sector_i, current_key_type_i ? 'B' : 'A'); } @@ -2021,13 +2087,13 @@ noValidKeyFound: e_sector[current_sector_i].foundKey[current_key_type_i] = 'A'; e_sector[current_sector_i].Key[current_key_type_i] = key64; num_to_bytes(key64, 6, tmp_key); - PrintAndLogEx(SUCCESS, "Found valid key: sector: %3d key type: %c key: " _YELLOW_("%s"), + PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [ " _YELLOW_("%s") "]", current_sector_i, current_key_type_i ? 'B' : 'A', sprint_hex(tmp_key, sizeof(tmp_key)) ); } else { - if (verbose) PrintAndLogEx(WARNING, "Unknown B key: sector: %3d key type: %c (reading the B key was not possible, maybe due to insufficient access rights) ", + if (verbose) PrintAndLogEx(WARNING, "unknown B key: sector: %3d key type: %c (reading the B key was not possible, maybe due to insufficient access rights) ", current_sector_i, current_key_type_i ? 'B' : 'A' ); @@ -2043,7 +2109,7 @@ skipReadBKey: uint8_t retries = 0; if (verbose) { PrintAndLogEx(INFO, _YELLOW_("======================= START NESTED ATTACK =======================")); - PrintAndLogEx(INFO, "Sector no: %3d, target key type: %c", + PrintAndLogEx(INFO, "sector no: %3d, target key type: %c", current_sector_i, current_key_type_i ? 'B' : 'A'); } @@ -2089,7 +2155,7 @@ tryNested: tryHardnested: // If the nested attack fails then we try the hardnested attack if (verbose) { PrintAndLogEx(INFO, _YELLOW_("======================= START HARDNESTED ATTACK =======================")); - PrintAndLogEx(INFO, "Sector no: %3d, target key type: %c, Slow: %s", + PrintAndLogEx(INFO, "sector no: %3d, target key type: %c, Slow: %s", current_sector_i, current_key_type_i ? 'B' : 'A', slow ? "Yes" : "No"); @@ -2121,7 +2187,7 @@ tryHardnested: // If the nested attack fails then we try the hardnested attack } // Check if the key was found if (e_sector[current_sector_i].foundKey[current_key_type_i]) { - PrintAndLogEx(SUCCESS, "Found valid key: sector: %3d key type: %c key: " _YELLOW_("%s"), + PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [ " _YELLOW_("%s") "]", current_sector_i, current_key_type_i ? 'B' : 'A', sprint_hex(tmp_key, sizeof(tmp_key)) @@ -2134,7 +2200,7 @@ tryHardnested: // If the nested attack fails then we try the hardnested attack // Show the results to the user PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "Found Keys:"); + PrintAndLogEx(INFO, "found Keys:"); char strA[12 + 1] = {0}; char strB[12 + 1] = {0}; @@ -2172,10 +2238,11 @@ tryHardnested: // If the nested attack fails then we try the hardnested attack ); // Dump the keys - PrintAndLogEx(INFO, "\nSaving keys"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "saving keys"); createMfcKeyDump(sectors_cnt, e_sector, GenerateFilename("hf-mf-", "-key.bin")); - PrintAndLogEx(SUCCESS, "Transferring keys to simulator memory (Cmd Error: 04 can occur)"); + PrintAndLogEx(SUCCESS, "transferring keys to simulator memory (Cmd Error: 04 can occur)"); for (current_sector_i = 0; current_sector_i < sectors_cnt; current_sector_i++) { mfEmlGetMem(block, current_sector_i, 1); @@ -2187,13 +2254,8 @@ tryHardnested: // If the nested attack fails then we try the hardnested attack mfEmlSetMem(block, FirstBlockOfSector(current_sector_i) + NumBlocksPerSector(current_sector_i) - 1, 1); } - // using ecfill trick, keys already in emulator mem, load data using Key A - clearCommandBuffer(); - SendCommandMIX(CMD_HF_MIFARE_EML_LOAD, sectors_cnt, 0, 0, NULL, 0); - - // using ecfill trick, keys already in emulator mem, load data using Key B - clearCommandBuffer(); - SendCommandMIX(CMD_HF_MIFARE_EML_LOAD, sectors_cnt, 1, 0, NULL, 0); + // use ecfill trick + FastDumpWithEcFill(sectors_cnt); bytes = block_cnt * MFBLOCK_SIZE; dump = calloc(bytes, sizeof(uint8_t)); @@ -2204,7 +2266,7 @@ tryHardnested: // If the nested attack fails then we try the hardnested attack } memset(dump, 0, bytes); - PrintAndLogEx(INFO, "Downloading the card content from emulator memory"); + PrintAndLogEx(INFO, "downloading the card content from emulator memory"); if (!GetFromDevice(BIG_BUF_EML, dump, bytes, 0, NULL, 0, NULL, 2500, false)) { PrintAndLogEx(ERR, "Fail, transfer from device time-out"); free(e_sector); @@ -2226,7 +2288,7 @@ tryHardnested: // If the nested attack fails then we try the hardnested attack // Generate and show statistics t1 = msclock() - t1; - PrintAndLogEx(INFO, "Autopwn execution time: " _YELLOW_("%.0f") " seconds", (float)t1 / 1000.0); + PrintAndLogEx(INFO, "autopwn execution time: " _YELLOW_("%.0f") " seconds", (float)t1 / 1000.0); free(dump); free(e_sector); @@ -2436,7 +2498,7 @@ static int CmdHF14AMfChk_fast(const char *Cmd) { firstChunk = false; // all keys, aborted - if (res == 0 || res == 2) + if (res == PM3_SUCCESS || res == 2) goto out; } // end chunks of keys firstChunk = true; @@ -2464,6 +2526,13 @@ out: printKeyTable(sectorsCnt, e_sector); + if ( use_flashmemory && found_keys == (sectorsCnt << 1) ) { + PrintAndLogEx(SUCCESS, "Card dumped aswell. run " _YELLOW_("`%s %c`"), + "hf mf esave", + GetFormatFromSector(sectorsCnt) + ); + } + if (transferToEml) { // fast push mode conn.block_after_ACK = true; @@ -2482,6 +2551,10 @@ out: mfEmlSetMem(block, blockno, 1); } PrintAndLogEx(SUCCESS, "Found keys have been transferred to the emulator memory"); + + if ( found_keys == (sectorsCnt << 1) ) { + FastDumpWithEcFill(sectorsCnt); + } } if (createDumpFile) { @@ -3459,8 +3532,12 @@ static int CmdHF14AMfECFill(const char *Cmd) { } PrintAndLogEx(NORMAL, "--params: numSectors: %d, keyType: %c\n", numSectors, (keyType == 0) ? 'A' : 'B'); + + mfc_eload_t payload; + payload.sectorcnt = numSectors; + payload.keytype = keyType; clearCommandBuffer(); - SendCommandMIX(CMD_HF_MIFARE_EML_LOAD, numSectors, keyType, 0, NULL, 0); + SendCommandNG(CMD_HF_MIFARE_EML_LOAD, (uint8_t *)&payload, sizeof(payload)); return PM3_SUCCESS; } diff --git a/client/cmdhw.c b/client/cmdhw.c index b6cb2bd87..1d65f5d1d 100644 --- a/client/cmdhw.c +++ b/client/cmdhw.c @@ -619,16 +619,14 @@ int CmdHW(const char *Cmd) { void pm3_version(bool verbose, bool oneliner) { - if (oneliner) { - char msg[70]; - memset(msg, 0x00, sizeof(msg)); - strcat(msg, "Client: RRG/Iceman compiled with "); #if defined(__clang__) - strcat(msg + strlen(msg), _YELLOW_("Clang/LLVM "__VERSION__)); +# define PM3CLIENTCOMPILER "Clang/LLVM " #elif defined(__GNUC__) || defined(__GNUG__) - strcat(msg + strlen(msg), _YELLOW_("GCC "__VERSION__)); +# define PM3CLIENTCOMPILER "GCC " #endif - PrintAndLogEx(NORMAL, "%s", msg); + + if (oneliner) { + PrintAndLogEx(NORMAL, "Client: RRG/Iceman compiled with " _YELLOW_(PM3CLIENTCOMPILER __VERSION__)); return; } @@ -644,12 +642,7 @@ void pm3_version(bool verbose, bool oneliner) { PrintAndLogEx(NORMAL, "\n" _BLUE_(" [ Proxmark3 RFID instrument ]") "\n"); PrintAndLogEx(NORMAL, "\n [ CLIENT ]"); PrintAndLogEx(NORMAL, " client: RRG/Iceman"); // TODO version info? -#if defined(__clang__) - PrintAndLogEx(NORMAL, " compiled with Clang/LLVM "__VERSION__); -#elif defined(__GNUC__) || defined(__GNUG__) - PrintAndLogEx(NORMAL, " compiled with GCC "__VERSION__); -#endif - + PrintAndLogEx(NORMAL, " compiled with " PM3CLIENTCOMPILER __VERSION__); PrintAndLogEx(NORMAL, "\n [ PROXMARK RDV4 ]"); PrintAndLogEx(NORMAL, " external flash: %s", IfPm3Flash() ? _GREEN_("present") : _YELLOW_("absent")); PrintAndLogEx(NORMAL, " smartcard reader: %s", IfPm3Smartcard() ? _GREEN_("present") : _YELLOW_("absent")); diff --git a/client/cmdlft55xx.c b/client/cmdlft55xx.c index 965a5db0b..46cc3e017 100644 --- a/client/cmdlft55xx.c +++ b/client/cmdlft55xx.c @@ -2129,9 +2129,11 @@ static int CmdT55xxChkPwds(const char *Cmd) { uint16_t keycount = 0; int res = loadFileDICTIONARY_safe(filename, (void**) &keyBlock, 4, &keycount); - if (res != PM3_SUCCESS || keycount <= 0 || keyBlock == NULL) { + if (res != PM3_SUCCESS || keycount == 0 || keyBlock == NULL) { PrintAndLogEx(WARNING, "No keys found in file"); - if (keyBlock != NULL) free(keyBlock); + if (keyBlock != NULL) + free(keyBlock); + return PM3_ESOFT; } diff --git a/client/fileutils.c b/client/fileutils.c index 500bb7ef8..72771f900 100644 --- a/client/fileutils.c +++ b/client/fileutils.c @@ -283,9 +283,9 @@ int saveFileJSON(const char *preferredName, JSONFileType ftype, uint8_t *data, s } case jsfIclass: { JsonSaveStr(root, "FileType", "iclass"); - uint8_t uid[8] = {0}; - memcpy(uid, data, 8); - JsonSaveBufAsHexCompact(root, "$.Card.UID", uid, sizeof(uid)); + uint8_t csn[8] = {0}; + memcpy(csn, data, 8); + JsonSaveBufAsHexCompact(root, "$.Card.CSN", csn, sizeof(csn)); for (size_t i = 0; i < (datalen / 8); i++) { char path[PATH_MAX_LENGTH] = {0}; @@ -316,13 +316,13 @@ int createMfcKeyDump(uint8_t sectorsCnt, sector_t *e_sector, char *fptr) { int i; if (fptr == NULL) { - return 1; + return PM3_EINVARG; } FILE *fkeys = fopen(fptr, "wb"); if (fkeys == NULL) { PrintAndLogEx(WARNING, "Could not create file " _YELLOW_("%s"), fptr); - return 1; + return PM3_EFILE; } PrintAndLogEx(SUCCESS, "Printing keys to binary file " _YELLOW_("%s")"...", fptr); @@ -338,14 +338,14 @@ int createMfcKeyDump(uint8_t sectorsCnt, sector_t *e_sector, char *fptr) { fclose(fkeys); PrintAndLogEx(SUCCESS, "Found keys have been dumped to " _YELLOW_("%s")" --> 0xffffffffffff has been inserted for unknown keys.", fptr); - return 0; + return PM3_SUCCESS; } int loadFile(const char *preferredName, const char *suffix, void *data, size_t maxdatalen, size_t *datalen) { if (data == NULL) return 1; char *fileName = filenamemcopy(preferredName, suffix); - if (fileName == NULL) return 1; + if (fileName == NULL) return PM3_EINVARG; int retval = PM3_SUCCESS; @@ -363,23 +363,24 @@ int loadFile(const char *preferredName, const char *suffix, void *data, size_t m if (fsize <= 0) { PrintAndLogEx(FAILED, "error, when getting filesize"); - retval = 1; + retval = PM3_EFILE; goto out; } uint8_t *dump = calloc(fsize, sizeof(uint8_t)); if (!dump) { PrintAndLogEx(FAILED, "error, cannot allocate memory"); - retval = 2; + retval = PM3_EMALLOC; goto out; } size_t bytes_read = fread(dump, 1, fsize, f); + fclose(f); if (bytes_read != fsize) { PrintAndLogEx(FAILED, "error, bytes read mismatch file size"); free(dump); - retval = 3; + retval = PM3_EFILE; goto out; } @@ -396,9 +397,7 @@ int loadFile(const char *preferredName, const char *suffix, void *data, size_t m *datalen = bytes_read; out: - fclose(f); free(fileName); - return retval; } @@ -432,7 +431,7 @@ int loadFileEML(const char *preferredName, void *data, size_t *datalen) { break; fclose(f); PrintAndLogEx(FAILED, "File reading error."); - retval = 2; + retval = PM3_EFILE; goto out; } @@ -471,13 +470,13 @@ int loadFileJSON(const char *preferredName, void *data, size_t maxdatalen, size_ root = json_load_file(fileName, 0, &error); if (!root) { PrintAndLogEx(ERR, "ERROR: json " _YELLOW_("%s") " error on line %d: %s", fileName, error.line, error.text); - retval = 2; + retval = PM3_ESOFT; goto out; } if (!json_is_object(root)) { PrintAndLogEx(ERR, "ERROR: Invalid json " _YELLOW_("%s") " format. root must be an object.", fileName); - retval = 3; + retval = PM3_ESOFT; goto out; } @@ -493,7 +492,7 @@ int loadFileJSON(const char *preferredName, void *data, size_t maxdatalen, size_ size_t sptr = 0; for (int i = 0; i < 256; i++) { if (sptr + 16 > maxdatalen) { - retval = 5; + retval = PM3_EMALLOC; goto out; } @@ -515,7 +514,7 @@ int loadFileJSON(const char *preferredName, void *data, size_t maxdatalen, size_ size_t sptr = 0; for (int i = 0; i < 256; i++) { if (sptr + 4 > maxdatalen) { - retval = 5; + retval = PM3_EMALLOC; goto out; } @@ -537,7 +536,7 @@ int loadFileJSON(const char *preferredName, void *data, size_t maxdatalen, size_ size_t sptr = 0; for (size_t i = 0; i < (maxdatalen / 4); i++) { if (sptr + 4 > maxdatalen) { - retval = 5; + retval = PM3_EMALLOC; goto out; } @@ -559,7 +558,7 @@ int loadFileJSON(const char *preferredName, void *data, size_t maxdatalen, size_ size_t sptr = 0; for (size_t i = 0; i < (maxdatalen / 8); i++) { if (sptr + 8 > maxdatalen) { - retval = 5; + retval = PM3_EMALLOC; goto out; } @@ -651,10 +650,8 @@ out: int loadFileDICTIONARY_safe(const char *preferredName, void **pdata, uint8_t keylen, uint16_t *keycnt) { - int block_size = 512; - int allocation_size = block_size; - size_t counter = 0; int retval = PM3_SUCCESS; + char *path; if (searchFile(&path, DICTIONARIES_SUBDIR, preferredName, ".dic") != PM3_SUCCESS) return PM3_EFILE; @@ -667,14 +664,20 @@ int loadFileDICTIONARY_safe(const char *preferredName, void **pdata, uint8_t key keylen = 6; } + size_t mem_size; + size_t block_size = 10 * keylen; + // double up since its chars keylen <<= 1; char line[255]; // allocate some space for the dictionary - *pdata = calloc(keylen * allocation_size, sizeof(uint8_t)); - if (*pdata == NULL) return PM3_EFILE; + *pdata = calloc( block_size , sizeof(uint8_t)); + if (*pdata == NULL) + return PM3_EFILE; + + mem_size = block_size; FILE *f = fopen(path, "r"); if (!f) { @@ -684,15 +687,17 @@ int loadFileDICTIONARY_safe(const char *preferredName, void **pdata, uint8_t key // read file while (fgets(line, sizeof(line), f)) { + // check if we have enough space (if not allocate more) - if ((*keycnt) >= allocation_size) { - allocation_size += block_size; - *pdata = realloc(*pdata, keylen * allocation_size * sizeof(uint8_t)); + if ( (*keycnt * (keylen >> 1) ) >= mem_size ) { + + mem_size += block_size; + *pdata = realloc(*pdata, mem_size); + if (*pdata == NULL) { return PM3_EFILE; } else { - // zero the new memory (safety first) - memset(*pdata + allocation_size - block_size, 0, block_size); + memset(*pdata + (mem_size - block_size), 0, block_size); } } @@ -714,10 +719,11 @@ int loadFileDICTIONARY_safe(const char *preferredName, void **pdata, uint8_t key uint64_t key = strtoull(line, NULL, 16); - num_to_bytes(key, keylen >> 1, *pdata + counter); + num_to_bytes(key, keylen >> 1, *pdata + (*keycnt * (keylen >> 1)) ); + (*keycnt)++; + memset(line, 0, sizeof(line)); - counter += (keylen >> 1); } fclose(f); PrintAndLogEx(SUCCESS, "loaded " _GREEN_("%2d") "keys from dictionary file " _YELLOW_("%s"), *keycnt, path); @@ -759,13 +765,14 @@ int convertOldMfuDump(uint8_t **dump, size_t *dumplen) { return PM3_SUCCESS; } -static int filelist(const char *path, const char *ext, bool last) { +static int filelist(const char *path, const char *ext, bool last, bool tentative) { struct dirent **namelist; int n; n = scandir(path, &namelist, NULL, alphasort); if (n == -1) { - PrintAndLogEx(NORMAL, "%s── %s => NOT FOUND", last ? "└" : "├", path); + if (!tentative) + PrintAndLogEx(NORMAL, "%s── %s", last ? "└" : "├", path); return PM3_EFILE; } @@ -781,25 +788,29 @@ static int filelist(const char *path, const char *ext, bool last) { } int searchAndList(const char *pm3dir, const char *ext) { + // display in same order as searched by searchFile + // try pm3 dirs in current workdir (dev mode) if (get_my_executable_directory() != NULL) { char script_directory_path[strlen(get_my_executable_directory()) + strlen(pm3dir) + 1]; strcpy(script_directory_path, get_my_executable_directory()); strcat(script_directory_path, pm3dir); - filelist(script_directory_path, ext, false); + filelist(script_directory_path, ext, false, true); } + // try pm3 dirs in user .proxmark3 (user mode) char *userpath = getenv("HOME"); if (userpath != NULL) { char script_directory_path[strlen(userpath) + strlen(PM3_USER_DIRECTORY) + strlen(pm3dir) + 1]; strcpy(script_directory_path, userpath); strcat(script_directory_path, PM3_USER_DIRECTORY); strcat(script_directory_path, pm3dir); - filelist(script_directory_path, ext, false); + filelist(script_directory_path, ext, false, false); } + // try pm3 dirs in pm3 installation dir (install mode) { char script_directory_path[strlen(PM3_SHARE_PATH) + strlen(pm3dir) + 1]; strcpy(script_directory_path, PM3_SHARE_PATH); strcat(script_directory_path, pm3dir); - filelist(script_directory_path, ext, true); + filelist(script_directory_path, ext, true, false); } return PM3_SUCCESS; } @@ -885,6 +896,8 @@ out: } int searchFile(char **foundpath, const char *pm3dir, const char *searchname, const char *suffix) { + if (foundpath == NULL) + return PM3_EINVARG; char *filename = filenamemcopy(searchname, suffix); if (filename == NULL) return PM3_EMALLOC; int res = searchFinalFile(foundpath, pm3dir, filename); diff --git a/client/fileutils.h b/client/fileutils.h index 113cac222..7bfc7c138 100644 --- a/client/fileutils.h +++ b/client/fileutils.h @@ -62,6 +62,13 @@ typedef enum { // jsfT55xx, } JSONFileType; +typedef enum { + BIN = 0, + EML, + JSON, + DICTIONARY, +} DumpFileType_t; + int fileExists(const char *filename); /** diff --git a/client/mifare/mifarehost.c b/client/mifare/mifarehost.c index d22073d02..54de89046 100644 --- a/client/mifare/mifarehost.c +++ b/client/mifare/mifarehost.c @@ -209,7 +209,8 @@ int mfCheckKeys_fast(uint8_t sectorsCnt, uint8_t firstChunk, uint8_t lastChunk, // initialize storage for found keys icesector_t *tmp = calloc(sectorsCnt, sizeof(icesector_t)); if (tmp == NULL) - return 1; + return PM3_EMALLOC; + memcpy(tmp, resp.data.asBytes, sectorsCnt * sizeof(icesector_t)); for (int i = 0; i < sectorsCnt; i++) { @@ -227,11 +228,11 @@ int mfCheckKeys_fast(uint8_t sectorsCnt, uint8_t firstChunk, uint8_t lastChunk, free(tmp); if (curr_keys == sectorsCnt * 2) - return 0; + return PM3_SUCCESS; if (lastChunk) - return 1; + return PM3_ESOFT; } - return 1; + return PM3_ESOFT; } // PM3 imp of J-Run mf_key_brute (part 2) diff --git a/client/proxmark3.c b/client/proxmark3.c index 6555ac0f2..913f3735f 100644 --- a/client/proxmark3.c +++ b/client/proxmark3.c @@ -31,7 +31,7 @@ static void showBanner(void) { PrintAndLogEx(NORMAL, "\n"); -#if defined(__linux__) || (__APPLE__) +#if defined(__linux__) || (__APPLE__) || (_WIN32) PrintAndLogEx(NORMAL, _BLUE_("██████╗ ███╗ ███╗ ████╗ ") " ...iceman fork"); PrintAndLogEx(NORMAL, _BLUE_("██╔══██╗████╗ ████║ ══█║") " ...dedicated to " _BLUE_("RDV40")); PrintAndLogEx(NORMAL, _BLUE_("██████╔╝██╔████╔██║ ████╔╝")); @@ -102,8 +102,13 @@ main_loop(char *script_cmds_file, char *script_cmd, bool stayInCommandLoop) { PrintAndLogEx(ERR, "could not open " _YELLOW_("%s") "...", script_cmds_file); } - read_history(".history"); - + char *my_history_path = NULL; + if (searchHomeFilePath(&my_history_path, PROXHISTORY, true) != PM3_SUCCESS) { + PrintAndLogEx(ERR, "could not create $HOME/" PROXHISTORY ", no history will be recorded"); + my_history_path = NULL; + } else { + read_history(my_history_path); + } // loops every time enter is pressed... while (1) { bool printprompt = false; @@ -220,8 +225,10 @@ main_loop(char *script_cmds_file, char *script_cmd, bool stayInCommandLoop) { if (sf) fclose(sf); - write_history(".history"); - + if (my_history_path) { + write_history(my_history_path); + free(my_history_path); + } if (cmd) { free(cmd); cmd = NULL; diff --git a/client/proxmark3.h b/client/proxmark3.h index 6d245da10..3da261c31 100644 --- a/client/proxmark3.h +++ b/client/proxmark3.h @@ -18,6 +18,8 @@ #define PROXPROMPT_USB "[usb] pm3 --> " #define PROXPROMPT_FPC "[fpc] pm3 --> " #define PROXPROMPT_OFFLINE "[offline] pm3 --> " +#define PROXHISTORY "history.txt" +#define PROXLOG "log_%Y%m%d.txt" #ifdef __cplusplus extern "C" { diff --git a/client/ui.c b/client/ui.c index 9927fd6d6..e6edb4369 100644 --- a/client/ui.c +++ b/client/ui.c @@ -24,7 +24,13 @@ #include #include #include "util.h" - +#include "proxmark3.h" // PROXLOG +#include "fileutils.h" +#include "pm3_cmd.h" +#ifdef _WIN32 +# include // _mkdir +#endif +#include session_arg_t session; double CursorScaleFactor = 1; @@ -36,9 +42,46 @@ bool GridLocked = false; bool showDemod = true; pthread_mutex_t print_lock = PTHREAD_MUTEX_INITIALIZER; -static const char *logfilename = "proxmark3.log"; + static void fPrintAndLog(FILE *stream, const char *fmt, ...); +// needed by flasher, so let's put it here instead of fileutils.c +int searchHomeFilePath(char **foundpath, const char *filename, bool create_home) { + if (foundpath == NULL) + return PM3_EINVARG; + char *user_path = getenv("HOME"); + if (user_path == NULL) + return PM3_EFILE; + char *path = calloc(strlen(user_path) + strlen(PM3_USER_DIRECTORY) + 1, sizeof(char)); + if (path == NULL) + return PM3_EMALLOC; + strcpy(path, user_path); + strcat(path, PM3_USER_DIRECTORY); + +// Mingw: _stat fails on mangled HOME path /pm3 => C:\ProxSpace\pm3, while stat works fine + struct stat st; + int result = stat(path, &st); + if ((result != 0) && create_home) { + +#ifdef _WIN32 + if (_mkdir(path)) { +#else + if (mkdir(path, 0700)) { +#endif + free(path); + return PM3_EFILE; + } + } + if (filename == NULL) { + *foundpath = path; + return PM3_SUCCESS; + } + path = realloc(path, (strlen(user_path) + strlen(PM3_USER_DIRECTORY) + strlen(filename) + 1) * sizeof(char)); + strcat(path, filename); + *foundpath = path; + return PM3_SUCCESS; +} + void PrintAndLogOptions(const char *str[][2], size_t size, size_t space) { char buff[2000] = "Options:\n"; char format[2000] = ""; @@ -166,10 +209,24 @@ static void fPrintAndLog(FILE *stream, const char *fmt, ...) { pthread_mutex_lock(&print_lock); if (logging && !logfile) { - logfile = fopen(logfilename, "a"); - if (!logfile) { - fprintf(stderr, "Can't open logfile, logging disabled!\n"); + char *my_logfile_path = NULL; + char filename[40]; + struct tm *timenow; + time_t now = time(NULL); + timenow = gmtime(&now); + strftime(filename, sizeof(filename), PROXLOG, timenow); + if (searchHomeFilePath(&my_logfile_path, filename, true) != PM3_SUCCESS) { + fprintf(stderr, "Could not create $HOME/.proxmark3/%s, no log will be recorded\n", filename); + my_logfile_path = NULL; logging = 0; + } else { + logfile = fopen(my_logfile_path, "a"); + if (logfile == NULL) { + fprintf(stderr, "Can't open logfile %s, logging disabled!\n", my_logfile_path); + logging = 0; + } + printf("Session is logged into %s\n", my_logfile_path); + free(my_logfile_path); } } @@ -228,10 +285,6 @@ static void fPrintAndLog(FILE *stream, const char *fmt, ...) { pthread_mutex_unlock(&print_lock); } -void SetLogFilename(char *fn) { - logfilename = fn; -} - void SetFlushAfterWrite(bool value) { flushAfterWrite = value; } diff --git a/client/ui.h b/client/ui.h index 648dce4c4..7e00ab52b 100644 --- a/client/ui.h +++ b/client/ui.h @@ -39,7 +39,6 @@ void ShowGraphWindow(void); void RepaintGraphWindow(void); void PrintAndLogOptions(const char *str[][2], size_t size, size_t space); void PrintAndLogEx(logLevel_t level, const char *fmt, ...); -void SetLogFilename(char *fn); void SetFlushAfterWrite(bool value); void memcpy_filter_ansi(void *dest, const void *src, size_t n, bool filter); @@ -49,6 +48,8 @@ extern uint32_t CursorCPos, CursorDPos; extern bool GridLocked; extern bool showDemod; +int searchHomeFilePath(char **foundpath, const char *filename, bool create_home); + extern pthread_mutex_t print_lock; void iceIIR_Butterworth(int *data, const size_t len); diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index 035e85405..dc48bd110 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -229,6 +229,10 @@ typedef struct { uint8_t key[6]; } PACKED mf_readblock_t; +typedef struct { + uint8_t sectorcnt; + uint8_t keytype; +} PACKED mfc_eload_t; // For the bootloader #define CMD_DEVICE_INFO 0x0000