Merge pull request #53 from RfidResearchGroup/master

Update
This commit is contained in:
mwalker33 2020-10-05 19:50:54 +11:00 committed by GitHub
commit ce61d78425
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
31 changed files with 1526 additions and 954 deletions

View file

@ -1,13 +1,17 @@
version: 3.0.1.{build} version: 3.0.1.{build}
image: Visual Studio 2019 image: Visual Studio 2019
clone_folder: C:\ProxSpace\pm3\proxmark clone_folder: C:\ProxSpace\pm3\proxmark
cache:
- C:\cache -> appveyor.yml
environment: environment:
proxspace_url: https://github.com/Gator96100/ProxSpace/archive/master.zip proxspace_url: https://github.com/Gator96100/ProxSpace/archive/master.zip
proxspace_zip_file: \proxspace.zip proxspace_zip_file: \proxspace.zip
proxspace_zip_folder_name: ProxSpace-* proxspace_zip_folder_name: ProxSpace-*
proxspace_path: \ProxSpace proxspace_path: C:\ProxSpace
proxspace_home_path: \ProxSpace\pm3 proxspace_home_path: \ProxSpace\pm3
proxspace_cache_path: C:\cache
wsl_git_path: C:\proxmark wsl_git_path: C:\proxmark
APPVEYOR_SAVE_CACHE_ON_ERROR: true
init: init:
- ps: >- - ps: >-
@ -34,39 +38,19 @@ init:
clone_script: clone_script:
- ps: >- - ps: >-
Function ExecUpdate($Text, $firstStart) { Function GitClone($Text, $Folder) {
Write-Host "$Text" Write-Host "$Text" -NoNewLine
Start-Process "cmd.exe" "/c ""cd /D $env:proxspace_path && runme64.bat -c ""exit""""" if(-not $env:appveyor_pull_request_number) {
$StartTime=[System.Environment]::TickCount git clone -q --branch=$env:appveyor_repo_branch https://github.com/$env:appveyor_repo_name.git $Folder
Start-Sleep -s 10 cd $Folder
while($true) { git checkout -qf $env:appveyor_repo_commit
$cmdprocess = Get-Process "cmd" -ErrorAction SilentlyContinue } else {
git clone -q https://github.com/$env:appveyor_repo_name.git $Folder
if (!$cmdprocess -Or $cmdprocess.HasExited) { cd $Folder
Write-Host "$Text" -NoNewLine git fetch -q origin +refs/pull/$env:appveyor_pull_request_number/merge:
Write-Host "[ OK ]" -ForegroundColor Green git checkout -qf FETCH_HEAD
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
} }
Write-Host "[ OK ]" -ForegroundColor Green
} }
$WSLjob = Start-Job -Name WSLInstall -ScriptBlock { $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 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) { Function GitClone($Text, $Folder) {
Write-Host "$Text" -NoNewLine Write-Host "$Text" -NoNewLine
if(-not $env:appveyor_pull_request_number) { if(-not $env:appveyor_pull_request_number) {
@ -101,41 +173,9 @@ clone_script:
Write-Host "[ OK ]" -ForegroundColor Green Write-Host "[ OK ]" -ForegroundColor Green
} }
Write-Host "ProxSpace: Removing folder..." -NoNewLine Write-Host "ProxSpace: move cache..." -NoNewLine
$PSInstallTime=[System.Environment]::TickCount Move-Item -Path "$env:proxspace_cache_path" -Destination "$env:proxspace_path\msys2\var\cache" -Force -ErrorAction SilentlyContinue
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)
Write-Host "[ OK ]" -ForegroundColor Gree Write-Host "[ OK ]" -ForegroundColor Gree
@ -143,21 +183,8 @@ clone_script:
ExecUpdate "ProxSpace: installing required packages..." $false ExecUpdate "ProxSpace: installing required packages..." $false
Add-AppveyorMessage -Message "ProxSpace download and update took $(([System.Environment]::TickCount-$env:PSInstallTime) / 1000) sec" -Category Information
$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
install:
build_script: build_script:
- ps: >- - ps: >-
@ -203,6 +230,9 @@ build_script:
} }
} }
#WSL: wait for installation to finish
Receive-Job -Wait -Name WSLInstall
#Windows Subsystem for Linux (WSL) #Windows Subsystem for Linux (WSL)
Write-Host "---------- WSL make ----------" -ForegroundColor Yellow Write-Host "---------- WSL make ----------" -ForegroundColor Yellow
cd $env:wsl_git_path cd $env:wsl_git_path
@ -234,6 +264,16 @@ build_script:
#ProxSpace #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 Write-Host "---------- PS make ----------" -ForegroundColor Yellow
$TestTime=[System.Environment]::TickCount $TestTime=[System.Environment]::TickCount

View file

@ -118,7 +118,7 @@ static int EPA_APDU(uint8_t *apdu, size_t length, uint8_t *response, uint16_t re
case 'a': case 'a':
return iso14_apdu(apdu, (uint16_t) length, false, response, NULL); return iso14_apdu(apdu, (uint16_t) length, false, response, NULL);
case 'b': case 'b':
return iso14443b_apdu(apdu, length, false, response, respmaxlen); return iso14443b_apdu(apdu, length, false, response, respmaxlen, NULL);
default: default:
return 0; return 0;
} }

View file

@ -99,7 +99,7 @@ int HfSniff(uint32_t samplesToSkip, uint32_t triggersToSkip, uint16_t *len) {
optimizedSniff((uint16_t *)mem, *len); optimizedSniff((uint16_t *)mem, *len);
if (DBGLEVEL >= DBG_INFO) { if (DBGLEVEL >= DBG_INFO) {
Dbprintf("Trigger kicked in (%d >= 180)", r); Dbprintf("Trigger kicked in (%d >= 180)", r);
Dbprintf("Collected %u samples", *len); Dbprintf("Collected %u samples", *len);
} }

View file

@ -2687,7 +2687,7 @@ void iso14443a_setup(uint8_t fpga_minor_mode) {
LED_D_ON(); LED_D_ON();
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | fpga_minor_mode); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | fpga_minor_mode);
SpinDelay(100); SpinDelay(50);
// Start the timer // Start the timer
StartCountSspClk(); StartCountSspClk();

View file

@ -784,6 +784,7 @@ static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) {
if (AMPLITUDE(ci, cq) > SUBCARRIER_DETECT_THRESHOLD) { 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 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 ((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 if (Demod.posCount < 10) { // refine signal approximation during first 10 samples
Demod.sumI += ci; Demod.sumI += ci;
Demod.sumQ += cq; Demod.sumQ += cq;
@ -1103,7 +1104,7 @@ static void CodeIso14443bAsReader(const uint8_t *cmd, int len) {
// Send SOF // Send SOF
// 10-11 ETUs of ZERO // 10-11 ETUs of ZERO
for (i = 0; i < 10; i++) { for (i = 0; i < 11; i++) {
tosend_stuffbit(0); tosend_stuffbit(0);
} }
// 2-3 ETUs of ONE // 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 // EGT extra guard time 1 ETU = 9us
// For PCD it ranges 0-57us === 0 - 6 ETU // For PCD it ranges 0-57us === 0 - 6 ETU
// FOR PICC it ranges 0-19us == 0 - 2 ETU // FOR PICC it ranges 0-19us == 0 - 2 ETU
} }
// Send EOF // Send EOF
// 10-11 ETUs of ZERO // 10-11 ETUs of ZERO
for (i = 0; i < 10; i++) { for (i = 0; i < 11; i++) {
tosend_stuffbit(0); tosend_stuffbit(0);
} }
tosend_stuffbit(1);
/* Transition time. TR0 - guard time /* Transition time. TR0 - guard time
* TR0 - 8 ETU's minimum. * TR0 - 8 ETU's minimum.
* TR0 - 32 ETU's maximum for ATQB only * TR0 - 32 ETU's maximum for ATQB only
* TR0 - FWT for all other commands * TR0 - FWT for all other commands
* 32,64,128,256,512, ... , 262144, 524288 ETU * 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) for (i = 0; i < 16 - pad; ++i)
tosend_stuffbit(1); tosend_stuffbit(1);
@ -1168,7 +1167,7 @@ static void CodeAndTransmit14443bAsReader(const uint8_t *cmd, int len, uint32_t
/* Sends an APDU to the tag /* Sends an APDU to the tag
* TODO: check CRC and preamble * 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]; 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); CodeAndTransmit14443bAsReader(real_cmd, msg_len + 3, &start_time, &eof_time);
eof_time += DELAY_ISO14443B_VCD_TO_VICC_READER; 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(); FpgaDisableTracing();
uint8_t *data_bytes = (uint8_t *) response; uint8_t *data_bytes = (uint8_t *) rxdata;
if (len <= 0) { if (len <= 0) {
return 0; //DATA LINK ERROR 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) // retrieve the result again (with increased timeout)
eof_time += DELAY_ISO14443B_VCD_TO_VICC_READER; 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(); FpgaDisableTracing();
data_bytes = response; data_bytes = rxdata;
// restore timeout // restore timeout
iso14b_set_timeout(save_iso14b_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 we received I-block with chaining we need to send ACK and receive another block of data
if (response) if (res)
*response = data_bytes[0]; *res = data_bytes[0];
// crc check // crc check
if (len >= 3 && !check_crc(CRC_14443_B, data_bytes, len)) { 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 // Signal field is on with the appropriate LED
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_SHALLOW_MOD); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_SHALLOW_MOD);
SpinDelay(100); SpinDelay(50);
// Start the timer // Start the timer
StartCountSspClk(); StartCountSspClk();
@ -1841,17 +1840,21 @@ void SendRawCommand14443B_Ex(PacketCommandNG *c) {
if ((param & ISO14B_CONNECT) == ISO14B_CONNECT) { if ((param & ISO14B_CONNECT) == ISO14B_CONNECT) {
iso14443b_setup(); iso14443b_setup();
clear_trace();
} }
if ((param & ISO14B_SET_TIMEOUT)) if ((param & ISO14B_SET_TIMEOUT) == ISO14B_SET_TIMEOUT) {
iso14b_set_timeout(timeout); iso14b_set_timeout(timeout);
}
if ((param & ISO14B_CLEARTRACE) == ISO14B_CLEARTRACE) {
clear_trace();
}
set_tracing(true); set_tracing(true);
int status; int status;
uint32_t sendlen = sizeof(iso14b_card_select_t); uint32_t sendlen = sizeof(iso14b_card_select_t);
iso14b_card_select_t card; iso14b_card_select_t card;
memset((void*)&card, 0x00, sizeof(card));
if ((param & ISO14B_SELECT_STD) == ISO14B_SELECT_STD) { if ((param & ISO14B_SELECT_STD) == ISO14B_SELECT_STD) {
status = iso14443b_select_card(&card); status = iso14443b_select_card(&card);
@ -1877,9 +1880,10 @@ void SendRawCommand14443B_Ex(PacketCommandNG *c) {
} }
if ((param & ISO14B_APDU) == ISO14B_APDU) { 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); 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) { if ((param & ISO14B_RAW) == ISO14B_RAW) {

View file

@ -27,7 +27,7 @@
#endif #endif
void iso14443b_setup(void); 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(iso14b_card_select_t *card);
int iso14443b_select_card_srx(iso14b_card_select_t *card); int iso14443b_select_card_srx(iso14b_card_select_t *card);

View file

@ -1479,6 +1479,7 @@ int SendDataTag(uint8_t *send, int sendlen, bool init, bool speed_fast, uint8_t
if (recv != NULL) { if (recv != NULL) {
res = GetIso15693AnswerFromTag(recv, max_recv_len, timeout, eof_time); res = GetIso15693AnswerFromTag(recv, max_recv_len, timeout, eof_time);
} }
FpgaDisableTracing();
return res; return res;
} }
@ -1494,6 +1495,7 @@ int SendDataTagEOF(uint8_t *recv, uint16_t max_recv_len, uint32_t start_time, ui
if (recv != NULL) { if (recv != NULL) {
res = GetIso15693AnswerFromTag(recv, max_recv_len, timeout, eof_time); res = GetIso15693AnswerFromTag(recv, max_recv_len, timeout, eof_time);
} }
FpgaDisableTracing();
return res; return res;
} }

View file

@ -1,6 +1,6 @@
#!/usr/bin/env -S pm3 -s #!/usr/bin/env -S pm3 -s
mem load f mfc_default_keys m mem load -f mfc_default_keys --mfc
mem load f t55xx_default_pwds t mem load -f t55xx_default_pwds --t55xx
mem load f iclass_default_keys i mem load -f iclass_default_keys --iclass
lf t55xx deviceconfig z p lf t55xx deviceconfig z p

View file

@ -14,7 +14,7 @@ lf search
rem Test of keri clone & read rem Test of keri clone & read
lf t55xx wipe lf t55xx wipe
lf keri clone 1337 lf keri clone --id 1337
lf keri read lf keri read
lf search lf search

View file

@ -1927,10 +1927,8 @@ struct arg_file *arg_filen(
#include <stdlib.h> #include <stdlib.h>
#include <limits.h> #include <limits.h>
#include <ctype.h> #include <ctype.h>
#include "argtable3.h" #include "argtable3.h"
static void arg_int_resetfn(struct arg_int *parent) { static void arg_int_resetfn(struct arg_int *parent) {
ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent)); ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
parent->count = 0; parent->count = 0;
@ -2226,6 +2224,263 @@ struct arg_int *arg_intn(
ARG_TRACE(("arg_intn() returns %p\n", result)); ARG_TRACE(("arg_intn() returns %p\n", result));
return result; return result;
} }
// uint64_t support
#include <stdint.h>
#include <limits.h>
#include <inttypes.h>
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 : "<u64>";
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. * 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 */ /* register an error for each unused argv[] entry */
while (optind < argc) { while (optind < argc) {
/*printf("arg_parse_untagged(): argv[%d]=\"%s\" not consumed\n",optind,argv[optind]);*/ /*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; return;
@ -4195,7 +4453,8 @@ static void arg_cat_option(char *dest,
#endif #endif
if (datatype) { if (datatype) {
arg_cat(&dest, "=", &ndest); // arg_cat(&dest, "=", &ndest);
arg_cat(&dest, " ", &ndest);
if (optvalue) { if (optvalue) {
arg_cat(&dest, "[", &ndest); arg_cat(&dest, "[", &ndest);
arg_cat(&dest, datatype, &ndest); arg_cat(&dest, datatype, &ndest);

View file

@ -35,6 +35,7 @@
#include <stdio.h> /* FILE */ #include <stdio.h> /* FILE */
#include <time.h> /* struct tm */ #include <time.h> /* struct tm */
#include <stdint.h>
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@ -110,6 +111,12 @@ struct arg_int {
int *ival; /* Array of parsed argument values */ 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_dbl {
struct arg_hdr hdr; /* The mandatory argtable header struct */ struct arg_hdr hdr; /* The mandatory argtable header struct */
int count; /* Number of matching command line args */ int count; /* Number of matching command line args */
@ -176,32 +183,29 @@ struct arg_lit *arg_litn(const char *shortopts,
int maxcount, int maxcount,
const char *glossary); const char *glossary);
struct arg_key *arg_key0(const char *keyword, struct arg_key *arg_key0(const char *keyword, int flags, const char *glossary);
int flags, 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); const char *glossary);
struct arg_key *arg_key1(const char *keyword, struct arg_u64 *arg_u64_1(const char *shortopts,
int flags, const char *longopts,
const char *datatype,
const char *glossary); const char *glossary);
struct arg_key *arg_keyn(const char *keyword, struct arg_u64 *arg_u64_n(const char *shortopts,
int flags, const char *longopts,
const char *datatype,
int mincount, int mincount,
int maxcount, int maxcount,
const char *glossary); 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, struct arg_dbl *arg_dbl0(const char *shortopts,
const char *longopts, const char *longopts,

View file

@ -251,12 +251,13 @@ int CLIParamStrToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int
if (!ibuf) if (!ibuf)
return 0; return 0;
if (ibuf > maxdatalen) { if (ibuf + 1 > maxdatalen) {
printf("Parameter error: string too long, expect max %i chars\n", maxdatalen - 1);
fflush(stdout); fflush(stdout);
return 2; return 2;
} }
memcpy(data, tmp_buf, ibuf); memcpy(data, tmp_buf, ibuf + 1);
*datalen = ibuf; *datalen = ibuf;
return 0; return 0;
} }

View file

@ -17,22 +17,39 @@
#define arg_param_begin arg_lit0("h", "help", "This help") #define arg_param_begin arg_lit0("h", "help", "This help")
#define arg_param_end arg_end(20) #define arg_param_end arg_end(20)
#define arg_getsize(a) (sizeof(a) / sizeof(a[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_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_count(ctx, n) (((struct arg_int*)((ctx)->argtable)[(n)])->count)
#define arg_get_int_def(ctx, n, def)(arg_get_int_count((ctx), n) ? (arg_get_int((ctx), n)) : (def)) #define arg_get_int(ctx, n) (((struct arg_int*)((ctx)->argtable)[(n)])->ival[0])
#define arg_get_str(ctx, n) ((struct arg_str*)((ctx)->argtable)[n]) #define arg_get_int_def(ctx, n, def)(arg_get_int_count((ctx), (n)) ? (arg_get_int((ctx), (n))) : (def))
#define arg_get_str_len(ctx, n) (strlen(((struct arg_str*)((ctx)->argtable)[n])->sval[0]))
#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_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 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 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 CLIExecWithReturn(ctx, cmd, atbl, ifempty) if (CLIParserParseString((ctx), (cmd), (atbl), arg_getsize((atbl)), (ifempty))) {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 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 { typedef struct {
void **argtable; void **argtable;

View file

@ -32,7 +32,7 @@ device-side.
local function calypso_parse(result) local function calypso_parse(result)
local r = Command.parse(result) local r = Command.parse(result)
if r.arg1 >= 0 then if r.arg1 >= 0 then
local len = r.arg2 * 2 local len = r.arg1 * 2
if len > 0 then if len > 0 then
r.data = string.sub(r.data, 0, len); r.data = string.sub(r.data, 0, len);
return r, nil return r, nil
@ -113,8 +113,9 @@ end
local function calypso_send_cmd_raw(data, ignoreresponse ) local function calypso_send_cmd_raw(data, ignoreresponse )
local command, flags, result, err local command, flags, result, err
flags = lib14b.ISO14B_COMMAND.ISO14B_RAW + flags = lib14b.ISO14B_COMMAND.ISO14B_APDU
lib14b.ISO14B_COMMAND.ISO14B_APPEND_CRC -- flags = lib14b.ISO14B_COMMAND.ISO14B_RAW +
-- lib14b.ISO14B_COMMAND.ISO14B_APPEND_CRC
data = data or "00" data = data or "00"
@ -162,6 +163,7 @@ local function calypso_apdu_status(apdu)
return status, desc, err return status, desc, err
end end
local CLA = '94'
local _calypso_cmds = { local _calypso_cmds = {
-- Break down of command bytes: -- Break down of command bytes:
@ -184,27 +186,25 @@ local _calypso_cmds = {
-- Electronic Purse file -- Electronic Purse file
-- Electronic Transaction log file -- Electronic Transaction log file
['01.Select ICC file'] = CLA..'a4 080004 3f00 0002',
--['01.Select ICC file'] = '0294 a4 00 0002 3f00', ['02.ICC'] = CLA..'b2 01 041d',
['01.Select ICC file'] = '0294 a4 080004 3f00 0002', ['03.Select EnvHol file'] = CLA..'a4 080004 2000 2001',
['02.ICC'] = '0394 b2 01 041d', ['04.EnvHol1'] = CLA..'b2 01 041d',
['03.Select EnvHol file'] = '0294 a4 080004 2000 2001', ['05.Select EvLog file'] = CLA..'a4 080004 2000 2010',
['04.EnvHol1'] = '0394 b2 01 041d', ['06.EvLog1'] = CLA..'b2 01 041d',
['05.Select EvLog file'] = '0294 a4 080004 2000 2010', ['07.EvLog2'] = CLA..'b2 02 041d',
['06.EvLog1'] = '0394 b2 01 041d', ['08.EvLog3'] = CLA..'b2 03 041d',
['07.EvLog2'] = '0294 b2 02 041d', ['09.Select ConList file']= CLA..'a4 080004 2000 2050',
['08.EvLog3'] = '0394 b2 03 041d', ['10.ConList'] = CLA..'b2 01 041d',
['09.Select ConList file']= '0294 a4 080004 2000 2050', ['11.Select Contra file'] = CLA..'a4 080004 2000 2020',
['10.ConList'] = '0394 b2 01 041d', ['12.Contra1'] = CLA..'b2 01 041d',
['11.Select Contra file'] = '0294 a4 080004 2000 2020', ['13.Contra2'] = CLA..'b2 02 041d',
['12.Contra1'] = '0394 b2 01 041d', ['14.Contra3'] = CLA..'b2 03 041d',
['13.Contra2'] = '0294 b2 02 041d', ['15.Contra4'] = CLA..'b2 04 041d',
['14.Contra3'] = '0394 b2 03 041d', ['16.Select Counter file']= CLA..'a4 080004 2000 2069',
['15.Contra4'] = '0294 b2 04 041d', ['17.Counter'] = CLA..'b2 01 041d',
['16.Select Counter file']= '0394 a4 080004 2000 2069', ['18.Select SpecEv file'] = CLA..'a4 080004 2000 2040',
['17.Counter'] = '0294 b2 01 041d', ['19.SpecEv1'] = CLA..'b2 01 041d',
['18.Select SpecEv file'] = '0394 a4 080004 2000 2040',
['19.SpecEv1'] = '0294 b2 01 041d',
} }
--- ---

View file

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

View file

@ -74,9 +74,9 @@ function main(args)
-- Upload dictionaries -- Upload dictionaries
print('Uploading dictionaries to RDV4 flashmemory') print('Uploading dictionaries to RDV4 flashmemory')
print(dash) print(dash)
core.console('mem load f mfc_default_keys m') core.console('mem load -f mfc_default_keys --mfc')
core.console('mem load f t55xx_default_pwds t') core.console('mem load -f t55xx_default_pwds --t55xx')
core.console('mem load f iclass_default_keys i') core.console('mem load -f iclass_default_keys --iclass')
print(dash) print(dash)
-- T55x7 Device configuration -- T55x7 Device configuration

View file

@ -50,20 +50,6 @@ static int usage_data_save(void) {
PrintAndLogEx(NORMAL, " data save f mytrace w - save graphbuffer to wave file"); PrintAndLogEx(NORMAL, " data save f mytrace w - save graphbuffer to wave file");
return PM3_SUCCESS; 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] <kHz>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h this help");
PrintAndLogEx(NORMAL, " <kHz> 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) { static int usage_data_printdemodbuf(void) {
PrintAndLogEx(NORMAL, "Usage: data printdemodbuffer x o <offset> l <length>"); PrintAndLogEx(NORMAL, "Usage: data printdemodbuffer x o <offset> l <length>");
PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, "Options:");
@ -1825,7 +1811,8 @@ static int CmdMtrim(const char *Cmd) {
uint32_t start = 0, stop = 0; uint32_t start = 0, stop = 0;
sscanf(Cmd, "%u %u", &start, &stop); 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 // leave start position sample
start++; start++;
@ -1912,14 +1899,32 @@ int CmdSave(const char *Cmd) {
} }
static int CmdScale(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); CLIParserContext *ctx;
if (CursorScaleFactor == 0) { CLIParserInit(&ctx, "data scale",
PrintAndLogEx(FAILED, "bad, can't have zero 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", "<float>", "sets scale according to sampling rate"),
arg_str0("u", "unit", "<string>", "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; CursorScaleFactor = 1;
} }
int len = 0;
CursorScaleFactorUnit[0] = '\x00';
CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t*)CursorScaleFactorUnit, sizeof(CursorScaleFactorUnit), &len);
CLIParserFree(ctx);
RepaintGraphWindow(); RepaintGraphWindow();
return PM3_SUCCESS; return PM3_SUCCESS;
} }

View file

@ -8,16 +8,13 @@
// Proxmark3 RDV40 Flash memory commands // Proxmark3 RDV40 Flash memory commands
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#include "cmdflashmem.h" #include "cmdflashmem.h"
#include <ctype.h> #include <ctype.h>
#include "cmdparser.h" // command_t
#include "cmdparser.h" // command_t #include "cliparser.h"
#include "pmflash.h" #include "pmflash.h"
#include "fileutils.h" //saveFile #include "fileutils.h" // saveFile
#include "comms.h" //getfromdevice #include "comms.h" // getfromdevice
#include "cmdflashmemspiffs.h" // spiffs commands #include "cmdflashmemspiffs.h" // spiffs commands
#include "rsa.h" #include "rsa.h"
#include "sha1.h" #include "sha1.h"
@ -29,90 +26,34 @@
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);
static int usage_flashmem_spibaud(void) {
PrintAndLogEx(NORMAL, "Usage: mem spibaud [h] <baudrate>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h this help");
PrintAndLogEx(NORMAL, " <baudrate> 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 <offset>] f <file name> [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> : offset in memory");
PrintAndLogEx(NORMAL, " f <filename> : 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 <offset>] [l <length>] [f <file name>] [p]");
PrintAndLogEx(NORMAL, " o <offset> : offset in memory");
PrintAndLogEx(NORMAL, " l <length> : length");
PrintAndLogEx(NORMAL, " f <filename> : 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 <page>");
PrintAndLogEx(NORMAL, " p <page> : 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) { static int CmdFlashmemSpiBaudrate(const char *Cmd) {
char ctmp = tolower(param_getchar(Cmd, 0)); CLIParserContext *ctx;
if (strlen(Cmd) < 1 || ctmp == 'h') { CLIParserInit(&ctx, "mem baudrate",
return usage_flashmem_spibaud(); "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);
if (br == -1) {
PrintAndLogEx(ERR, "failed to get baudrate");
return PM3_EINVARG;
} }
uint32_t baudrate = param_get32ex(Cmd, 0, 0, 10); uint32_t baudrate = br * 1000000;
baudrate = baudrate * 1000000;
if (baudrate != FLASH_BAUD && baudrate != FLASH_MINBAUD) { if (baudrate != FLASH_BAUD && baudrate != FLASH_MINBAUD) {
usage_flashmem_spibaud(); PrintAndLogEx(ERR, "wrong baudrate. Only 24 or 48 is allowed");
return PM3_EINVARG; return PM3_EINVARG;
} }
SendCommandNG(CMD_FLASHMEM_SET_SPIBAUDRATE, (uint8_t *)&baudrate, sizeof(uint32_t)); 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) { 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", "<dec>", "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", "<filename>", "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}; char filename[FILE_PATH_SIZE] = {0};
bool errors = false; CLIParamStrToBuf(arg_get_str(ctx, 5), (uint8_t*)filename, FILE_PATH_SIZE, &fnlen);
uint8_t cmdp = 0; CLIParserFree(ctx);
Dictionary_t d = DICTIONARY_NONE; Dictionary_t d = DICTIONARY_NONE;
if (is_mfc) {
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { d = DICTIONARY_MIFARE;
switch (tolower(param_getchar(Cmd, cmdp))) { PrintAndLogEx(INFO, "treating file as MIFARE Classic keys");
case 'h': } else if (is_iclass) {
return usage_flashmem_load(); d = DICTIONARY_ICLASS;
case 'f': PrintAndLogEx(INFO, "treating file as iCLASS keys");
if (param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE) >= FILE_PATH_SIZE) { } else if (is_t55xx) {
PrintAndLogEx(FAILED, "Filename too long"); d = DICTIONARY_T55XX;
errors = true; PrintAndLogEx(INFO, "treating file as T55xx passwords");
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;
}
} }
//Validations
if (errors || cmdp == 0) {
usage_flashmem_load();
return PM3_EINVARG;
}
size_t datalen = 0; size_t datalen = 0;
uint32_t keycount = 0; uint32_t keycount = 0;
int res = 0; int res = 0;
@ -174,7 +113,7 @@ static int CmdFlashMemLoad(const char *Cmd) {
switch (d) { switch (d) {
case DICTIONARY_MIFARE: case DICTIONARY_MIFARE:
start_index = DEFAULT_MF_KEYS_OFFSET; offset = DEFAULT_MF_KEYS_OFFSET;
res = loadFileDICTIONARY(filename, data + 2, &datalen, 6, &keycount); res = loadFileDICTIONARY(filename, data + 2, &datalen, 6, &keycount);
if (res || !keycount) { if (res || !keycount) {
free(data); free(data);
@ -189,7 +128,7 @@ static int CmdFlashMemLoad(const char *Cmd) {
datalen += 2; datalen += 2;
break; break;
case DICTIONARY_T55XX: case DICTIONARY_T55XX:
start_index = DEFAULT_T55XX_KEYS_OFFSET; offset = DEFAULT_T55XX_KEYS_OFFSET;
res = loadFileDICTIONARY(filename, data + 2, &datalen, 4, &keycount); res = loadFileDICTIONARY(filename, data + 2, &datalen, 4, &keycount);
if (res || !keycount) { if (res || !keycount) {
free(data); free(data);
@ -204,7 +143,7 @@ static int CmdFlashMemLoad(const char *Cmd) {
datalen += 2; datalen += 2;
break; break;
case DICTIONARY_ICLASS: case DICTIONARY_ICLASS:
start_index = DEFAULT_ICLASS_KEYS_OFFSET; offset = DEFAULT_ICLASS_KEYS_OFFSET;
res = loadFileDICTIONARY(filename, data + 2, &datalen, 8, &keycount); res = loadFileDICTIONARY(filename, data + 2, &datalen, 8, &keycount);
if (res || !keycount) { if (res || !keycount) {
free(data); free(data);
@ -253,13 +192,13 @@ static int CmdFlashMemLoad(const char *Cmd) {
clearCommandBuffer(); 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_remaining -= bytes_in_packet;
bytes_sent += bytes_in_packet; bytes_sent += bytes_in_packet;
PacketResponseNG resp; PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { if (WaitForResponseTimeout(CMD_ACK, &resp, 2000) == false) {
PrintAndLogEx(WARNING, "timeout while waiting for reply."); PrintAndLogEx(WARNING, "timeout while waiting for reply.");
conn.block_after_ACK = false; conn.block_after_ACK = false;
free(data); free(data);
@ -276,54 +215,37 @@ static int CmdFlashMemLoad(const char *Cmd) {
conn.block_after_ACK = false; conn.block_after_ACK = false;
free(data); 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; return PM3_SUCCESS;
} }
static int CmdFlashMemDump(const char *Cmd) { 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", "<dec>", "offset in memory"),
arg_int0("l", "len", "<dec>", "length"),
arg_lit0("v", "view", "view dump"),
arg_strx0("f", "file", "<filename>", "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}; char filename[FILE_PATH_SIZE] = {0};
uint8_t cmdp = 0; CLIParamStrToBuf(arg_get_str(ctx, 4), (uint8_t*)filename, FILE_PATH_SIZE, &fnlen);
bool errors = false; CLIParserFree(ctx);
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;
}
uint8_t *dump = calloc(len, sizeof(uint8_t)); uint8_t *dump = calloc(len, sizeof(uint8_t));
if (!dump) { if (!dump) {
@ -331,14 +253,15 @@ static int CmdFlashMemDump(const char *Cmd) {
return PM3_EMALLOC; return PM3_EMALLOC;
} }
PrintAndLogEx(INFO, "downloading "_YELLOW_("%u")" bytes from flashmem", len); PrintAndLogEx(INFO, "downloading "_YELLOW_("%u")" bytes from flash memory", len);
if (!GetFromDevice(FLASH_MEM, dump, len, start_index, NULL, 0, NULL, -1, true)) { if (!GetFromDevice(FLASH_MEM, dump, len, offset, NULL, 0, NULL, -1, true)) {
PrintAndLogEx(FAILED, "ERROR; downloading from flashmemory"); PrintAndLogEx(FAILED, "ERROR; downloading from flash memory");
free(dump); free(dump);
return PM3_EFLASH; return PM3_EFLASH;
} }
if (print) { if (view) {
PrintAndLogEx(INFO, "---- " _CYAN_("data") " ---------------");
print_hex_break(dump, len, 32); print_hex_break(dump, len, 32);
} }
@ -350,39 +273,32 @@ static int CmdFlashMemDump(const char *Cmd) {
free(dump); free(dump);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int CmdFlashMemWipe(const char *Cmd) { static int CmdFlashMemWipe(const char *Cmd) {
uint8_t cmdp = 0; CLIParserContext *ctx;
bool errors = false; CLIParserInit(&ctx, "mem wipe",
bool initalwipe = false; "Wipe flash memory on device, which fills it with 0xFF\n"
uint8_t page = 0; _WHITE_("[ ") _RED_("!!! OBS") " ] use with caution",
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { "mem wipe -p 0 -> wipes first page"
switch (tolower(param_getchar(Cmd, cmdp))) { // "mem wipe -i -> inital total wipe"
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;
}
}
//Validations void *argtable[] = {
if (errors || cmdp == 0) { arg_param_begin,
usage_flashmem_wipe(); arg_int0("p", NULL, "<dec>", "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; return PM3_EINVARG;
} }
@ -393,59 +309,51 @@ static int CmdFlashMemWipe(const char *Cmd) {
PrintAndLogEx(WARNING, "timeout while waiting for reply."); PrintAndLogEx(WARNING, "timeout while waiting for reply.");
return PM3_ETIMEOUT; return PM3_ETIMEOUT;
} }
const char* msg = "Flash WIPE ";
uint8_t isok = resp.oldarg[0] & 0xFF; uint8_t isok = resp.oldarg[0] & 0xFF;
if (isok) if (isok)
PrintAndLogEx(SUCCESS, "Flash WIPE ok"); PrintAndLogEx(SUCCESS, "%s ( " _GREEN_("ok")" )", msg);
else { else {
PrintAndLogEx(FAILED, "Flash WIPE failed"); PrintAndLogEx(FAILED, "%s ( " _RED_("failed") " )", msg);
return PM3_EFLASH; return PM3_EFLASH;
} }
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int CmdFlashMemInfo(const char *Cmd) { static int CmdFlashMemInfo(const char *Cmd) {
uint8_t sha_hash[20] = {0}; CLIParserContext *ctx;
mbedtls_rsa_context rsa; CLIParserInit(&ctx, "mem info",
"Collect signature and verify it from flash memory",
"mem info"
// "mem info -s"
);
uint8_t cmdp = 0; void *argtable[] = {
bool errors = false, shall_write = false, shall_sign = false; arg_param_begin,
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { // arg_lit0("s", NULL, "create a signature"),
switch (tolower(param_getchar(Cmd, cmdp))) { // arg_lit0("w", NULL, "write signature to flash memory"),
case 'h': arg_param_end
return usage_flashmem_info(); };
case 's': { CLIExecWithReturn(ctx, Cmd, argtable, true);
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;
}
}
//Validations bool shall_sign = false, shall_write = false;
if (errors) { // shall_sign = arg_get_lit(ctx, 1);
usage_flashmem_info(); // shall_write = arg_get_lit(ctx, 2);
return PM3_EINVARG; CLIParserFree(ctx);
}
clearCommandBuffer(); clearCommandBuffer();
SendCommandNG(CMD_FLASHMEM_INFO, NULL, 0); SendCommandNG(CMD_FLASHMEM_INFO, NULL, 0);
PacketResponseNG resp; PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) { if (WaitForResponseTimeout(CMD_ACK, &resp, 2500) == false) {
PrintAndLogEx(WARNING, "timeout while waiting for reply."); PrintAndLogEx(WARNING, "timeout while waiting for reply");
return PM3_ETIMEOUT; return PM3_ETIMEOUT;
} }
uint8_t isok = resp.oldarg[0] & 0xFF; uint8_t isok = resp.oldarg[0] & 0xFF;
if (!isok) { if (isok == false) {
PrintAndLogEx(FAILED, "failed"); PrintAndLogEx(FAILED, "failed");
return PM3_EFLASH; 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)); memcpy(&mem, (rdv40_validation_t *)resp.data.asBytes, sizeof(rdv40_validation_t));
// Flash ID hash (sha1) // Flash ID hash (sha1)
uint8_t sha_hash[20] = {0};
mbedtls_sha1(mem.flashid, sizeof(mem.flashid), sha_hash); mbedtls_sha1(mem.flashid, sizeof(mem.flashid), sha_hash);
// print header // print header
PrintAndLogEx(INFO, "\n--- Flash memory Information ---------"); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, "-------------------------------------------------------------"); PrintAndLogEx(INFO, "--- " _CYAN_("Flash memory Information") " ---------");
PrintAndLogEx(INFO, "ID | %s", sprint_hex(mem.flashid, sizeof(mem.flashid))); // PrintAndLogEx(INFO, "-----------------------------------------------------------------");
PrintAndLogEx(INFO, "SHA1 | %s", sprint_hex(sha_hash, sizeof(sha_hash))); PrintAndLogEx(INFO, "ID................... %s", sprint_hex_inrow(mem.flashid, sizeof(mem.flashid)));
PrintAndLogEx(INFO, "RSA SIGNATURE |"); PrintAndLogEx(INFO, "SHA1................. %s", sprint_hex_inrow(sha_hash, sizeof(sha_hash)));
print_hex_break(mem.signature, sizeof(mem.signature), 32); 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 // RRG Public RSA Key
@ -473,7 +386,10 @@ static int CmdFlashMemInfo(const char *Cmd) {
#define RSA_E "010001" #define RSA_E "010001"
// public key modulus N // 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) // Example RSA-1024 keypair, for test purposes (from common/polarssl/rsa.c)
@ -516,9 +432,9 @@ static int CmdFlashMemInfo(const char *Cmd) {
"F5A3B2A5D33605AEBBCCBA7FEB9F2D2F" \ "F5A3B2A5D33605AEBBCCBA7FEB9F2D2F" \
"A74206CEC169D74BF5A8C50D6F48EA08" "A74206CEC169D74BF5A8C50D6F48EA08"
#define KEY_LEN 128 #define KEY_LEN 128
mbedtls_rsa_context rsa;
mbedtls_rsa_init(&rsa, MBEDTLS_RSA_PKCS_V15, 0); mbedtls_rsa_init(&rsa, MBEDTLS_RSA_PKCS_V15, 0);
rsa.len = KEY_LEN; 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.DQ, 16, RSA_DQ);
mbedtls_mpi_read_string(&rsa.QP, 16, RSA_QP); 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); 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) if (is_keyok)
PrintAndLogEx(SUCCESS, "RSA key validation ok"); PrintAndLogEx(SUCCESS, "%s( " _GREEN_("ok") " )", msgkey);
else else
PrintAndLogEx(FAILED, "RSA key validation failed"); PrintAndLogEx(FAILED, "%s( " _RED_("failed") " )", msgkey);
// //
uint8_t from_device[KEY_LEN]; uint8_t from_device[KEY_LEN];
@ -554,10 +488,11 @@ static int CmdFlashMemInfo(const char *Cmd) {
if (shall_sign) { if (shall_sign) {
int is_signed = mbedtls_rsa_pkcs1_sign(&rsa, NULL, NULL, MBEDTLS_RSA_PRIVATE, MBEDTLS_MD_SHA1, 20, sha_hash, 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) if (is_signed == 0)
PrintAndLogEx(SUCCESS, "RSA Signing ok"); PrintAndLogEx(SUCCESS, "%s( " _GREEN_("ok") " )", msgsign);
else else
PrintAndLogEx(FAILED, "RSA Signing failed"); PrintAndLogEx(FAILED, "%s( " _RED_("failed") " )", msgsign);
if (shall_write) { if (shall_write) {
// save to mem // save to mem
@ -574,29 +509,33 @@ static int CmdFlashMemInfo(const char *Cmd) {
} }
} }
PrintAndLogEx(INFO, "Signed | "); PrintAndLogEx(INFO, "Signed");
print_hex_break(sign, sizeof(sign), 32); for (int i = 0; i < (sizeof(sign) / 32); i++) {
PrintAndLogEx(INFO, " %s", sprint_hex_inrow(sign + (i * 32), 32));
}
} }
// Verify (public key) // Verify (public key)
int is_verified = mbedtls_rsa_pkcs1_verify(&rsa, NULL, NULL, MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA1, 20, sha_hash, from_device); 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) if (is_verified == 0)
PrintAndLogEx(SUCCESS, "RSA Verification ok"); PrintAndLogEx(SUCCESS, "%s( " _GREEN_("ok") " )", msgverify);
else else
PrintAndLogEx(FAILED, "RSA Verification failed"); PrintAndLogEx(FAILED, "%s( " _RED_("failed") " )", msgverify);
PrintAndLogEx(NORMAL, "");
mbedtls_rsa_free(&rsa); mbedtls_rsa_free(&rsa);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static command_t CommandTable[] = { static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"}, {"help", CmdHelp, AlwaysAvailable, "This help"},
{"spiffs", CmdFlashMemSpiFFS, IfPm3Flash, "High level SPI FileSystem Flash manipulation [rdv40]"}, {"baudrate", CmdFlashmemSpiBaudrate, IfPm3Flash, "Set Flash memory Spi baudrate"},
{"spibaud", CmdFlashmemSpiBaudrate, IfPm3Flash, "Set Flash memory Spi baudrate [rdv40]"}, {"spiffs", CmdFlashMemSpiFFS, IfPm3Flash, "High level SPI FileSystem Flash manipulation"},
{"info", CmdFlashMemInfo, IfPm3Flash, "Flash memory information [rdv40]"}, {"info", CmdFlashMemInfo, IfPm3Flash, "Flash memory information"},
{"load", CmdFlashMemLoad, IfPm3Flash, "Load data into flash memory [rdv40]"}, {"load", CmdFlashMemLoad, IfPm3Flash, "Load data into flash memory"},
{"dump", CmdFlashMemDump, IfPm3Flash, "Dump data from flash memory [rdv40]"}, {"dump", CmdFlashMemDump, IfPm3Flash, "Dump data from flash memory"},
{"wipe", CmdFlashMemWipe, IfPm3Flash, "Wipe data from flash memory [rdv40]"}, {"wipe", CmdFlashMemWipe, IfPm3Flash, "Wipe data from flash memory"},
{NULL, NULL, NULL, NULL} {NULL, NULL, NULL, NULL}
}; };

View file

@ -63,7 +63,7 @@ static uint16_t get_sw(uint8_t *d, uint8_t n) {
return d[n] * 0x0100 + d[n + 1]; 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; PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) { 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); uint16_t len = (resp.oldarg[1] & 0xFFFF);
uint8_t *data = resp.data.asBytes; 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 (verbose) {
if (len >= 3) { if (len >= 3) {
@ -121,12 +138,14 @@ static int CmdHF14BSim(const char *Cmd) {
uint8_t pupi[4]; uint8_t pupi[4];
int n = 0; 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); CLIParserFree(ctx);
clearCommandBuffer(); clearCommandBuffer();
SendCommandNG(CMD_HF_ISO14443B_SIMULATE, pupi, sizeof(pupi)); SendCommandNG(CMD_HF_ISO14443B_SIMULATE, pupi, sizeof(pupi));
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -161,27 +180,26 @@ static int CmdHF14BCmdRaw(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf 14b raw", CLIParserInit(&ctx, "hf 14b raw",
"Sends raw bytes to card ", "Sends raw bytes to card ",
"hf 14b raw -s -c -k 0200a40400\n" "hf 14b raw -cks --data 0200a40400 -> standard select\n"
"hf 14b raw --sr -c -k 0200a40400\n" "hf 14b raw -ck --sr --data 0200a40400 -> SRx select\n"
"hf 14b raw --cts -c -k 0200a40400\n" "hf 14b raw -ck --cts --data 0200a40400 -> C-ticket select\n"
); );
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_lit0("k", "keep", "leave the signal field ON after receive response"), arg_lit0("k", "keep", "leave the signal field ON after receive response"),
arg_lit0("s", "std", "activate field and select standard card"), arg_lit0("s", "std", "activate field and select standard card"),
arg_lit0(NULL, "sr", "activate field and select SRx ST"), arg_lit0(NULL, "sr", "activate field and select SRx ST"),
arg_lit0(NULL, "cts", "activate field and select ASK C-ticket"), arg_lit0(NULL, "cts", "activate field and select ASK C-ticket"),
arg_lit0("c", "crc", "calculate and append CRC"), arg_lit0("c", "crc", "calculate and append CRC"),
arg_lit0("r", "noresponse", "do not read response"), arg_lit0("r", "noresponse", "do not read response"),
arg_int0("t", "timeout", "decimal", "timeout in ms"), arg_int0("t", "timeout", "<dec>", "timeout in ms"),
arg_lit0("v", "verbose", "verbose"), arg_lit0("v", "verbose", "verbose"),
arg_strx0(NULL, NULL, "<data (hex)>", "bytes to send"), arg_strx0("d", "data", "<hex>", "data, bytes to send"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, false); CLIExecWithReturn(ctx, Cmd, argtable, false);
bool select = false;
bool keep_field_on = arg_get_lit(ctx, 1); bool keep_field_on = arg_get_lit(ctx, 1);
bool select_std = arg_get_lit(ctx, 2); bool select_std = arg_get_lit(ctx, 2);
bool select_sr = arg_get_lit(ctx, 3); bool select_sr = arg_get_lit(ctx, 3);
@ -197,25 +215,25 @@ static int CmdHF14BCmdRaw(const char *Cmd) {
} }
if (select_std) { if (select_std) {
select = true; flags |= (ISO14B_SELECT_STD | ISO14B_CLEARTRACE);
flags |= ISO14B_SELECT_STD;
if (verbose) if (verbose)
PrintAndLogEx(INFO, "using standard select"); PrintAndLogEx(INFO, "using standard select");
} else if (select_sr) { } else if (select_sr) {
select = true; flags |= (ISO14B_SELECT_SR | ISO14B_CLEARTRACE);
flags |= ISO14B_SELECT_SR;
if (verbose) if (verbose)
PrintAndLogEx(INFO, "using SRx ST select"); PrintAndLogEx(INFO, "using ST/SRx select");
} else if (select_cts) { } else if (select_cts) {
select = true; flags |= (ISO14B_SELECT_CTS | ISO14B_CLEARTRACE);
flags |= ISO14B_SELECT_CTS;
if (verbose) if (verbose)
PrintAndLogEx(INFO, "using ASK C-ticket select"); PrintAndLogEx(INFO, "using ASK/C-ticket select");
} }
uint8_t data[PM3_CMD_DATA_SIZE] = {0x00}; uint8_t data[PM3_CMD_DATA_SIZE] = {0x00};
int datalen = 0; 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); CLIParserFree(ctx);
uint32_t time_wait = 0; uint32_t time_wait = 0;
@ -244,18 +262,33 @@ static int CmdHF14BCmdRaw(const char *Cmd) {
clearCommandBuffer(); clearCommandBuffer();
SendCommandMIX(CMD_HF_ISO14443B_COMMAND, flags, datalen, time_wait, data, datalen); SendCommandMIX(CMD_HF_ISO14443B_COMMAND, flags, datalen, time_wait, data, datalen);
if (read_reply == false) { if (read_reply == false) {
clearCommandBuffer();
return PM3_SUCCESS; return PM3_SUCCESS;
} }
bool success = true; bool success = true;
// get back iso14b_card_select_t, don't print it. // Select, device will send back iso14b_card_select_t, don't print it.
if (select) { if (select_std) {
success = wait_cmd_14b(verbose); 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. // get back response from the raw bytes you sent.
if (success && datalen > 0) { if (success && datalen > 0) {
wait_cmd_14b(true); wait_cmd_14b(true, false);
} }
return PM3_SUCCESS; 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); return CmdHF14BCmdRaw(str);
} }
@ -1525,10 +1558,10 @@ static int CmdHF14BAPDU(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "hf 14b apdu", 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", "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 -s --hex 94a40800043f000002\n"
"hf 14b apdu -sd 00A404000E325041592E5359532E444446303100 -> decode apdu\n" "hf 14b apdu -sd --hex 00A404000E325041592E5359532E444446303100 -> decode apdu\n"
"hf 14b apdu -sm 00A40400 325041592E5359532E4444463031 -l 256 -> encode standard apdu\n" "hf 14b apdu -sm 00A40400 -l 256 --hex 325041592E5359532E4444463031 -> encode standard apdu\n"
"hf 14b apdu -sm 00A40400 325041592E5359532E4444463031 -el 65536 -> encode extended apdu\n"); "hf 14b apdu -sm 00A40400 -el 65536 --hex 325041592E5359532E4444463031 -> encode extended apdu\n");
void *argtable[] = { void *argtable[] = {
arg_param_begin, 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("k", "keep", "leave the signal field ON after receive response"),
arg_lit0("t", "tlv", "executes TLV decoder if it possible"), arg_lit0("t", "tlv", "executes TLV decoder if it possible"),
arg_lit0("d", "decode", "decode apdu request if it possible"), arg_lit0("d", "decode", "decode apdu request if it possible"),
arg_str0("m", "make", "<head (CLA INS P1 P2) hex>", "make apdu with head from this field and data from data field. Must be 4 bytes length: <CLA INS P1 P2>"), arg_str0("m", "make", "<hex>", "make apdu with head from this field and data from data field. Must be 4 bytes length: <CLA INS P1 P2>"),
arg_lit0("e", "extended", "make extended length apdu if `m` parameter included"), arg_lit0("e", "extended", "make extended length apdu if `m` parameter included"),
arg_int0("l", "le", "<Le (int)>", "Le apdu parameter if `m` parameter included"), arg_int0("l", "le", "<int>", "Le apdu parameter if `m` parameter included"),
arg_strx1(NULL, NULL, "<APDU (hex) | data (hex)>", "data if `m` parameter included"), arg_strx1(NULL, "hex", "<hex>", "<APDU | data> if `m` parameter included"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, false); CLIExecWithReturn(ctx, Cmd, argtable, false);

View file

@ -325,8 +325,8 @@ static int cmd_hf_st_sim(const char *Cmd) {
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, false); CLIExecWithReturn(ctx, Cmd, argtable, false);
CLIGetHexWithReturn(ctx, 1, uid, &uidlen); CLIGetHexWithReturn(ctx, 1, uid, &uidlen);
CLIParserFree(ctx);
if (uidlen != 7) { if (uidlen != 7) {
PrintAndLogEx(ERR, "UID must be 7 hex bytes"); PrintAndLogEx(ERR, "UID must be 7 hex bytes");
@ -350,12 +350,12 @@ static int cmd_hf_st_ndef(const char *Cmd) {
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_str0("p", "password", "<hex>", "16 byte read password"), arg_str0("p", "pwd", "<hex>", "16 byte read password"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, true); CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIGetHexWithReturn(ctx, 1, pwd, &pwdlen); CLIGetHexWithReturn(ctx, 1, pwd, &pwdlen);
CLIParserFree(ctx);
if (pwdlen == 0) { if (pwdlen == 0) {
with_pwd = false; with_pwd = false;
@ -483,13 +483,10 @@ static int cmd_hf_st_protect(const char *Cmd) {
disable_protection = arg_get_lit(ctx, 2); disable_protection = arg_get_lit(ctx, 2);
read_protection = arg_get_lit(ctx, 3); read_protection = arg_get_lit(ctx, 3);
write_protection = arg_get_lit(ctx, 4); write_protection = arg_get_lit(ctx, 4);
CLIGetHexWithReturn(ctx, 5, pwd, &pwdlen); CLIGetHexWithReturn(ctx, 5, pwd, &pwdlen);
CLIParserFree(ctx); CLIParserFree(ctx);
//Validations //Validations
if (enable_protection && disable_protection) { if (enable_protection && disable_protection) {
PrintAndLogEx(ERR, "Must specify either enable or disable protection, not both"); PrintAndLogEx(ERR, "Must specify either enable or disable protection, not both");
return PM3_EINVARG; 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_read_password = arg_get_lit(ctx, 1);
change_write_password = arg_get_lit(ctx, 2); change_write_password = arg_get_lit(ctx, 2);
CLIGetHexWithReturn(ctx, 3, pwd, &pwdlen); CLIGetHexWithReturn(ctx, 3, pwd, &pwdlen);
CLIGetHexWithReturn(ctx, 4, newpwd, &newpwdlen); CLIGetHexWithReturn(ctx, 4, newpwd, &newpwdlen);
CLIParserFree(ctx);
if (change_read_password && change_write_password) { if (change_read_password && change_write_password) {
PrintAndLogEx(ERR, "Must specify either read or write, not both"); PrintAndLogEx(ERR, "Must specify either read or write, not both");
CLIParserFree(ctx);
return PM3_EINVARG; return PM3_EINVARG;
} else { } else {
if (change_read_password) { if (change_read_password) {
@ -643,8 +638,6 @@ static int cmd_hf_st_pwd(const char *Cmd) {
} }
} }
CLIParserFree(ctx);
if (pwdlen != 16) { if (pwdlen != 16) {
PrintAndLogEx(ERR, "Original write password must be 16 hex bytes"); PrintAndLogEx(ERR, "Original write password must be 16 hex bytes");
return PM3_EINVARG; return PM3_EINVARG;
@ -727,9 +720,7 @@ static int cmd_hf_st_pwd(const char *Cmd) {
return PM3_ESOFT; return PM3_ESOFT;
} }
PrintAndLogEx(SUCCESS, " %s password changed", ((changePwd[2] & 0x01) == 0x01) ? _YELLOW_("read") : _YELLOW_("write")); PrintAndLogEx(SUCCESS, " %s password changed", ((changePwd[2] & 0x01) == 0x01) ? _YELLOW_("read") : _YELLOW_("write"));
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int cmd_hf_st_list(const char *Cmd) { static int cmd_hf_st_list(const char *Cmd) {

View file

@ -29,6 +29,7 @@
#include "cmdparser.h" // command_t #include "cmdparser.h" // command_t
#include "comms.h" #include "comms.h"
#include "commonutil.h" // ARRAYLEN #include "commonutil.h" // ARRAYLEN
#include "cliparser.h"
#include "ui.h" #include "ui.h"
#include "graph.h" #include "graph.h"
#include "cmddata.h" //for g_debugMode, demodbuff cmds #include "cmddata.h" //for g_debugMode, demodbuff cmds
@ -43,70 +44,6 @@
static int CmdHelp(const char *Cmd); 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 <format> [<field> (decimal)>] [up|down] {...}");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : This help");
PrintAndLogEx(NORMAL, " w <format> : see " _YELLOW_("`wiegand list`") " for available formats");
PrintAndLogEx(NORMAL, " f <facility-code> : facility code");
PrintAndLogEx(NORMAL, " c <cardnumber> : card number to start with");
PrintAndLogEx(NORMAL, " i <issuelevel> : issue level");
PrintAndLogEx(NORMAL, " o <oem> : OEM code");
PrintAndLogEx(NORMAL, " d <delay> : 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? // sending three times. Didn't seem to break the previous sim?
static int sendPing(void) { static int sendPing(void) {
SendCommandNG(CMD_PING, NULL, 0); SendCommandNG(CMD_PING, NULL, 0);
@ -276,8 +213,20 @@ static int CmdHIDRead(const char *Cmd) {
// this read loops on device side. // this read loops on device side.
// uses the demod in lfops.c // uses the demod in lfops.c
static int CmdHIDWatch(const char *Cmd) { static int CmdHIDWatch(const char *Cmd) {
uint8_t c = tolower(param_getchar(Cmd, 0)); CLIParserContext *ctx;
if (c == 'h') return usage_lf_hid_watch();
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(SUCCESS, "Watching for HID Prox cards - place tag on antenna");
PrintAndLogEx(INFO, "Press pm3-button to stop reading cards"); 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) { static int CmdHIDSim(const char *Cmd) {
int idlen = 0;
uint8_t id[10] = {0};
lf_hidsim_t payload; lf_hidsim_t payload;
payload.longFMT = 0; payload.longFMT = 0;
uint32_t hi2 = 0, hi = 0, lo = 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)); CLIParserContext *ctx;
if (strlen(Cmd) == 0 || ctmp == 'h') return usage_lf_hid_sim(); CLIParserInit(&ctx, "lf hid sim",
"Enables simulation of HID card with card number.",
"lf hid sim 2006ec0c86"
);
if (strchr(Cmd, 'l') != 0) { void *argtable[] = {
i++; arg_param_begin,
while (sscanf(&Cmd[i++], "%1x", &n) == 1) { arg_lit0("l", "long", "Simulate HID tag with long ID"),
arg_str1(NULL, NULL, "<hex>", "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);
if (long_id) {
for (i=0; i < idlen; ++i) {
hi2 = (hi2 << 4) | (hi >> 28); hi2 = (hi2 << 4) | (hi >> 28);
hi = (hi << 4) | (lo >> 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); PrintAndLogEx(INFO, "Simulating HID tag with long ID: " _GREEN_("%x%08x%08x"), hi2, hi, lo);
payload.longFMT = 1; payload.longFMT = 1;
} else { } else {
while (sscanf(&Cmd[i++], "%1x", &n) == 1) { for (i=0; i < idlen; ++i) {
hi = (hi << 4) | (lo >> 28); 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); PrintAndLogEx(SUCCESS, "Simulating HID tag with ID: " _GREEN_("%x%08x"), hi, lo);
hi2 = 0; hi2 = 0;
@ -334,28 +307,55 @@ static int CmdHIDSim(const char *Cmd) {
} }
static int CmdHIDClone(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 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, "<hex>", "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}; uint8_t longid[1] = {0};
if (strchr(Cmd, 'l') != 0) {
i++; if (long_id) {
while (sscanf(&Cmd[i++], "%1x", &n) == 1) { for (i=0; i < idlen; ++i) {
hi2 = (hi2 << 4) | (hi >> 28); hi2 = (hi2 << 4) | (hi >> 28);
hi = (hi << 4) | (lo >> 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); PrintAndLogEx(INFO, "Preparing to clone HID tag with long ID: " _GREEN_("%x%08x%08x"), hi2, hi, lo);
longid[0] = 1; longid[0] = 1;
} else { } else {
while (sscanf(&Cmd[i++], "%1x", &n) == 1) { for (i=0; i < idlen; ++i) {
hi = (hi << 4) | (lo >> 28); 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); PrintAndLogEx(INFO, "Preparing to clone HID tag with ID: " _GREEN_("%x%08x"), hi, lo);
hi2 = 0; hi2 = 0;
@ -385,82 +385,63 @@ static int CmdHIDClone(const char *Cmd) {
static int CmdHIDBrute(const char *Cmd) { static int CmdHIDBrute(const char *Cmd) {
bool errors = false, verbose = false;
uint32_t delay = 1000; uint32_t delay = 1000;
uint8_t cmdp = 0;
int format_idx = -1; int format_idx = -1;
int direction = 0; int direction = 0;
char format[16] = {0}; uint8_t format[16] = {0};
int formatLen;
wiegand_card_t cn_hi, cn_low; wiegand_card_t cn_hi, cn_low;
memset(&cn_hi, 0, sizeof(wiegand_card_t)); 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"
);
char s[10] = {0}; void *argtable[] = {
if (param_getstr(Cmd, cmdp, s, sizeof(s)) > 0) { arg_param_begin,
if (strlen(s) > 1) { arg_lit0("v", "verbose", "verbose logging, show all tries"),
str_lower((char *)s); arg_str1("w", "wiegand", "format", "see " _YELLOW_("`wiegand list`") " for available formats"),
if (str_startswith(s, "up")) { arg_int0("f", "fn", "dec", "facility code"),
direction = 1; arg_int0("c", "cn", "dec", "card number to start with"),
} else if (str_startswith(s, "do")) { arg_int0("i", NULL, "dec", "issue level"),
direction = 2; arg_int0("o", "oem", "dec", "OEM code"),
} arg_int0("d", "delay", "dec", "delay betweens attempts in ms. Default 1000ms"),
cmdp++; arg_lit0(NULL, "up", "direction to increment card number. (default is both directions)"),
continue; arg_lit0(NULL, "down", "direction to decrement card number. (default is both directions)"),
} arg_param_end
} };
CLIExecWithReturn(ctx, Cmd, argtable, false);
switch (tolower(param_getchar(Cmd, cmdp))) { bool verbose = arg_get_lit(ctx, 1);
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;
}
}
CLIGetStrWithReturn(ctx, 2, format, &formatLen);
format_idx = HIDFindCardFormat((char*) format);
if (format_idx == -1) { if (format_idx == -1) {
PrintAndLogEx(ERR, "You must select a wiegand format. See " _YELLOW_("`wiegand list`") " for available formats\n"); PrintAndLogEx(WARNING, "Unknown format: " _YELLOW_("%s"), format);
errors = true; 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) { if (verbose) {
PrintAndLogEx(INFO, "Wiegand format#.. %i", format_idx); PrintAndLogEx(INFO, "Wiegand format#.. %i", format_idx);

View file

@ -17,6 +17,7 @@
#include "commonutil.h" // ARRAYLEN #include "commonutil.h" // ARRAYLEN
#include "cmdparser.h" // command_t #include "cmdparser.h" // command_t
#include "cliparser.h"
#include "comms.h" #include "comms.h"
#include "ui.h" #include "ui.h"
#include "cmddata.h" #include "cmddata.h"
@ -26,43 +27,6 @@
#include "cmdlft55xx.h" // verifywrite #include "cmdlft55xx.h" // verifywrite
static int CmdHelp(const char *Cmd); 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] <id> <Q5>");
PrintAndLogEx(NORMAL, "Usage extended: lf keri clone [h] t <m|i> [f <fc>] [c <cardnumber>] <Q5>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : This help");
PrintAndLogEx(NORMAL, " <id> : Keri Internal ID");
PrintAndLogEx(NORMAL, " <Q5> : specify writing to Q5/T5555 tag");
// New format
PrintAndLogEx(NORMAL, " <t> [m|i] : Type m - MS, i - Internal ID");
PrintAndLogEx(NORMAL, " <f> <fc> : Facility Code");
PrintAndLogEx(NORMAL, " <c> <cn> : 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] <id>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : This help");
PrintAndLogEx(NORMAL, " <id> : 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; typedef enum {Scramble = 0, Descramble = 1} KeriMSScramble_t;
static int CmdKeriMSScramble(KeriMSScramble_t Action, uint32_t *FC, uint32_t *ID, uint32_t *CardID) { 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) { static int CmdKeriClone(const char *Cmd) {
bool q5 = false; 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 fc = 0;
uint32_t cid = 0; uint32_t cid = 0;
uint32_t internalid = 0; uint32_t internalid = 0;
@ -240,42 +205,35 @@ static int CmdKeriClone(const char *Cmd) {
// dynamic bitrate used // dynamic bitrate used
blocks[0] |= 0xF << 18; blocks[0] |= 0xF << 18;
char cmdp = tolower(param_getchar(Cmd, 0)); CLIParserContext *ctx;
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_keri_clone(); 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 void *argtable[] = {
cid = param_get32ex(Cmd, 0, 0, 10); arg_param_begin,
arg_lit0("q", "q5", "specify writing to Q5/T5555 tag"),
arg_str0("t", "type", "<m|i>", "Type m - MS, i - Internal ID"),
arg_int0(NULL, "fc", "<dec>", "Facility Code"),
arg_int1(NULL, "id", "<dec>", "Keri ID"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
// find other options if (arg_get_lit(ctx, 1)) {
while (param_getchar(Cmd, cmdidx) != 0x00) { // && !errors) { blocks[0] = T5555_FIXED | T5555_MODULATION_PSK1 | T5555_SET_BITRATE(32) | T5555_PSK_RF_2 | 2 << T5555_MAXBLOCK_SHIFT;
switch (tolower(param_getchar(Cmd, cmdidx))) { q5 = true;
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++;
}
} }
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 // Setup card data/build internal id
switch (keritype) { switch (keritype[0]) {
case 'i' : // Internal ID case 'i' : // Internal ID
// MSB is ONE // MSB is ONE
internalid = cid | 0x80000000; internalid = cid | 0x80000000;
@ -283,6 +241,9 @@ static int CmdKeriClone(const char *Cmd) {
case 'm' : // MS case 'm' : // MS
CmdKeriMSScramble(Scramble, &fc, &cid, &internalid); CmdKeriMSScramble(Scramble, &fc, &cid, &internalid);
break; break;
default :
PrintAndLogEx(ERR, "Invalid type");
return PM3_EINVARG;
} }
// Prepare and write to card // Prepare and write to card
@ -303,11 +264,23 @@ static int CmdKeriClone(const char *Cmd) {
static int CmdKeriSim(const char *Cmd) { static int CmdKeriSim(const char *Cmd) {
char cmdp = tolower(param_getchar(Cmd, 0)); CLIParserContext *ctx;
if (strlen(Cmd) == 0 || cmdp == 'h') CLIParserInit(&ctx, "lf keri sim",
return usage_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", "<dec>", "KERI Internal ID"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
uint64_t internalid = arg_get_int_def(ctx, 1, 0);
CLIParserFree(ctx);
uint64_t internalid = param_get32ex(Cmd, 0, 0, 10);
internalid |= 0x80000000; internalid |= 0x80000000;
internalid <<= 3; internalid <<= 3;
internalid += 7; internalid += 7;

View file

@ -13,6 +13,7 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include "cmdparser.h" // command_t #include "cmdparser.h" // command_t
#include "cliparser.h"
#include "comms.h" #include "comms.h"
#include "pm3_cmd.h" #include "pm3_cmd.h"
#include "protocols.h" #include "protocols.h"
@ -24,172 +25,134 @@
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);
static int usage_wiegand_list(void) { static void print_wiegand_code(wiegand_message_t *packed) {
PrintAndLogEx(NORMAL, "List available wiegand formats"); const char* s = "Encoded wiegand: ";
return PM3_SUCCESS;
}
static int usage_wiegand_encode(void) {
PrintAndLogEx(NORMAL, "Encode wiegand formatted number to raw hex");
PrintAndLogEx(NORMAL, "Usage: wiegand encode [w <format>] [<field> <value (decimal)>] {...}");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " w <format> see `wiegand list` for available formats");
PrintAndLogEx(NORMAL, " c <value> card number");
PrintAndLogEx(NORMAL, " f <value> facility code");
PrintAndLogEx(NORMAL, " i <value> issue Level");
PrintAndLogEx(NORMAL, " o <value> 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] <p>");
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) {
if (packed->Top != 0) { if (packed->Top != 0) {
PrintAndLogEx(SUCCESS, "Card ID: %X%08X%08X", PrintAndLogEx(SUCCESS, "%s" _GREEN_("%X%08X%08X"),
(uint32_t)packed->Top, s,
(uint32_t)packed->Mid, (uint32_t)packed->Top,
(uint32_t)packed->Bot) (uint32_t)packed->Mid,
; (uint32_t)packed->Bot
);
} else { } else {
PrintAndLogEx(SUCCESS, "Card ID: %X%08X", PrintAndLogEx(SUCCESS, "%s" _YELLOW_("%X%08X"),
(uint32_t)packed->Mid, s,
(uint32_t)packed->Bot) (uint32_t)packed->Mid,
; (uint32_t)packed->Bot
);
} }
} }
int CmdWiegandList(const char *Cmd) { int CmdWiegandList(const char *Cmd) {
bool errors = false;
char cmdp = 0; CLIParserContext *ctx;
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { CLIParserInit(&ctx, "wiegand info",
switch (tolower(param_getchar(Cmd, cmdp))) { "List available wiegand formats",
case 'h': "wiegand list"
return usage_wiegand_list(); );
default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); void *argtable[] = {
errors = true; arg_param_begin,
break; arg_param_end
} };
} CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIParserFree(ctx);
HIDListFormats(); HIDListFormats();
return PM3_SUCCESS; return PM3_SUCCESS;
} }
int CmdWiegandEncode(const char *Cmd) { int CmdWiegandEncode(const char *Cmd) {
int format_idx = -1; CLIParserContext *ctx;
char format[16] = {0}; 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", "<dec>", "facility number"),
arg_u64_1(NULL, "cn", "<dec>", "card number"),
arg_u64_0(NULL, "issue", "<dec>", "issue level"),
arg_u64_0(NULL, "oem", "<dec>", "OEM code"),
arg_strx1("w", "wiegand", "<format>", "see `wiegand list` for available formats"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
wiegand_card_t data; wiegand_card_t data;
memset(&data, 0, sizeof(wiegand_card_t)); memset(&data, 0, sizeof(wiegand_card_t));
bool errors = false; data.FacilityCode = arg_get_u32_def(ctx, 1, 0);
char cmdp = 0; data.CardNumber = arg_get_u64_def(ctx, 2, 0);
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { data.IssueLevel = arg_get_u32_def(ctx, 3, 0);
switch (tolower(param_getchar(Cmd, cmdp))) { data.OEM = arg_get_u32_def(ctx, 4, 0);
case 'h':
return usage_wiegand_encode(); int len = 0;
case 'w': char format[16] = {0};
param_getstr(Cmd, cmdp + 1, format, sizeof(format)); CLIParamStrToBuf(arg_get_str(ctx, 5), (uint8_t*)format, sizeof(format), &len);
format_idx = HIDFindCardFormat(format); CLIParserFree(ctx);
if (format_idx == -1) {
PrintAndLogEx(WARNING, "Unknown format: %s", format); int idx = HIDFindCardFormat(format);
errors = true; if (idx == -1) {
} PrintAndLogEx(WARNING, "Unknown format: %s", format);
cmdp += 2; return PM3_EINVARG;
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;
}
} }
if (errors || cmdp == 0) return usage_wiegand_encode();
wiegand_message_t packed; wiegand_message_t packed;
memset(&packed, 0, sizeof(wiegand_message_t)); 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."); PrintAndLogEx(WARNING, "The card data could not be encoded in the selected format.");
return PM3_ESOFT; return PM3_ESOFT;
} }
PrintTagId(&packed); print_wiegand_code(&packed);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
int CmdWiegandDecode(const char *Cmd) { int CmdWiegandDecode(const char *Cmd) {
uint32_t top = 0, mid = 0, bot = 0; CLIParserContext *ctx;
bool ignore_parity = false, gothex = false; CLIParserInit(&ctx, "wiegand decode",
bool errors = false; "Decode raw hex to wiegand format",
char cmdp = 0; "wiegand decode --raw 2006f623ae"
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;
if (errors || cmdp < 1) return usage_wiegand_decode(); void *argtable[] = {
arg_param_begin,
arg_lit0("p", "parity", "ignore invalid parity"),
arg_strx1(NULL, "raw", "<hex>", "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); wiegand_message_t packed = initialize_message_object(top, mid, bot);
HIDTryUnpack(&packed, ignore_parity); HIDTryUnpack(&packed, ignore_parity);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static command_t CommandTable[] = { static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"}, {"help", CmdHelp, AlwaysAvailable, "This help"},
{"list", CmdWiegandList, AlwaysAvailable, "List available wiegand formats"}, {"list", CmdWiegandList, AlwaysAvailable, "List available wiegand formats"},
{"encode", CmdWiegandEncode, AlwaysAvailable, "Convert "}, {"encode", CmdWiegandEncode, AlwaysAvailable, "Encode to wiegand raw hex"},
{"decode", CmdWiegandDecode, AlwaysAvailable, "Convert raw hex to wiegand format"}, {"decode", CmdWiegandDecode, AlwaysAvailable, "Convert raw hex to decoded wiegand format"},
{NULL, NULL, NULL, NULL} {NULL, NULL, NULL, NULL}
}; };

View file

@ -27,6 +27,7 @@ void InitGraphics(int argc, char **argv, char *script_cmds_file, char *script_cm
void ExitGraphics(void); void ExitGraphics(void);
extern double CursorScaleFactor; extern double CursorScaleFactor;
extern char CursorScaleFactorUnit[11];
extern int PlotGridX, PlotGridY, PlotGridXdefault, PlotGridYdefault, GridOffset; extern int PlotGridX, PlotGridY, PlotGridXdefault, PlotGridYdefault, GridOffset;
extern uint32_t CursorCPos, CursorDPos; extern uint32_t CursorCPos, CursorDPos;
extern int CommandFinished; extern int CommandFinished;

View file

@ -8,7 +8,7 @@
// GUI (QT) // GUI (QT)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#include "proxguiqt.h" #include "proxguiqt.h"
#include <inttypes.h>
#include <stdbool.h> #include <stdbool.h>
#include <iostream> #include <iostream>
#include <QPainterPath> #include <QPainterPath>
@ -424,7 +424,8 @@ void Plot::PlotGraph(int *buffer, size_t len, QRect plotRect, QRect annotationRe
if (len == 0) return; if (len == 0) return;
// clock_t begin = clock(); // clock_t begin = clock();
QPainterPath penPath; 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; uint32_t i = 0;
int x = xCoordOf(GraphStart, plotRect); int x = xCoordOf(GraphStart, plotRect);
int y = yCoordOf(buffer[GraphStart], plotRect, g_absVMax); 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; if (v > vMax) vMax = v;
vMean += v; vMean += v;
} }
vMean /= (i - GraphStart); GraphStop = i;
vMean /= (GraphStop - GraphStart);
painter->setPen(getColor(graphNum)); painter->setPen(getColor(graphNum));
@ -483,10 +485,9 @@ void Plot::PlotGraph(int *buffer, size_t len, QRect plotRect, QRect annotationRe
//Graph annotations //Graph annotations
painter->drawPath(penPath); painter->drawPath(penPath);
char str[200]; char str[200];
sprintf(str, "max=%d min=%d mean=%d n=%u/%zu CursorAVal=[%d] CursorBVal=[%d]", sprintf(str, "max=%d min=%d mean=%" PRId64 " n=%u/%zu CursorAVal=[%d] CursorBVal=[%d]",
vMax, vMin, vMean, i, len, buffer[CursorAPos], buffer[CursorBPos]); vMax, vMin, vMean, GraphStop - GraphStart, len, buffer[CursorAPos], buffer[CursorBPos]);
painter->drawText(20, annotationRect.bottom() - 23 - 20 * graphNum, str); painter->drawText(20, annotationRect.bottom() - 23 - 20 * graphNum, str);
//clock_t end = clock(); //clock_t end = clock();
//double elapsed_secs = double(end - begin) / CLOCKS_PER_SEC; //double elapsed_secs = double(end - begin) / CLOCKS_PER_SEC;
//printf("Plot time %f\n", elapsed_secs); //printf("Plot time %f\n", elapsed_secs);
@ -596,10 +597,19 @@ void Plot::paintEvent(QPaintEvent *event) {
//Draw annotations //Draw annotations
char str[200]; 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, GraphStart,
GraphStop,
CursorBPos - CursorAPos, CursorBPos - CursorAPos,
((int32_t)(CursorBPos - CursorAPos)) / CursorScaleFactor, scalestr,
GraphPixelsPerPoint, GraphPixelsPerPoint,
CursorAPos, CursorAPos,
CursorBPos, CursorBPos,
@ -637,7 +647,7 @@ void Plot::closeEvent(QCloseEvent *event) {
g_useOverlays = false; g_useOverlays = false;
} }
void Plot::Zoom(float factor, int refX) { void Plot::Zoom(double factor, int refX) {
if (factor >= 1) { // Zoom in if (factor >= 1) { // Zoom in
if (GraphPixelsPerPoint <= 25 * factor) { if (GraphPixelsPerPoint <= 25 * factor) {
GraphPixelsPerPoint *= 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) { void Plot::wheelEvent(QWheelEvent *event) {
// event->delta() // event->delta()
// 120 => shift right 5% // 120 => shift right 5%
// -120 => shift left 5% // -120 => shift left 5%
const float move_offset = 0.05; const float move_offset = 0.05;
// -120+shift => zoom in 10% // -120+shift => zoom in (5 times = *2)
// 120+shift => zoom out 10% // 120+shift => zoom out (5 times = /2)
const float zoom_offset = 0.1; const double zoom_offset = 1.148698354997035; // 2**(1/5)
if (event->modifiers() & Qt::ShiftModifier) { 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 // 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 #if QT_VERSION >= 0x050d00
@ -697,10 +731,15 @@ void Plot::wheelEvent(QWheelEvent *event) {
x += GraphStart; 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 // 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 #if QT_VERSION >= 0x050d00
Zoom(1.0 - (float)event->angleDelta().y() / (120 / zoom_offset), x); float delta = event->angleDelta().y();
#else #else
Zoom(1.0 - (float)event->delta() / (120 / zoom_offset), x); float delta = event->delta();
#endif #endif
if (delta < 0) {
Zoom(zoom_offset, x);
} else {
Zoom(1.0 / zoom_offset, x);
}
} else { } else {
#if QT_VERSION >= 0x050d00 #if QT_VERSION >= 0x050d00
Move(PageWidth * (-(float)event->angleDelta().y() / (120 / move_offset))); Move(PageWidth * (-(float)event->angleDelta().y() / (120 / move_offset)));
@ -794,6 +833,7 @@ void Plot::keyPressEvent(QKeyEvent *event) {
puts("\tH Show help"); puts("\tH Show help");
puts("\tL Toggle lock grid relative to samples"); puts("\tL Toggle lock grid relative to samples");
puts("\tQ Hide window"); 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("\tHOME Move to the start of the graph");
puts("\tEND Move to the end of the graph"); puts("\tEND Move to the end of the graph");
puts("\tPGUP Page left"); puts("\tPGUP Page left");
@ -823,6 +863,10 @@ void Plot::keyPressEvent(QKeyEvent *event) {
master->hide(); master->hide();
break; break;
case Qt::Key_T:
Trim();
break;
case Qt::Key_Home: case Qt::Key_Home:
GraphStart = 0; GraphStart = 0;
break; break;

View file

@ -32,6 +32,7 @@ class Plot: public QWidget {
private: private:
QWidget *master; QWidget *master;
uint32_t GraphStart; // Starting point/offset for the left side of the graph 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) double GraphPixelsPerPoint; // How many visual pixels are between each sample point (x axis)
uint32_t CursorAPos; uint32_t CursorAPos;
uint32_t CursorBPos; uint32_t CursorBPos;
@ -50,8 +51,9 @@ class Plot: public QWidget {
protected: protected:
void paintEvent(QPaintEvent *event); void paintEvent(QPaintEvent *event);
void closeEvent(QCloseEvent *event); void closeEvent(QCloseEvent *event);
void Zoom(float factor, int refX); void Zoom(double factor, int refX);
void Move(int offset); void Move(int offset);
void Trim(void);
void wheelEvent(QWheelEvent *event); void wheelEvent(QWheelEvent *event);
void mouseMoveEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event);
void mousePressEvent(QMouseEvent *event) { mouseMoveEvent(event); } void mousePressEvent(QMouseEvent *event) { mouseMoveEvent(event); }

View file

@ -38,6 +38,7 @@
session_arg_t session; session_arg_t session;
double CursorScaleFactor = 1; double CursorScaleFactor = 1;
char CursorScaleFactorUnit[11] = {0};
int PlotGridX = 0, PlotGridY = 0, PlotGridXdefault = 64, PlotGridYdefault = 64; int PlotGridX = 0, PlotGridY = 0, PlotGridXdefault = 64, PlotGridYdefault = 64;
uint32_t CursorCPos = 0, CursorDPos = 0; uint32_t CursorCPos = 0, CursorDPos = 0;
double GraphPixelsPerPoint = 1.f; // How many visual pixels are between each sample point (x axis) double GraphPixelsPerPoint = 1.f; // How many visual pixels are between each sample point (x axis)

View file

@ -332,23 +332,25 @@ Convert Site & Facility code to Wiegand raw hex
``` ```
Options Options
--- ---
w <format> o <OEM> f <FC> c <CN> i <issuelevel> -w <format> --oem <OEM> --fc <FC> --cn <CN> --issue <issuelevel>
w : wiegand format to use
o : OEM number / site code
f : facility code
c : card number
i : issue level
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 Convert Site & Facility code from Wiegand raw hex to numbers
``` ```
Options 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 ## HID Prox
@ -379,14 +381,18 @@ Brute force HID reader
``` ```
Options Options
--- ---
a <format> : 26|33|34|35|37|40|44|84 -v, --verbose : verbose logging, show all tries
f <facility-code> : 8-bit value HID facility code -w, --wiegand format : see `wiegand list` for available formats
c <cardnumber> : (optional) cardnumber to start with, max 65535 -f, --fn dec : facility code
d <delay> : delay betweens attempts in ms. Default 1000ms -c, --cn dec : card number to start with
v : verbose logging, show all tries -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 -w H10301 -f 224
pm3 --> lf hid brute v a 26 f 21 c 200 d 2000 pm3 --> lf hid brute -v -w H10301 -f 21 -c 200 -d 2000
``` ```
## Indala ## Indala
@ -552,7 +558,7 @@ pm3 --> script list
View lua helptext View lua helptext
``` ```
pm3 --> script run <nameofscript> -h pm3 --> script run <nameofscript> -h
``` ```
@ -595,15 +601,15 @@ Load default keys into flash memory (RDV4 only)
``` ```
Options Options
--- ---
o <offset> : offset in memory -o <offset> : offset in memory
f <filename> : file name -f <filename> : file name
m : upload 6 bytes keys (mifare key dictionary) --mfc : upload 6 bytes keys (mifare key dictionary)
i : upload 8 bytes keys (iClass key dictionary) --iclass : upload 8 bytes keys (iClass key dictionary)
t : upload 4 bytes keys (pwd dictionary) --t55xx : upload 4 bytes keys (pwd dictionary)
pm3 --> mem load f mfc_default_keys m pm3 --> mem load -f mfc_default_keys --mfc
pm3 --> mem load f t55xx_default_pwds t pm3 --> mem load -f t55xx_default_pwds --t5xx
pm3 --> mem load f iclass_default_keys i pm3 --> mem load -f iclass_default_keys --iclass
``` ```
## Sim Module ## Sim Module

View file

@ -25,14 +25,14 @@ And then it fell into silence since it wasn't well documented how to use the cli
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. 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) ![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 ## cliparser setup and use
@ -45,7 +45,7 @@ It will also add the `-h --help` option automatic.
* where possible all options should be lowercase. * where possible all options should be lowercase.
* extended options preceded with -- should be short * extended options preceded with -- should be short
* options provided directly (without an option identifier) should be avoided. * options provided directly (without an option identifier) should be avoided.
* -vv for extra verbos should be avoided; use of debug level is preferred. * -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 '=' * with --options the equal is not needed (will work with and without) so don't use '='
e.g. cmd --cn 12345 e.g. cmd --cn 12345
@ -59,7 +59,7 @@ It will also add the `-h --help` option automatic.
--raw : raw data --raw : raw data
-k --key : key supplied -k --key : key supplied
-n --keyno : key number to use -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 -1 --buffer : use the sample buffer
@ -77,7 +77,7 @@ In the command function, setup the context
### define the context ### define the context
CLIParserInit (\<context\>, \<description\>, \<notes\n examples ... \>); `CLIParserInit (\<context\>, \<description\>, \<notes\n examples ... \>);`
use -> to separate example and example comment and \\n to separate examples. use -> to separate example and example comment and \\n to separate examples.
e.g. lf indala clone -r a0000000a0002021 -> this uses ..... e.g. lf indala clone -r a0000000a0002021 -> this uses .....
@ -103,43 +103,59 @@ 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. _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:** ### Notes:
**bool option. true if supplied** #### bool option. true if supplied
bool : arg_lit0 ("\<short option\>", "\<long option\>", \["\<format\>",\] \<"description"\>) `bool : arg_lit0 ("<short option>", "<long option>", <"description">)`
**integer that is optional** #### integer that is optional
optional integer : arg_int0 ("\<short option\>", "\<long option\>", \["\<format\>",\] \<"description"\>) `optional integer : arg_int0 ("<short option>", "<long option>", "<format>", <"description">)`
**integer that is required** #### integer that is required
required integer : arg_int1 ("\<short option\>", "\<long option\>", \["\<format\>",\] \<"description"\>) `required integer : arg_int1 ("<short option>", "<long option>", "<format>", <"description">)`
**String option that is optional and only one instance can be provided** #### double that is optional
optional string : arg_str0("\<short option\>", "\<long option\>", \["\<format\>",\] \<"description"\>) `optional double : arg_dbl0 ("<short option>", "<long option>", "<format>", <"description">)`
**String option that is required and only one instance can be provided** #### double that is required
required string : arg_str1("\<short option\>", "\<long option\>", \["\<format\>",\] \<"description"\>) `required double : arg_dbl1 ("<short option>", "<long option>", "<format>", <"description">)`
**String option that is optional and can have up to 250 instances provided** #### String option that is optional and only one instance can be provided
optional string : arg_strx0 ("\<short option\>", "\<long option\>", \["\<format\>",\] \<"description"\>) `optional string : arg_str0 ("<short option>", "<long option>", "<format>", <"description">)`
#### String option that is required and only one instance can be provided
`required string : arg_str1 ("<short option>", "<long option>", "<format>", <"description">)`
#### String option that is optional and can have up to 250 instances provided
`optional string : arg_strx0 ("<short option>", "<long option>", "<format>", <"description">)`
#### String option that is required/at least one instance and can have up to 250 instances
`required string : arg_strx1 ("<short option>", "<long option>", "<format>", <"description">)`
Unsigned values, like u32 and u64 can be accomplished with
#### unsigned integer optional
`optional unsigned : arg_u64_0 ("<short option>", "<long option>", "<format>", <"description">)`
#### unsigned integer required
`required unsigned : arg_u64_1 ("<short option>", "<long option>", "<format>", <"description">)`
**String option that is required/at least one instance and can have up to 250 instances**
required string : arg_strx1 ("\<short option\>", "\<long option\>", \["\<format\>",\] \<"description"\>)
**if an option does not have a short or long option, use NULL in its place** **if an option does not have a short or long option, use NULL in its place**
### show the menu ### show the menu
CLIExecWithReturn(\<context\>, \<command line to parse\>, \<arg/opt table\>, \<return on error\>); `CLIExecWithReturn(\<context\>, \<command line to parse\>, \<arg/opt table\>, \<return on error\>);`
CLIExecWithReturn(ctx, Cmd, argtable, false); CLIExecWithReturn(ctx, Cmd, argtable, false);
### clean up ### clean up
Once you have extracted the options, cleanup the context. 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. The parser will format and color and layout as needed.
@ -156,6 +172,18 @@ arg_get_int_def(\<context\>, \<opt index\>, \<default value\>);
cardnumber = arg_get_int_def(ctx, 2, -1); cardnumber = arg_get_int_def(ctx, 2, -1);
**uint32**
arg_get_u32_def(\<context\>, \<opt index\>, \<default value\>);
cardnumber = arg_get_u32_def(ctx, 2, 0);
**uint64**
arg_get_u64_def(\<context\>, \<opt index\>, \<default value\>);
cardnumber = arg_get_u64_def(ctx, 2, 0);
**hex option** **hex option**
CLIGetHexWithReturn(\<context\>, \<opt index\>, \<store variable\>, \<ptr to stored length\>); CLIGetHexWithReturn(\<context\>, \<opt index\>, \<store variable\>, \<ptr to stored length\>);
?? as an array of uint_8 ?? ?? as an array of uint_8 ??

View file

@ -38,6 +38,7 @@ typedef enum ISO14B_COMMAND {
ISO14B_SET_TIMEOUT = (1 << 8), ISO14B_SET_TIMEOUT = (1 << 8),
ISO14B_SEND_CHAINING = (1 << 9), ISO14B_SEND_CHAINING = (1 << 9),
ISO14B_SELECT_CTS = (1 << 10), ISO14B_SELECT_CTS = (1 << 10),
ISO14B_CLEARTRACE = (1 << 11),
} iso14b_command_t; } iso14b_command_t;
#endif // _ISO14B_H_ #endif // _ISO14B_H_

View file

@ -32,7 +32,7 @@ lf hid clone 2006ec0c86
lf read s 10000 lf read s 10000
data save f lf_t5577_hid data save f lf_t5577_hid
lf hid clone l 2006ec0c86 lf hid clone -l 2006ec0c86
lf read s 20000 lf read s 20000
data save f lf_t5577_hid_84 data save f lf_t5577_hid_84
@ -56,15 +56,15 @@ lf jablotron clone 112233
lf read s 16000 lf read s 16000
data save f lf_t5577_jablotron data save f lf_t5577_jablotron
lf keri clone 112233 lf keri clone --id 112233
lf read s 10000 lf read s 10000
data save f lf_t5577_keri 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 lf read s 10000
data save f lf_t5577_keri_internalid 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 lf read s 10000
data save f lf_t5577_keri_msid data save f lf_t5577_keri_msid