mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 05:43:48 -07:00
Merge branch 'master' of https://github.com/RfidResearchGroup/proxmark3 into autopwn_restyle
This commit is contained in:
commit
a69fbdd3af
18 changed files with 451 additions and 186 deletions
|
@ -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)
|
||||
|
|
58
appveyor.yml
58
appveyor.yml
|
@ -77,9 +77,63 @@ clone_script:
|
|||
|
||||
$env:Path = "C:\ProxSpace\msys2\usr\bin;C:\ProxSpace\msys2\mingw32\bin;C:\ProxSpace\gcc-arm-none-eabi\bin;$env:Path"
|
||||
|
||||
C:\ProxSpace\msys2\msys2_shell.cmd -mingw32 -defterm -no-start /dev/null 1> msys1.txt 2>&1
|
||||
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
|
||||
|
||||
$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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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 > DBG_ERROR)
|
||||
Dbprintf("Halt error");
|
||||
}
|
||||
|
||||
if (mifare_classic_halt(pcs, cuid))
|
||||
if (DBGLEVEL >= 1)
|
||||
Dbprintf("Halt error");
|
||||
if (DBGLEVEL >= DBG_INFO) DbpString("Emulator fill sectors finished");
|
||||
|
||||
// ----------------------------- crypto1 destroy
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
201
client/cmdhfmf.c
201
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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"));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -62,6 +62,13 @@ typedef enum {
|
|||
// jsfT55xx,
|
||||
} JSONFileType;
|
||||
|
||||
typedef enum {
|
||||
BIN = 0,
|
||||
EML,
|
||||
JSON,
|
||||
DICTIONARY,
|
||||
} DumpFileType_t;
|
||||
|
||||
int fileExists(const char *filename);
|
||||
|
||||
/**
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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" {
|
||||
|
|
71
client/ui.c
71
client/ui.c
|
@ -24,7 +24,13 @@
|
|||
#include <readline/readline.h>
|
||||
#include <complex.h>
|
||||
#include "util.h"
|
||||
|
||||
#include "proxmark3.h" // PROXLOG
|
||||
#include "fileutils.h"
|
||||
#include "pm3_cmd.h"
|
||||
#ifdef _WIN32
|
||||
# include <direct.h> // _mkdir
|
||||
#endif
|
||||
#include <time.h>
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue