diff --git a/appveyor.yml b/appveyor.yml index d5ef4ac7f..8586bb48a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,13 +1,17 @@ version: 3.0.1.{build} image: Visual Studio 2019 clone_folder: C:\ProxSpace\pm3\proxmark +cache: + - C:\cache -> appveyor.yml environment: proxspace_url: https://github.com/Gator96100/ProxSpace/archive/master.zip proxspace_zip_file: \proxspace.zip proxspace_zip_folder_name: ProxSpace-* - proxspace_path: \ProxSpace + proxspace_path: C:\ProxSpace proxspace_home_path: \ProxSpace\pm3 + proxspace_cache_path: C:\cache wsl_git_path: C:\proxmark + APPVEYOR_SAVE_CACHE_ON_ERROR: true init: - ps: >- @@ -34,39 +38,19 @@ init: clone_script: - ps: >- - Function ExecUpdate($Text, $firstStart) { - Write-Host "$Text" - Start-Process "cmd.exe" "/c ""cd /D $env:proxspace_path && runme64.bat -c ""exit""""" - $StartTime=[System.Environment]::TickCount - Start-Sleep -s 10 - while($true) { - $cmdprocess = Get-Process "cmd" -ErrorAction SilentlyContinue - - if (!$cmdprocess -Or $cmdprocess.HasExited) { - Write-Host "$Text" -NoNewLine - Write-Host "[ OK ]" -ForegroundColor Green - break - } - - if ($firstStart -And (Test-Path "$env:proxspace_path\msys2\etc\pacman.conf.pacnew")) { - Start-Sleep -s 5 - $tmp = $cmdprocess.CloseMainWindow() - Start-Sleep -s 5 - Stop-Process -Name "cmd" -Force -ErrorAction SilentlyContinue - Write-Host "$Text" -NoNewLine - Write-Host "Exit by pacman.conf" -ForegroundColor Green - break - } - - if ([System.Environment]::TickCount-$StartTime -gt 1000000) { - Write-Host "$Text" -NoNewLine - Write-host "Exit by timeout" -ForegroundColor Yellow - break - } - - Start-Sleep -s 5 - Receive-Job -Job $WSLjob + Function GitClone($Text, $Folder) { + Write-Host "$Text" -NoNewLine + if(-not $env:appveyor_pull_request_number) { + git clone -q --branch=$env:appveyor_repo_branch https://github.com/$env:appveyor_repo_name.git $Folder + cd $Folder + git checkout -qf $env:appveyor_repo_commit + } else { + git clone -q https://github.com/$env:appveyor_repo_name.git $Folder + cd $Folder + git fetch -q origin +refs/pull/$env:appveyor_pull_request_number/merge: + git checkout -qf FETCH_HEAD } + Write-Host "[ OK ]" -ForegroundColor Green } $WSLjob = Start-Job -Name WSLInstall -ScriptBlock { @@ -86,6 +70,94 @@ clone_script: Add-AppveyorMessage -Message "WSL setup took $(([System.Environment]::TickCount-$WSLInstallTime) / 1000) sec" -Category Information } + $env:PSInstallTime=[System.Environment]::TickCount + + Write-Host "ProxSpace: Removing folder..." -NoNewLine + + cd \ + + Remove-Item -Recurse -Force -Path $env:proxspace_path -ErrorAction SilentlyContinue + + Write-Host "[ OK ]" -ForegroundColor Green + + Write-Host "ProxSpace: downloading..." -NoNewLine + + [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 + + Invoke-WebRequest "$env:proxspace_url" -outfile "$env:proxspace_zip_file" + + Write-Host "[ OK ]" -ForegroundColor Green + + Write-Host "ProxSpace: extracting..." -NoNewLine + + Expand-Archive -LiteralPath "$env:proxspace_zip_file" -DestinationPath "\" + + Remove-Item "$env:proxspace_zip_file" + + Write-Host "[ OK ]" -ForegroundColor Green + + Write-Host "ProxSpace: renaming folder..." -NoNewLine + + Get-ChildItem -Path "\$env:proxspace_zip_folder_name" | Rename-Item -NewName (Split-Path $env:proxspace_path -Leaf) + + Write-Host "[ OK ]" -ForegroundColor Gree + + $psversion = (Select-String -Pattern 'PSVERSION=' -SimpleMatch -Path "$env:proxspace_path\msys2\ps\09-proxspace_setup.post").Line.Split("""")[1] + + Write-Host "ProxSpace version: $psversion" -ForegroundColor Yellow + + GitClone "ProxSpace: Cloning repository <$env:appveyor_repo_name> to $env:appveyor_build_folder ..." $env:appveyor_build_folder + + GitClone "WSL: Cloning repository <$env:appveyor_repo_name> to $env:wsl_git_path ..." $env:wsl_git_path + + +install: +- ps: >- + + Function ExecUpdate($Text, $firstStart) { + Write-Host "$Text" + + $PSjob = Start-Job -Name PSInstall -ScriptBlock { + cd $env:proxspace_path + ./runme64.bat -c "exit" + } + + $StartTime=[System.Environment]::TickCount + Start-Sleep -s 10 + while($true) { + if ($PSjob.State -eq 'Completed') { + Write-Host "$Text" -NoNewLine + Write-Host "[ OK ]" -ForegroundColor Green + break + } + + if ($PSjob.State -eq 'Failed') { + Write-Host "$Text" -NoNewLine + Write-Host "[ Failed ]" -ForegroundColor Red + break + } + + if ($firstStart -And (Test-Path "$env:proxspace_path\msys2\etc\pacman.conf.pacnew")) { + Start-Sleep -s 5 + Stop-Job -Job $PSjob + Start-Sleep -s 5 + Write-Host "$Text" -NoNewLine + Write-Host "Exit by pacman.conf" -ForegroundColor Green + break + } + + if ([System.Environment]::TickCount-$StartTime -gt 1000000) { + Stop-Job -Job $PSjob + Write-Host "$Text" -NoNewLine + Write-host "Exit by timeout" -ForegroundColor Yellow + break + } + + Start-Sleep -s 5 + Receive-Job -Name WSLInstall + } + } + Function GitClone($Text, $Folder) { Write-Host "$Text" -NoNewLine if(-not $env:appveyor_pull_request_number) { @@ -101,63 +173,18 @@ clone_script: Write-Host "[ OK ]" -ForegroundColor Green } - Write-Host "ProxSpace: Removing folder..." -NoNewLine + Write-Host "ProxSpace: move cache..." -NoNewLine - $PSInstallTime=[System.Environment]::TickCount - - cd \ - - Remove-Item -Recurse -Force -Path $env:proxspace_path - - Write-Host "[ OK ]" -ForegroundColor Green - - Receive-Job -Job $WSLjob - - Write-Host "ProxSpace: downloading..." -NoNewLine - - [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 - - Invoke-WebRequest "$env:proxspace_url" -outfile "$env:proxspace_zip_file" - - Write-Host "[ OK ]" -ForegroundColor Green - - Receive-Job -Job $WSLjob - - Write-Host "ProxSpace: extracting..." -NoNewLine - - Expand-Archive -LiteralPath "$env:proxspace_zip_file" -DestinationPath "\" - - Remove-Item "$env:proxspace_zip_file" - - Write-Host "[ OK ]" -ForegroundColor Green - - Receive-Job -Job $WSLjob - - Write-Host "ProxSpace: renaming folder..." -NoNewLine - - Get-ChildItem -Path "\$env:proxspace_zip_folder_name" | Rename-Item -NewName (Split-Path $env:proxspace_path -Leaf) + Move-Item -Path "$env:proxspace_cache_path" -Destination "$env:proxspace_path\msys2\var\cache" -Force -ErrorAction SilentlyContinue Write-Host "[ OK ]" -ForegroundColor Gree ExecUpdate "ProxSpace: initial msys2 startup..." $true - ExecUpdate "ProxSpace: installing required packages..." $false - - - $psversion = (Select-String -Pattern 'PSVERSION=' -SimpleMatch -Path "$env:proxspace_path\msys2\ps\09-proxspace_setup.post").Line.Split("""")[1] - - Write-Host "ProxSpace version: $psversion" -ForegroundColor Yellow - - Add-AppveyorMessage -Message "ProxSpace download and update took $(([System.Environment]::TickCount-$PSInstallTime) / 1000) sec" -Category Information - - GitClone "ProxSpace: Cloning repository <$env:appveyor_repo_name> to $env:appveyor_build_folder ..." $env:appveyor_build_folder - - Receive-Job -Wait -Job $WSLjob - - GitClone "WSL: Cloning repository <$env:appveyor_repo_name> to $env:wsl_git_path ..." $env:wsl_git_path + ExecUpdate "ProxSpace: installing required packages..." $false + Add-AppveyorMessage -Message "ProxSpace download and update took $(([System.Environment]::TickCount-$env:PSInstallTime) / 1000) sec" -Category Information -install: build_script: - ps: >- @@ -202,6 +229,9 @@ build_script: throw "Tests error." } } + + #WSL: wait for installation to finish + Receive-Job -Wait -Name WSLInstall #Windows Subsystem for Linux (WSL) Write-Host "---------- WSL make ----------" -ForegroundColor Yellow @@ -234,6 +264,16 @@ build_script: #ProxSpace + Write-Host "ProxSpace: create new cache..." -NoNewLine + + ExecMinGWCmd 'yes | pacman -Sc > /dev/null 2>&1' + + Remove-Item -Recurse -Force -Path "$env:proxspace_cache_path" -ErrorAction SilentlyContinue + + Move-Item -Path "$env:proxspace_path\msys2\var\cache" -Destination "$env:proxspace_cache_path" -Force + + Write-Host "[ OK ]" -ForegroundColor Gree + Write-Host "---------- PS make ----------" -ForegroundColor Yellow $TestTime=[System.Environment]::TickCount diff --git a/armsrc/epa.c b/armsrc/epa.c index 317f2ce7b..2a0025610 100644 --- a/armsrc/epa.c +++ b/armsrc/epa.c @@ -118,7 +118,7 @@ static int EPA_APDU(uint8_t *apdu, size_t length, uint8_t *response, uint16_t re case 'a': return iso14_apdu(apdu, (uint16_t) length, false, response, NULL); case 'b': - return iso14443b_apdu(apdu, length, false, response, respmaxlen); + return iso14443b_apdu(apdu, length, false, response, respmaxlen, NULL); default: return 0; } diff --git a/armsrc/hfsnoop.c b/armsrc/hfsnoop.c index ec13dbc85..4e4539f3e 100644 --- a/armsrc/hfsnoop.c +++ b/armsrc/hfsnoop.c @@ -99,7 +99,7 @@ int HfSniff(uint32_t samplesToSkip, uint32_t triggersToSkip, uint16_t *len) { optimizedSniff((uint16_t *)mem, *len); - if (DBGLEVEL >= DBG_INFO) { + if (DBGLEVEL >= DBG_INFO) { Dbprintf("Trigger kicked in (%d >= 180)", r); Dbprintf("Collected %u samples", *len); } diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 6ada61171..6cd7c9525 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -2687,7 +2687,7 @@ void iso14443a_setup(uint8_t fpga_minor_mode) { LED_D_ON(); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | fpga_minor_mode); - SpinDelay(100); + SpinDelay(50); // Start the timer StartCountSspClk(); diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c index ccbe06e5c..f333ac88e 100644 --- a/armsrc/iso14443b.c +++ b/armsrc/iso14443b.c @@ -784,6 +784,7 @@ static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) { if (AMPLITUDE(ci, cq) > SUBCARRIER_DETECT_THRESHOLD) { if (((ABS(Demod.sumI) > ABS(Demod.sumQ)) && (((ci > 0) && (Demod.sumI > 0)) || ((ci < 0) && (Demod.sumI < 0)))) || // signal closer to horizontal, polarity check based on on I ((ABS(Demod.sumI) <= ABS(Demod.sumQ)) && (((cq > 0) && (Demod.sumQ > 0)) || ((cq < 0) && (Demod.sumQ < 0))))) { // signal closer to vertical, polarity check based on on Q + if (Demod.posCount < 10) { // refine signal approximation during first 10 samples Demod.sumI += ci; Demod.sumQ += cq; @@ -1103,7 +1104,7 @@ static void CodeIso14443bAsReader(const uint8_t *cmd, int len) { // Send SOF // 10-11 ETUs of ZERO - for (i = 0; i < 10; i++) { + for (i = 0; i < 11; i++) { tosend_stuffbit(0); } // 2-3 ETUs of ONE @@ -1132,23 +1133,21 @@ static void CodeIso14443bAsReader(const uint8_t *cmd, int len) { // EGT extra guard time 1 ETU = 9us // For PCD it ranges 0-57us === 0 - 6 ETU // FOR PICC it ranges 0-19us == 0 - 2 ETU - } // Send EOF // 10-11 ETUs of ZERO - for (i = 0; i < 10; i++) { + for (i = 0; i < 11; i++) { tosend_stuffbit(0); } - tosend_stuffbit(1); /* Transition time. TR0 - guard time * TR0 - 8 ETU's minimum. * TR0 - 32 ETU's maximum for ATQB only * TR0 - FWT for all other commands * 32,64,128,256,512, ... , 262144, 524288 ETU */ - int pad = (12 + (len * 10) + 11) & 0x7; + int pad = (11 + 2 + (len * 10) + 11) & 0x7; for (i = 0; i < 16 - pad; ++i) tosend_stuffbit(1); @@ -1168,7 +1167,7 @@ static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len, uint32_t /* Sends an APDU to the tag * TODO: check CRC and preamble */ -int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, uint8_t *response, uint16_t respmaxlen) { +int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void *rxdata, uint16_t rxmaxlen, uint8_t *res) { uint8_t real_cmd[msg_len + 4]; @@ -1195,10 +1194,10 @@ int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, uint8 CodeAndTransmit14443bAsReader(real_cmd, msg_len + 3, &start_time, &eof_time); eof_time += DELAY_ISO14443B_VCD_TO_VICC_READER; - int len = Get14443bAnswerFromTag(response, respmaxlen, ISO14443B_READER_TIMEOUT, &eof_time); + int len = Get14443bAnswerFromTag(rxdata, rxmaxlen, ISO14443B_READER_TIMEOUT, &eof_time); FpgaDisableTracing(); - uint8_t *data_bytes = (uint8_t *) response; + uint8_t *data_bytes = (uint8_t *) rxdata; if (len <= 0) { return 0; //DATA LINK ERROR @@ -1219,10 +1218,10 @@ int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, uint8 // retrieve the result again (with increased timeout) eof_time += DELAY_ISO14443B_VCD_TO_VICC_READER; - len = Get14443bAnswerFromTag(response, respmaxlen, ISO14443B_READER_TIMEOUT, &eof_time); + len = Get14443bAnswerFromTag(rxdata, rxmaxlen, ISO14443B_READER_TIMEOUT, &eof_time); FpgaDisableTracing(); - data_bytes = response; + data_bytes = rxdata; // restore timeout iso14b_set_timeout(save_iso14b_timeout); } @@ -1237,8 +1236,8 @@ int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, uint8 } // if we received I-block with chaining we need to send ACK and receive another block of data - if (response) - *response = data_bytes[0]; + if (res) + *res = data_bytes[0]; // crc check if (len >= 3 && !check_crc(CRC_14443_B, data_bytes, len)) { @@ -1524,7 +1523,7 @@ void iso14443b_setup(void) { // Signal field is on with the appropriate LED FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_SHALLOW_MOD); - SpinDelay(100); + SpinDelay(50); // Start the timer StartCountSspClk(); @@ -1841,17 +1840,21 @@ void SendRawCommand14443B_Ex(PacketCommandNG *c) { if ((param & ISO14B_CONNECT) == ISO14B_CONNECT) { iso14443b_setup(); - clear_trace(); } - if ((param & ISO14B_SET_TIMEOUT)) + if ((param & ISO14B_SET_TIMEOUT) == ISO14B_SET_TIMEOUT) { iso14b_set_timeout(timeout); - + } + + if ((param & ISO14B_CLEARTRACE) == ISO14B_CLEARTRACE) { + clear_trace(); + } set_tracing(true); int status; uint32_t sendlen = sizeof(iso14b_card_select_t); iso14b_card_select_t card; + memset((void*)&card, 0x00, sizeof(card)); if ((param & ISO14B_SELECT_STD) == ISO14B_SELECT_STD) { status = iso14443b_select_card(&card); @@ -1877,9 +1880,10 @@ void SendRawCommand14443B_Ex(PacketCommandNG *c) { } if ((param & ISO14B_APDU) == ISO14B_APDU) { - status = iso14443b_apdu(cmd, len, (param & ISO14B_SEND_CHAINING), buf, sizeof(buf)); + uint8_t res; + status = iso14443b_apdu(cmd, len, (param & ISO14B_SEND_CHAINING), buf, sizeof(buf), &res); sendlen = MIN(Demod.len, PM3_CMD_DATA_SIZE); - reply_mix(CMD_HF_ISO14443B_COMMAND, status, status, 0, buf, sendlen); + reply_mix(CMD_HF_ISO14443B_COMMAND, status, res, 0, buf, sendlen); } if ((param & ISO14B_RAW) == ISO14B_RAW) { diff --git a/armsrc/iso14443b.h b/armsrc/iso14443b.h index 7e5023e1b..f770bbf8c 100644 --- a/armsrc/iso14443b.h +++ b/armsrc/iso14443b.h @@ -27,7 +27,7 @@ #endif void iso14443b_setup(void); -int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, uint8_t *response, uint16_t respmaxlen); +int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void *rxdata, uint16_t rxmaxlen, uint8_t *res); int iso14443b_select_card(iso14b_card_select_t *card); int iso14443b_select_card_srx(iso14b_card_select_t *card); diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index 3125f90bf..f3c3494a9 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -1479,6 +1479,7 @@ int SendDataTag(uint8_t *send, int sendlen, bool init, bool speed_fast, uint8_t if (recv != NULL) { res = GetIso15693AnswerFromTag(recv, max_recv_len, timeout, eof_time); } + FpgaDisableTracing(); return res; } @@ -1494,6 +1495,7 @@ int SendDataTagEOF(uint8_t *recv, uint16_t max_recv_len, uint32_t start_time, ui if (recv != NULL) { res = GetIso15693AnswerFromTag(recv, max_recv_len, timeout, eof_time); } + FpgaDisableTracing(); return res; } diff --git a/client/cmdscripts/rdv4_init_extflash.cmd b/client/cmdscripts/rdv4_init_extflash.cmd index 2cae05294..6fe6de3ba 100755 --- a/client/cmdscripts/rdv4_init_extflash.cmd +++ b/client/cmdscripts/rdv4_init_extflash.cmd @@ -1,6 +1,6 @@ #!/usr/bin/env -S pm3 -s -mem load f mfc_default_keys m -mem load f t55xx_default_pwds t -mem load f iclass_default_keys i +mem load -f mfc_default_keys --mfc +mem load -f t55xx_default_pwds --t55xx +mem load -f iclass_default_keys --iclass lf t55xx deviceconfig z p diff --git a/client/cmdscripts/test_psk_clone.cmd b/client/cmdscripts/test_psk_clone.cmd index f37ddcfea..784fecd1e 100644 --- a/client/cmdscripts/test_psk_clone.cmd +++ b/client/cmdscripts/test_psk_clone.cmd @@ -14,7 +14,7 @@ lf search rem Test of keri clone & read lf t55xx wipe -lf keri clone 1337 +lf keri clone --id 1337 lf keri read lf search diff --git a/client/deps/cliparser/argtable3.c b/client/deps/cliparser/argtable3.c index 134c82306..c34ee982b 100644 --- a/client/deps/cliparser/argtable3.c +++ b/client/deps/cliparser/argtable3.c @@ -1927,10 +1927,8 @@ struct arg_file *arg_filen( #include #include #include - #include "argtable3.h" - static void arg_int_resetfn(struct arg_int *parent) { ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent)); parent->count = 0; @@ -2226,6 +2224,263 @@ struct arg_int *arg_intn( ARG_TRACE(("arg_intn() returns %p\n", result)); return result; } + + +// uint64_t support +#include +#include +#include +static uint64_t strtollu0X(const char *str, + const char * *endptr, + char X, + int base) { + uint64_t val; /* stores result */ + int s = 1; /* sign is +1 or -1 */ + const char *ptr = str; /* ptr to current position in str */ + + /* skip leading whitespace */ + while (ISSPACE(*ptr)) + ptr++; + // printf("1) %s\n",ptr); + + /* scan optional sign character */ + switch (*ptr) { + case '+': + ptr++; + s = 1; + break; + case '-': + ptr++; + s = -1; + break; + default: + s = 1; + break; + } + // printf("2) %s\n",ptr); + + /* '0X' prefix */ + if ((*ptr++) != '0') { + /* printf("failed to detect '0'\n"); */ + *endptr = str; + return 0; + } + // printf("3) %s\n",ptr); + if (toupper(*ptr++) != toupper(X)) { + /* printf("failed to detect '%c'\n",X); */ + *endptr = str; + return 0; + } + // printf("4) %s\n",ptr); + + /* attempt conversion on remainder of string using strtol() */ + val = strtoull(ptr, (char * *)endptr, base); + + if (*endptr == ptr) { + /* conversion failed */ + *endptr = str; + return 0; + } + + /* success */ + return s * val; +} + + +static void arg_u64_resetfn(struct arg_u64 *parent) { + ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent)); + parent->count = 0; +} + +static int arg_u64_scanfn(struct arg_u64 *parent, const char *argval) { + int errorcode = 0; + if (parent->count == parent->hdr.maxcount) { + /* maximum number of arguments exceeded */ + errorcode = EMAXCOUNT; + } else if (!argval) { + /* a valid argument with no argument value was given. */ + /* This happens when an optional argument value was invoked. */ + /* leave parent arguiment value unaltered but still count the argument. */ + parent->count++; + } else { + uint64_t val; + const char *end; + + /* attempt to extract hex integer (eg: +0x123) from argval into val conversion */ + val = strtollu0X(argval, &end, 'X', 16); + if (end == argval) { + /* hex failed, attempt octal conversion (eg +0o123) */ + val = strtollu0X(argval, &end, 'O', 8); + if (end == argval) { + /* octal failed, attempt binary conversion (eg +0B101) */ + val = strtollu0X(argval, &end, 'B', 2); + if (end == argval) { + /* binary failed, attempt decimal conversion with no prefix (eg 1234) */ + val = strtoull(argval, (char * *)&end, 10); + if (end == argval) { + /* all supported number formats failed */ + return EBADINT; + } + } + } + } + + /* Safety check for integer overflow. WARNING: this check */ + /* achieves nothing on machines where size(int)==size(long). */ + if (val > ULLONG_MAX) +#ifdef __STDC_WANT_SECURE_LIB__ + errorcode = EOVERFLOW_; +#else + errorcode = EOVERFLOW; +#endif + + /* Detect any suffixes (KB,MB,GB) and multiply argument value appropriately. */ + /* We need to be mindful of integer overflows when using such big numbers. */ + if (detectsuffix(end, "KB")) { /* kilobytes */ + if (val > (ULLONG_MAX / 1024)) +#ifdef __STDC_WANT_SECURE_LIB__ + errorcode = EOVERFLOW_; /* Overflow would occur if we proceed */ +#else + errorcode = EOVERFLOW; /* Overflow would occur if we proceed */ +#endif + else + val *= 1024; /* 1KB = 1024 */ + } else if (detectsuffix(end, "MB")) { /* megabytes */ + if (val > (ULLONG_MAX / 1048576)) +#ifdef __STDC_WANT_SECURE_LIB__ + errorcode = EOVERFLOW_; /* Overflow would occur if we proceed */ +#else + errorcode = EOVERFLOW; /* Overflow would occur if we proceed */ +#endif + else + val *= 1048576; /* 1MB = 1024*1024 */ + } else if (detectsuffix(end, "GB")) { /* gigabytes */ + if (val > (ULLONG_MAX / 1073741824)) +#ifdef __STDC_WANT_SECURE_LIB__ + errorcode = EOVERFLOW_; /* Overflow would occur if we proceed */ +#else + errorcode = EOVERFLOW; /* Overflow would occur if we proceed */ +#endif + else + val *= 1073741824; /* 1GB = 1024*1024*1024 */ + } else if (!detectsuffix(end, "")) + errorcode = EBADINT; /* invalid suffix detected */ + + /* if success then store result in parent->uval[] array */ + if (errorcode == 0) + parent->uval[parent->count++] = val; + } + + /* printf("%s:scanfn(%p,%p) returns %d\n",__FILE__,parent,argval,errorcode); */ + return errorcode; +} + +static int arg_u64_checkfn(struct arg_u64 *parent) { + int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0; + /*printf("%s:checkfn(%p) returns %d\n",__FILE__,parent,errorcode);*/ + return errorcode; +} + +static void arg_u64_errorfn( + struct arg_u64 *parent, + FILE *fp, + int errorcode, + const char *argval, + const char *progname) { + const char *shortopts = parent->hdr.shortopts; + const char *longopts = parent->hdr.longopts; + const char *datatype = parent->hdr.datatype; + + /* make argval NULL safe */ + argval = argval ? argval : ""; + + fprintf(fp, "%s: ", progname); + switch (errorcode) { + case EMINCOUNT: + fputs("missing option ", fp); + arg_print_option(fp, shortopts, longopts, datatype, "\n"); + break; + + case EMAXCOUNT: + fputs("excess option ", fp); + arg_print_option(fp, shortopts, longopts, argval, "\n"); + break; + + case EBADINT: + fprintf(fp, "invalid argument \"%s\" to option ", argval); + arg_print_option(fp, shortopts, longopts, datatype, "\n"); + break; + +#ifdef __STDC_WANT_SECURE_LIB__ + case EOVERFLOW_: +#else + case EOVERFLOW: +#endif + fputs("integer overflow at option ", fp); + arg_print_option(fp, shortopts, longopts, datatype, " "); + fprintf(fp, "(%s is too large)\n", argval); + break; + } +} + +struct arg_u64 *arg_u64_0( + const char *shortopts, + const char *longopts, + const char *datatype, + const char *glossary) { + return arg_u64_n(shortopts, longopts, datatype, 0, 1, glossary); +} + +struct arg_u64 *arg_u64_1( + const char *shortopts, + const char *longopts, + const char *datatype, + const char *glossary) { + return arg_u64_n(shortopts, longopts, datatype, 1, 1, glossary); +} + +struct arg_u64 *arg_u64_n( + const char *shortopts, + const char *longopts, + const char *datatype, + int mincount, + int maxcount, + const char *glossary) { + size_t nbytes; + struct arg_u64 *result; + + /* foolproof things by ensuring maxcount is not less than mincount */ + maxcount = (maxcount < mincount) ? mincount : maxcount; + + nbytes = sizeof(struct arg_u64) /* storage for struct arg_u64 */ + + maxcount * sizeof(uint64_t); /* storage for uval[maxcount] array */ + + result = (struct arg_u64 *)malloc(nbytes); + if (result) { + /* init the arg_hdr struct */ + result->hdr.flag = ARG_HASVALUE; + result->hdr.shortopts = shortopts; + result->hdr.longopts = longopts; + result->hdr.datatype = datatype ? datatype : ""; + result->hdr.glossary = glossary; + result->hdr.mincount = mincount; + result->hdr.maxcount = maxcount; + result->hdr.parent = result; + result->hdr.resetfn = (arg_resetfn *)arg_u64_resetfn; + result->hdr.scanfn = (arg_scanfn *)arg_u64_scanfn; + result->hdr.checkfn = (arg_checkfn *)arg_u64_checkfn; + result->hdr.errorfn = (arg_errorfn *)arg_u64_errorfn; + + /* store the uval[maxcount] array immediately after the arg_int struct */ + result->uval = (uint64_t *)(result + 1); + result->count = 0; + } + + ARG_TRACE(("arg_u64_n() returns %p\n", result)); + return result; +} + + /******************************************************************************* * This file is part of the argtable3 library. * @@ -4020,7 +4275,10 @@ static void arg_parse_untagged(int argc, /* register an error for each unused argv[] entry */ while (optind < argc) { /*printf("arg_parse_untagged(): argv[%d]=\"%s\" not consumed\n",optind,argv[optind]);*/ - arg_register_error(endtable, endtable, ARG_ENOMATCH, argv[optind++]); + if (argv[optind][0] != '\x00') { + arg_register_error(endtable, endtable, ARG_ENOMATCH, argv[optind]); + } + optind++; } return; @@ -4195,7 +4453,8 @@ static void arg_cat_option(char *dest, #endif if (datatype) { - arg_cat(&dest, "=", &ndest); +// arg_cat(&dest, "=", &ndest); + arg_cat(&dest, " ", &ndest); if (optvalue) { arg_cat(&dest, "[", &ndest); arg_cat(&dest, datatype, &ndest); diff --git a/client/deps/cliparser/argtable3.h b/client/deps/cliparser/argtable3.h index d8e3c53cc..2988d013f 100644 --- a/client/deps/cliparser/argtable3.h +++ b/client/deps/cliparser/argtable3.h @@ -35,6 +35,7 @@ #include /* FILE */ #include /* struct tm */ +#include #ifdef __cplusplus extern "C" { @@ -110,6 +111,12 @@ struct arg_int { int *ival; /* Array of parsed argument values */ }; +struct arg_u64 { + struct arg_hdr hdr; /* The mandatory argtable header struct */ + int count; /* Number of matching command line args */ + uint64_t *uval; /* Array of parsed argument values */ +}; + struct arg_dbl { struct arg_hdr hdr; /* The mandatory argtable header struct */ int count; /* Number of matching command line args */ @@ -176,32 +183,29 @@ struct arg_lit *arg_litn(const char *shortopts, int maxcount, const char *glossary); -struct arg_key *arg_key0(const char *keyword, - int flags, +struct arg_key *arg_key0(const char *keyword, int flags, const char *glossary); +struct arg_key *arg_key1(const char *keyword, int flags, const char *glossary); +struct arg_key *arg_keyn(const char *keyword, int flags, int mincount, int maxcount, const char *glossary); + +struct arg_int *arg_int0(const char *shortopts, const char *longopts, const char *datatype, const char *glossary); +struct arg_int *arg_int1(const char *shortopts, const char *longopts, const char *datatype, const char *glossary); +struct arg_int *arg_intn(const char *shortopts, const char *longopts, const char *datatype, int mincount, int maxcount, const char *glossary); + +struct arg_u64 *arg_u64_0(const char *shortopts, + const char *longopts, + const char *datatype, const char *glossary); -struct arg_key *arg_key1(const char *keyword, - int flags, +struct arg_u64 *arg_u64_1(const char *shortopts, + const char *longopts, + const char *datatype, const char *glossary); -struct arg_key *arg_keyn(const char *keyword, - int flags, +struct arg_u64 *arg_u64_n(const char *shortopts, + const char *longopts, + const char *datatype, int mincount, int maxcount, const char *glossary); -struct arg_int *arg_int0(const char *shortopts, - const char *longopts, - const char *datatype, - const char *glossary); -struct arg_int *arg_int1(const char *shortopts, - const char *longopts, - const char *datatype, - const char *glossary); -struct arg_int *arg_intn(const char *shortopts, - const char *longopts, - const char *datatype, - int mincount, - int maxcount, - const char *glossary); struct arg_dbl *arg_dbl0(const char *shortopts, const char *longopts, diff --git a/client/deps/cliparser/cliparser.c b/client/deps/cliparser/cliparser.c index 4ec4eb303..8ce757792 100644 --- a/client/deps/cliparser/cliparser.c +++ b/client/deps/cliparser/cliparser.c @@ -251,12 +251,13 @@ int CLIParamStrToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int if (!ibuf) return 0; - if (ibuf > maxdatalen) { + if (ibuf + 1 > maxdatalen) { + printf("Parameter error: string too long, expect max %i chars\n", maxdatalen - 1); fflush(stdout); return 2; } - memcpy(data, tmp_buf, ibuf); + memcpy(data, tmp_buf, ibuf + 1); *datalen = ibuf; return 0; } diff --git a/client/deps/cliparser/cliparser.h b/client/deps/cliparser/cliparser.h index 51c2ed8d5..68beca038 100644 --- a/client/deps/cliparser/cliparser.h +++ b/client/deps/cliparser/cliparser.h @@ -17,22 +17,39 @@ #define arg_param_begin arg_lit0("h", "help", "This help") #define arg_param_end arg_end(20) -#define arg_getsize(a) (sizeof(a) / sizeof(a[0])) -#define arg_get_lit(ctx, n) (((struct arg_lit*)((ctx)->argtable)[n])->count) -#define arg_get_int_count(ctx, n)(((struct arg_int*)((ctx)->argtable)[n])->count) -#define arg_get_int(ctx, n) (((struct arg_int*)((ctx)->argtable)[n])->ival[0]) -#define arg_get_int_def(ctx, n, def)(arg_get_int_count((ctx), n) ? (arg_get_int((ctx), n)) : (def)) -#define arg_get_str(ctx, n) ((struct arg_str*)((ctx)->argtable)[n]) -#define arg_get_str_len(ctx, n) (strlen(((struct arg_str*)((ctx)->argtable)[n])->sval[0])) +#define arg_getsize(a) (sizeof(a) / sizeof(a[0])) +#define arg_get_lit(ctx, n) (((struct arg_lit*)((ctx)->argtable)[(n)])->count) + +#define arg_get_int_count(ctx, n) (((struct arg_int*)((ctx)->argtable)[(n)])->count) +#define arg_get_int(ctx, n) (((struct arg_int*)((ctx)->argtable)[(n)])->ival[0]) +#define arg_get_int_def(ctx, n, def)(arg_get_int_count((ctx), (n)) ? (arg_get_int((ctx), (n))) : (def)) + +#define arg_get_dbl_count(ctx, n) (((struct arg_dbl*)((ctx)->argtable)[(n)])->count) +#define arg_get_dbl(ctx, n) (((struct arg_dbl*)((ctx)->argtable)[(n)])->dval[0]) +#define arg_get_dbl_def(ctx, n, def)(arg_get_dbl_count((ctx), (n)) ? (arg_get_dbl((ctx), (n))) : (def)) + +#define arg_get_u32(ctx, n) (uint32_t)(((struct arg_u64*)((ctx)->argtable)[(n)])->uval[0]) +#define arg_get_u32_def(ctx, n, def) (arg_get_u64_count((ctx), (n)) ? (arg_get_u32((ctx), (n))) : (uint32_t)(def)) + +#define arg_get_u64_count(ctx, n) (((struct arg_u64*)((ctx)->argtable)[(n)])->count) +#define arg_get_u64(ctx, n) (((struct arg_u64*)((ctx)->argtable)[(n)])->uval[0]) +#define arg_get_u64_def(ctx, n, def) (arg_get_u64_count((ctx), (n)) ? (arg_get_u64((ctx), (n))) : (uint64_t)(def)) + +#define arg_get_str(ctx, n) ((struct arg_str*)((ctx)->argtable)[(n)]) +#define arg_get_str_len(ctx, n) (strlen(((struct arg_str*)((ctx)->argtable)[(n)])->sval[0])) #define arg_strx1(shortopts, longopts, datatype, glossary) (arg_strn((shortopts), (longopts), (datatype), 1, 250, (glossary))) #define arg_strx0(shortopts, longopts, datatype, glossary) (arg_strn((shortopts), (longopts), (datatype), 0, 250, (glossary))) -#define CLIParserFree(ctx) if ((ctx)) {arg_freetable(ctx->argtable, ctx->argtableLen); free((ctx)); (ctx)=NULL;} -#define CLIExecWithReturn(ctx, cmd, atbl, ifempty) if (CLIParserParseString(ctx, cmd, atbl, arg_getsize(atbl), ifempty)) {CLIParserFree((ctx)); return PM3_ESOFT;} -#define CLIGetHexBLessWithReturn(ctx, paramnum, data, datalen, delta) if (CLIParamHexToBuf(arg_get_str(ctx, paramnum), data, sizeof(data) - (delta), datalen)) {CLIParserFree((ctx)); return PM3_ESOFT;} -#define CLIGetHexWithReturn(ctx, paramnum, data, datalen) if (CLIParamHexToBuf(arg_get_str(ctx, paramnum), data, sizeof(data), datalen)) {CLIParserFree((ctx)); return PM3_ESOFT;} -#define CLIGetStrWithReturn(ctx, paramnum, data, datalen) if (CLIParamStrToBuf(arg_get_str(ctx, paramnum), data, sizeof(data), datalen)) {CLIParserFree((ctx)); return PM3_ESOFT;} +#define CLIParserFree(ctx) if ((ctx)) {arg_freetable((ctx)->argtable, (ctx)->argtableLen); free((ctx)); (ctx)=NULL;} + +#define CLIExecWithReturn(ctx, cmd, atbl, ifempty) if (CLIParserParseString((ctx), (cmd), (atbl), arg_getsize((atbl)), (ifempty))) {CLIParserFree((ctx)); return PM3_ESOFT;} + +#define CLIGetHexBLessWithReturn(ctx, paramnum, data, datalen, delta) if (CLIParamHexToBuf(arg_get_str((ctx), (paramnum)), (data), sizeof((data)) - (delta), (datalen))) {CLIParserFree((ctx)); return PM3_ESOFT;} + +#define CLIGetHexWithReturn(ctx, paramnum, data, datalen) if (CLIParamHexToBuf(arg_get_str((ctx), (paramnum)), (data), sizeof((data)), (datalen))) {CLIParserFree((ctx)); return PM3_ESOFT;} + +#define CLIGetStrWithReturn(ctx, paramnum, data, datalen) if (CLIParamStrToBuf(arg_get_str((ctx), (paramnum)), (data), sizeof((data)), (datalen))) {CLIParserFree((ctx)); return PM3_ESOFT;} typedef struct { void **argtable; diff --git a/client/luascripts/hf_14b_calypso.lua b/client/luascripts/hf_14b_calypso.lua index 6fa40711e..72ac0f102 100644 --- a/client/luascripts/hf_14b_calypso.lua +++ b/client/luascripts/hf_14b_calypso.lua @@ -32,7 +32,7 @@ device-side. local function calypso_parse(result) local r = Command.parse(result) if r.arg1 >= 0 then - local len = r.arg2 * 2 + local len = r.arg1 * 2 if len > 0 then r.data = string.sub(r.data, 0, len); return r, nil @@ -113,8 +113,9 @@ end local function calypso_send_cmd_raw(data, ignoreresponse ) local command, flags, result, err - flags = lib14b.ISO14B_COMMAND.ISO14B_RAW + - lib14b.ISO14B_COMMAND.ISO14B_APPEND_CRC + flags = lib14b.ISO14B_COMMAND.ISO14B_APDU +-- flags = lib14b.ISO14B_COMMAND.ISO14B_RAW + +-- lib14b.ISO14B_COMMAND.ISO14B_APPEND_CRC data = data or "00" @@ -162,6 +163,7 @@ local function calypso_apdu_status(apdu) return status, desc, err end +local CLA = '94' local _calypso_cmds = { -- Break down of command bytes: @@ -184,27 +186,25 @@ local _calypso_cmds = { -- Electronic Purse file -- Electronic Transaction log file - - --['01.Select ICC file'] = '0294 a4 00 0002 3f00', - ['01.Select ICC file'] = '0294 a4 080004 3f00 0002', - ['02.ICC'] = '0394 b2 01 041d', - ['03.Select EnvHol file'] = '0294 a4 080004 2000 2001', - ['04.EnvHol1'] = '0394 b2 01 041d', - ['05.Select EvLog file'] = '0294 a4 080004 2000 2010', - ['06.EvLog1'] = '0394 b2 01 041d', - ['07.EvLog2'] = '0294 b2 02 041d', - ['08.EvLog3'] = '0394 b2 03 041d', - ['09.Select ConList file']= '0294 a4 080004 2000 2050', - ['10.ConList'] = '0394 b2 01 041d', - ['11.Select Contra file'] = '0294 a4 080004 2000 2020', - ['12.Contra1'] = '0394 b2 01 041d', - ['13.Contra2'] = '0294 b2 02 041d', - ['14.Contra3'] = '0394 b2 03 041d', - ['15.Contra4'] = '0294 b2 04 041d', - ['16.Select Counter file']= '0394 a4 080004 2000 2069', - ['17.Counter'] = '0294 b2 01 041d', - ['18.Select SpecEv file'] = '0394 a4 080004 2000 2040', - ['19.SpecEv1'] = '0294 b2 01 041d', + ['01.Select ICC file'] = CLA..'a4 080004 3f00 0002', + ['02.ICC'] = CLA..'b2 01 041d', + ['03.Select EnvHol file'] = CLA..'a4 080004 2000 2001', + ['04.EnvHol1'] = CLA..'b2 01 041d', + ['05.Select EvLog file'] = CLA..'a4 080004 2000 2010', + ['06.EvLog1'] = CLA..'b2 01 041d', + ['07.EvLog2'] = CLA..'b2 02 041d', + ['08.EvLog3'] = CLA..'b2 03 041d', + ['09.Select ConList file']= CLA..'a4 080004 2000 2050', + ['10.ConList'] = CLA..'b2 01 041d', + ['11.Select Contra file'] = CLA..'a4 080004 2000 2020', + ['12.Contra1'] = CLA..'b2 01 041d', + ['13.Contra2'] = CLA..'b2 02 041d', + ['14.Contra3'] = CLA..'b2 03 041d', + ['15.Contra4'] = CLA..'b2 04 041d', + ['16.Select Counter file']= CLA..'a4 080004 2000 2069', + ['17.Counter'] = CLA..'b2 01 041d', + ['18.Select SpecEv file'] = CLA..'a4 080004 2000 2040', + ['19.SpecEv1'] = CLA..'b2 01 041d', } --- diff --git a/client/luascripts/hf_14b_mobib.lua b/client/luascripts/hf_14b_mobib.lua new file mode 100644 index 000000000..01dd0f3a0 --- /dev/null +++ b/client/luascripts/hf_14b_mobib.lua @@ -0,0 +1,277 @@ +local cmds = require('commands') +local getopt = require('getopt') +local lib14b = require('read14b') +local utils = require('utils') +local iso7816 = require('7816_error') +local ansicolors = require('ansicolors') + +copyright = '' +author = 'Iceman' +version = 'v1.0.0' +desc = [[ +This is a script to communicate with a MOBIB tag using the '14b raw' commands +]] +example = [[ + script run hf_14b_mobib + script run hf_14b_mobib -b 11223344 + +]] +usage = [[ +script run hf_14b_mobib -h -b +]] +arguments = [[ + h this helptext + b raw bytes to send +]] + +--[[ +This script communicates with /armsrc/iso14443b.c, +Check there for details about data format and how commands are interpreted on the +device-side. +]] + +local function calypso_parse(result) + local r = Command.parse(result) + if r.arg1 >= 0 then + local len = r.arg1 * 2 + if len > 0 then + r.data = string.sub(r.data, 0, len); + return r, nil + end + end + return nil,nil +end +--- +-- A debug printout-function +local function dbg(args) + if not DEBUG then return end + if type(args) == 'table' then + local i = 1 + while args[i] do + dbg(args[i]) + i = i+1 + end + else + print('###', args) + end +end +--- +-- This is only meant to be used when errors occur +local function oops(err) + print('ERROR: ', err) + lib14b.disconnect() + return nil, err +end +--- +-- Usage help +local function help() + print(copyright) + print(author) + print(version) + print(desc) + print(ansicolors.cyan..'Usage'..ansicolors.reset) + print(usage) + print(ansicolors.cyan..'Arguments'..ansicolors.reset) + print(arguments) + print(ansicolors.cyan..'Example usage'..ansicolors.reset) + print(example) +end +-- +-- helper function, give current count of items in lua-table. +local function tablelen(T) + local count = 0 + for _ in pairs(T) do count = count + 1 end + return count +end +--- +-- helper function, gives a sorted table from table t, +-- order can be a seperate sorting-order function. +local function spairs(t, order) + -- collect the keys + local keys = {} + for k in pairs(t) do keys[#keys+1] = k end + + -- if order function given, sort by it by passing the table and keys a, b, + -- otherwise just sort the keys + if order then + table.sort(keys, function(a,b) return order(t, a, b) end) + else + table.sort(keys) + end + + -- return the iterator function + local i = 0 + return function() + i = i + 1 + if keys[i] then + return keys[i], t[keys[i]] + end + end +end +--- +-- Sends a usbpackage , "hf 14b raw" +-- if it reads the response, it converts it to a lua object "Command" first and the Data is cut to correct length. +local function calypso_send_cmd_raw(data, ignoreresponse ) + + local command, flags, result, err + flags = lib14b.ISO14B_COMMAND.ISO14B_APDU + + data = data or "00" + + command = Command:newMIX{ + cmd = cmds.CMD_HF_ISO14443B_COMMAND, + arg1 = flags, + arg2 = #data/2, -- LEN of data, half the length of the ASCII-string hex string + data = data} -- data bytes (commands etc) + + local use_cmd_ack = true + result, err = command:sendMIX(ignoreresponse, 2000, use_cmd_ack) + if result then + local count,cmd,arg0,arg1,arg2 = bin.unpack('LLLL', result) + if arg0 >= 0 then + return calypso_parse(result) + else + err = 'card response failed' + end + else + err = 'No response from card' + end + return result, err +end +--- +-- calypso_card_num : Reads card number from ATR and +-- writes it in the tree in decimal format. +local function calypso_card_num(card) + if not card then return end + local card_num = tonumber( card.uid:sub(1,8),16 ) + print('') + print('Card UID ' ..ansicolors.green..card.uid:format('%x')..ansicolors.reset) + print('Card Number ' ..ansicolors.green..string.format('%u', card_num)..ansicolors.reset) + print('-----------------------') +end +--- +-- analyse CALYPSO apdu status bytes. +local function calypso_apdu_status(apdu) + -- last two is CRC + -- next two is APDU status bytes. + local mess = 'FAIL' + local sw = apdu:sub( #apdu-7, #apdu-4) + desc, err = iso7816.tostring(sw) + --print ('SW', sw, desc, err ) + local status = ( sw == '9000' ) + return status, desc, err +end + +local CLA = '00' +local _calypso_cmds = { + ['01.SELECT AID 1TIC.ICA'] = CLA..'a4 0400 08 315449432e494341', + ['02.Select ICC file a'] = CLA..'a4 0000 02 3f00', + ['03.Select ICC file b'] = CLA..'a4 0000 02 0002', + ['04.ICC'] = CLA..'b2 0104 1d', + ['05.Select Holder file'] = CLA..'a4 0000 02 3f1c', + ['06.Holder1'] = CLA..'b2 0104 1d', + ['07.Holder2'] = CLA..'b2 0204 1d', + ['08.Select EnvHol file a'] = CLA..'a4 0000 00', + ['09.Select EnvHol file b'] = CLA..'a4 0000 02 2000', + ['10.Select EnvHol file c'] = CLA..'a4 0000 02 2001', + ['11.EnvHol1'] = CLA..'b2 0104 1d', + ['11.EnvHol2'] = CLA..'b2 0204 1d', + ['12.Select EvLog file'] = CLA..'a4 0000 02 2010', + ['13.EvLog1'] = CLA..'b2 0104 1d', + ['14.EvLog2'] = CLA..'b2 0204 1d', + ['15.EvLog3'] = CLA..'b2 0304 1d', + ['16.Select ConList file'] = CLA..'a4 0000 02 2050', + ['17.ConList'] = CLA..'b2 0104 1d', + ['18.Select Contra file'] = CLA..'a4 0000 02 2020', + ['19.Contra1'] = CLA..'b2 0104 1d', + ['20.Contra2'] = CLA..'b2 0204 1d', + ['21.Contra3'] = CLA..'b2 0304 1d', + ['22.Contra4'] = CLA..'b2 0404 1d', + ['23.Contra5'] = CLA..'b2 0504 1d', + ['24.Contra6'] = CLA..'b2 0604 1d', + ['25.Contra7'] = CLA..'b2 0704 1d', + ['26.Contra8'] = CLA..'b2 0804 1d', + ['27.Contra9'] = CLA..'b2 0904 1d', + ['28.ContraA'] = CLA..'b2 0a04 1d', + ['29.ContraB'] = CLA..'b2 0b04 1d', + ['30.ContraC'] = CLA..'b2 0c04 1d', + ['31.Select Counter file'] = CLA..'a4 0000 02 2069', + ['32.Counter'] = CLA..'b2 0104 1d', + ['33.Select LoadLog file a'] = CLA..'a4 0000 00', + ['34.Select LoadLog file b'] = CLA..'a4 0000 02 1000', + ['35.Select LoadLog file c'] = CLA..'a4 0000 02 1014', + ['36.LoadLog'] = CLA..'b2 0104 1d', + ['37.Select Purcha file'] = CLA..'a4 0000 02 1015', + ['38.Purcha1'] = CLA..'b2 0104 1d', + ['39.Purcha2'] = CLA..'b2 0204 1d', + ['40.Purcha3'] = CLA..'b2 0304 1d', + ['41.Select SpecEv file a'] = CLA..'a4 0000 00', + ['42.Select SpecEv file b'] = CLA..'a4 0000 02 2000', + ['43.Select SpecEv file c'] = CLA..'a4 0000 02 2040', + ['44.SpecEv1'] = CLA..'b2 0104 1d', + ['45.SpecEv2'] = CLA..'b2 0204 1d', + ['46.SpecEv3'] = CLA..'b2 0304 1d', + ['47.SpecEv4'] = CLA..'b2 0404 1d', +} + +--- +-- The main entry point +function main(args) + + print( string.rep('--',20) ) + print( string.rep('--',20) ) + print() + + local data, apdu, flags, uid, cid, result, err, card + -- Read the parameters + for o, a in getopt.getopt(args, 'h') do + if o == 'h' then return help() end + if o == 'b' then bytes = a end + end + +-- lib14b.connect() + + -- Select 14b tag. + card, err = lib14b.waitFor14443b() + if not card then return oops(err) end + + calypso_card_num(card) + cid = card.cid + + for i, apdu in spairs(_calypso_cmds) do + print('>> '..ansicolors.yellow..i..ansicolors.reset) + apdu = apdu:gsub('%s+', '') + result, err = calypso_send_cmd_raw(apdu , false) + if err then + print('<< '..err) + else + if result then + local status, desc, err = calypso_apdu_status(result.data) + local d = result.data:sub(3, (#result.data - 8)) + if status then + print('<< '..d..' ('..ansicolors.green..'ok'..ansicolors.reset..')') + else + print('<< '..d..' '..ansicolors.red..err..ansicolors.reset ) + end + else + print('<< no answer') + end + end + end + lib14b.disconnect() +end +--- +-- a simple selftest function, tries to convert +function selftest() + DEBUG = true + dbg('Performing test') + dbg('Tests done') +end +-- Flip the switch here to perform a sanity check. +-- It read a nonce in two different ways, as specified in the usage-section +if '--test'==args then + selftest() +else + -- Call the main + main(args) +end diff --git a/client/luascripts/init_rdv4.lua b/client/luascripts/init_rdv4.lua index bc18dc0a9..a724ed189 100644 --- a/client/luascripts/init_rdv4.lua +++ b/client/luascripts/init_rdv4.lua @@ -74,9 +74,9 @@ function main(args) -- Upload dictionaries print('Uploading dictionaries to RDV4 flashmemory') print(dash) - core.console('mem load f mfc_default_keys m') - core.console('mem load f t55xx_default_pwds t') - core.console('mem load f iclass_default_keys i') + core.console('mem load -f mfc_default_keys --mfc') + core.console('mem load -f t55xx_default_pwds --t55xx') + core.console('mem load -f iclass_default_keys --iclass') print(dash) -- T55x7 Device configuration diff --git a/client/src/cmddata.c b/client/src/cmddata.c index ffa6785b4..cdbf1f04b 100644 --- a/client/src/cmddata.c +++ b/client/src/cmddata.c @@ -50,20 +50,6 @@ static int usage_data_save(void) { PrintAndLogEx(NORMAL, " data save f mytrace w - save graphbuffer to wave file"); return PM3_SUCCESS; } -static int usage_data_scale(void) { - PrintAndLogEx(NORMAL, "Set cursor display scale."); - PrintAndLogEx(NORMAL, "Setting the scale makes the differential `dt` reading between the yellow and purple markers meaningful. "); - PrintAndLogEx(NORMAL, "once the scale is set, the differential reading between brackets is the time duration in seconds."); - PrintAndLogEx(NORMAL, "For example, if acquiring in 125kHz, use scale 125."); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: data scale [h] "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h this help"); - PrintAndLogEx(NORMAL, " sets scale of carrier frequency expressed in kHz"); - PrintAndLogEx(NORMAL, "Samples:"); - PrintAndLogEx(NORMAL, " data scale 125 - if sampled in 125kHz"); - return PM3_SUCCESS; -} static int usage_data_printdemodbuf(void) { PrintAndLogEx(NORMAL, "Usage: data printdemodbuffer x o l "); PrintAndLogEx(NORMAL, "Options:"); @@ -1825,7 +1811,8 @@ static int CmdMtrim(const char *Cmd) { uint32_t start = 0, stop = 0; sscanf(Cmd, "%u %u", &start, &stop); - if (start > GraphTraceLen || stop > GraphTraceLen || start > stop) return PM3_ESOFT; + if (start > GraphTraceLen || stop > GraphTraceLen || start >= stop) + return PM3_ESOFT; // leave start position sample start++; @@ -1912,14 +1899,32 @@ int CmdSave(const char *Cmd) { } static int CmdScale(const char *Cmd) { - char cmdp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) == 0 || cmdp == 'h') return usage_data_scale(); - CursorScaleFactor = atoi(Cmd); - if (CursorScaleFactor == 0) { - PrintAndLogEx(FAILED, "bad, can't have zero scale"); + CLIParserContext *ctx; + CLIParserInit(&ctx, "data scale", + "Set cursor display scale.\n" + "Setting the scale makes the differential `dt` reading between the yellow and purple markers meaningful.\n" + "once the scale is set, the differential reading between brackets can become a time duration.", + "data scale --sr 125 -u ms -> for LF sampled at 125 kHz. Reading will be in milliseconds\n" + "data scale --sr 1.695 -u us -> for HF sampled at 1.695 MHz. Reading will be in microseconds\n" + "data scale --sr 16 -u ETU -> for HF with 16 samples per ETU. Reading will be in ETUs" + ); + void *argtable[] = { + arg_param_begin, + arg_dbl1(NULL, "sr", "", "sets scale according to sampling rate"), + arg_str0("u", "unit", "", "time unit to display (max 10 chars)"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + CursorScaleFactor = arg_get_dbl_def(ctx, 1, 1); + if (CursorScaleFactor <= 0) { + PrintAndLogEx(FAILED, "bad, can't have negative or zero scale"); CursorScaleFactor = 1; } + int len = 0; + CursorScaleFactorUnit[0] = '\x00'; + CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t*)CursorScaleFactorUnit, sizeof(CursorScaleFactorUnit), &len); + CLIParserFree(ctx); RepaintGraphWindow(); return PM3_SUCCESS; } diff --git a/client/src/cmdflashmem.c b/client/src/cmdflashmem.c index e90e6025c..1262b5645 100644 --- a/client/src/cmdflashmem.c +++ b/client/src/cmdflashmem.c @@ -8,16 +8,13 @@ // Proxmark3 RDV40 Flash memory commands //----------------------------------------------------------------------------- #include "cmdflashmem.h" - #include - -#include "cmdparser.h" // command_t - +#include "cmdparser.h" // command_t +#include "cliparser.h" #include "pmflash.h" -#include "fileutils.h" //saveFile -#include "comms.h" //getfromdevice +#include "fileutils.h" // saveFile +#include "comms.h" // getfromdevice #include "cmdflashmemspiffs.h" // spiffs commands - #include "rsa.h" #include "sha1.h" @@ -29,90 +26,34 @@ static int CmdHelp(const char *Cmd); -static int usage_flashmem_spibaud(void) { - PrintAndLogEx(NORMAL, "Usage: mem spibaud [h] "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h this help"); - PrintAndLogEx(NORMAL, " SPI baudrate in MHz [24|48]"); - PrintAndLogEx(NORMAL, " "); - PrintAndLogEx(NORMAL, " If >= 24MHz, FASTREADS instead of READS instruction will be used."); - PrintAndLogEx(NORMAL, " Reading Flash ID will virtually always fail under 48MHz setting"); - PrintAndLogEx(NORMAL, " Unless you know what you are doing, please stay at 24MHz"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " mem spibaud 48"); - return PM3_SUCCESS; -} - -static int usage_flashmem_load(void) { - PrintAndLogEx(NORMAL, "Loads binary file into flash memory on device"); - PrintAndLogEx(NORMAL, "Usage: mem load [o ] f [m|t|i]"); - PrintAndLogEx(NORMAL, "Warning: mem area to be written must have been wiped first"); - PrintAndLogEx(NORMAL, "(this is already taken care when loading dictionaries)"); - PrintAndLogEx(NORMAL, " o : offset in memory"); - PrintAndLogEx(NORMAL, " f : file name"); - PrintAndLogEx(NORMAL, " m : upload 6 bytes keys (mifare key dictionary)"); - PrintAndLogEx(NORMAL, " i : upload 8 bytes keys (iClass key dictionary)"); - PrintAndLogEx(NORMAL, " t : upload 4 bytes keys (pwd dictionary)"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " mem load f myfile"); // upload file myfile at default offset 0 - PrintAndLogEx(NORMAL, " mem load f myfile o 1024"); // upload file myfile at offset 1024 - PrintAndLogEx(NORMAL, " mem load f mfc_default_keys m"); - PrintAndLogEx(NORMAL, " mem load f t55xx_default_pwds t"); - PrintAndLogEx(NORMAL, " mem load f iclass_default_keys i"); - return PM3_SUCCESS; -} -static int usage_flashmem_dump(void) { - PrintAndLogEx(NORMAL, "Dumps flash memory on device into a file or in console"); - PrintAndLogEx(NORMAL, " Usage: mem dump [o ] [l ] [f ] [p]"); - PrintAndLogEx(NORMAL, " o : offset in memory"); - PrintAndLogEx(NORMAL, " l : length"); - PrintAndLogEx(NORMAL, " f : file name"); - PrintAndLogEx(NORMAL, " p : print dump in console"); - PrintAndLogEx(NORMAL, " You must specify at lease option f or option p, both if you wish"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " mem dump f myfile"); // download whole flashmem to file myfile - PrintAndLogEx(NORMAL, " mem dump p o 262015 l 128"); // display 128 bytes from offset 262015 (RSA sig) - PrintAndLogEx(NORMAL, " mem dump p f myfile o 241664 l 58"); // download and display 58 bytes from offset 241664 to file myfile - return PM3_SUCCESS; -} -static int usage_flashmem_wipe(void) { - - PrintAndLogEx(WARNING, "[OBS] use with caution."); - PrintAndLogEx(NORMAL, "Wipe flash memory on device, which fills memory with 0xFF\n"); - - PrintAndLogEx(NORMAL, " Usage: mem wipe p "); - PrintAndLogEx(NORMAL, " p : 0,1,2 page memory"); -// PrintAndLogEx(NORMAL, " i : inital total wipe"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " mem wipe p 0"); // wipes first page. - return PM3_SUCCESS; -} -static int usage_flashmem_info(void) { - PrintAndLogEx(NORMAL, "Collect signature and verify it from flash memory\n"); - PrintAndLogEx(NORMAL, " Usage: mem info"); -// PrintAndLogEx(NORMAL, " s : create a signature"); -// PrintAndLogEx(NORMAL, " w : write signature to flash memory"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, " mem info"); -// PrintAndLogEx(NORMAL, " mem info s"); - return PM3_SUCCESS; -} - static int CmdFlashmemSpiBaudrate(const char *Cmd) { + + CLIParserContext *ctx; + CLIParserInit(&ctx, "mem baudrate", + "Set the baudrate for the SPI flash memory communications.\n" + "Reading Flash ID will virtually always fail under 48MHz setting.\n" + "Unless you know what you are doing, please stay at 24MHz.\n" + "If >= 24MHz, FASTREADS instead of READS instruction will be used.", + "mem baudrate --mhz 48" + ); + + void *argtable[] = { + arg_param_begin, + arg_int1(NULL, "mhz", "<24|48>", "SPI baudrate in MHz"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + int br = arg_get_int_def(ctx, 1, -1); + CLIParserFree(ctx); - char ctmp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) < 1 || ctmp == 'h') { - return usage_flashmem_spibaud(); + if (br == -1) { + PrintAndLogEx(ERR, "failed to get baudrate"); + return PM3_EINVARG; } - uint32_t baudrate = param_get32ex(Cmd, 0, 0, 10); - baudrate = baudrate * 1000000; + uint32_t baudrate = br * 1000000; if (baudrate != FLASH_BAUD && baudrate != FLASH_MINBAUD) { - usage_flashmem_spibaud(); + PrintAndLogEx(ERR, "wrong baudrate. Only 24 or 48 is allowed"); return PM3_EINVARG; } SendCommandNG(CMD_FLASHMEM_SET_SPIBAUDRATE, (uint8_t *)&baudrate, sizeof(uint32_t)); @@ -121,52 +62,50 @@ static int CmdFlashmemSpiBaudrate(const char *Cmd) { static int CmdFlashMemLoad(const char *Cmd) { - uint32_t start_index = 0; + CLIParserContext *ctx; + CLIParserInit(&ctx, "mem load", + "Loads binary file into flash memory on device\n" + "Warning: mem area to be written must have been wiped first\n" + "( this is already taken care when loading dictionaries )", + "mem load -f myfile -> upload file myfile values at default offset 0\n" + "mem load -f myfile -o 1024 -> upload file myfile values at offset 1024\n" + "mem load -f mfc_default_keys -m -> upload MFC keys\n" + "mem load -f t55xx_default_pwds -t -> upload T55XX passwords\n" + "mem load -f iclass_default_keys -i -> upload iCLASS keys\n" + ); + + void *argtable[] = { + arg_param_begin, + arg_int0("o", "offset", "", "offset in memory"), + arg_lit0("m", "mifare,mfc", "upload 6 bytes keys (mifare key dictionary)"), + arg_lit0("i", "iclass", "upload 8 bytes keys (iClass key dictionary)"), + arg_lit0("t", "t55xx", "upload 4 bytes keys (password dictionary)"), + arg_strx0("f", "file", "", "file name"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + int offset = arg_get_int_def(ctx, 1, 0); + bool is_mfc = arg_get_lit(ctx, 2); + bool is_iclass = arg_get_lit(ctx, 3); + bool is_t55xx = arg_get_lit(ctx, 4); + int fnlen = 0; char filename[FILE_PATH_SIZE] = {0}; - bool errors = false; - uint8_t cmdp = 0; + CLIParamStrToBuf(arg_get_str(ctx, 5), (uint8_t*)filename, FILE_PATH_SIZE, &fnlen); + CLIParserFree(ctx); + Dictionary_t d = DICTIONARY_NONE; - - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_flashmem_load(); - case 'f': - if (param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE) >= FILE_PATH_SIZE) { - PrintAndLogEx(FAILED, "Filename too long"); - errors = true; - break; - } - cmdp += 2; - break; - case 'o': - start_index = param_get32ex(Cmd, cmdp + 1, 0, 10); - cmdp += 2; - break; - case 'm': - d = DICTIONARY_MIFARE; - cmdp++; - break; - case 't': - d = DICTIONARY_T55XX; - cmdp++; - break; - case 'i': - d = DICTIONARY_ICLASS; - cmdp++; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } + if (is_mfc) { + d = DICTIONARY_MIFARE; + PrintAndLogEx(INFO, "treating file as MIFARE Classic keys"); + } else if (is_iclass) { + d = DICTIONARY_ICLASS; + PrintAndLogEx(INFO, "treating file as iCLASS keys"); + } else if (is_t55xx) { + d = DICTIONARY_T55XX; + PrintAndLogEx(INFO, "treating file as T55xx passwords"); } - //Validations - if (errors || cmdp == 0) { - usage_flashmem_load(); - return PM3_EINVARG; - } size_t datalen = 0; uint32_t keycount = 0; int res = 0; @@ -174,7 +113,7 @@ static int CmdFlashMemLoad(const char *Cmd) { switch (d) { case DICTIONARY_MIFARE: - start_index = DEFAULT_MF_KEYS_OFFSET; + offset = DEFAULT_MF_KEYS_OFFSET; res = loadFileDICTIONARY(filename, data + 2, &datalen, 6, &keycount); if (res || !keycount) { free(data); @@ -189,7 +128,7 @@ static int CmdFlashMemLoad(const char *Cmd) { datalen += 2; break; case DICTIONARY_T55XX: - start_index = DEFAULT_T55XX_KEYS_OFFSET; + offset = DEFAULT_T55XX_KEYS_OFFSET; res = loadFileDICTIONARY(filename, data + 2, &datalen, 4, &keycount); if (res || !keycount) { free(data); @@ -204,7 +143,7 @@ static int CmdFlashMemLoad(const char *Cmd) { datalen += 2; break; case DICTIONARY_ICLASS: - start_index = DEFAULT_ICLASS_KEYS_OFFSET; + offset = DEFAULT_ICLASS_KEYS_OFFSET; res = loadFileDICTIONARY(filename, data + 2, &datalen, 8, &keycount); if (res || !keycount) { free(data); @@ -253,13 +192,13 @@ static int CmdFlashMemLoad(const char *Cmd) { clearCommandBuffer(); - SendCommandOLD(CMD_FLASHMEM_WRITE, start_index + bytes_sent, bytes_in_packet, 0, data + bytes_sent, bytes_in_packet); + SendCommandOLD(CMD_FLASHMEM_WRITE, offset + bytes_sent, bytes_in_packet, 0, data + bytes_sent, bytes_in_packet); bytes_remaining -= bytes_in_packet; bytes_sent += bytes_in_packet; PacketResponseNG resp; - if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { + if (WaitForResponseTimeout(CMD_ACK, &resp, 2000) == false) { PrintAndLogEx(WARNING, "timeout while waiting for reply."); conn.block_after_ACK = false; free(data); @@ -276,54 +215,37 @@ static int CmdFlashMemLoad(const char *Cmd) { conn.block_after_ACK = false; free(data); - PrintAndLogEx(SUCCESS, "Wrote "_GREEN_("%zu")" bytes to offset "_GREEN_("%u"), datalen, start_index); + PrintAndLogEx(SUCCESS, "Wrote "_GREEN_("%zu")" bytes to offset "_GREEN_("%u"), datalen, offset); return PM3_SUCCESS; } + static int CmdFlashMemDump(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "mem dump", + "Dumps flash memory on device into a file or view in console", + "mem dump -f myfile -> download all flashmem to file\n" + "mem dump --view -o 262015 --len 128 -> display 128 bytes from offset 262015 (RSA sig)\n" + "mem dump --view -f myfile -o 241664 --len 58 -> display 58 bytes from offset 241664 and save to file" + ); + + void *argtable[] = { + arg_param_begin, + arg_int0("o", "offset", "", "offset in memory"), + arg_int0("l", "len", "", "length"), + arg_lit0("v", "view", "view dump"), + arg_strx0("f", "file", "", "file name"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + int offset = arg_get_int_def(ctx, 1, 0); + int len = arg_get_int_def(ctx, 2, FLASH_MEM_MAX_SIZE); + bool view = arg_get_lit(ctx, 3); + int fnlen = 0; char filename[FILE_PATH_SIZE] = {0}; - uint8_t cmdp = 0; - bool errors = false; - bool print = false; - uint32_t start_index = 0, len = FLASH_MEM_MAX_SIZE; - - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_flashmem_dump(); - case 'l': - len = param_get32ex(Cmd, cmdp + 1, FLASH_MEM_MAX_SIZE, 10); - cmdp += 2; - break; - case 'o': - start_index = param_get32ex(Cmd, cmdp + 1, 0, 10); - cmdp += 2; - break; - case 'p': - print = true; - cmdp += 1; - break; - case 'f': - //File handling - if (param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE) >= FILE_PATH_SIZE) { - PrintAndLogEx(FAILED, "Filename too long"); - errors = true; - break; - } - cmdp += 2; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } - - //Validations - if (errors || cmdp == 0) { - usage_flashmem_dump(); - return PM3_EINVARG; - } + CLIParamStrToBuf(arg_get_str(ctx, 4), (uint8_t*)filename, FILE_PATH_SIZE, &fnlen); + CLIParserFree(ctx); uint8_t *dump = calloc(len, sizeof(uint8_t)); if (!dump) { @@ -331,14 +253,15 @@ static int CmdFlashMemDump(const char *Cmd) { return PM3_EMALLOC; } - PrintAndLogEx(INFO, "downloading "_YELLOW_("%u")" bytes from flashmem", len); - if (!GetFromDevice(FLASH_MEM, dump, len, start_index, NULL, 0, NULL, -1, true)) { - PrintAndLogEx(FAILED, "ERROR; downloading from flashmemory"); + PrintAndLogEx(INFO, "downloading "_YELLOW_("%u")" bytes from flash memory", len); + if (!GetFromDevice(FLASH_MEM, dump, len, offset, NULL, 0, NULL, -1, true)) { + PrintAndLogEx(FAILED, "ERROR; downloading from flash memory"); free(dump); return PM3_EFLASH; } - if (print) { + if (view) { + PrintAndLogEx(INFO, "---- " _CYAN_("data") " ---------------"); print_hex_break(dump, len, 32); } @@ -350,39 +273,32 @@ static int CmdFlashMemDump(const char *Cmd) { free(dump); return PM3_SUCCESS; } + static int CmdFlashMemWipe(const char *Cmd) { - uint8_t cmdp = 0; - bool errors = false; - bool initalwipe = false; - uint8_t page = 0; - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_flashmem_wipe(); - case 'p': - page = param_get8ex(Cmd, cmdp + 1, 0, 10); - if (page > 2) { - PrintAndLogEx(WARNING, "page must be 0, 1 or 2"); - errors = true; - break; - } - cmdp += 2; - break; - case 'i': - initalwipe = true; - cmdp++; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } + CLIParserContext *ctx; + CLIParserInit(&ctx, "mem wipe", + "Wipe flash memory on device, which fills it with 0xFF\n" + _WHITE_("[ ") _RED_("!!! OBS") " ] use with caution", + "mem wipe -p 0 -> wipes first page" +// "mem wipe -i -> inital total wipe" + ); - //Validations - if (errors || cmdp == 0) { - usage_flashmem_wipe(); + void *argtable[] = { + arg_param_begin, + arg_int0("p", NULL, "", "0,1,2 page memory"), +// arg_lit0("i", NULL, "inital total wipe"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + bool initalwipe = false; + int page = arg_get_int_def(ctx, 1, -1); +// initalwipe = arg_get_lit(ctx, 2); + CLIParserFree(ctx); + + if (page < 0 || page > 2 ) { + PrintAndLogEx(WARNING, "page must be 0, 1 or 2"); return PM3_EINVARG; } @@ -393,59 +309,51 @@ static int CmdFlashMemWipe(const char *Cmd) { PrintAndLogEx(WARNING, "timeout while waiting for reply."); return PM3_ETIMEOUT; } + + const char* msg = "Flash WIPE "; uint8_t isok = resp.oldarg[0] & 0xFF; if (isok) - PrintAndLogEx(SUCCESS, "Flash WIPE ok"); + PrintAndLogEx(SUCCESS, "%s ( " _GREEN_("ok")" )", msg); else { - PrintAndLogEx(FAILED, "Flash WIPE failed"); + PrintAndLogEx(FAILED, "%s ( " _RED_("failed") " )", msg); return PM3_EFLASH; } return PM3_SUCCESS; } + static int CmdFlashMemInfo(const char *Cmd) { - uint8_t sha_hash[20] = {0}; - mbedtls_rsa_context rsa; + CLIParserContext *ctx; + CLIParserInit(&ctx, "mem info", + "Collect signature and verify it from flash memory", + "mem info" +// "mem info -s" + ); - uint8_t cmdp = 0; - bool errors = false, shall_write = false, shall_sign = false; - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_flashmem_info(); - case 's': { - shall_sign = true; - cmdp++; - break; - } - case 'w': - shall_write = true; - cmdp++; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } + void *argtable[] = { + arg_param_begin, +// arg_lit0("s", NULL, "create a signature"), +// arg_lit0("w", NULL, "write signature to flash memory"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); - //Validations - if (errors) { - usage_flashmem_info(); - return PM3_EINVARG; - } + bool shall_sign = false, shall_write = false; +// shall_sign = arg_get_lit(ctx, 1); +// shall_write = arg_get_lit(ctx, 2); + CLIParserFree(ctx); clearCommandBuffer(); SendCommandNG(CMD_FLASHMEM_INFO, NULL, 0); PacketResponseNG resp; - if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) { - PrintAndLogEx(WARNING, "timeout while waiting for reply."); + if (WaitForResponseTimeout(CMD_ACK, &resp, 2500) == false) { + PrintAndLogEx(WARNING, "timeout while waiting for reply"); return PM3_ETIMEOUT; } uint8_t isok = resp.oldarg[0] & 0xFF; - if (!isok) { + if (isok == false) { PrintAndLogEx(FAILED, "failed"); return PM3_EFLASH; } @@ -455,15 +363,20 @@ static int CmdFlashMemInfo(const char *Cmd) { memcpy(&mem, (rdv40_validation_t *)resp.data.asBytes, sizeof(rdv40_validation_t)); // Flash ID hash (sha1) + uint8_t sha_hash[20] = {0}; mbedtls_sha1(mem.flashid, sizeof(mem.flashid), sha_hash); // print header - PrintAndLogEx(INFO, "\n--- Flash memory Information ---------"); - PrintAndLogEx(INFO, "-------------------------------------------------------------"); - PrintAndLogEx(INFO, "ID | %s", sprint_hex(mem.flashid, sizeof(mem.flashid))); - PrintAndLogEx(INFO, "SHA1 | %s", sprint_hex(sha_hash, sizeof(sha_hash))); - PrintAndLogEx(INFO, "RSA SIGNATURE |"); - print_hex_break(mem.signature, sizeof(mem.signature), 32); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "--- " _CYAN_("Flash memory Information") " ---------"); +// PrintAndLogEx(INFO, "-----------------------------------------------------------------"); + PrintAndLogEx(INFO, "ID................... %s", sprint_hex_inrow(mem.flashid, sizeof(mem.flashid))); + PrintAndLogEx(INFO, "SHA1................. %s", sprint_hex_inrow(sha_hash, sizeof(sha_hash))); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "--- " _CYAN_("RDV4 RSA signature") " ---------------"); + for (int i = 0; i < (sizeof(mem.signature) / 32); i++) { + PrintAndLogEx(INFO, " %s", sprint_hex_inrow(mem.signature + (i * 32), 32)); + } //------------------------------------------------------------------------------- // RRG Public RSA Key @@ -473,7 +386,10 @@ static int CmdFlashMemInfo(const char *Cmd) { #define RSA_E "010001" // public key modulus N -#define RSA_N "E28D809BF323171D11D1ACA4C32A5B7E0A8974FD171E75AD120D60E9B76968FF4B0A6364AE50583F9555B8EE1A725F279E949246DF0EFCE4C02B9F3ACDCC623F9337F21C0C066FFB703D8BFCB5067F309E056772096642C2B1A8F50305D5EC33DB7FB5A3C8AC42EB635AE3C148C910750ABAA280CE82DC2F180F49F30A1393B5" +#define RSA_N "E28D809BF323171D11D1ACA4C32A5B7E0A8974FD171E75AD120D60E9B76968FF" \ + "4B0A6364AE50583F9555B8EE1A725F279E949246DF0EFCE4C02B9F3ACDCC623F" \ + "9337F21C0C066FFB703D8BFCB5067F309E056772096642C2B1A8F50305D5EC33" \ + "DB7FB5A3C8AC42EB635AE3C148C910750ABAA280CE82DC2F180F49F30A1393B5" //------------------------------------------------------------------------------- // Example RSA-1024 keypair, for test purposes (from common/polarssl/rsa.c) @@ -516,9 +432,9 @@ static int CmdFlashMemInfo(const char *Cmd) { "F5A3B2A5D33605AEBBCCBA7FEB9F2D2F" \ "A74206CEC169D74BF5A8C50D6F48EA08" - #define KEY_LEN 128 + mbedtls_rsa_context rsa; mbedtls_rsa_init(&rsa, MBEDTLS_RSA_PKCS_V15, 0); rsa.len = KEY_LEN; @@ -532,13 +448,31 @@ static int CmdFlashMemInfo(const char *Cmd) { mbedtls_mpi_read_string(&rsa.DQ, 16, RSA_DQ); mbedtls_mpi_read_string(&rsa.QP, 16, RSA_QP); - PrintAndLogEx(INFO, "KEY length | %d", KEY_LEN); - bool is_keyok = (mbedtls_rsa_check_pubkey(&rsa) == 0 || mbedtls_rsa_check_privkey(&rsa) == 0); + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "--- " _CYAN_("RDV4 RSA Public key") " --------------"); + + char str_exp[10]; + char str_pk[261]; + size_t exlen = 0, pklen = 0; + mbedtls_mpi_write_string(&rsa.E, 16, str_exp, sizeof(str_exp), &exlen); + mbedtls_mpi_write_string(&rsa.N, 16, str_pk, sizeof(str_pk), &pklen); + + PrintAndLogEx(INFO, "Len.................. %u", rsa.len); + PrintAndLogEx(INFO, "Exponent............. %s", str_exp); + PrintAndLogEx(INFO, "Public key modulus N"); + PrintAndLogEx(INFO, " %.64s", str_pk); + PrintAndLogEx(INFO, " %.64s", str_pk + 64); + PrintAndLogEx(INFO, " %.64s", str_pk + 128); + PrintAndLogEx(INFO, " %.64s", str_pk + 192); + + PrintAndLogEx(NORMAL, ""); + const char *msgkey = "RSA key validation... "; if (is_keyok) - PrintAndLogEx(SUCCESS, "RSA key validation ok"); + PrintAndLogEx(SUCCESS, "%s( " _GREEN_("ok") " )", msgkey); else - PrintAndLogEx(FAILED, "RSA key validation failed"); + PrintAndLogEx(FAILED, "%s( " _RED_("failed") " )", msgkey); // uint8_t from_device[KEY_LEN]; @@ -554,10 +488,11 @@ static int CmdFlashMemInfo(const char *Cmd) { if (shall_sign) { int is_signed = mbedtls_rsa_pkcs1_sign(&rsa, NULL, NULL, MBEDTLS_RSA_PRIVATE, MBEDTLS_MD_SHA1, 20, sha_hash, sign); + const char *msgsign = "RSA signing.......... "; if (is_signed == 0) - PrintAndLogEx(SUCCESS, "RSA Signing ok"); + PrintAndLogEx(SUCCESS, "%s( " _GREEN_("ok") " )", msgsign); else - PrintAndLogEx(FAILED, "RSA Signing failed"); + PrintAndLogEx(FAILED, "%s( " _RED_("failed") " )", msgsign); if (shall_write) { // save to mem @@ -574,29 +509,33 @@ static int CmdFlashMemInfo(const char *Cmd) { } } - PrintAndLogEx(INFO, "Signed | "); - print_hex_break(sign, sizeof(sign), 32); + PrintAndLogEx(INFO, "Signed"); + for (int i = 0; i < (sizeof(sign) / 32); i++) { + PrintAndLogEx(INFO, " %s", sprint_hex_inrow(sign + (i * 32), 32)); + } } // Verify (public key) int is_verified = mbedtls_rsa_pkcs1_verify(&rsa, NULL, NULL, MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA1, 20, sha_hash, from_device); + const char *msgverify = "RSA verification..... "; if (is_verified == 0) - PrintAndLogEx(SUCCESS, "RSA Verification ok"); + PrintAndLogEx(SUCCESS, "%s( " _GREEN_("ok") " )", msgverify); else - PrintAndLogEx(FAILED, "RSA Verification failed"); + PrintAndLogEx(FAILED, "%s( " _RED_("failed") " )", msgverify); + PrintAndLogEx(NORMAL, ""); mbedtls_rsa_free(&rsa); return PM3_SUCCESS; } static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, - {"spiffs", CmdFlashMemSpiFFS, IfPm3Flash, "High level SPI FileSystem Flash manipulation [rdv40]"}, - {"spibaud", CmdFlashmemSpiBaudrate, IfPm3Flash, "Set Flash memory Spi baudrate [rdv40]"}, - {"info", CmdFlashMemInfo, IfPm3Flash, "Flash memory information [rdv40]"}, - {"load", CmdFlashMemLoad, IfPm3Flash, "Load data into flash memory [rdv40]"}, - {"dump", CmdFlashMemDump, IfPm3Flash, "Dump data from flash memory [rdv40]"}, - {"wipe", CmdFlashMemWipe, IfPm3Flash, "Wipe data from flash memory [rdv40]"}, + {"baudrate", CmdFlashmemSpiBaudrate, IfPm3Flash, "Set Flash memory Spi baudrate"}, + {"spiffs", CmdFlashMemSpiFFS, IfPm3Flash, "High level SPI FileSystem Flash manipulation"}, + {"info", CmdFlashMemInfo, IfPm3Flash, "Flash memory information"}, + {"load", CmdFlashMemLoad, IfPm3Flash, "Load data into flash memory"}, + {"dump", CmdFlashMemDump, IfPm3Flash, "Dump data from flash memory"}, + {"wipe", CmdFlashMemWipe, IfPm3Flash, "Wipe data from flash memory"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdhf14b.c b/client/src/cmdhf14b.c index 87589f299..542dc3aec 100644 --- a/client/src/cmdhf14b.c +++ b/client/src/cmdhf14b.c @@ -63,7 +63,7 @@ static uint16_t get_sw(uint8_t *d, uint8_t n) { return d[n] * 0x0100 + d[n + 1]; } -static bool wait_cmd_14b(bool verbose) { +static bool wait_cmd_14b(bool verbose, bool is_select) { PacketResponseNG resp; if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) { @@ -71,6 +71,23 @@ static bool wait_cmd_14b(bool verbose) { uint16_t len = (resp.oldarg[1] & 0xFFFF); uint8_t *data = resp.data.asBytes; + // handle select responses + if (is_select) { + + // 0: OK; -1: attrib fail; -2:crc fail + int status = (int)resp.oldarg[0]; + if (status == 0) { + + if (verbose) { + PrintAndLogEx(SUCCESS, "len %u | %s", len, sprint_hex(data, len)); + } + return true; + } else { + return false; + } + } + + // handle raw bytes responses if (verbose) { if (len >= 3) { @@ -121,12 +138,14 @@ static int CmdHF14BSim(const char *Cmd) { uint8_t pupi[4]; int n = 0; - CLIParamHexToBuf(arg_get_str(ctx, 1), pupi, sizeof(pupi), &n); + int res = CLIParamHexToBuf(arg_get_str(ctx, 1), pupi, sizeof(pupi), &n); + if (res) { + PrintAndLogEx(FAILED, "failed to read pupi"); + return PM3_EINVARG; + } CLIParserFree(ctx); - clearCommandBuffer(); - SendCommandNG(CMD_HF_ISO14443B_SIMULATE, pupi, sizeof(pupi)); - + SendCommandNG(CMD_HF_ISO14443B_SIMULATE, pupi, sizeof(pupi)); return PM3_SUCCESS; } @@ -161,27 +180,26 @@ static int CmdHF14BCmdRaw(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf 14b raw", "Sends raw bytes to card ", - "hf 14b raw -s -c -k 0200a40400\n" - "hf 14b raw --sr -c -k 0200a40400\n" - "hf 14b raw --cts -c -k 0200a40400\n" + "hf 14b raw -cks --data 0200a40400 -> standard select\n" + "hf 14b raw -ck --sr --data 0200a40400 -> SRx select\n" + "hf 14b raw -ck --cts --data 0200a40400 -> C-ticket select\n" ); void *argtable[] = { arg_param_begin, - arg_lit0("k", "keep", "leave the signal field ON after receive response"), - arg_lit0("s", "std", "activate field and select standard card"), - arg_lit0(NULL, "sr", "activate field and select SRx ST"), - arg_lit0(NULL, "cts", "activate field and select ASK C-ticket"), - arg_lit0("c", "crc", "calculate and append CRC"), + arg_lit0("k", "keep", "leave the signal field ON after receive response"), + arg_lit0("s", "std", "activate field and select standard card"), + arg_lit0(NULL, "sr", "activate field and select SRx ST"), + arg_lit0(NULL, "cts", "activate field and select ASK C-ticket"), + arg_lit0("c", "crc", "calculate and append CRC"), arg_lit0("r", "noresponse", "do not read response"), - arg_int0("t", "timeout", "decimal", "timeout in ms"), + arg_int0("t", "timeout", "", "timeout in ms"), arg_lit0("v", "verbose", "verbose"), - arg_strx0(NULL, NULL, "", "bytes to send"), + arg_strx0("d", "data", "", "data, bytes to send"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); - bool select = false; bool keep_field_on = arg_get_lit(ctx, 1); bool select_std = arg_get_lit(ctx, 2); bool select_sr = arg_get_lit(ctx, 3); @@ -197,25 +215,25 @@ static int CmdHF14BCmdRaw(const char *Cmd) { } if (select_std) { - select = true; - flags |= ISO14B_SELECT_STD; + flags |= (ISO14B_SELECT_STD | ISO14B_CLEARTRACE); if (verbose) PrintAndLogEx(INFO, "using standard select"); } else if (select_sr) { - select = true; - flags |= ISO14B_SELECT_SR; + flags |= (ISO14B_SELECT_SR | ISO14B_CLEARTRACE); if (verbose) - PrintAndLogEx(INFO, "using SRx ST select"); + PrintAndLogEx(INFO, "using ST/SRx select"); } else if (select_cts) { - select = true; - flags |= ISO14B_SELECT_CTS; + flags |= (ISO14B_SELECT_CTS | ISO14B_CLEARTRACE); if (verbose) - PrintAndLogEx(INFO, "using ASK C-ticket select"); + PrintAndLogEx(INFO, "using ASK/C-ticket select"); } uint8_t data[PM3_CMD_DATA_SIZE] = {0x00}; int datalen = 0; - CLIParamHexToBuf(arg_get_str(ctx, 9), data, sizeof(data), &datalen); + int res = CLIParamHexToBuf(arg_get_str(ctx, 9), data, sizeof(data), &datalen); + if (res && verbose) { + PrintAndLogEx(INFO, "called with no raw bytes"); + } CLIParserFree(ctx); uint32_t time_wait = 0; @@ -244,18 +262,33 @@ static int CmdHF14BCmdRaw(const char *Cmd) { clearCommandBuffer(); SendCommandMIX(CMD_HF_ISO14443B_COMMAND, flags, datalen, time_wait, data, datalen); if (read_reply == false) { + clearCommandBuffer(); return PM3_SUCCESS; } - bool success = true; - // get back iso14b_card_select_t, don't print it. - if (select) { - success = wait_cmd_14b(verbose); + bool success = true; + // Select, device will send back iso14b_card_select_t, don't print it. + if (select_std) { + success = wait_cmd_14b(verbose, true); + if (verbose && success) + PrintAndLogEx(SUCCESS, "Got response for standard select"); + } + + if (select_sr) { + success = wait_cmd_14b(verbose, true); + if (verbose && success) + PrintAndLogEx(SUCCESS, "Got response for ST/SRx select"); + } + + if (select_cts) { + success = wait_cmd_14b(verbose, true); + if (verbose && success) + PrintAndLogEx(SUCCESS, "Got response for ASK/C-ticket select"); } // get back response from the raw bytes you sent. if (success && datalen > 0) { - wait_cmd_14b(true); + wait_cmd_14b(true, false); } return PM3_SUCCESS; @@ -1022,7 +1055,7 @@ static int CmdHF14BWriteSri(const char *Cmd) { ); } - sprintf(str, "-ss -c %02x %02x %02x %02x %02x %02x", ISO14443B_WRITE_BLK, blockno, data[0], data[1], data[2], data[3]); + sprintf(str, "--ss -c %02x %02x %02x %02x %02x %02x", ISO14443B_WRITE_BLK, blockno, data[0], data[1], data[2], data[3]); return CmdHF14BCmdRaw(str); } @@ -1525,10 +1558,10 @@ static int CmdHF14BAPDU(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf 14b apdu", "Sends an ISO 7816-4 APDU via ISO 14443-4 block transmission protocol (T=CL). works with all apdu types from ISO 7816-4:2013", - "hf 14b apdu -s 94a40800043f000002\n" - "hf 14b apdu -sd 00A404000E325041592E5359532E444446303100 -> decode apdu\n" - "hf 14b apdu -sm 00A40400 325041592E5359532E4444463031 -l 256 -> encode standard apdu\n" - "hf 14b apdu -sm 00A40400 325041592E5359532E4444463031 -el 65536 -> encode extended apdu\n"); + "hf 14b apdu -s --hex 94a40800043f000002\n" + "hf 14b apdu -sd --hex 00A404000E325041592E5359532E444446303100 -> decode apdu\n" + "hf 14b apdu -sm 00A40400 -l 256 --hex 325041592E5359532E4444463031 -> encode standard apdu\n" + "hf 14b apdu -sm 00A40400 -el 65536 --hex 325041592E5359532E4444463031 -> encode extended apdu\n"); void *argtable[] = { arg_param_begin, @@ -1536,10 +1569,10 @@ static int CmdHF14BAPDU(const char *Cmd) { arg_lit0("k", "keep", "leave the signal field ON after receive response"), arg_lit0("t", "tlv", "executes TLV decoder if it possible"), arg_lit0("d", "decode", "decode apdu request if it possible"), - arg_str0("m", "make", "", "make apdu with head from this field and data from data field. Must be 4 bytes length: "), + arg_str0("m", "make", "", "make apdu with head from this field and data from data field. Must be 4 bytes length: "), arg_lit0("e", "extended", "make extended length apdu if `m` parameter included"), - arg_int0("l", "le", "", "Le apdu parameter if `m` parameter included"), - arg_strx1(NULL, NULL, "", "data if `m` parameter included"), + arg_int0("l", "le", "", "Le apdu parameter if `m` parameter included"), + arg_strx1(NULL, "hex", "", " if `m` parameter included"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); diff --git a/client/src/cmdhfst.c b/client/src/cmdhfst.c index ff2b682bc..78b3006ef 100644 --- a/client/src/cmdhfst.c +++ b/client/src/cmdhfst.c @@ -325,8 +325,8 @@ static int cmd_hf_st_sim(const char *Cmd) { arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); - CLIGetHexWithReturn(ctx, 1, uid, &uidlen); + CLIParserFree(ctx); if (uidlen != 7) { PrintAndLogEx(ERR, "UID must be 7 hex bytes"); @@ -350,12 +350,12 @@ static int cmd_hf_st_ndef(const char *Cmd) { void *argtable[] = { arg_param_begin, - arg_str0("p", "password", "", "16 byte read password"), + arg_str0("p", "pwd", "", "16 byte read password"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); - CLIGetHexWithReturn(ctx, 1, pwd, &pwdlen); + CLIParserFree(ctx); if (pwdlen == 0) { with_pwd = false; @@ -483,13 +483,10 @@ static int cmd_hf_st_protect(const char *Cmd) { disable_protection = arg_get_lit(ctx, 2); read_protection = arg_get_lit(ctx, 3); write_protection = arg_get_lit(ctx, 4); - CLIGetHexWithReturn(ctx, 5, pwd, &pwdlen); - CLIParserFree(ctx); //Validations - if (enable_protection && disable_protection) { PrintAndLogEx(ERR, "Must specify either enable or disable protection, not both"); return PM3_EINVARG; @@ -625,14 +622,12 @@ static int cmd_hf_st_pwd(const char *Cmd) { change_read_password = arg_get_lit(ctx, 1); change_write_password = arg_get_lit(ctx, 2); - CLIGetHexWithReturn(ctx, 3, pwd, &pwdlen); - CLIGetHexWithReturn(ctx, 4, newpwd, &newpwdlen); - + CLIParserFree(ctx); + if (change_read_password && change_write_password) { PrintAndLogEx(ERR, "Must specify either read or write, not both"); - CLIParserFree(ctx); return PM3_EINVARG; } else { if (change_read_password) { @@ -643,8 +638,6 @@ static int cmd_hf_st_pwd(const char *Cmd) { } } - CLIParserFree(ctx); - if (pwdlen != 16) { PrintAndLogEx(ERR, "Original write password must be 16 hex bytes"); return PM3_EINVARG; @@ -727,9 +720,7 @@ static int cmd_hf_st_pwd(const char *Cmd) { return PM3_ESOFT; } PrintAndLogEx(SUCCESS, " %s password changed", ((changePwd[2] & 0x01) == 0x01) ? _YELLOW_("read") : _YELLOW_("write")); - return PM3_SUCCESS; - } static int cmd_hf_st_list(const char *Cmd) { diff --git a/client/src/cmdlfhid.c b/client/src/cmdlfhid.c index 383243523..e7a45ed75 100644 --- a/client/src/cmdlfhid.c +++ b/client/src/cmdlfhid.c @@ -29,6 +29,7 @@ #include "cmdparser.h" // command_t #include "comms.h" #include "commonutil.h" // ARRAYLEN +#include "cliparser.h" #include "ui.h" #include "graph.h" #include "cmddata.h" //for g_debugMode, demodbuff cmds @@ -43,70 +44,6 @@ static int CmdHelp(const char *Cmd); -static int usage_lf_hid_watch(void) { - PrintAndLogEx(NORMAL, "Enables HID compatible reader mode printing details."); - PrintAndLogEx(NORMAL, "By default, values are printed and logged until the button is pressed or another USB command is issued."); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf hid watch"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf hid watch")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} -static int usage_lf_hid_sim(void) { - PrintAndLogEx(NORMAL, "Enables simulation of HID card with card number."); - PrintAndLogEx(NORMAL, "Simulation runs until the button is pressed or another USB command is issued."); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf hid sim [h] [ID]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - This help"); - PrintAndLogEx(NORMAL, " ID - HID id"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf hid sim 2006ec0c86")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} -static int usage_lf_hid_clone(void) { - PrintAndLogEx(NORMAL, "Clone HID to T55x7. " _BLUE_("Tag must be on antenna!")); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf hid clone [h] [l] ID"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h - This help"); - PrintAndLogEx(NORMAL, " l - 84bit ID"); - PrintAndLogEx(NORMAL, " ID - HID id"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf hid clone 2006ec0c86")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf hid clone l 2006ec0c86")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} -static int usage_lf_hid_brute(void) { - PrintAndLogEx(NORMAL, "Enables bruteforce of HID readers with specified facility code."); - PrintAndLogEx(NORMAL, "This is a attack against reader. if cardnumber is given, it starts with it and goes up / down one step"); - PrintAndLogEx(NORMAL, "if cardnumber is not given, it starts with 1 and goes up to 65535"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf hid brute [h] [v] w [ (decimal)>] [up|down] {...}"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : This help"); - PrintAndLogEx(NORMAL, " w : see " _YELLOW_("`wiegand list`") " for available formats"); - PrintAndLogEx(NORMAL, " f : facility code"); - PrintAndLogEx(NORMAL, " c : card number to start with"); - PrintAndLogEx(NORMAL, " i : issue level"); - PrintAndLogEx(NORMAL, " o : OEM code"); - PrintAndLogEx(NORMAL, " d : delay betweens attempts in ms. Default 1000ms"); - PrintAndLogEx(NORMAL, " v : verbose logging, show all tries"); - PrintAndLogEx(NORMAL, " up : direction to increment card number. (default is both directions)"); - PrintAndLogEx(NORMAL, " down : direction to decrement card number. (default is both directions)"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf hid brute w H10301 f 224")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf hid brute w H10301 f 21 d 2000")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf hid brute v w H10301 f 21 c 200 d 2000")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} - // sending three times. Didn't seem to break the previous sim? static int sendPing(void) { SendCommandNG(CMD_PING, NULL, 0); @@ -276,8 +213,20 @@ static int CmdHIDRead(const char *Cmd) { // this read loops on device side. // uses the demod in lfops.c static int CmdHIDWatch(const char *Cmd) { - uint8_t c = tolower(param_getchar(Cmd, 0)); - if (c == 'h') return usage_lf_hid_watch(); + CLIParserContext *ctx; + + CLIParserInit(&ctx, "lf hid watch", + "Enables HID compatible reader mode printing details.\n" + "By default, values are printed and logged until the button is pressed or another USB command is issued.\n", + "lf hid watch" + ); + + void *argtable[] = { + arg_param_begin, + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIParserFree(ctx); PrintAndLogEx(SUCCESS, "Watching for HID Prox cards - place tag on antenna"); PrintAndLogEx(INFO, "Press pm3-button to stop reading cards"); @@ -290,28 +239,52 @@ static int CmdHIDWatch(const char *Cmd) { } static int CmdHIDSim(const char *Cmd) { + int idlen = 0; + uint8_t id[10] = {0}; lf_hidsim_t payload; payload.longFMT = 0; uint32_t hi2 = 0, hi = 0, lo = 0; - uint32_t n = 0, i = 0; + uint32_t i = 0; - uint8_t ctmp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) == 0 || ctmp == 'h') return usage_lf_hid_sim(); + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf hid sim", + "Enables simulation of HID card with card number.", + "lf hid sim 2006ec0c86" + ); + + void *argtable[] = { + arg_param_begin, + arg_lit0("l", "long", "Simulate HID tag with long ID"), + arg_str1(NULL, NULL, "", "HID tag ID"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); - if (strchr(Cmd, 'l') != 0) { - i++; - while (sscanf(&Cmd[i++], "%1x", &n) == 1) { + bool long_id = arg_get_lit(ctx, 1); + + CLIGetHexWithReturn(ctx, 2, id, &idlen); + + CLIParserFree(ctx); + + if (long_id) { + for (i=0; i < idlen; ++i) { hi2 = (hi2 << 4) | (hi >> 28); hi = (hi << 4) | (lo >> 28); - lo = (lo << 4) | (n & 0xf); - } + lo = (lo << 4) | (id[i] >> 4); //get first 4 bits + hi2 = (hi2 << 4) | (hi >> 28); + hi = (hi << 4) | (lo >> 28); + lo = (lo << 4) | (id[i] & 0xf); //get last 4 bits + } PrintAndLogEx(INFO, "Simulating HID tag with long ID: " _GREEN_("%x%08x%08x"), hi2, hi, lo); payload.longFMT = 1; } else { - while (sscanf(&Cmd[i++], "%1x", &n) == 1) { + for (i=0; i < idlen; ++i) { hi = (hi << 4) | (lo >> 28); - lo = (lo << 4) | (n & 0xf); + lo = (lo << 4) | (id[i] >> 4); //get first 4 bits + + hi = (hi << 4) | (lo >> 28); + lo = (lo << 4) | (id[i] & 0xf); //get last 4 bits } PrintAndLogEx(SUCCESS, "Simulating HID tag with ID: " _GREEN_("%x%08x"), hi, lo); hi2 = 0; @@ -334,28 +307,55 @@ static int CmdHIDSim(const char *Cmd) { } static int CmdHIDClone(const char *Cmd) { + int idlen = 0; + uint8_t id[10] = {0}; uint32_t hi2 = 0, hi = 0, lo = 0; - uint32_t n = 0, i = 0; + uint32_t i = 0; + + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf hid clone", + "Clone HID to T55x7. Tag must be on antenna!", + "lf hid clone 2006ec0c86\n" + "lf hid clone -l 2006ec0c86" + ); + + void *argtable[] = { + arg_param_begin, + arg_lit0("l", "long", "84bit HID long ID"), + arg_str1(NULL, NULL, "", "HID tag ID"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + bool long_id = arg_get_lit(ctx, 1); + + CLIGetHexWithReturn(ctx, 2, id, &idlen); + + CLIParserFree(ctx); - uint8_t ctmp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) == 0 || ctmp == 'h') return usage_lf_hid_clone(); uint8_t longid[1] = {0}; - if (strchr(Cmd, 'l') != 0) { - i++; - while (sscanf(&Cmd[i++], "%1x", &n) == 1) { + + if (long_id) { + for (i=0; i < idlen; ++i) { hi2 = (hi2 << 4) | (hi >> 28); hi = (hi << 4) | (lo >> 28); - lo = (lo << 4) | (n & 0xf); - } + lo = (lo << 4) | (id[i] >> 4); //get first 4 bits + hi2 = (hi2 << 4) | (hi >> 28); + hi = (hi << 4) | (lo >> 28); + lo = (lo << 4) | (id[i] & 0xf); //get last 4 bits + } PrintAndLogEx(INFO, "Preparing to clone HID tag with long ID: " _GREEN_("%x%08x%08x"), hi2, hi, lo); longid[0] = 1; } else { - while (sscanf(&Cmd[i++], "%1x", &n) == 1) { + for (i=0; i < idlen; ++i) { hi = (hi << 4) | (lo >> 28); - lo = (lo << 4) | (n & 0xf); + lo = (lo << 4) | (id[i] >> 4); //get first 4 bits + + hi = (hi << 4) | (lo >> 28); + lo = (lo << 4) | (id[i] & 0xf); //get last 4 bits } PrintAndLogEx(INFO, "Preparing to clone HID tag with ID: " _GREEN_("%x%08x"), hi, lo); hi2 = 0; @@ -385,82 +385,63 @@ static int CmdHIDClone(const char *Cmd) { static int CmdHIDBrute(const char *Cmd) { - bool errors = false, verbose = false; uint32_t delay = 1000; - uint8_t cmdp = 0; int format_idx = -1; int direction = 0; - char format[16] = {0}; + uint8_t format[16] = {0}; + int formatLen; wiegand_card_t cn_hi, cn_low; memset(&cn_hi, 0, sizeof(wiegand_card_t)); - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf hid brute", + "Enables bruteforce of HID readers with specified facility code.\n" + "This is a attack against reader. if cardnumber is given, it starts with it and goes up / down one step\n" + "if cardnumber is not given, it starts with 1 and goes up to 65535", + "lf hid brute -w H10301 -f 224\n" + "lf hid brute -w H10301 -f 21 -d 2000\n" + "lf hid brute -v -w H10301 -f 21 -c 200 -d 2000\n" + ); + + void *argtable[] = { + arg_param_begin, + arg_lit0("v", "verbose", "verbose logging, show all tries"), + arg_str1("w", "wiegand", "format", "see " _YELLOW_("`wiegand list`") " for available formats"), + arg_int0("f", "fn", "dec", "facility code"), + arg_int0("c", "cn", "dec", "card number to start with"), + arg_int0("i", NULL, "dec", "issue level"), + arg_int0("o", "oem", "dec", "OEM code"), + arg_int0("d", "delay", "dec", "delay betweens attempts in ms. Default 1000ms"), + arg_lit0(NULL, "up", "direction to increment card number. (default is both directions)"), + arg_lit0(NULL, "down", "direction to decrement card number. (default is both directions)"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); - char s[10] = {0}; - if (param_getstr(Cmd, cmdp, s, sizeof(s)) > 0) { - if (strlen(s) > 1) { - str_lower((char *)s); - if (str_startswith(s, "up")) { - direction = 1; - } else if (str_startswith(s, "do")) { - direction = 2; - } - cmdp++; - continue; - } - } - - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_lf_hid_brute(); - case 'w': - param_getstr(Cmd, cmdp + 1, format, sizeof(format)); - format_idx = HIDFindCardFormat(format); - if (format_idx == -1) { - PrintAndLogEx(WARNING, "Unknown format: " _YELLOW_("%s"), format); - errors = true; - } - cmdp += 2; - break; - case 'c': - cn_hi.CardNumber = param_get32ex(Cmd, cmdp + 1, 0, 10); - cmdp += 2; - break; - case 'd': - // delay between attemps, defaults to 1000ms. - delay = param_get32ex(Cmd, cmdp + 1, 1000, 10); - cmdp += 2; - break; - case 'f': - cn_hi.FacilityCode = param_get32ex(Cmd, cmdp + 1, 0, 10); - cmdp += 2; - break; - case 'i': - cn_hi.IssueLevel = param_get32ex(Cmd, cmdp + 1, 0, 10); - cmdp += 2; - break; - case 'o': - cn_hi.OEM = param_get32ex(Cmd, cmdp + 1, 0, 10); - cmdp += 2; - break; - case 'v': - verbose = true; - cmdp++; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter: " _YELLOW_("'%c'"), param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } + bool verbose = arg_get_lit(ctx, 1); + + CLIGetStrWithReturn(ctx, 2, format, &formatLen); + format_idx = HIDFindCardFormat((char*) format); if (format_idx == -1) { - PrintAndLogEx(ERR, "You must select a wiegand format. See " _YELLOW_("`wiegand list`") " for available formats\n"); - errors = true; + PrintAndLogEx(WARNING, "Unknown format: " _YELLOW_("%s"), format); + return PM3_EINVARG; } - if (errors) return usage_lf_hid_brute(); + cn_hi.FacilityCode = arg_get_int_def(ctx, 3, 0); + cn_hi.CardNumber = arg_get_int_def(ctx, 4, 0); + cn_hi.IssueLevel = arg_get_int_def(ctx, 5, 0); + cn_hi.OEM = arg_get_int_def(ctx, 6, 0); + delay = arg_get_int_def(ctx, 7, 1000); + + if (arg_get_lit(ctx, 8) && arg_get_lit(ctx, 9)) { + direction = 0; + } else if (arg_get_lit(ctx, 8)) { + direction = 1; + } else if (arg_get_lit(ctx, 9)) { + direction = 2; + } if (verbose) { PrintAndLogEx(INFO, "Wiegand format#.. %i", format_idx); diff --git a/client/src/cmdlfkeri.c b/client/src/cmdlfkeri.c index eafa53648..ee11144d8 100644 --- a/client/src/cmdlfkeri.c +++ b/client/src/cmdlfkeri.c @@ -17,6 +17,7 @@ #include "commonutil.h" // ARRAYLEN #include "cmdparser.h" // command_t +#include "cliparser.h" #include "comms.h" #include "ui.h" #include "cmddata.h" @@ -26,43 +27,6 @@ #include "cmdlft55xx.h" // verifywrite static int CmdHelp(const char *Cmd); - -static int usage_lf_keri_clone(void) { - PrintAndLogEx(NORMAL, "clone a KERI tag to a T55x7 or Q5/T5555 tag\n"); - PrintAndLogEx(NORMAL, "Usage: lf keri clone [h] "); - PrintAndLogEx(NORMAL, "Usage extended: lf keri clone [h] t [f ] [c ] "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : This help"); - PrintAndLogEx(NORMAL, " : Keri Internal ID"); - PrintAndLogEx(NORMAL, " : specify writing to Q5/T5555 tag"); - // New format - PrintAndLogEx(NORMAL, " [m|i] : Type m - MS, i - Internal ID"); - PrintAndLogEx(NORMAL, " : Facility Code"); - PrintAndLogEx(NORMAL, " : Card Number"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf keri clone 112233")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf keri clone t i fc 6 cn 12345")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf keri clone t m f 6 c 12345")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} - -static int usage_lf_keri_sim(void) { - PrintAndLogEx(NORMAL, "Enables simulation of KERI card with specified card number."); - PrintAndLogEx(NORMAL, "Simulation runs until the button is pressed or another USB command is issued."); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: lf keri sim [h] "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h : This help"); - PrintAndLogEx(NORMAL, " : Keri Internal ID"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" lf keri sim 112233")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} - typedef enum {Scramble = 0, Descramble = 1} KeriMSScramble_t; static int CmdKeriMSScramble(KeriMSScramble_t Action, uint32_t *FC, uint32_t *ID, uint32_t *CardID) { @@ -222,8 +186,9 @@ static int CmdKeriRead(const char *Cmd) { static int CmdKeriClone(const char *Cmd) { bool q5 = false; - uint8_t cmdidx = 0; - char keritype = 'i'; // default to internalid + + uint8_t keritype[2] = {'i'}; // default to internalid + int typeLen = 0; uint32_t fc = 0; uint32_t cid = 0; uint32_t internalid = 0; @@ -240,42 +205,35 @@ static int CmdKeriClone(const char *Cmd) { // dynamic bitrate used blocks[0] |= 0xF << 18; - char cmdp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_keri_clone(); + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf keri clone", + "clone a KERI tag to a T55x7 or Q5/T5555 tag", + "lf keri clone -t i --id 12345\n" + "lf keri clone -t m --fc 6 --id 12345\n"); - // Assume old format for backwards compatibility and only parameter is the internal id - cid = param_get32ex(Cmd, 0, 0, 10); - - // find other options - while (param_getchar(Cmd, cmdidx) != 0x00) { // && !errors) { - switch (tolower(param_getchar(Cmd, cmdidx))) { - case 'h': // help - return usage_lf_keri_clone(); - case 't': // format type - keritype = tolower(param_getchar(Cmd, cmdidx + 1)); - cmdidx += 2; - break; - case 'f': // fc - fc = param_get32ex(Cmd, cmdidx + 1, 0, 10); - cmdidx += 2; - break; - case 'c': // cardid - cid = param_get32ex(Cmd, cmdidx + 1, 0, 10); - cmdidx += 2; - break; - case 'q': // q5 - blocks[0] = T5555_FIXED | T5555_MODULATION_PSK1 | T5555_SET_BITRATE(32) | T5555_PSK_RF_2 | 2 << T5555_MAXBLOCK_SHIFT; - q5 = true; - cmdidx++; - break; - default: - // Skip unknown - cmdidx++; - } + void *argtable[] = { + arg_param_begin, + arg_lit0("q", "q5", "specify writing to Q5/T5555 tag"), + arg_str0("t", "type", "", "Type m - MS, i - Internal ID"), + arg_int0(NULL, "fc", "", "Facility Code"), + arg_int1(NULL, "id", "", "Keri ID"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + if (arg_get_lit(ctx, 1)) { + blocks[0] = T5555_FIXED | T5555_MODULATION_PSK1 | T5555_SET_BITRATE(32) | T5555_PSK_RF_2 | 2 << T5555_MAXBLOCK_SHIFT; + q5 = true; } + CLIGetStrWithReturn(ctx, 2, keritype, &typeLen); + + fc = arg_get_int_def(ctx, 3, 0); + cid = arg_get_int_def(ctx, 4, 0); + CLIParserFree(ctx); + // Setup card data/build internal id - switch (keritype) { + switch (keritype[0]) { case 'i' : // Internal ID // MSB is ONE internalid = cid | 0x80000000; @@ -283,6 +241,9 @@ static int CmdKeriClone(const char *Cmd) { case 'm' : // MS CmdKeriMSScramble(Scramble, &fc, &cid, &internalid); break; + default : + PrintAndLogEx(ERR, "Invalid type"); + return PM3_EINVARG; } // Prepare and write to card @@ -303,11 +264,23 @@ static int CmdKeriClone(const char *Cmd) { static int CmdKeriSim(const char *Cmd) { - char cmdp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) == 0 || cmdp == 'h') - return usage_lf_keri_sim(); + CLIParserContext *ctx; + CLIParserInit(&ctx, "lf keri sim", + "Enables simulation of KERI card with card number.", + "lf keri sim --id 112233" + ); + + void *argtable[] = { + arg_param_begin, + arg_int1(NULL, "id", "", "KERI Internal ID"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); - uint64_t internalid = param_get32ex(Cmd, 0, 0, 10); + uint64_t internalid = arg_get_int_def(ctx, 1, 0); + + CLIParserFree(ctx); + internalid |= 0x80000000; internalid <<= 3; internalid += 7; diff --git a/client/src/cmdwiegand.c b/client/src/cmdwiegand.c index 19f166284..f81d7c177 100644 --- a/client/src/cmdwiegand.c +++ b/client/src/cmdwiegand.c @@ -13,6 +13,7 @@ #include #include #include "cmdparser.h" // command_t +#include "cliparser.h" #include "comms.h" #include "pm3_cmd.h" #include "protocols.h" @@ -24,172 +25,134 @@ static int CmdHelp(const char *Cmd); -static int usage_wiegand_list(void) { - PrintAndLogEx(NORMAL, "List available wiegand formats"); - return PM3_SUCCESS; -} -static int usage_wiegand_encode(void) { - PrintAndLogEx(NORMAL, "Encode wiegand formatted number to raw hex"); - PrintAndLogEx(NORMAL, "Usage: wiegand encode [w ] [ ] {...}"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " w see `wiegand list` for available formats"); - PrintAndLogEx(NORMAL, " c card number"); - PrintAndLogEx(NORMAL, " f facility code"); - PrintAndLogEx(NORMAL, " i issue Level"); - PrintAndLogEx(NORMAL, " o OEM code"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "samples:"); - PrintAndLogEx(NORMAL, " wiegand encode w H10301 f 101 c 1337"); - return PM3_SUCCESS; -} -static int usage_wiegand_decode(void) { - PrintAndLogEx(NORMAL, "Decode raw hex to wiegand format"); - PrintAndLogEx(NORMAL, "Usage: wiegand decode [id]

"); - PrintAndLogEx(NORMAL, " p ignore invalid parity"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Samples:"); - PrintAndLogEx(NORMAL, " wiegand decode 2006f623ae"); - return PM3_SUCCESS; -} - -static void PrintTagId(wiegand_message_t *packed) { +static void print_wiegand_code(wiegand_message_t *packed) { + const char* s = "Encoded wiegand: "; if (packed->Top != 0) { - PrintAndLogEx(SUCCESS, "Card ID: %X%08X%08X", - (uint32_t)packed->Top, - (uint32_t)packed->Mid, - (uint32_t)packed->Bot) - ; + PrintAndLogEx(SUCCESS, "%s" _GREEN_("%X%08X%08X"), + s, + (uint32_t)packed->Top, + (uint32_t)packed->Mid, + (uint32_t)packed->Bot + ); } else { - PrintAndLogEx(SUCCESS, "Card ID: %X%08X", - (uint32_t)packed->Mid, - (uint32_t)packed->Bot) - ; + PrintAndLogEx(SUCCESS, "%s" _YELLOW_("%X%08X"), + s, + (uint32_t)packed->Mid, + (uint32_t)packed->Bot + ); } } int CmdWiegandList(const char *Cmd) { - bool errors = false; - char cmdp = 0; - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_wiegand_list(); - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } + + CLIParserContext *ctx; + CLIParserInit(&ctx, "wiegand info", + "List available wiegand formats", + "wiegand list" + ); + + void *argtable[] = { + arg_param_begin, + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIParserFree(ctx); + HIDListFormats(); return PM3_SUCCESS; } int CmdWiegandEncode(const char *Cmd) { - int format_idx = -1; - char format[16] = {0}; + CLIParserContext *ctx; + CLIParserInit(&ctx, "wiegand encode", + "Encode wiegand formatted number to raw hex", + "wiegand encode -w H10301 --fc 101 --cn 1337" + ); + + void *argtable[] = { + arg_param_begin, + arg_u64_0(NULL, "fc", "", "facility number"), + arg_u64_1(NULL, "cn", "", "card number"), + arg_u64_0(NULL, "issue", "", "issue level"), + arg_u64_0(NULL, "oem", "", "OEM code"), + arg_strx1("w", "wiegand", "", "see `wiegand list` for available formats"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); wiegand_card_t data; memset(&data, 0, sizeof(wiegand_card_t)); + + data.FacilityCode = arg_get_u32_def(ctx, 1, 0); + data.CardNumber = arg_get_u64_def(ctx, 2, 0); + data.IssueLevel = arg_get_u32_def(ctx, 3, 0); + data.OEM = arg_get_u32_def(ctx, 4, 0); + + int len = 0; + char format[16] = {0}; + CLIParamStrToBuf(arg_get_str(ctx, 5), (uint8_t*)format, sizeof(format), &len); + CLIParserFree(ctx); - bool errors = false; - char cmdp = 0; - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_wiegand_encode(); - case 'w': - param_getstr(Cmd, cmdp + 1, format, sizeof(format)); - format_idx = HIDFindCardFormat(format); - if (format_idx == -1) { - PrintAndLogEx(WARNING, "Unknown format: %s", format); - errors = true; - } - cmdp += 2; - break; - case 'i': - data.IssueLevel = param_get32ex(Cmd, cmdp + 1, 0, 10); - cmdp += 2; - break; - case 'f': - data.FacilityCode = param_get32ex(Cmd, cmdp + 1, 0, 10); - cmdp += 2; - break; - case 'c': - data.CardNumber = param_get64ex(Cmd, cmdp + 1, 0, 10); - cmdp += 2; - break; - case 'o': - data.OEM = param_get32ex(Cmd, cmdp + 1, 0, 10); - cmdp += 2; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } + int idx = HIDFindCardFormat(format); + if (idx == -1) { + PrintAndLogEx(WARNING, "Unknown format: %s", format); + return PM3_EINVARG; } - if (errors || cmdp == 0) return usage_wiegand_encode(); wiegand_message_t packed; memset(&packed, 0, sizeof(wiegand_message_t)); - if (HIDPack(format_idx, &data, &packed) == false) { + if (HIDPack(idx, &data, &packed) == false) { PrintAndLogEx(WARNING, "The card data could not be encoded in the selected format."); return PM3_ESOFT; } - PrintTagId(&packed); + print_wiegand_code(&packed); return PM3_SUCCESS; } int CmdWiegandDecode(const char *Cmd) { - uint32_t top = 0, mid = 0, bot = 0; - bool ignore_parity = false, gothex = false; - bool errors = false; - char cmdp = 0; - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - uint32_t slen = param_getlength(Cmd, cmdp); - slen++; // null termin - if (slen > 2) { - char *s = calloc(slen, sizeof(uint8_t)); - param_getstr(Cmd, cmdp, s, slen); - hexstring_to_u96(&top, &mid, &bot, s); - free(s); - gothex = true; - cmdp++; - continue; - } - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_wiegand_decode(); - case 'p': - ignore_parity = true; - cmdp++; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } - if (gothex == false) - errors = true; + CLIParserContext *ctx; + CLIParserInit(&ctx, "wiegand decode", + "Decode raw hex to wiegand format", + "wiegand decode --raw 2006f623ae" + ); - if (errors || cmdp < 1) return usage_wiegand_decode(); + void *argtable[] = { + arg_param_begin, + arg_lit0("p", "parity", "ignore invalid parity"), + arg_strx1(NULL, "raw", "", "raw hex to be decoded"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + bool ignore_parity = arg_get_lit(ctx, 1); + int len = 0; + char hex[40] = {0}; + CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t*)hex, sizeof(hex), &len); + CLIParserFree(ctx); + + if (len == 0) { + PrintAndLogEx(ERR, "empty input"); + return PM3_EINVARG; + } + + uint32_t top = 0, mid = 0, bot = 0; + hexstring_to_u96(&top, &mid, &bot, hex); wiegand_message_t packed = initialize_message_object(top, mid, bot); - HIDTryUnpack(&packed, ignore_parity); + return PM3_SUCCESS; } static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, {"list", CmdWiegandList, AlwaysAvailable, "List available wiegand formats"}, - {"encode", CmdWiegandEncode, AlwaysAvailable, "Convert "}, - {"decode", CmdWiegandDecode, AlwaysAvailable, "Convert raw hex to wiegand format"}, + {"encode", CmdWiegandEncode, AlwaysAvailable, "Encode to wiegand raw hex"}, + {"decode", CmdWiegandDecode, AlwaysAvailable, "Convert raw hex to decoded wiegand format"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/proxgui.h b/client/src/proxgui.h index cc9c9e118..921e4dcd5 100644 --- a/client/src/proxgui.h +++ b/client/src/proxgui.h @@ -27,6 +27,7 @@ void InitGraphics(int argc, char **argv, char *script_cmds_file, char *script_cm void ExitGraphics(void); extern double CursorScaleFactor; +extern char CursorScaleFactorUnit[11]; extern int PlotGridX, PlotGridY, PlotGridXdefault, PlotGridYdefault, GridOffset; extern uint32_t CursorCPos, CursorDPos; extern int CommandFinished; diff --git a/client/src/proxguiqt.cpp b/client/src/proxguiqt.cpp index aa74a83fd..15b96a16a 100644 --- a/client/src/proxguiqt.cpp +++ b/client/src/proxguiqt.cpp @@ -8,7 +8,7 @@ // GUI (QT) //----------------------------------------------------------------------------- #include "proxguiqt.h" - +#include #include #include #include @@ -424,7 +424,8 @@ void Plot::PlotGraph(int *buffer, size_t len, QRect plotRect, QRect annotationRe if (len == 0) return; // clock_t begin = clock(); QPainterPath penPath; - int vMin = INT_MAX, vMax = INT_MIN, vMean = 0, v = 0; + int vMin = INT_MAX, vMax = INT_MIN, v = 0; + int64_t vMean = 0; uint32_t i = 0; int x = xCoordOf(GraphStart, plotRect); int y = yCoordOf(buffer[GraphStart], plotRect, g_absVMax); @@ -447,7 +448,8 @@ void Plot::PlotGraph(int *buffer, size_t len, QRect plotRect, QRect annotationRe if (v > vMax) vMax = v; vMean += v; } - vMean /= (i - GraphStart); + GraphStop = i; + vMean /= (GraphStop - GraphStart); painter->setPen(getColor(graphNum)); @@ -483,10 +485,9 @@ void Plot::PlotGraph(int *buffer, size_t len, QRect plotRect, QRect annotationRe //Graph annotations painter->drawPath(penPath); char str[200]; - sprintf(str, "max=%d min=%d mean=%d n=%u/%zu CursorAVal=[%d] CursorBVal=[%d]", - vMax, vMin, vMean, i, len, buffer[CursorAPos], buffer[CursorBPos]); + sprintf(str, "max=%d min=%d mean=%" PRId64 " n=%u/%zu CursorAVal=[%d] CursorBVal=[%d]", + vMax, vMin, vMean, GraphStop - GraphStart, len, buffer[CursorAPos], buffer[CursorBPos]); painter->drawText(20, annotationRect.bottom() - 23 - 20 * graphNum, str); - //clock_t end = clock(); //double elapsed_secs = double(end - begin) / CLOCKS_PER_SEC; //printf("Plot time %f\n", elapsed_secs); @@ -596,10 +597,19 @@ void Plot::paintEvent(QPaintEvent *event) { //Draw annotations char str[200]; - sprintf(str, "@%u dt=%u [%2.2f] zoom=%2.2f CursorAPos=%u CursorBPos=%u GridX=%d GridY=%d (%s) GridXoffset=%d", + char scalestr[30] = {0}; + if (CursorScaleFactor != 1) { + if (CursorScaleFactorUnit[0] == '\x00') { + sprintf(scalestr, "[%2.2f] ", ((int32_t)(CursorBPos - CursorAPos)) / CursorScaleFactor); + } else { + sprintf(scalestr, "[%2.2f %s] ", ((int32_t)(CursorBPos - CursorAPos)) / CursorScaleFactor, CursorScaleFactorUnit); + } + } + sprintf(str, "@%u..%u dt=%i %szoom=%2.2f CursorAPos=%u CursorBPos=%u GridX=%d GridY=%d (%s) GridXoffset=%d", GraphStart, + GraphStop, CursorBPos - CursorAPos, - ((int32_t)(CursorBPos - CursorAPos)) / CursorScaleFactor, + scalestr, GraphPixelsPerPoint, CursorAPos, CursorBPos, @@ -637,7 +647,7 @@ void Plot::closeEvent(QCloseEvent *event) { g_useOverlays = false; } -void Plot::Zoom(float factor, int refX) { +void Plot::Zoom(double factor, int refX) { if (factor >= 1) { // Zoom in if (GraphPixelsPerPoint <= 25 * factor) { GraphPixelsPerPoint *= factor; @@ -677,14 +687,38 @@ void Plot::Move(int offset) { } } +void Plot::Trim(void) { + uint32_t lref, rref; + const double zoom_offset = 1.148698354997035; // 2**(1/5) + if ((CursorAPos == 0) || (CursorBPos == 0)) { // if we don't have both cursors set + lref = GraphStart; + rref = GraphStop; + } else { + lref = CursorAPos < CursorBPos ? CursorAPos : CursorBPos; + rref = CursorAPos < CursorBPos ? CursorBPos : CursorAPos; + // GraphPixelsPerPoint mush remain a power of zoom_offset + double GPPPtarget = GraphPixelsPerPoint * (GraphStop - GraphStart) / (rref - lref); + while (GraphPixelsPerPoint < GPPPtarget) { + GraphPixelsPerPoint *= zoom_offset; + } + GraphPixelsPerPoint /= zoom_offset; + CursorAPos -= lref; + CursorBPos -= lref; + } + for (uint32_t i = lref; i < rref; ++i) + GraphBuffer[i - lref] = GraphBuffer[i]; + GraphTraceLen = rref - lref; + GraphStart = 0; +} + void Plot::wheelEvent(QWheelEvent *event) { // event->delta() // 120 => shift right 5% // -120 => shift left 5% const float move_offset = 0.05; - // -120+shift => zoom in 10% - // 120+shift => zoom out 10% - const float zoom_offset = 0.1; + // -120+shift => zoom in (5 times = *2) + // 120+shift => zoom out (5 times = /2) + const double zoom_offset = 1.148698354997035; // 2**(1/5) if (event->modifiers() & Qt::ShiftModifier) { // event->position doesn't exist in QT5.12.8, both exist in 5.14.2 and event->x doesn't exist in 5.15.0 #if QT_VERSION >= 0x050d00 @@ -697,10 +731,15 @@ void Plot::wheelEvent(QWheelEvent *event) { x += GraphStart; // event->angleDelta doesn't exist in QT4, both exist in 5.12.8 and 5.14.2 and event->delta doesn't exist in 5.15.0 #if QT_VERSION >= 0x050d00 - Zoom(1.0 - (float)event->angleDelta().y() / (120 / zoom_offset), x); + float delta = event->angleDelta().y(); #else - Zoom(1.0 - (float)event->delta() / (120 / zoom_offset), x); + float delta = event->delta(); #endif + if (delta < 0) { + Zoom(zoom_offset, x); + } else { + Zoom(1.0 / zoom_offset, x); + } } else { #if QT_VERSION >= 0x050d00 Move(PageWidth * (-(float)event->angleDelta().y() / (120 / move_offset))); @@ -794,6 +833,7 @@ void Plot::keyPressEvent(QKeyEvent *event) { puts("\tH Show help"); puts("\tL Toggle lock grid relative to samples"); puts("\tQ Hide window"); + puts("\tT Trim data on displayed window or on cursors if defined"); puts("\tHOME Move to the start of the graph"); puts("\tEND Move to the end of the graph"); puts("\tPGUP Page left"); @@ -823,6 +863,10 @@ void Plot::keyPressEvent(QKeyEvent *event) { master->hide(); break; + case Qt::Key_T: + Trim(); + break; + case Qt::Key_Home: GraphStart = 0; break; diff --git a/client/src/proxguiqt.h b/client/src/proxguiqt.h index 3264a2919..49a69454f 100644 --- a/client/src/proxguiqt.h +++ b/client/src/proxguiqt.h @@ -32,6 +32,7 @@ class Plot: public QWidget { private: QWidget *master; uint32_t GraphStart; // Starting point/offset for the left side of the graph + uint32_t GraphStop; // Stop point/offset for the right side of the graph double GraphPixelsPerPoint; // How many visual pixels are between each sample point (x axis) uint32_t CursorAPos; uint32_t CursorBPos; @@ -50,8 +51,9 @@ class Plot: public QWidget { protected: void paintEvent(QPaintEvent *event); void closeEvent(QCloseEvent *event); - void Zoom(float factor, int refX); + void Zoom(double factor, int refX); void Move(int offset); + void Trim(void); void wheelEvent(QWheelEvent *event); void mouseMoveEvent(QMouseEvent *event); void mousePressEvent(QMouseEvent *event) { mouseMoveEvent(event); } diff --git a/client/src/ui.c b/client/src/ui.c index f05a96682..ecc0cb94e 100644 --- a/client/src/ui.c +++ b/client/src/ui.c @@ -38,6 +38,7 @@ session_arg_t session; double CursorScaleFactor = 1; +char CursorScaleFactorUnit[11] = {0}; int PlotGridX = 0, PlotGridY = 0, PlotGridXdefault = 64, PlotGridYdefault = 64; uint32_t CursorCPos = 0, CursorDPos = 0; double GraphPixelsPerPoint = 1.f; // How many visual pixels are between each sample point (x axis) diff --git a/doc/cheatsheet.md b/doc/cheatsheet.md index 7da56cbcd..bee2b2b5e 100644 --- a/doc/cheatsheet.md +++ b/doc/cheatsheet.md @@ -332,23 +332,25 @@ Convert Site & Facility code to Wiegand raw hex ``` Options --- -w o f c i -w : wiegand format to use -o : OEM number / site code -f : facility code -c : card number -i : issue level +-w --oem --fc --cn --issue -pm3 --> wiegand encode 0 56 150 +-w : wiegand format to use +--oem : OEM number / site code +--fc : facility code +--cn : card number +--issue : issue level + +pm3 --> wiegand encode -w H10301 --oem 0 --fc 56 --cn 150 ``` Convert Site & Facility code from Wiegand raw hex to numbers ``` Options --- -p : ignore parity errors +-p : ignore parity errors +--raw : raw hex to be decoded -pm3 --> wiegand decode 2006f623ae +pm3 --> wiegand decode --raw 2006f623ae ``` ## HID Prox @@ -379,14 +381,18 @@ Brute force HID reader ``` Options --- -a : 26|33|34|35|37|40|44|84 -f : 8-bit value HID facility code -c : (optional) cardnumber to start with, max 65535 -d : delay betweens attempts in ms. Default 1000ms -v : verbose logging, show all tries +-v, --verbose : verbose logging, show all tries +-w, --wiegand format : see `wiegand list` for available formats +-f, --fn dec : facility code +-c, --cn dec : card number to start with +-i dec : issue level +-o, --oem dec : OEM code +-d, --delay dec : delay betweens attempts in ms. Default 1000ms +--up : direction to increment card number. (default is both directions) +--down : direction to decrement card number. (default is both directions) -pm3 --> lf hid brute a 26 f 224 -pm3 --> lf hid brute v a 26 f 21 c 200 d 2000 +pm3 --> lf hid brute -w H10301 -f 224 +pm3 --> lf hid brute -v -w H10301 -f 21 -c 200 -d 2000 ``` ## Indala @@ -552,7 +558,7 @@ pm3 --> script list View lua helptext ``` -pm3 --> script run -h +pm3 --> script run -h ``` @@ -595,15 +601,15 @@ Load default keys into flash memory (RDV4 only) ``` Options --- -o : offset in memory -f : file name -m : upload 6 bytes keys (mifare key dictionary) -i : upload 8 bytes keys (iClass key dictionary) -t : upload 4 bytes keys (pwd dictionary) +-o : offset in memory +-f : file name +--mfc : upload 6 bytes keys (mifare key dictionary) +--iclass : upload 8 bytes keys (iClass key dictionary) +--t55xx : upload 4 bytes keys (pwd dictionary) -pm3 --> mem load f mfc_default_keys m -pm3 --> mem load f t55xx_default_pwds t -pm3 --> mem load f iclass_default_keys i +pm3 --> mem load -f mfc_default_keys --mfc +pm3 --> mem load -f t55xx_default_pwds --t5xx +pm3 --> mem load -f iclass_default_keys --iclass ``` ## Sim Module diff --git a/doc/cliparser.md b/doc/cliparser.md index e4cc8e062..cba87777a 100644 --- a/doc/cliparser.md +++ b/doc/cliparser.md @@ -13,26 +13,26 @@ lf config h H even the external tools which we collected into this repo, under folder */tools/* folder uses their own argument parsing. -In order to counter this and unify it, there was discussion over at the official repository a few years ago [link to issue](https://github.com/Proxmark/proxmark3/issues/467) and there it became clear a change is needed. Among the different solutions suggested @merlokk's idea of using the lib cliparser was agreed upon. The lib was adapted and implemented for commands like +In order to counter this and unify it, there was discussion over at the official repository a few years ago [link to issue](https://github.com/Proxmark/proxmark3/issues/467) and there it became clear a change is needed. Among the different solutions suggested @merlokk's idea of using the lib cliparser was agreed upon. The lib was adapted and implemented for commands like ``` [usb] pm3 --> emv [usb] pm3 --> hf fido ``` -And then it fell into silence since it wasn't well documented how to use the cliparser. Looking at source code wasn't very efficient. However the need of a better cli parsing was still there. +And then it fell into silence since it wasn't well documented how to use the cliparser. Looking at source code wasn't very efficient. However the need of a better cli parsing was still there. Fast forward today, where more commands has used the cliparser but it still wasn't the natural way when adding a new client command to the Proxmark3 client. -After more discussions among @doegox, @iceman1001 and @mrwalker the concept became more clear on how to use the cliparser lib in the _preferred_ way. +After more discussions among @doegox, @iceman1001 and @mrwalker the concept became more clear on how to use the cliparser lib in the _preferred_ way. -The aftermath was a design and layout specfied which lead to a simpler implemtentation of the cliparser in the client source code while still unfiy all helptexts with the new colours support and a defined layout. As seen below, the simplicity and clearness. +The aftermath was a design and layout specified which lead to a simpler implementation of the cliparser in the client source code while still unifiy all helptexts with the new colours support and a defined layout. As seen below, the simplicity and clearness. ![sample of new style helptext](http://www.icedev.se/proxmark3/helptext.png) -Furthermore @mrwalker offered to take notes and thus this document was created. +Furthermore @mrwalker offered to take notes and thus this document was created. -This is the _new_ and _prefered_ way to implement _helptext_ and _cli parsing_ for Proxmark3 client commands and it's external tools. +This is the _new_ and _preferred_ way to implement _helptext_ and _cli parsing_ for Proxmark3 client commands and it's external tools. ## cliparser setup and use @@ -42,11 +42,11 @@ It will also add the `-h --help` option automatic. ## design comments -* where possible all options should be lowercase. -* extended options preceded with -- should be short -* options provided directly (without an option identifier) should be avoided. -* -vv for extra verbos should be avoided; use of debug level is preferred. -* with --options the equal is not needed (will work with and without) so don't use '=' +* where possible all options should be lowercase. +* extended options preceded with -- should be short +* options provided directly (without an option identifier) should be avoided. +* -vv for extra verbose should be avoided; use of debug level is preferred. +* with --options the equal is not needed (will work with and without) so don't use '=' e.g. cmd --cn 12345 @@ -59,7 +59,7 @@ It will also add the `-h --help` option automatic. --raw : raw data -k --key : key supplied -n --keyno : key number to use - -v --verbose : flag when output should provide more information, not conidered debug. + -v --verbose : flag when output should provide more information, not considered debug. -1 --buffer : use the sample buffer @@ -77,14 +77,14 @@ In the command function, setup the context ### define the context -CLIParserInit (\, \, \); +`CLIParserInit (\, \, \);` use -> to separate example and example comment and \\n to separate examples. e.g. lf indala clone -r a0000000a0002021 -> this uses ..... - CLIParserInit(&ctx, "lf indala clone", - "clone INDALA UID to T55x7 or Q5/T5555 tag", - "lf indala clone --heden 888\n" + CLIParserInit(&ctx, "lf indala clone", + "clone INDALA UID to T55x7 or Q5/T5555 tag", + "lf indala clone --heden 888\n" "lf indala clone --fc 123 --cn 1337\n" "lf indala clone -r a0000000a0002021\n" "lf indala clone -l -r 80000001b23523a6c2e31eba3cbee4afb3c6ad1fcf649393928c14e5"); @@ -93,9 +93,9 @@ e.g. lf indala clone -r a0000000a0002021 -> this uses ..... void *argtable[] = { arg_param_begin, - arg_lit0("l", "long", "optional - long UID 224 bits"), - arg_int0("c", "heden", "", "Cardnumber for Heden 2L format"), - arg_strx0("r", "raw", "", "raw bytes"), + arg_lit0("l", "long", "optional - long UID 224 bits"), + arg_int0("c", "heden", "", "Cardnumber for Heden 2L format"), + arg_strx0("r", "raw", "", "raw bytes"), arg_lit0("q", "Q5", "optional - specify writing to Q5/T5555 tag"), arg_int0(NULL, "fc", "", "Facility Code (26 bit format)"), arg_int0(NULL, "cn", "", "Cardnumber (26 bit format)"), @@ -103,75 +103,103 @@ e.g. lf indala clone -r a0000000a0002021 -> this uses ..... }; _All options has a parameter index, since `-h --help` is added automatic, it will be assigned index 0. -Hence all options you add will start at index 1 and upwards._ +Hence all options you add will start at index 1 and upwards. It added in the define "arg_param_begin_ -**Notes:** -**bool option. true if supplied** -bool : arg_lit0 ("\", "\", \["\",\] \<"description"\>) +### Notes: +#### bool option. true if supplied +`bool : arg_lit0 ("", "", <"description">)` -**integer that is optional** - optional integer : arg_int0 ("\", "\", \["\",\] \<"description"\>) +#### integer that is optional +`optional integer : arg_int0 ("", "", "", <"description">)` -**integer that is required** - required integer : arg_int1 ("\", "\", \["\",\] \<"description"\>) +#### integer that is required +`required integer : arg_int1 ("", "", "", <"description">)` -**String option that is optional and only one instance can be provided** - optional string : arg_str0("\", "\", \["\",\] \<"description"\>) +#### double that is optional +`optional double : arg_dbl0 ("", "", "", <"description">)` -**String option that is required and only one instance can be provided** - required string : arg_str1("\", "\", \["\",\] \<"description"\>) +#### double that is required +`required double : arg_dbl1 ("", "", "", <"description">)` -**String option that is optional and can have up to 250 instances provided** - optional string : arg_strx0 ("\", "\", \["\",\] \<"description"\>) +#### String option that is optional and only one instance can be provided +`optional string : arg_str0 ("", "", "", <"description">)` + +#### String option that is required and only one instance can be provided +`required string : arg_str1 ("", "", "", <"description">)` + +#### String option that is optional and can have up to 250 instances provided +`optional string : arg_strx0 ("", "", "", <"description">)` + +#### String option that is required/at least one instance and can have up to 250 instances +`required string : arg_strx1 ("", "", "", <"description">)` + +Unsigned values, like u32 and u64 can be accomplished with + +#### unsigned integer optional +`optional unsigned : arg_u64_0 ("", "", "", <"description">)` + +#### unsigned integer required +`required unsigned : arg_u64_1 ("", "", "", <"description">)` + + +**if an option does not have a short or long option, use NULL in its place** -**String option that is required/at least one instance and can have up to 250 instances** - required string : arg_strx1 ("\", "\", \["\",\] \<"description"\>) -**if an option does not have a short or long option, use NULL in its place** - ### show the menu -CLIExecWithReturn(\, \, \, \); +`CLIExecWithReturn(\, \, \, \);` CLIExecWithReturn(ctx, Cmd, argtable, false); ### clean up Once you have extracted the options, cleanup the context. - CLIParserFree(ctx); + CLIParserFree(ctx); -### retreiving options +### retrieving options The parser will format and color and layout as needed. It will also add the `-h --help` option automatic. -**bool option** +**bool option** arg_get_lit(\, \); is_long_uid = arg_get_lit(ctx, 1); -**int option** +**int option** arg_get_int_def(\, \, \); cardnumber = arg_get_int_def(ctx, 2, -1); -**hex option** + +**uint32** +arg_get_u32_def(\, \, \); + + cardnumber = arg_get_u32_def(ctx, 2, 0); + +**uint64** +arg_get_u64_def(\, \, \); + + cardnumber = arg_get_u64_def(ctx, 2, 0); + + +**hex option** CLIGetHexWithReturn(\, \, \, \); ?? as an array of uint_8 ?? - + uint8_t aid[2] = {0}; int aidlen; CLIGetHexWithReturn(ctx, 2, aid, &aidlen); -**hex option returning ???** +**hex option returning ???** uint8_t key[24] = {0}; int keylen = 0; int res_klen = CLIParamHexToBuf(arg_get_str(ctx, 3), key, 24, &keylen); - quick test : seems res_keylen == 0 when ok so not key len ??? + quick test : seems res_keylen == 0 when ok so not key len ??? -**string option** +**string option** CLIGetStrWithReturn(\,\, \, \); uint8_t Buffer[100]; diff --git a/include/iso14b.h b/include/iso14b.h index e1baf231a..4be7a8753 100644 --- a/include/iso14b.h +++ b/include/iso14b.h @@ -38,6 +38,7 @@ typedef enum ISO14B_COMMAND { ISO14B_SET_TIMEOUT = (1 << 8), ISO14B_SEND_CHAINING = (1 << 9), ISO14B_SELECT_CTS = (1 << 10), + ISO14B_CLEARTRACE = (1 << 11), } iso14b_command_t; #endif // _ISO14B_H_ \ No newline at end of file diff --git a/traces/lf_ATA5577.txt b/traces/lf_ATA5577.txt index 5e3c27995..9feb1478d 100644 --- a/traces/lf_ATA5577.txt +++ b/traces/lf_ATA5577.txt @@ -32,7 +32,7 @@ lf hid clone 2006ec0c86 lf read s 10000 data save f lf_t5577_hid -lf hid clone l 2006ec0c86 +lf hid clone -l 2006ec0c86 lf read s 20000 data save f lf_t5577_hid_84 @@ -56,15 +56,15 @@ lf jablotron clone 112233 lf read s 16000 data save f lf_t5577_jablotron -lf keri clone 112233 +lf keri clone --id 112233 lf read s 10000 data save f lf_t5577_keri -lf keri clone t i fc 6 cn 12345 +lf keri clone -t i --fc 6 --id 12345 lf read s 10000 data save f lf_t5577_keri_internalid -lf keri clone t m f 6 c 12345 +lf keri clone -t m --fc 6 --id 12345 lf read s 10000 data save f lf_t5577_keri_msid