mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-21 05:43:48 -07:00
commit
46fe7d1292
139 changed files with 25421 additions and 23275 deletions
1
.lsan_suppressions
Normal file
1
.lsan_suppressions
Normal file
|
@ -0,0 +1 @@
|
|||
leak:libfontconfig.so
|
29
Makefile
29
Makefile
|
@ -248,7 +248,7 @@ print-%: ; @echo $* = $($*)
|
|||
style:
|
||||
# Make sure astyle is installed
|
||||
@which astyle >/dev/null || ( echo "Please install 'astyle' package first" ; exit 1 )
|
||||
# Remove spaces & tabs at EOL, add LF at EOF if needed on *.c, *.h, *.cpp. *.lua, *.py, *.pl, Makefile
|
||||
# Remove spaces & tabs at EOL, add LF at EOF if needed on *.c, *.h, *.cpp. *.lua, *.py, *.pl, Makefile, *.v
|
||||
find . \( -not -path "./cov-int/*" -and -not -path "./fpga/xst/*" -and \( -name "*.[ch]" -or \( -name "*.cpp" -and -not -name "*.moc.cpp" \) -or -name "*.lua" -or -name "*.py" -or -name "*.pl" -or -name "Makefile" -or -name "*.v" \) \) \
|
||||
-exec perl -pi -e 's/[ \t]+$$//' {} \; \
|
||||
-exec sh -c "tail -c1 {} | xxd -p | tail -1 | grep -q -v 0a$$" \; \
|
||||
|
@ -259,23 +259,32 @@ style:
|
|||
--keep-one-line-blocks --max-instatement-indent=60 \
|
||||
--style=google --pad-oper --unpad-paren --pad-header \
|
||||
--align-pointer=name {} \;
|
||||
# Update commands.md
|
||||
[ -x client/proxmark3 ] && client/proxmark3 -m > doc/commands.md
|
||||
|
||||
# Detecting weird codepages and tabs.
|
||||
ifeq ($(platform),Darwin)
|
||||
miscchecks: TABSCMD=egrep -l '\t' {}
|
||||
else
|
||||
miscchecks: TABSCMD=grep -lP '\t' {}
|
||||
endif
|
||||
ifneq (,$(EDIT))
|
||||
miscchecks: TABSCMD+= && vi {} -c ':set tabstop=4' -c ':set et|retab' -c ':wq'
|
||||
endif
|
||||
miscchecks:
|
||||
# Make sure recode is installed
|
||||
# Make sure recode is installed
|
||||
@which recode >/dev/null || ( echo "Please install 'recode' package first" ; exit 1 )
|
||||
@echo "Files with suspicious chars:"
|
||||
@find . \( -name "*.[ch]" -or -name "*.cpp" -or -name "*.lua" -or -name "*.py" -or -name "*.pl" -or -name "Makefile" -or -name "*.v" \) \
|
||||
@find . \( -not -path "./cov-int/*" -and -not -path "./client/deps/*" -and \( -name "*.[ch]" -or -name "*.cpp" -or -name "*.lua" -or -name "*.py" -or -name "*.pl" -or -name "Makefile" -or -name "*.v" \) \) \
|
||||
-exec sh -c "cat {} |recode utf8.. >/dev/null || echo {}" \;
|
||||
@echo "Files with tabs:"
|
||||
# to remove tabs within lines, one can try with: vi $file -c ':set tabstop=4' -c ':set et|retab' -c ':wq'
|
||||
ifeq ($(platform),Darwin)
|
||||
@find . \( -name "*.[ch]" -or \( -name "*.cpp" -and -not -name "*.moc.cpp" \) -or -name "*.lua" -or -name "*.py" -or -name "*.pl" -or -name "*.md" -or -name "*.txt" -or -name "*.awk" -or -name "*.v" \) \
|
||||
-exec egrep -l '\t' {} \;
|
||||
ifneq (,$(EDIT))
|
||||
@echo "Files with tabs: (EDIT enabled, files will be rewritten!)"
|
||||
else
|
||||
@find . \( -name "*.[ch]" -or \( -name "*.cpp" -and -not -name "*.moc.cpp" \) -or -name "*.lua" -or -name "*.py" -or -name "*.pl" -or -name "*.md" -or -name "*.txt" -or -name "*.awk" -or -name "*.v" \) \
|
||||
-exec grep -lP '\t' {} \;
|
||||
@echo "Files with tabs: (rerun with EDIT=1 if you want to convert them with vim)"
|
||||
endif
|
||||
# to remove tabs within lines, one can try with: vi $file -c ':set tabstop=4' -c ':set et|retab' -c ':wq'
|
||||
@find . \( -not -path "./cov-int/*" -and -not -path "./client/deps/*" -and \( -name "*.[ch]" -or \( -name "*.cpp" -and -not -name "*.moc.cpp" \) -or -name "*.lua" -or -name "*.py" -or -name "*.pl" -or -name "*.md" -or -name "*.txt" -or -name "*.awk" -or -name "*.v" \) \) \
|
||||
-exec sh -c "$(TABSCMD)" \;
|
||||
# @echo "Files with printf \\\\t:"
|
||||
# @find . \( -name "*.[ch]" -or \( -name "*.cpp" -and -not -name "*.moc.cpp" \) -or -name "*.lua" -or -name "*.py" -or -name "*.pl" -or -name "*.md" -or -name "*.txt" -or -name "*.awk" -or -name "*.v" \) \
|
||||
# -exec grep -lP '\\t' {} \;
|
||||
|
|
|
@ -50,6 +50,13 @@ endif
|
|||
|
||||
DEFCXXFLAGS = -Wall -Werror -O3 -pipe
|
||||
DEFCFLAGS = -Wall -Werror -O3 -fstrict-aliasing -pipe
|
||||
DEFLDFLAGS =
|
||||
# Next ones are activated only if SANITIZE=1
|
||||
ifeq ($(SANITIZE),1)
|
||||
DEFCFLAGS += -g -fsanitize=address -fno-omit-frame-pointer
|
||||
DEFCXXFLAGS += -g -fsanitize=address -fno-omit-frame-pointer
|
||||
DEFLDFLAGS += -g -fsanitize=address
|
||||
endif
|
||||
# Some more warnings we want as errors:
|
||||
DEFCFLAGS += -Wbad-function-cast -Wredundant-decls -Wmissing-prototypes -Wchar-subscripts -Wshadow -Wundef -Wwrite-strings -Wunused -Wuninitialized -Wpointer-arith -Winline -Wformat -Wformat-security -Winit-self -Wmissing-include-dirs -Wnested-externs -Wmissing-declarations -Wempty-body -Wignored-qualifiers -Wmissing-field-initializers -Wtype-limits -Wold-style-definition
|
||||
# Some more warnings we need first to eliminate, so temporarely tolerated:
|
||||
|
|
|
@ -19,6 +19,7 @@ CFLAGS ?= $(DEFCFLAGS)
|
|||
CFLAGS += $(MYDEFS) $(MYCFLAGS) $(MYINCLUDES)
|
||||
CXXFLAGS ?= $(DEFCXXFLAGS)
|
||||
CXXFLAGS += $(MYDEFS) $(MYCXXFLAGS) $(MYINCLUDES)
|
||||
LDFLAGS ?= $(DEFLDFLAGS)
|
||||
LDFLAGS += $(MYLDFLAGS)
|
||||
LDLIBS += $(MYLDLIBS)
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
| ------------------- |:-------------------:| -------------------:|
|
||||
|[Notes on UART](/doc/uart_notes.md)|[Notes on Termux / Android](/doc/termux_notes.md)|[Notes on paths](/doc/path_notes.md)|
|
||||
|[Notes on frame format](/doc/new_frame_format.md)|[Notes on tracelog / wireshark](/doc/trace_notes.md)|[Notes on EMV](/doc/emv_notes.md)|
|
||||
|[Notes on external flash](/doc/ext_flash_notes.md)|[Notes on loclass](/doc/loclass_notes.md)|[Notes on Coverity Scan Config & Run](/doc/md/Development/Coverity-Scan-Config-%26-Run.md)|
|
||||
|[Notes on external flash](/doc/ext_flash_notes.md)|[Notes on loclass](/doc/loclass_notes.md)|[Notes on Coverity Scan Config & Run](/doc/md/Development/Coverity-Scan-Config-and-Run.md)|
|
||||
|[Notes on file formats used with Proxmark3](/doc/extensions_notes.md)|[Notes on MFU binary format](/doc/mfu_binary_format_notes.md)|[Notes on FPGA & ARM](/doc/fpga_arm_notes.md)|
|
||||
|[Developing standalone mode](/armsrc/Standalone/readme.md)|[Wiki about standalone mode](https://github.com/RfidResearchGroup/proxmark3/wiki/Standalone-mode)|[Notes on Magic cards](/doc/magic_cards_notes.md)|
|
||||
|[Notes on Color usage](/doc/colors_notes.md)|[Makefile vs CMake](/doc/md/Development/Makefile-vs-CMake.md)|[Notes on Cloner guns](/doc/cloner_notes.md)|
|
||||
|
@ -57,7 +57,7 @@ On the software side: quite a lot, see the [Changelog file](CHANGELOG.md).
|
|||
|
||||
This repo compiles nicely on
|
||||
- Proxspace v3.x
|
||||
- [latest release v3.6](https://github.com/Gator96100/ProxSpace/releases)
|
||||
- [latest release v3.7](https://github.com/Gator96100/ProxSpace/releases)
|
||||
- Windows/mingw environment with Qt5.6.1 & GCC 4.9
|
||||
- Ubuntu 16.04 -> 20.04
|
||||
- ParrotOS, Gentoo, Pentoo, Kali, Nethunter, Archlinux, Fedora, Debian
|
||||
|
|
31
appveyor.yml
31
appveyor.yml
|
@ -2,14 +2,14 @@ version: 3.0.1.{build}
|
|||
image: Visual Studio 2019
|
||||
clone_folder: C:\ProxSpace\pm3\proxmark
|
||||
cache:
|
||||
- C:\cache -> appveyor.yml
|
||||
- C:\ps-cache -> appveyor.yml
|
||||
environment:
|
||||
proxspace_url: https://github.com/Gator96100/ProxSpace/archive/master.zip
|
||||
proxspace_zip_file: \proxspace.zip
|
||||
proxspace_zip_folder_name: ProxSpace-*
|
||||
proxspace_path: C:\ProxSpace
|
||||
proxspace_home_path: \ProxSpace\pm3
|
||||
proxspace_cache_path: C:\cache
|
||||
proxspace_cache_path: C:\ps-cache
|
||||
wsl_git_path: C:\proxmark
|
||||
APPVEYOR_SAVE_CACHE_ON_ERROR: true
|
||||
|
||||
|
@ -29,7 +29,6 @@ init:
|
|||
|
||||
$releasename+=$env:APPVEYOR_BUILD_VERSION + " [" + $env:APPVEYOR_REPO_COMMIT_SHORT + "]"
|
||||
|
||||
|
||||
Write-Host "repository: $env:appveyor_repo_name branch:$env:APPVEYOR_REPO_BRANCH release: $releasename" -ForegroundColor Yellow
|
||||
|
||||
Add-AppveyorMessage -Message "[$env:APPVEYOR_REPO_COMMIT_SHORT]$env:appveyor_repo_name($env:APPVEYOR_REPO_BRANCH)" -Category Information -Details "repository: $env:appveyor_repo_name branch: $env:APPVEYOR_REPO_BRANCH release: $releasename"
|
||||
|
@ -68,6 +67,7 @@ clone_script:
|
|||
WSLExec "WSL install..." "sudo apt-get -y install --reinstall --no-install-recommends git ca-certificates build-essential pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev libbz2-dev qtbase5-dev cmake 1>/dev/null"
|
||||
WSLExec "WSL QT fix..." "sudo strip --remove-section=.note.ABI-tag /usr/lib/x86_64-linux-gnu/libQt5Core.so.5"
|
||||
Add-AppveyorMessage -Message "WSL setup took $(([System.Environment]::TickCount-$WSLInstallTime) / 1000) sec" -Category Information
|
||||
New-Item -ItemType "file" -Path "C:\WSL-Finished.txt" -Force | Out-Null
|
||||
}
|
||||
|
||||
$env:PSInstallTime=[System.Environment]::TickCount
|
||||
|
@ -154,8 +154,9 @@ install:
|
|||
}
|
||||
|
||||
Start-Sleep -s 5
|
||||
Receive-Job -Name WSLInstall
|
||||
Receive-Job -Name WSLInstall -ErrorAction SilentlyContinue
|
||||
}
|
||||
#Receive-Job -Wait -Name PSInstall
|
||||
}
|
||||
|
||||
Function GitClone($Text, $Folder) {
|
||||
|
@ -175,7 +176,9 @@ install:
|
|||
|
||||
Write-Host "ProxSpace: move cache..." -NoNewLine
|
||||
|
||||
Move-Item -Path "$env:proxspace_cache_path" -Destination "$env:proxspace_path\msys2\var\cache" -Force -ErrorAction SilentlyContinue
|
||||
New-Item -ItemType Directory -Force -Path "$env:proxspace_path\msys2\var\cache\" | Out-Null
|
||||
|
||||
Copy-Item -Path "$env:proxspace_cache_path\*" -Destination "$env:proxspace_path\msys2\var\cache\" -Force -Recurse -ErrorAction SilentlyContinue
|
||||
|
||||
Write-Host "[ OK ]" -ForegroundColor Gree
|
||||
|
||||
|
@ -212,6 +215,7 @@ build_script:
|
|||
|
||||
$WSLjob = Start-Job -Name WSLCompile -ScriptBlock {
|
||||
Function ExecWSLCmd($Cmd) {
|
||||
cd $env:wsl_git_path
|
||||
wsl -- bash -c $Cmd
|
||||
}
|
||||
|
||||
|
@ -231,11 +235,17 @@ build_script:
|
|||
}
|
||||
|
||||
#WSL: wait for installation to finish
|
||||
Receive-Job -Wait -Name WSLInstall
|
||||
if(!(Test-Path "C:\WSL-Finished.txt")){
|
||||
Write-Host "Waiting for WSL installation to finish..." -NoNewLine
|
||||
while(!(Test-Path "C:\WSL-Finished.txt")) {
|
||||
Start-Sleep -s 5
|
||||
}
|
||||
Remove-Item -Force "C:\WSL-Finished.txt" -ErrorAction SilentlyContinue
|
||||
Write-Host "$Name [ OK ]" -ForegroundColor Green
|
||||
}
|
||||
|
||||
#Windows Subsystem for Linux (WSL)
|
||||
Write-Host "---------- WSL make ----------" -ForegroundColor Yellow
|
||||
cd $env:wsl_git_path
|
||||
$TestTime=[System.Environment]::TickCount
|
||||
ExecWSLCmd "make clean;make V=1"
|
||||
#some checks
|
||||
|
@ -266,7 +276,9 @@ build_script:
|
|||
|
||||
Write-Host "ProxSpace: create new cache..." -NoNewLine
|
||||
|
||||
ExecMinGWCmd 'yes | pacman -Sc > /dev/null 2>&1'
|
||||
cd $env:proxspace_path
|
||||
|
||||
./runme64.bat -c "yes | pacman -Sc > /dev/null 2>&1"
|
||||
|
||||
Remove-Item -Recurse -Force -Path "$env:proxspace_cache_path" -ErrorAction SilentlyContinue
|
||||
|
||||
|
@ -316,8 +328,9 @@ build_script:
|
|||
|
||||
ExecCheck "PS cmake Tests"
|
||||
|
||||
Receive-Job -Wait -Job $WSLjob
|
||||
Receive-Job -Wait -Name WSLInstall -ErrorAction SilentlyContinue
|
||||
|
||||
Receive-Job -Wait -Job $WSLjob
|
||||
|
||||
test_script:
|
||||
- ps: >-
|
||||
|
|
|
@ -147,14 +147,18 @@ void RunMod(void) {
|
|||
int state = STATE_SEARCH;
|
||||
|
||||
DbpString("Scanning...");
|
||||
int button_pressed = BUTTON_NO_CLICK;
|
||||
for (;;) {
|
||||
// Was our button held down or pressed?
|
||||
int button_pressed = BUTTON_HELD(1000);
|
||||
button_pressed = BUTTON_HELD(1000);
|
||||
|
||||
if (button_pressed != BUTTON_NO_CLICK || data_available())
|
||||
break;
|
||||
else if (state == STATE_SEARCH) {
|
||||
if (!iso14443a_select_card(NULL, &card, NULL, true, 0, true)) {
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
LED_D_OFF();
|
||||
SpinDelay(500);
|
||||
continue;
|
||||
} else {
|
||||
if (card.sak == SAK && card.atqa[0] == ATQA0 && card.atqa[1] == ATQA1 && card.uidlen == 7) {
|
||||
|
@ -245,6 +249,8 @@ void RunMod(void) {
|
|||
state = STATE_SEARCH;
|
||||
}
|
||||
}
|
||||
if (button_pressed == BUTTON_HOLD) //Holding down the button
|
||||
break;
|
||||
}
|
||||
|
||||
DbpString("exiting");
|
||||
|
|
|
@ -484,22 +484,18 @@ failtag:
|
|||
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
|
||||
SpinOff(50);
|
||||
LED_A_ON();
|
||||
uint8_t ticker = 0;
|
||||
|
||||
while (!iso14443a_select_card(cjuid, &p_card, &cjcuid, true, 0, true)) {
|
||||
WDT_HIT();
|
||||
|
||||
ticker++;
|
||||
if (ticker % 64 == 0) {
|
||||
LED_A_INV();
|
||||
}
|
||||
|
||||
if (BUTTON_HELD(10) == BUTTON_HOLD) {
|
||||
WDT_HIT();
|
||||
DbprintfEx(FLAG_NEWLINE, "\t\t\t[ READING FLASH ]");
|
||||
ReadLastTagFromFlash();
|
||||
goto readysim;
|
||||
}
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
SpinDelay(500);
|
||||
LED_A_INV();
|
||||
}
|
||||
|
||||
SpinOff(50);
|
||||
|
|
|
@ -125,7 +125,7 @@ static void download_instructions(uint8_t t) {
|
|||
case ICE_STATE_FULLSIM: {
|
||||
DbpString("The emulator memory was saved to SPIFFS");
|
||||
DbpString("1. " _YELLOW_("mem spiffs dump o " HF_ICLASS_FULLSIM_MOD_BIN " f " HF_ICLASS_FULLSIM_MOD" e"));
|
||||
DbpString("2. " _YELLOW_("hf iclass view f " HF_ICLASS_FULLSIM_MOD_BIN));
|
||||
DbpString("2. " _YELLOW_("hf iclass view -f " HF_ICLASS_FULLSIM_MOD_BIN));
|
||||
break;
|
||||
}
|
||||
case ICE_STATE_ATTACK: {
|
||||
|
|
|
@ -575,4 +575,5 @@ void RunMod(void) {
|
|||
}
|
||||
}
|
||||
}
|
||||
LEDsoff();
|
||||
}
|
||||
|
|
|
@ -305,6 +305,8 @@ void RunMod(void) {
|
|||
DbpString("\n"_YELLOW_("!!") "Waiting for a card reader...");
|
||||
}
|
||||
}
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
LED_D_OFF();
|
||||
} else if (state == STATE_EMU) {
|
||||
LED_A_OFF();
|
||||
LED_C_ON();
|
||||
|
|
|
@ -54,7 +54,7 @@ void RunMod(void) {
|
|||
for (;;) {
|
||||
WDT_HIT();
|
||||
// exit from Standalone Mode, send a usbcommand.
|
||||
if (data_available()) return;
|
||||
if (data_available()) break;
|
||||
|
||||
SpinDelay(300);
|
||||
|
||||
|
@ -72,7 +72,7 @@ void RunMod(void) {
|
|||
|
||||
for (;;) {
|
||||
// exit from Standalone Mode, send a usbcommand.
|
||||
if (data_available()) return;
|
||||
if (data_available()) break;
|
||||
|
||||
if (BUTTON_PRESS()) {
|
||||
if (cardRead[selected]) {
|
||||
|
@ -89,6 +89,9 @@ void RunMod(void) {
|
|||
}
|
||||
|
||||
if (!iso14443a_select_card(NULL, &card[selected], NULL, true, 0, true)) {
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
LED_D_OFF();
|
||||
SpinDelay(500);
|
||||
continue;
|
||||
} else {
|
||||
Dbprintf("Read UID:");
|
||||
|
@ -220,7 +223,7 @@ void RunMod(void) {
|
|||
DbpString("Playing");
|
||||
for (; ;) {
|
||||
// exit from Standalone Mode, send a usbcommand.
|
||||
if (data_available()) return;
|
||||
if (data_available()) break;
|
||||
|
||||
int button_pressed = BUTTON_HELD(1000);
|
||||
if (button_pressed == BUTTON_NO_CLICK) { // No button action, proceed with sim
|
||||
|
@ -277,4 +280,6 @@ void RunMod(void) {
|
|||
LED(selected + 1, 0);
|
||||
}
|
||||
}
|
||||
DbpString(_YELLOW_("[=]") "exiting");
|
||||
LEDsoff();
|
||||
}
|
||||
|
|
|
@ -68,6 +68,24 @@ extern uint32_t _stack_start, _stack_end;
|
|||
struct common_area common_area __attribute__((section(".commonarea")));
|
||||
static int button_status = BUTTON_NO_CLICK;
|
||||
static bool allow_send_wtx = false;
|
||||
static uint16_t tearoff_delay_us = 0;
|
||||
static bool tearoff_enabled = false;
|
||||
|
||||
int tearoff_hook(void) {
|
||||
if (tearoff_enabled) {
|
||||
if (tearoff_delay_us == 0) {
|
||||
Dbprintf(_RED_("No tear-off delay configured!"));
|
||||
return PM3_SUCCESS; // SUCCESS = the hook didn't do anything
|
||||
}
|
||||
SpinDelayUsPrecision(tearoff_delay_us);
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
tearoff_enabled = false;
|
||||
Dbprintf(_YELLOW_("Tear-off triggered!"));
|
||||
return PM3_ETEAROFF;
|
||||
} else {
|
||||
return PM3_SUCCESS; // SUCCESS = the hook didn't do anything
|
||||
}
|
||||
}
|
||||
|
||||
void send_wtx(uint16_t wtx) {
|
||||
if (allow_send_wtx) {
|
||||
|
@ -731,6 +749,24 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
reply_ng(CMD_SET_DBGMODE, PM3_SUCCESS, NULL, 0);
|
||||
break;
|
||||
}
|
||||
case CMD_SET_TEAROFF: {
|
||||
struct p {
|
||||
uint16_t delay_us;
|
||||
bool on;
|
||||
bool off;
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *)packet->data.asBytes;
|
||||
if (payload->on && payload->off)
|
||||
reply_ng(CMD_SET_TEAROFF, PM3_EINVARG, NULL, 0);
|
||||
if (payload->on)
|
||||
tearoff_enabled = true;
|
||||
if (payload->off)
|
||||
tearoff_enabled = false;
|
||||
if (payload->delay_us > 0)
|
||||
tearoff_delay_us = payload->delay_us;
|
||||
reply_ng(CMD_SET_TEAROFF, PM3_SUCCESS, NULL, 0);
|
||||
break;
|
||||
}
|
||||
// always available
|
||||
case CMD_HF_DROPFIELD: {
|
||||
hf_field_off();
|
||||
|
@ -827,7 +863,8 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
break;
|
||||
}
|
||||
case CMD_LF_HID_CLONE: {
|
||||
CopyHIDtoT55x7(packet->oldarg[0], packet->oldarg[1], packet->oldarg[2], packet->data.asBytes[0]);
|
||||
lf_hidsim_t *payload = (lf_hidsim_t *)packet->data.asBytes;
|
||||
CopyHIDtoT55x7(payload->hi2, payload->hi, payload->lo, payload->longFMT);
|
||||
break;
|
||||
}
|
||||
case CMD_LF_IO_WATCH: {
|
||||
|
@ -954,6 +991,16 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
EM4xWriteWord(payload->address, payload->data, payload->password, payload->usepwd);
|
||||
break;
|
||||
}
|
||||
case CMD_LF_EM4X_PROTECTWORD: {
|
||||
struct p {
|
||||
uint32_t password;
|
||||
uint32_t data;
|
||||
uint8_t usepwd;
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *) packet->data.asBytes;
|
||||
EM4xProtectWord(payload->data, payload->password, payload->usepwd);
|
||||
break;
|
||||
}
|
||||
case CMD_LF_AWID_WATCH: {
|
||||
uint32_t high, low;
|
||||
int res = lf_awid_watch(0, &high, &low);
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
extern int g_rsamples; // = 0;
|
||||
extern uint8_t g_trigger;
|
||||
|
||||
int tearoff_hook(void);
|
||||
|
||||
// ADC Vref = 3300mV, and an (10M+1M):1M voltage divider on the HF input can measure voltages up to 36300 mV
|
||||
#define MAX_ADC_HF_VOLTAGE 36300
|
||||
// ADC Vref = 3300mV, (240k-10M):240k voltage divider, 140800 mV
|
||||
|
|
|
@ -134,11 +134,36 @@ static hf14a_config hf14aconfig = { 0, 0, 0, 0, 0 } ;
|
|||
|
||||
void printHf14aConfig(void) {
|
||||
DbpString(_CYAN_("HF 14a config"));
|
||||
Dbprintf("[a] Anticol override......%i: %s%s%s", hf14aconfig.forceanticol, (hf14aconfig.forceanticol == 0) ? _GREEN_("No") " (follow standard)" : "", (hf14aconfig.forceanticol == 1) ? _RED_("Yes: Always do anticol") : "", (hf14aconfig.forceanticol == 2) ? _RED_("Yes: Always skip anticol") : "");
|
||||
Dbprintf("[b] BCC override..........%i: %s%s%s", hf14aconfig.forcebcc, (hf14aconfig.forcebcc == 0) ? _GREEN_("No") " (follow standard)" : "", (hf14aconfig.forcebcc == 1) ? _RED_("Yes: Always do CL2") : "", (hf14aconfig.forcebcc == 2) ? _RED_("Yes: Always use card BCC") : "");
|
||||
Dbprintf("[2] CL2 override..........%i: %s%s%s", hf14aconfig.forcecl2, (hf14aconfig.forcecl2 == 0) ? _GREEN_("No") " (follow standard)" : "", (hf14aconfig.forcecl2 == 1) ? _RED_("Yes: Always do CL2") : "", (hf14aconfig.forcecl2 == 2) ? _RED_("Yes: Always skip CL2") : "");
|
||||
Dbprintf("[3] CL3 override..........%i: %s%s%s", hf14aconfig.forcecl3, (hf14aconfig.forcecl3 == 0) ? _GREEN_("No") " (follow standard)" : "", (hf14aconfig.forcecl3 == 1) ? _RED_("Yes: Always do CL3") : "", (hf14aconfig.forcecl3 == 2) ? _RED_("Yes: Always skip CL3") : "");
|
||||
Dbprintf("[r] RATS override.........%i: %s%s%s", hf14aconfig.forcerats, (hf14aconfig.forcerats == 0) ? _GREEN_("No") " (follow standard)" : "", (hf14aconfig.forcerats == 1) ? _RED_("Yes: Always do RATS") : "", (hf14aconfig.forcerats == 2) ? _RED_("Yes: Always skip RATS") : "");
|
||||
Dbprintf(" [a] Anticol override....%i %s%s%s",
|
||||
hf14aconfig.forceanticol,
|
||||
(hf14aconfig.forceanticol == 0) ? "( " _GREEN_("No") " ) follow standard " : "",
|
||||
(hf14aconfig.forceanticol == 1) ? "( " _RED_("Yes") " ) always do anticol" : "",
|
||||
(hf14aconfig.forceanticol == 2) ? "( " _RED_("Yes") " ) always skip anticol" : ""
|
||||
);
|
||||
Dbprintf(" [b] BCC override........%i %s%s%s",
|
||||
hf14aconfig.forcebcc,
|
||||
(hf14aconfig.forcebcc == 0) ? "( " _GREEN_("No") " ) follow standard" : "",
|
||||
(hf14aconfig.forcebcc == 1) ? "( " _RED_("Yes") " ) always do CL2" : "",
|
||||
(hf14aconfig.forcebcc == 2) ? "( " _RED_("Yes") " ) always use card BCC" : ""
|
||||
);
|
||||
Dbprintf(" [2] CL2 override........%i %s%s%s",
|
||||
hf14aconfig.forcecl2,
|
||||
(hf14aconfig.forcecl2 == 0) ? "( " _GREEN_("No") " ) follow standard" : "",
|
||||
(hf14aconfig.forcecl2 == 1) ? "( " _RED_("Yes") " ) always do CL2" : "",
|
||||
(hf14aconfig.forcecl2 == 2) ? "( " _RED_("Yes") " ) always skip CL2" : ""
|
||||
);
|
||||
Dbprintf(" [3] CL3 override........%i %s%s%s",
|
||||
hf14aconfig.forcecl3,
|
||||
(hf14aconfig.forcecl3 == 0) ? "( " _GREEN_("No") " ) follow standard" : "",
|
||||
(hf14aconfig.forcecl3 == 1) ? "( " _RED_("Yes") " ) always do CL3" : "",
|
||||
(hf14aconfig.forcecl3 == 2) ? "( " _RED_("Yes") " ) always skip CL3" : ""
|
||||
);
|
||||
Dbprintf(" [r] RATS override.......%i %s%s%s",
|
||||
hf14aconfig.forcerats,
|
||||
(hf14aconfig.forcerats == 0) ? "( " _GREEN_("No") " q follow standard " : "",
|
||||
(hf14aconfig.forcerats == 1) ? "( " _RED_("Yes") " ) always do RATS" : "",
|
||||
(hf14aconfig.forcerats == 2) ? "( " _RED_("Yes") " ) always skip RATS" : ""
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -752,26 +752,26 @@ static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) {
|
|||
// The soft decision on the bit uses an estimate of just the
|
||||
// quadrant of the reference angle, not the exact angle.
|
||||
#define MAKE_SOFT_DECISION() { \
|
||||
if(Demod.sumI > 0) { \
|
||||
v = ci; \
|
||||
} else { \
|
||||
v = -ci; \
|
||||
} \
|
||||
if(Demod.sumQ > 0) { \
|
||||
v += cq; \
|
||||
} else { \
|
||||
v -= cq; \
|
||||
} \
|
||||
}
|
||||
if(Demod.sumI > 0) { \
|
||||
v = ci; \
|
||||
} else { \
|
||||
v = -ci; \
|
||||
} \
|
||||
if(Demod.sumQ > 0) { \
|
||||
v += cq; \
|
||||
} else { \
|
||||
v -= cq; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define SUBCARRIER_DETECT_THRESHOLD 8
|
||||
#define SUBCARRIER_DETECT_THRESHOLD 8
|
||||
// Subcarrier amplitude v = sqrt(ci^2 + cq^2), approximated here by max(abs(ci),abs(cq)) + 1/2*min(abs(ci),abs(cq)))
|
||||
#define AMPLITUDE(ci,cq) (MAX(ABS(ci),ABS(cq)) + (MIN(ABS(ci),ABS(cq))/2))
|
||||
|
||||
switch (Demod.state) {
|
||||
|
||||
case DEMOD_UNSYNCD: {
|
||||
if (AMPLITUDE(ci, cq) > SUBCARRIER_DETECT_THRESHOLD) { // subcarrier detected
|
||||
if (AMPLITUDE(ci, cq) > SUBCARRIER_DETECT_THRESHOLD) { // subcarrier detected
|
||||
Demod.state = DEMOD_PHASE_REF_TRAINING;
|
||||
Demod.sumI = ci;
|
||||
Demod.sumQ = cq;
|
||||
|
@ -783,7 +783,7 @@ static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) {
|
|||
// While we get a constant signal
|
||||
if (AMPLITUDE(ci, cq) > SUBCARRIER_DETECT_THRESHOLD) {
|
||||
if (((ABS(Demod.sumI) > ABS(Demod.sumQ)) && (((ci > 0) && (Demod.sumI > 0)) || ((ci < 0) && (Demod.sumI < 0)))) || // signal closer to horizontal, polarity check based on on I
|
||||
((ABS(Demod.sumI) <= ABS(Demod.sumQ)) && (((cq > 0) && (Demod.sumQ > 0)) || ((cq < 0) && (Demod.sumQ < 0))))) { // signal closer to vertical, polarity check based on on Q
|
||||
((ABS(Demod.sumI) <= ABS(Demod.sumQ)) && (((cq > 0) && (Demod.sumQ > 0)) || ((cq < 0) && (Demod.sumQ < 0))))) { // signal closer to vertical, polarity check based on on Q
|
||||
|
||||
if (Demod.posCount < 10) { // refine signal approximation during first 10 samples
|
||||
Demod.sumI += ci;
|
||||
|
@ -799,7 +799,7 @@ static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) {
|
|||
} else {
|
||||
// at this point it can be start of 14b' data or start of 14b SOF
|
||||
MAKE_SOFT_DECISION();
|
||||
Demod.posCount = 1; // this was the first half
|
||||
Demod.posCount = 1; // this was the first half
|
||||
Demod.thisBit = v;
|
||||
Demod.shiftReg = 0;
|
||||
Demod.state = DEMOD_RECEIVING_DATA;
|
||||
|
@ -815,7 +815,7 @@ static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) {
|
|||
Demod.posCount++;
|
||||
MAKE_SOFT_DECISION();
|
||||
if (v > 0) {
|
||||
if (Demod.posCount > 3 * 2) { // max 19us between characters = 16 1/fs, max 3 etu after low phase of SOF = 24 1/fs
|
||||
if (Demod.posCount > 3 * 2) { // max 19us between characters = 16 1/fs, max 3 etu after low phase of SOF = 24 1/fs
|
||||
LED_C_OFF();
|
||||
if (Demod.bitCount == 0 && Demod.len == 0) { // received SOF only, this is valid for iClass/Picopass
|
||||
return true;
|
||||
|
@ -823,8 +823,8 @@ static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) {
|
|||
Demod.state = DEMOD_UNSYNCD;
|
||||
}
|
||||
}
|
||||
} else { // start bit detected
|
||||
Demod.posCount = 1; // this was the first half
|
||||
} else { // start bit detected
|
||||
Demod.posCount = 1; // this was the first half
|
||||
Demod.thisBit = v;
|
||||
Demod.shiftReg = 0;
|
||||
Demod.state = DEMOD_RECEIVING_DATA;
|
||||
|
@ -857,14 +857,14 @@ static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) {
|
|||
|
||||
MAKE_SOFT_DECISION();
|
||||
|
||||
if (Demod.posCount == 0) { // first half of bit
|
||||
if (Demod.posCount == 0) { // first half of bit
|
||||
Demod.thisBit = v;
|
||||
Demod.posCount = 1;
|
||||
} else { // second half of bit
|
||||
} else { // second half of bit
|
||||
Demod.thisBit += v;
|
||||
|
||||
Demod.shiftReg >>= 1;
|
||||
if (Demod.thisBit > 0) { // logic '1'
|
||||
if (Demod.thisBit > 0) { // logic '1'
|
||||
Demod.shiftReg |= 0x200;
|
||||
}
|
||||
|
||||
|
@ -996,7 +996,7 @@ static int Get14443bAnswerFromTag(uint8_t *response, uint16_t max_len, int timeo
|
|||
|
||||
if (Handle14443bSamplesFromTag(ci, cq)) {
|
||||
|
||||
*eof_time = dma_start_time + (samples ) - DELAY_TAG_TO_ARM; // end of EOF
|
||||
*eof_time = dma_start_time + (samples) - DELAY_TAG_TO_ARM; // end of EOF
|
||||
|
||||
if (Demod.len > Demod.max_len) {
|
||||
ret = -2; // overflow
|
||||
|
@ -1854,7 +1854,7 @@ void SendRawCommand14443B_Ex(PacketCommandNG *c) {
|
|||
int status;
|
||||
uint32_t sendlen = sizeof(iso14b_card_select_t);
|
||||
iso14b_card_select_t card;
|
||||
memset((void*)&card, 0x00, sizeof(card));
|
||||
memset((void *)&card, 0x00, sizeof(card));
|
||||
|
||||
if ((param & ISO14B_SELECT_STD) == ISO14B_SELECT_STD) {
|
||||
status = iso14443b_select_card(&card);
|
||||
|
|
|
@ -1883,112 +1883,112 @@ void LockPassSlixIso15693(uint32_t pass_id, uint32_t password) {
|
|||
|
||||
LED_A_ON();
|
||||
|
||||
uint8_t cmd_inventory[] = {ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_INVENTORY | ISO15693_REQINV_SLOT1, 0x01, 0x00, 0x00, 0x00 };
|
||||
uint8_t cmd_get_rnd[] = {ISO15693_REQ_DATARATE_HIGH, 0xB2, 0x04, 0x00, 0x00 };
|
||||
uint8_t cmd_set_pass[] = {ISO15693_REQ_DATARATE_HIGH, 0xB3, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
//uint8_t cmd_write_pass[] = {ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_ADDRESS, 0xB4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
uint8_t cmd_lock_pass[] = {ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_ADDRESS, 0xB5, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00 };
|
||||
uint16_t crc;
|
||||
int recvlen = 0;
|
||||
uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH];
|
||||
uint32_t start_time = 0;
|
||||
bool done = false;
|
||||
uint8_t cmd_inventory[] = {ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_INVENTORY | ISO15693_REQINV_SLOT1, 0x01, 0x00, 0x00, 0x00 };
|
||||
uint8_t cmd_get_rnd[] = {ISO15693_REQ_DATARATE_HIGH, 0xB2, 0x04, 0x00, 0x00 };
|
||||
uint8_t cmd_set_pass[] = {ISO15693_REQ_DATARATE_HIGH, 0xB3, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
//uint8_t cmd_write_pass[] = {ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_ADDRESS, 0xB4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
uint8_t cmd_lock_pass[] = {ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_ADDRESS, 0xB5, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00 };
|
||||
uint16_t crc;
|
||||
int recvlen = 0;
|
||||
uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH];
|
||||
uint32_t start_time = 0;
|
||||
bool done = false;
|
||||
|
||||
// setup 'get random number' command
|
||||
crc = Iso15693Crc(cmd_get_rnd, 3);
|
||||
cmd_get_rnd[3] = crc & 0xff;
|
||||
cmd_get_rnd[4] = crc >> 8;
|
||||
// setup 'get random number' command
|
||||
crc = Iso15693Crc(cmd_get_rnd, 3);
|
||||
cmd_get_rnd[3] = crc & 0xff;
|
||||
cmd_get_rnd[4] = crc >> 8;
|
||||
|
||||
Dbprintf("LockPass: Press button lock password, long-press to terminate.");
|
||||
Dbprintf("LockPass: Press button lock password, long-press to terminate.");
|
||||
|
||||
while (!done) {
|
||||
while (!done) {
|
||||
|
||||
LED_D_ON();
|
||||
switch(BUTTON_HELD(1000)) {
|
||||
case BUTTON_SINGLE_CLICK:
|
||||
Dbprintf("LockPass: Reset 'DONE'-LED (A)");
|
||||
LED_A_OFF();
|
||||
LED_B_OFF();
|
||||
LED_C_OFF();
|
||||
break;
|
||||
case BUTTON_HOLD:
|
||||
Dbprintf("LockPass: Terminating");
|
||||
done = true;
|
||||
break;
|
||||
default:
|
||||
SpinDelay(50);
|
||||
continue;
|
||||
}
|
||||
LED_D_ON();
|
||||
switch(BUTTON_HELD(1000)) {
|
||||
case BUTTON_SINGLE_CLICK:
|
||||
Dbprintf("LockPass: Reset 'DONE'-LED (A)");
|
||||
LED_A_OFF();
|
||||
LED_B_OFF();
|
||||
LED_C_OFF();
|
||||
break;
|
||||
case BUTTON_HOLD:
|
||||
Dbprintf("LockPass: Terminating");
|
||||
done = true;
|
||||
break;
|
||||
default:
|
||||
SpinDelay(50);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (done) [
|
||||
break;
|
||||
}
|
||||
if (done) [
|
||||
break;
|
||||
}
|
||||
|
||||
recvlen = SendDataTag(cmd_get_rnd, sizeof(cmd_get_rnd), true, true, recvbuf, sizeof(recvbuf), start_time);
|
||||
if (recvlen != 5) {
|
||||
LED_C_ON();
|
||||
} else {
|
||||
Dbprintf("LockPass: Received random 0x%02X%02X (%d)", recvbuf[1], recvbuf[2], recvlen);
|
||||
recvlen = SendDataTag(cmd_get_rnd, sizeof(cmd_get_rnd), true, true, recvbuf, sizeof(recvbuf), start_time);
|
||||
if (recvlen != 5) {
|
||||
LED_C_ON();
|
||||
} else {
|
||||
Dbprintf("LockPass: Received random 0x%02X%02X (%d)", recvbuf[1], recvbuf[2], recvlen);
|
||||
|
||||
// setup 'set password' command
|
||||
cmd_set_pass[4] = ((password>>0) &0xFF) ^ recvbuf[1];
|
||||
cmd_set_pass[5] = ((password>>8) &0xFF) ^ recvbuf[2];
|
||||
cmd_set_pass[6] = ((password>>16) &0xFF) ^ recvbuf[1];
|
||||
cmd_set_pass[7] = ((password>>24) &0xFF) ^ recvbuf[2];
|
||||
// setup 'set password' command
|
||||
cmd_set_pass[4] = ((password>>0) &0xFF) ^ recvbuf[1];
|
||||
cmd_set_pass[5] = ((password>>8) &0xFF) ^ recvbuf[2];
|
||||
cmd_set_pass[6] = ((password>>16) &0xFF) ^ recvbuf[1];
|
||||
cmd_set_pass[7] = ((password>>24) &0xFF) ^ recvbuf[2];
|
||||
|
||||
crc = Iso15693Crc(cmd_set_pass, 8);
|
||||
cmd_set_pass[8] = crc & 0xff;
|
||||
cmd_set_pass[9] = crc >> 8;
|
||||
crc = Iso15693Crc(cmd_set_pass, 8);
|
||||
cmd_set_pass[8] = crc & 0xff;
|
||||
cmd_set_pass[9] = crc >> 8;
|
||||
|
||||
Dbprintf("LockPass: Sending old password to end privacy mode", cmd_set_pass[4], cmd_set_pass[5], cmd_set_pass[6], cmd_set_pass[7]);
|
||||
recvlen = SendDataTag(cmd_set_pass, sizeof(cmd_set_pass), false, true, recvbuf, sizeof(recvbuf), start_time);
|
||||
if (recvlen != 3) {
|
||||
Dbprintf("LockPass: Failed to set password (%d)", recvlen);
|
||||
LED_B_ON();
|
||||
} else {
|
||||
crc = Iso15693Crc(cmd_inventory, 3);
|
||||
cmd_inventory[3] = crc & 0xff;
|
||||
cmd_inventory[4] = crc >> 8;
|
||||
Dbprintf("LockPass: Sending old password to end privacy mode", cmd_set_pass[4], cmd_set_pass[5], cmd_set_pass[6], cmd_set_pass[7]);
|
||||
recvlen = SendDataTag(cmd_set_pass, sizeof(cmd_set_pass), false, true, recvbuf, sizeof(recvbuf), start_time);
|
||||
if (recvlen != 3) {
|
||||
Dbprintf("LockPass: Failed to set password (%d)", recvlen);
|
||||
LED_B_ON();
|
||||
} else {
|
||||
crc = Iso15693Crc(cmd_inventory, 3);
|
||||
cmd_inventory[3] = crc & 0xff;
|
||||
cmd_inventory[4] = crc >> 8;
|
||||
|
||||
Dbprintf("LockPass: Searching for tag...");
|
||||
recvlen = SendDataTag(cmd_inventory, sizeof(cmd_inventory), false, true, recvbuf, sizeof(recvbuf), start_time);
|
||||
if (recvlen != 12) {
|
||||
Dbprintf("LockPass: Failed to read inventory (%d)", recvlen);
|
||||
LED_B_ON();
|
||||
LED_C_ON();
|
||||
} else {
|
||||
Dbprintf("LockPass: Searching for tag...");
|
||||
recvlen = SendDataTag(cmd_inventory, sizeof(cmd_inventory), false, true, recvbuf, sizeof(recvbuf), start_time);
|
||||
if (recvlen != 12) {
|
||||
Dbprintf("LockPass: Failed to read inventory (%d)", recvlen);
|
||||
LED_B_ON();
|
||||
LED_C_ON();
|
||||
} else {
|
||||
|
||||
Dbprintf("LockPass: Answer from %02X%02X%02X%02X%02X%02X%02X%02X", recvbuf[9], recvbuf[8], recvbuf[7], recvbuf[6], recvbuf[5], recvbuf[4], recvbuf[3], recvbuf[2]);
|
||||
Dbprintf("LockPass: Answer from %02X%02X%02X%02X%02X%02X%02X%02X", recvbuf[9], recvbuf[8], recvbuf[7], recvbuf[6], recvbuf[5], recvbuf[4], recvbuf[3], recvbuf[2]);
|
||||
|
||||
memcpy(&cmd_lock_pass[3], &recvbuf[2], 8);
|
||||
memcpy(&cmd_lock_pass[3], &recvbuf[2], 8);
|
||||
|
||||
cmd_lock_pass[8+3] = pass_id;
|
||||
cmd_lock_pass[8+3] = pass_id;
|
||||
|
||||
crc = Iso15693Crc(cmd_lock_pass, 8+4);
|
||||
cmd_lock_pass[8+4] = crc & 0xff;
|
||||
cmd_lock_pass[8+5] = crc >> 8;
|
||||
crc = Iso15693Crc(cmd_lock_pass, 8+4);
|
||||
cmd_lock_pass[8+4] = crc & 0xff;
|
||||
cmd_lock_pass[8+5] = crc >> 8;
|
||||
|
||||
Dbprintf("LockPass: locking to password 0x%02X%02X%02X%02X for ID %02X", cmd_set_pass[4], cmd_set_pass[5], cmd_set_pass[6], cmd_set_pass[7], pass_id);
|
||||
Dbprintf("LockPass: locking to password 0x%02X%02X%02X%02X for ID %02X", cmd_set_pass[4], cmd_set_pass[5], cmd_set_pass[6], cmd_set_pass[7], pass_id);
|
||||
|
||||
recvlen = SendDataTag(cmd_lock_pass, sizeof(cmd_lock_pass), false, true, recvbuf, sizeof(recvbuf), start_time);
|
||||
if (recvlen != 3) {
|
||||
Dbprintf("LockPass: Failed to lock password (%d)", recvlen);
|
||||
} else {
|
||||
Dbprintf("LockPass: Successful (%d)", recvlen);
|
||||
}
|
||||
LED_A_ON();
|
||||
}
|
||||
} }
|
||||
}
|
||||
recvlen = SendDataTag(cmd_lock_pass, sizeof(cmd_lock_pass), false, true, recvbuf, sizeof(recvbuf), start_time);
|
||||
if (recvlen != 3) {
|
||||
Dbprintf("LockPass: Failed to lock password (%d)", recvlen);
|
||||
} else {
|
||||
Dbprintf("LockPass: Successful (%d)", recvlen);
|
||||
}
|
||||
LED_A_ON();
|
||||
}
|
||||
} }
|
||||
}
|
||||
|
||||
Dbprintf("LockPass: Finishing");
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
Dbprintf("LockPass: Finishing");
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
|
||||
cmd_send(CMD_ACK, recvlen, 0, 0, recvbuf, recvlen);
|
||||
LED_A_OFF();
|
||||
LED_B_OFF();
|
||||
LED_C_OFF();
|
||||
LED_D_OFF();
|
||||
cmd_send(CMD_ACK, recvlen, 0, 0, recvbuf, recvlen);
|
||||
LED_A_OFF();
|
||||
LED_B_OFF();
|
||||
LED_C_OFF();
|
||||
LED_D_OFF();
|
||||
}
|
||||
*/
|
||||
|
||||
|
|
|
@ -2369,6 +2369,7 @@ int copy_em410x_to_t55xx(uint8_t card, uint8_t clock, uint32_t id_hi, uint32_t i
|
|||
#define FWD_CMD_LOGIN 0xC
|
||||
#define FWD_CMD_WRITE 0xA
|
||||
#define FWD_CMD_READ 0x9
|
||||
#define FWD_CMD_PROTECT 0x3
|
||||
#define FWD_CMD_DISABLE 0x5
|
||||
|
||||
static uint8_t forwardLink_data[64]; //array of forwarded bits
|
||||
|
@ -2572,14 +2573,61 @@ void EM4xWriteWord(uint8_t addr, uint32_t data, uint32_t pwd, uint8_t usepwd) {
|
|||
|
||||
SendForward(len);
|
||||
|
||||
// Wait 20ms for write to complete?
|
||||
WaitMS(7);
|
||||
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured
|
||||
StopTicks();
|
||||
reply_ng(CMD_LF_EM4X_WRITEWORD, PM3_ETEAROFF, NULL, 0);
|
||||
} else {
|
||||
// Wait 20ms for write to complete?
|
||||
// No, when write is denied, err preamble comes much sooner
|
||||
//WaitUS(10820); // tPC+tWEE
|
||||
|
||||
DoPartialAcquisition(20, false, 6000, 1000);
|
||||
DoPartialAcquisition(0, false, 6000, 1000);
|
||||
|
||||
StopTicks();
|
||||
StopTicks();
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
reply_ng(CMD_LF_EM4X_WRITEWORD, PM3_SUCCESS, NULL, 0);
|
||||
}
|
||||
LEDsoff();
|
||||
}
|
||||
|
||||
void EM4xProtectWord(uint32_t data, uint32_t pwd, uint8_t usepwd) {
|
||||
|
||||
StartTicks();
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
reply_ng(CMD_LF_EM4X_WRITEWORD, PM3_SUCCESS, NULL, 0);
|
||||
WaitMS(50);
|
||||
|
||||
LED_A_ON();
|
||||
|
||||
// clear buffer now so it does not interfere with timing later
|
||||
BigBuf_Clear_ext(false);
|
||||
|
||||
/* should we read answer from Logincommand?
|
||||
*
|
||||
* should receive
|
||||
* 0000 1010 ok.
|
||||
* 0000 0001 fail
|
||||
**/
|
||||
if (usepwd) EM4xLogin(pwd);
|
||||
|
||||
forward_ptr = forwardLink_data;
|
||||
uint8_t len = Prepare_Cmd(FWD_CMD_PROTECT);
|
||||
len += Prepare_Data(data & 0xFFFF, data >> 16);
|
||||
|
||||
SendForward(len);
|
||||
|
||||
if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured
|
||||
StopTicks();
|
||||
reply_ng(CMD_LF_EM4X_PROTECTWORD, PM3_ETEAROFF, NULL, 0);
|
||||
} else {
|
||||
// Wait 20ms for write to complete?
|
||||
// No, when write is denied, err preamble comes much sooner
|
||||
//WaitUS(13640); // tPC+tPR
|
||||
|
||||
DoPartialAcquisition(0, false, 6000, 1000);
|
||||
StopTicks();
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
reply_ng(CMD_LF_EM4X_PROTECTWORD, PM3_SUCCESS, NULL, 0);
|
||||
}
|
||||
LEDsoff();
|
||||
}
|
||||
|
||||
|
|
|
@ -58,6 +58,7 @@ void TurnReadLFOn(uint32_t delay);
|
|||
|
||||
void EM4xReadWord(uint8_t addr, uint32_t pwd, uint8_t usepwd);
|
||||
void EM4xWriteWord(uint8_t addr, uint32_t data, uint32_t pwd, uint8_t usepwd);
|
||||
void EM4xProtectWord(uint32_t data, uint32_t pwd, uint8_t usepwd);
|
||||
|
||||
void Cotag(uint32_t arg0);
|
||||
void setT55xxConfig(uint8_t arg0, t55xx_configurations_t *c);
|
||||
|
|
|
@ -2702,25 +2702,24 @@ void MifareU_Otp_Tearoff(uint8_t arg0, uint32_t arg1, uint8_t *datain) {
|
|||
uint8_t data_testwrite[4] = {0x00};
|
||||
memcpy(data_fullwrite, datain, 4);
|
||||
memcpy(data_testwrite, datain + 4, 4);
|
||||
// optional authentication before?
|
||||
|
||||
if (DBGLEVEL >= DBG_ERROR) DbpString("Preparing OTP tear-off");
|
||||
if (DBGLEVEL >= DBG_DEBUG) DbpString("Preparing OTP tear-off");
|
||||
|
||||
if (tearOffTime > 43000)
|
||||
tearOffTime = 43000;
|
||||
|
||||
MifareUWriteBlock(blockNo, 0, data_fullwrite);
|
||||
|
||||
LEDsoff();
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
|
||||
clear_trace();
|
||||
set_tracing(true);
|
||||
|
||||
StartTicks();
|
||||
|
||||
// write cmd to send, include CRC
|
||||
// 1b write, 1b block, 4b data, 2 crc
|
||||
uint8_t cmd[] = {MIFARE_ULC_WRITE, blockNo, data_testwrite[0], data_testwrite[1], data_testwrite[2], data_testwrite[3], 0, 0};
|
||||
|
||||
MifareUWriteBlock(blockNo, 0, data_fullwrite);
|
||||
|
||||
AddCrc14A(cmd, sizeof(cmd) - 2);
|
||||
if (DBGLEVEL >= DBG_ERROR) DbpString("Transmitting");
|
||||
|
||||
// anticollision / select card
|
||||
if (!iso14443a_select_card(NULL, NULL, NULL, true, 0, true)) {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card");
|
||||
|
@ -2732,11 +2731,10 @@ void MifareU_Otp_Tearoff(uint8_t arg0, uint32_t arg1, uint8_t *datain) {
|
|||
|
||||
// Wait before cutting power. aka tear-off
|
||||
LED_D_ON();
|
||||
WaitUS(tearOffTime);
|
||||
|
||||
SpinDelayUsPrecision(tearOffTime);
|
||||
if (DBGLEVEL >= DBG_DEBUG) Dbprintf(_YELLOW_("OTP tear-off triggered!"));
|
||||
switch_off();
|
||||
|
||||
reply_ng(CMD_HF_MFU_OTP_TEAROFF, PM3_SUCCESS, NULL, 0);
|
||||
StopTicks();
|
||||
|
||||
if (DBGLEVEL >= DBG_ERROR) DbpString("Done");
|
||||
}
|
||||
|
|
|
@ -13,6 +13,31 @@
|
|||
#include "proxmark3_arm.h"
|
||||
#include "dbprint.h"
|
||||
|
||||
|
||||
// timer counts in 666ns increments (32/48MHz), rounding applies
|
||||
// WARNING: timer can't measure more than 43ms (666ns * 0xFFFF)
|
||||
void SpinDelayUsPrecision(int us) {
|
||||
int ticks = ((MCK / 1000000) * us + 16) >> 5;
|
||||
|
||||
// Borrow a PWM unit for my real-time clock
|
||||
AT91C_BASE_PWMC->PWMC_ENA = PWM_CHANNEL(0);
|
||||
|
||||
// 48 MHz / 32 gives 1.5 Mhz
|
||||
AT91C_BASE_PWMC_CH0->PWMC_CMR = PWM_CH_MODE_PRESCALER(5); // Channel Mode Register
|
||||
AT91C_BASE_PWMC_CH0->PWMC_CDTYR = 0; // Channel Duty Cycle Register
|
||||
AT91C_BASE_PWMC_CH0->PWMC_CPRDR = 0xFFFF; // Channel Period Register
|
||||
|
||||
uint16_t start = AT91C_BASE_PWMC_CH0->PWMC_CCNTR;
|
||||
|
||||
for (;;) {
|
||||
uint16_t now = AT91C_BASE_PWMC_CH0->PWMC_CCNTR;
|
||||
if (now == (uint16_t)(start + ticks))
|
||||
return;
|
||||
|
||||
WDT_HIT();
|
||||
}
|
||||
}
|
||||
|
||||
// timer counts in 21.3us increments (1024/48MHz), rounding applies
|
||||
// WARNING: timer can't measure more than 1.39s (21.3us * 0xffff)
|
||||
void SpinDelayUs(int us) {
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
void SpinDelay(int ms);
|
||||
void SpinDelayUs(int us);
|
||||
void SpinDelayUsPrecision(int us); // precision 0.6us , running for 43ms before
|
||||
|
||||
void StartTickCount(void);
|
||||
uint32_t RAMFUNC GetTickCount(void);
|
||||
|
|
|
@ -248,7 +248,7 @@ set (TARGET_SOURCES
|
|||
${PM3_ROOT}/client/src/cmdlfcotag.c
|
||||
${PM3_ROOT}/client/src/cmdlfem4x.c
|
||||
${PM3_ROOT}/client/src/cmdlfem4x50.c
|
||||
${PM3_ROOT}/client/src/cmdlffdx.c
|
||||
${PM3_ROOT}/client/src/cmdlffdxb.c
|
||||
${PM3_ROOT}/client/src/cmdlfgallagher.c
|
||||
${PM3_ROOT}/client/src/cmdlfguard.c
|
||||
${PM3_ROOT}/client/src/cmdlfhid.c
|
||||
|
|
|
@ -309,6 +309,7 @@ ifeq ($(QT_FOUND),1)
|
|||
endif
|
||||
endif
|
||||
|
||||
LDFLAGS ?= $(DEFLDFLAGS)
|
||||
PM3LDFLAGS = $(LDFLAGS)
|
||||
ifeq ($(platform),Darwin)
|
||||
PM3LDFLAGS += -framework Foundation -framework AppKit
|
||||
|
@ -442,7 +443,7 @@ SRCS = aidsearch.c \
|
|||
cmdlfcotag.c \
|
||||
cmdlfem4x.c \
|
||||
cmdlfem4x50.c \
|
||||
cmdlffdx.c \
|
||||
cmdlffdxb.c \
|
||||
cmdlfguard.c \
|
||||
cmdlfgallagher.c \
|
||||
cmdlfhid.c \
|
||||
|
|
|
@ -127,7 +127,7 @@ add_library(pm3rrg_rdv4 SHARED
|
|||
${PM3_ROOT}/client/src/cmdlfcotag.c
|
||||
${PM3_ROOT}/client/src/cmdlfem4x.c
|
||||
${PM3_ROOT}/client/src/cmdlfem4x50.c
|
||||
${PM3_ROOT}/client/src/cmdlffdx.c
|
||||
${PM3_ROOT}/client/src/cmdlffdxb.c
|
||||
${PM3_ROOT}/client/src/cmdlfgallagher.c
|
||||
${PM3_ROOT}/client/src/cmdlfguard.c
|
||||
${PM3_ROOT}/client/src/cmdlfhid.c
|
||||
|
|
|
@ -2231,9 +2231,9 @@ struct arg_int *arg_intn(
|
|||
#include <limits.h>
|
||||
#include <inttypes.h>
|
||||
static uint64_t strtollu0X(const char *str,
|
||||
const char * *endptr,
|
||||
char X,
|
||||
int base) {
|
||||
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 */
|
||||
|
@ -4529,11 +4529,11 @@ static void arg_cat_optionv(char *dest,
|
|||
}
|
||||
|
||||
if (datatype) {
|
||||
/* if (longopts)
|
||||
arg_cat(&dest, "=", &ndest);
|
||||
else if (shortopts)
|
||||
arg_cat(&dest, " ", &ndest);
|
||||
*/
|
||||
/* if (longopts)
|
||||
arg_cat(&dest, "=", &ndest);
|
||||
else if (shortopts)
|
||||
arg_cat(&dest, " ", &ndest);
|
||||
*/
|
||||
if (longopts)
|
||||
arg_cat(&dest, " ", &ndest);
|
||||
else if (shortopts)
|
||||
|
|
|
@ -192,19 +192,19 @@ struct arg_int *arg_int1(const char *shortopts, const char *longopts, const char
|
|||
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 *longopts,
|
||||
const char *datatype,
|
||||
const char *glossary);
|
||||
struct arg_u64 *arg_u64_1(const char *shortopts,
|
||||
const char *longopts,
|
||||
const char *datatype,
|
||||
const char *glossary);
|
||||
const char *longopts,
|
||||
const char *datatype,
|
||||
const char *glossary);
|
||||
struct arg_u64 *arg_u64_n(const char *shortopts,
|
||||
const char *longopts,
|
||||
const char *datatype,
|
||||
int mincount,
|
||||
int maxcount,
|
||||
const char *glossary);
|
||||
const char *longopts,
|
||||
const char *datatype,
|
||||
int mincount,
|
||||
int maxcount,
|
||||
const char *glossary);
|
||||
|
||||
|
||||
struct arg_dbl *arg_dbl0(const char *shortopts,
|
||||
|
|
|
@ -174,7 +174,7 @@ crack_states_thread(void *x) {
|
|||
char progress_text[80];
|
||||
char keystr[19];
|
||||
sprintf(keystr, "%012" PRIx64 " ", key);
|
||||
sprintf(progress_text, "Brute force phase completed. Key found: " _YELLOW_("%s"), keystr);
|
||||
sprintf(progress_text, "Brute force phase completed. Key found: " _YELLOW_("%s"), keystr);
|
||||
hardnested_print_progress(thread_arg->num_acquired_nonces, progress_text, 0.0, 0);
|
||||
break;
|
||||
} else if (keys_found) {
|
||||
|
|
|
@ -740,8 +740,12 @@ static int unpack(scanner_t *s, json_t *root, va_list *ap) {
|
|||
|
||||
case 'b':
|
||||
if (root && !json_is_boolean(root)) {
|
||||
set_error(s, "<validation>", json_error_wrong_type, "Expected true or false, got %s",
|
||||
type_name(root));
|
||||
set_error(s,
|
||||
"<validation>",
|
||||
json_error_wrong_type,
|
||||
"Expected true or false, got %s",
|
||||
type_name(root)
|
||||
);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -167,8 +167,9 @@ int reveng_main(int argc, char *argv[]) {
|
|||
pkchop(&model.spoly);
|
||||
width = plen(model.spoly);
|
||||
rflags |= R_HAVEP;
|
||||
if (c == 'P')
|
||||
if (c == 'P') {
|
||||
prcp(&model.spoly);
|
||||
}
|
||||
mnovel(&model);
|
||||
break;
|
||||
case 'l': /* l little-endian input and output */
|
||||
|
@ -332,6 +333,7 @@ ipqx:
|
|||
mbynum(&model, --args);
|
||||
ufound(&model);
|
||||
} while (args);
|
||||
mfree(&model);
|
||||
break;
|
||||
case 'd': /* d dump CRC model */
|
||||
/* maybe we don't want to do this:
|
||||
|
@ -387,6 +389,10 @@ ipqx:
|
|||
apolys = calloc(args * sizeof(poly_t), sizeof(char));
|
||||
if (!apolys) {
|
||||
uerror("cannot allocate memory for argument list");
|
||||
pfree(&model.spoly);
|
||||
pfree(&model.init);
|
||||
pfree(&model.xorout);
|
||||
mfree(&model);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -421,16 +427,20 @@ ipqx:
|
|||
continue;
|
||||
if (rflags & R_HAVEX && psncmp(&model.xorout, &pset.xorout))
|
||||
continue;
|
||||
|
||||
apoly = pclone(pset.xorout);
|
||||
if (pset.flags & P_REFOUT)
|
||||
if (pset.flags & P_REFOUT) {
|
||||
prev(&apoly);
|
||||
}
|
||||
|
||||
for (qptr = apolys; qptr < pptr; ++qptr) {
|
||||
crc = pcrc(*qptr, pset.spoly, pset.init, apoly, 0);
|
||||
if (ptst(crc)) {
|
||||
pfree(&crc);
|
||||
break;
|
||||
} else
|
||||
} else {
|
||||
pfree(&crc);
|
||||
}
|
||||
}
|
||||
pfree(&apoly);
|
||||
if (qptr == pptr) {
|
||||
|
@ -444,14 +454,19 @@ ipqx:
|
|||
/* toggle refIn/refOut and reflect arguments */
|
||||
if (~rflags & R_HAVERI) {
|
||||
model.flags ^= P_REFIN | P_REFOUT;
|
||||
for (qptr = apolys; qptr < pptr; ++qptr)
|
||||
for (qptr = apolys; qptr < pptr; ++qptr) {
|
||||
prevch(qptr, ibperhx);
|
||||
}
|
||||
}
|
||||
} while (~rflags & R_HAVERI && ++pass < 2);
|
||||
}
|
||||
|
||||
if (uflags & C_RESULT) {
|
||||
for (qptr = apolys; qptr < pptr; ++qptr)
|
||||
for (qptr = apolys; qptr < pptr; ++qptr) {
|
||||
pfree(qptr);
|
||||
}
|
||||
free(apolys);
|
||||
mfree(&model);
|
||||
return 1;
|
||||
//exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
@ -467,8 +482,10 @@ ipqx:
|
|||
pass = 0;
|
||||
do {
|
||||
mptr = candmods = reveng(&model, qpoly, rflags, args, apolys);
|
||||
if (mptr && plen(mptr->spoly))
|
||||
if (mptr && plen(mptr->spoly)) {
|
||||
uflags |= C_RESULT;
|
||||
}
|
||||
|
||||
while (mptr && plen(mptr->spoly)) {
|
||||
/* results were printed by the callback
|
||||
* string = mtostr(mptr);
|
||||
|
@ -478,26 +495,31 @@ ipqx:
|
|||
mfree(mptr++);
|
||||
}
|
||||
free(candmods);
|
||||
|
||||
if (~rflags & R_HAVERI) {
|
||||
model.flags ^= P_REFIN | P_REFOUT;
|
||||
for (qptr = apolys; qptr < pptr; ++qptr)
|
||||
for (qptr = apolys; qptr < pptr; ++qptr) {
|
||||
prevch(qptr, ibperhx);
|
||||
}
|
||||
}
|
||||
} while (~rflags & R_HAVERI && ++pass < 2);
|
||||
for (qptr = apolys; qptr < pptr; ++qptr)
|
||||
|
||||
for (qptr = apolys; qptr < pptr; ++qptr) {
|
||||
pfree(qptr);
|
||||
}
|
||||
|
||||
free(apolys);
|
||||
|
||||
if (~uflags & C_RESULT)
|
||||
uerror("no models found");
|
||||
|
||||
break;
|
||||
default: /* no mode specified */
|
||||
fprintf(stderr, "%s: no mode switch specified. Use %s -h for help.\n", myname, myname);
|
||||
return 0;
|
||||
//exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
return 1;
|
||||
//exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -77,65 +77,65 @@ local function setdevicedebug( status )
|
|||
end
|
||||
|
||||
local function xteaCrypt(num_rounds, v, key)
|
||||
local v0 = v[0]
|
||||
local v1 = v[1]
|
||||
local delta = 0x9E3779B9
|
||||
local sum = 0
|
||||
local v0 = v[0]
|
||||
local v1 = v[1]
|
||||
local delta = 0x9E3779B9
|
||||
local sum = 0
|
||||
|
||||
for i = 0, num_rounds-1 do
|
||||
-- v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
|
||||
v0 = band(bxor(bxor(lsh(v1,4), rsh(v1,5)) + v1, sum + key[band(sum,3)]) + v0, 0xFFFFFFFF)
|
||||
sum = band(sum + delta, 0xFFFFFFFF)
|
||||
-- v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
|
||||
v1 = band(bxor(bxor(lsh(v0,4), rsh(v0,5)) + v0, sum + key[band(rsh(sum,11),3)]) + v1, 0xFFFFFFFF)
|
||||
end
|
||||
v[0] = v0
|
||||
v[1] = v1
|
||||
for i = 0, num_rounds-1 do
|
||||
-- v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
|
||||
v0 = band(bxor(bxor(lsh(v1,4), rsh(v1,5)) + v1, sum + key[band(sum,3)]) + v0, 0xFFFFFFFF)
|
||||
sum = band(sum + delta, 0xFFFFFFFF)
|
||||
-- v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
|
||||
v1 = band(bxor(bxor(lsh(v0,4), rsh(v0,5)) + v0, sum + key[band(rsh(sum,11),3)]) + v1, 0xFFFFFFFF)
|
||||
end
|
||||
v[0] = v0
|
||||
v[1] = v1
|
||||
end
|
||||
|
||||
local function xteaDecrypt(num_rounds, v, key)
|
||||
local v0 = v[0]
|
||||
local v1 = v[1]
|
||||
local delta = 0x9E3779B9
|
||||
local sum = band(delta * num_rounds, 0xFFFFFFFF)
|
||||
local v0 = v[0]
|
||||
local v1 = v[1]
|
||||
local delta = 0x9E3779B9
|
||||
local sum = band(delta * num_rounds, 0xFFFFFFFF)
|
||||
|
||||
for i = 0, num_rounds-1 do
|
||||
-- v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
|
||||
v1 = band(v1 - bxor(bxor(lsh(v0,4), rsh(v0,5)) + v0, sum + key[band(rsh(sum,11),3)]), 0xFFFFFFFF)
|
||||
sum = band(sum - delta, 0xFFFFFFFF)
|
||||
-- v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
|
||||
v0 = band(v0 - bxor(bxor(lsh(v1,4), rsh(v1,5)) + v1, sum + key[band(sum,3)]), 0xFFFFFFFF)
|
||||
end
|
||||
v[0] = v0
|
||||
v[1] = v1
|
||||
for i = 0, num_rounds-1 do
|
||||
-- v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]);
|
||||
v1 = band(v1 - bxor(bxor(lsh(v0,4), rsh(v0,5)) + v0, sum + key[band(rsh(sum,11),3)]), 0xFFFFFFFF)
|
||||
sum = band(sum - delta, 0xFFFFFFFF)
|
||||
-- v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
|
||||
v0 = band(v0 - bxor(bxor(lsh(v1,4), rsh(v1,5)) + v1, sum + key[band(sum,3)]), 0xFFFFFFFF)
|
||||
end
|
||||
v[0] = v0
|
||||
v[1] = v1
|
||||
end
|
||||
|
||||
local function createxteakey(mfuid)
|
||||
local xteakey = {}
|
||||
local buid = {}
|
||||
local tmpkey = {}
|
||||
local uid = {}
|
||||
local xteakey = {}
|
||||
local buid = {}
|
||||
local tmpkey = {}
|
||||
local uid = {}
|
||||
|
||||
-- Warning ! "it is customary in Lua to START ARRAYS WITH ONE"
|
||||
buid = utils.ConvertHexToBytes(mfuid)
|
||||
uid[0] = bor(buid[1], lsh(buid[2], 8))
|
||||
uid[1] = bor(buid[3], lsh(buid[4], 8))
|
||||
-- Warning ! "it is customary in Lua to START ARRAYS WITH ONE"
|
||||
buid = utils.ConvertHexToBytes(mfuid)
|
||||
uid[0] = bor(buid[1], lsh(buid[2], 8))
|
||||
uid[1] = bor(buid[3], lsh(buid[4], 8))
|
||||
|
||||
tmpkey[0] = 0x198B
|
||||
tmpkey[1] = uid[0]
|
||||
tmpkey[2] = 0x46D8
|
||||
tmpkey[3] = uid[1]
|
||||
tmpkey[4] = 0x5310
|
||||
tmpkey[5] = bxor(uid[0], 0xA312)
|
||||
tmpkey[6] = 0xFFCB
|
||||
tmpkey[7] = bxor(uid[1], 0x55AA)
|
||||
tmpkey[0] = 0x198B
|
||||
tmpkey[1] = uid[0]
|
||||
tmpkey[2] = 0x46D8
|
||||
tmpkey[3] = uid[1]
|
||||
tmpkey[4] = 0x5310
|
||||
tmpkey[5] = bxor(uid[0], 0xA312)
|
||||
tmpkey[6] = 0xFFCB
|
||||
tmpkey[7] = bxor(uid[1], 0x55AA)
|
||||
|
||||
xteakey[0] = bor(lsh(tmpkey[1], 16), tmpkey[0])
|
||||
xteakey[1] = bor(lsh(tmpkey[3], 16), tmpkey[2])
|
||||
xteakey[2] = bor(lsh(tmpkey[5], 16), tmpkey[4])
|
||||
xteakey[3] = bor(lsh(tmpkey[7], 16), tmpkey[6])
|
||||
xteakey[0] = bor(lsh(tmpkey[1], 16), tmpkey[0])
|
||||
xteakey[1] = bor(lsh(tmpkey[3], 16), tmpkey[2])
|
||||
xteakey[2] = bor(lsh(tmpkey[5], 16), tmpkey[4])
|
||||
xteakey[3] = bor(lsh(tmpkey[7], 16), tmpkey[6])
|
||||
|
||||
return xteakey
|
||||
return xteakey
|
||||
end
|
||||
|
||||
local function getblockdata(response)
|
||||
|
@ -160,38 +160,38 @@ local function readblock(blockno, key)
|
|||
end
|
||||
|
||||
local function readtag(mfkey,xteakey)
|
||||
local tagdata = {}
|
||||
local cleardata = {}
|
||||
local v = {}
|
||||
local vv = {}
|
||||
local tagdata = {}
|
||||
local cleardata = {}
|
||||
local v = {}
|
||||
local vv = {}
|
||||
|
||||
-- Read 4 sectors and build table
|
||||
for sect = 8, 11 do
|
||||
for blockn = sect * 4, (sect * 4) + 2 do
|
||||
local blockdata = readblock(blockn, mfkey)
|
||||
if not blockdata then return oops('[!] failed reading block') end
|
||||
table.insert(tagdata, blockdata)
|
||||
end
|
||||
end
|
||||
-- Read 4 sectors and build table
|
||||
for sect = 8, 11 do
|
||||
for blockn = sect * 4, (sect * 4) + 2 do
|
||||
local blockdata = readblock(blockn, mfkey)
|
||||
if not blockdata then return oops('[!] failed reading block') end
|
||||
table.insert(tagdata, blockdata)
|
||||
end
|
||||
end
|
||||
|
||||
-- Decrypt data and build clear table
|
||||
for key,value in ipairs(tagdata) do
|
||||
local clearblockdata
|
||||
v[0] = utils.SwapEndianness(value:sub(1, 8), 32)
|
||||
v[1] = utils.SwapEndianness(value:sub(9, 16), 32)
|
||||
xteaDecrypt(16, v, xteakey)
|
||||
vv[0] = utils.SwapEndianness(value:sub(17, 24), 32)
|
||||
vv[1] = utils.SwapEndianness(value:sub(25, 32), 32)
|
||||
xteaDecrypt(16, vv, xteakey)
|
||||
clearblockdata=string.format("%08X%08X%08X%08X",
|
||||
utils.SwapEndianness(string.format("%08X", v[0]), 32),
|
||||
utils.SwapEndianness(string.format("%08X", v[1]), 32),
|
||||
utils.SwapEndianness(string.format("%08X", vv[0]), 32),
|
||||
utils.SwapEndianness(string.format("%08X", vv[1]), 32))
|
||||
table.insert(cleardata, clearblockdata)
|
||||
end
|
||||
-- Decrypt data and build clear table
|
||||
for key,value in ipairs(tagdata) do
|
||||
local clearblockdata
|
||||
v[0] = utils.SwapEndianness(value:sub(1, 8), 32)
|
||||
v[1] = utils.SwapEndianness(value:sub(9, 16), 32)
|
||||
xteaDecrypt(16, v, xteakey)
|
||||
vv[0] = utils.SwapEndianness(value:sub(17, 24), 32)
|
||||
vv[1] = utils.SwapEndianness(value:sub(25, 32), 32)
|
||||
xteaDecrypt(16, vv, xteakey)
|
||||
clearblockdata=string.format("%08X%08X%08X%08X",
|
||||
utils.SwapEndianness(string.format("%08X", v[0]), 32),
|
||||
utils.SwapEndianness(string.format("%08X", v[1]), 32),
|
||||
utils.SwapEndianness(string.format("%08X", vv[0]), 32),
|
||||
utils.SwapEndianness(string.format("%08X", vv[1]), 32))
|
||||
table.insert(cleardata, clearblockdata)
|
||||
end
|
||||
|
||||
return tagdata,cleardata
|
||||
return tagdata,cleardata
|
||||
|
||||
end
|
||||
|
||||
|
@ -203,98 +203,98 @@ local function main(args)
|
|||
if o == 'h' then return help() end
|
||||
end
|
||||
|
||||
local xteakey = {}
|
||||
-- local v = {}
|
||||
local edata = {}
|
||||
local cdata = {}
|
||||
local xteakey = {}
|
||||
-- local v = {}
|
||||
local edata = {}
|
||||
local cdata = {}
|
||||
|
||||
-- Turn off Debug
|
||||
setdevicedebug(false)
|
||||
-- Turn off Debug
|
||||
setdevicedebug(false)
|
||||
|
||||
-- GET TAG UID
|
||||
tag, err = lib14a.read(false, true)
|
||||
if err then
|
||||
lib14a.disconnect()
|
||||
return oops(err)
|
||||
end
|
||||
core.clearCommandBuffer()
|
||||
-- GET TAG UID
|
||||
tag, err = lib14a.read(false, true)
|
||||
if err then
|
||||
lib14a.disconnect()
|
||||
return oops(err)
|
||||
end
|
||||
core.clearCommandBuffer()
|
||||
|
||||
-- simple tag check
|
||||
if 0x08 ~= tag.sak then
|
||||
if 0x0400 ~= tag.atqa then
|
||||
return oops(('[fail] found tag %s :: looking for Mifare S50 1k'):format(tag.name))
|
||||
end
|
||||
end
|
||||
-- simple tag check
|
||||
if 0x08 ~= tag.sak then
|
||||
if 0x0400 ~= tag.atqa then
|
||||
return oops(('[fail] found tag %s :: looking for Mifare S50 1k'):format(tag.name))
|
||||
end
|
||||
end
|
||||
|
||||
xteakey = createxteakey(tag.uid)
|
||||
print(acblue.."UID: "..tag.uid..acoff)
|
||||
print(acblue..string.format("XTEA key: %08X %08X %08X %08X", xteakey[0], xteakey[1], xteakey[2], xteakey[3])..acoff)
|
||||
xteakey = createxteakey(tag.uid)
|
||||
print(acblue.."UID: "..tag.uid..acoff)
|
||||
print(acblue..string.format("XTEA key: %08X %08X %08X %08X", xteakey[0], xteakey[1], xteakey[2], xteakey[3])..acoff)
|
||||
|
||||
edata, cdata = readtag("415A54454B4D", xteakey)
|
||||
edata, cdata = readtag("415A54454B4D", xteakey)
|
||||
|
||||
if edata == nil or cdata == nil then
|
||||
print("ERROR Reading tag!")
|
||||
return nil
|
||||
end
|
||||
if edata == nil or cdata == nil then
|
||||
print("ERROR Reading tag!")
|
||||
return nil
|
||||
end
|
||||
|
||||
print("Ciphered data:")
|
||||
for key,value in ipairs(edata) do
|
||||
print(value)
|
||||
if key % 3 == 0 then print("") end
|
||||
end
|
||||
print("Ciphered data:")
|
||||
for key,value in ipairs(edata) do
|
||||
print(value)
|
||||
if key % 3 == 0 then print("") end
|
||||
end
|
||||
|
||||
-- compute CRC for each segment
|
||||
-- compute CRC for each segment
|
||||
crcH = utils.SwapEndianness(core.reveng_runmodel("CRC-16/ARC", cdata[1]..cdata[2]..cdata[3]:sub(1,28), false, '0'),16)
|
||||
crcA = utils.SwapEndianness(core.reveng_runmodel("CRC-16/ARC", cdata[4]..cdata[5]..cdata[6]..cdata[7]:sub(1,28), false, '0'),16)
|
||||
crcB = utils.SwapEndianness(core.reveng_runmodel("CRC-16/ARC", cdata[8]..cdata[9]..cdata[10]..cdata[11]:sub(1,28), false, '0'),16)
|
||||
|
||||
print("\nHeader:")
|
||||
for key,value in ipairs(cdata) do
|
||||
if key == 3 then
|
||||
print(value:sub(1,28)..acmagenta..value:sub(29,32)..acoff)
|
||||
if utils.SwapEndianness(value:sub(29,32),16) == crcH then strcrc = " OK" else strcrc = acred.." CRCERROR !!" end
|
||||
print(acmagenta.."CRC16/ARC = "..string.format("0x%04X", crcH)..strcrc..acoff)
|
||||
print("\nDataA:")
|
||||
elseif key == 4 then
|
||||
print(acgreen..value:sub(1,4)..acoff..value:sub(5,16)..accyan..value:sub(17,24)..acoff..value:sub(25,26)..accyan..value:sub(27,28)..acoff..value:sub(29,32))
|
||||
versionA = utils.SwapEndianness(value:sub(1,4),16)
|
||||
dateA = string.format("%d/%02d/%02d %02d:%02d", tonumber(value:sub(17,18),10)+2000, tonumber(value:sub(19,20),10),
|
||||
tonumber(string.format("%02X", band(tonumber(value:sub(21,22),16),0x3f)),10),
|
||||
tonumber(value:sub(23,24),10), tonumber(value:sub(27,28),10))
|
||||
elseif key == 8 then
|
||||
print(acgreen..value:sub(1,4)..acoff..value:sub(5,16)..accyan..value:sub(17,24)..acoff..value:sub(25,26)..accyan..value:sub(27,28)..acoff..value:sub(29,32))
|
||||
versionB = utils.SwapEndianness(value:sub(1,4),16)
|
||||
dateB = string.format("%d/%02d/%02d %02d:%02d", tonumber(value:sub(17,18),10)+2000, tonumber(value:sub(19,20),10),
|
||||
tonumber(string.format("%02X", band(tonumber(value:sub(21,22),16),0x3f)),10),
|
||||
tonumber(value:sub(23,24),10), tonumber(value:sub(27,28),10))
|
||||
elseif key == 5 then
|
||||
print(acyellow..value:sub(1,4)..acoff..value:sub(5,32))
|
||||
creditA = utils.SwapEndianness(value:sub(1,4),16)/100
|
||||
elseif key == 9 then
|
||||
print(acyellow..value:sub(1,4)..acoff..value:sub(5,32))
|
||||
creditB = utils.SwapEndianness(value:sub(1,4),16)/100
|
||||
elseif key == 7 then
|
||||
print(value:sub(1,28)..acmagenta..value:sub(29,32)..acoff)
|
||||
print(acgreen.."Version "..string.format("0x%04X", versionA)..acoff)
|
||||
print(acyellow.."Credit : "..creditA..acoff)
|
||||
if utils.SwapEndianness(value:sub(29,32),16) == crcA then strcrc = " OK" else strcrc = acred.." CRCERROR !!" end
|
||||
print(acmagenta.."CRC16/ARC = "..string.format("0x%04X", crcA)..strcrc..acoff)
|
||||
print(accyan.."Date: "..dateA..acoff)
|
||||
print("\nDataB:")
|
||||
elseif key == 11 then
|
||||
print(value:sub(1,28)..acmagenta..value:sub(29,32)..acoff)
|
||||
print(acgreen.."Version "..string.format("0x%04X", versionB)..acoff)
|
||||
print(acyellow.."Credit : "..creditB..acoff)
|
||||
if utils.SwapEndianness(value:sub(29,32),16) == crcB then strcrc = " OK" else strcrc = acred.." CRCERROR !!" end
|
||||
print(acmagenta.."CRC16/ARC = "..string.format("0x%04X", crcB)..strcrc..acoff)
|
||||
print(accyan.."Date: "..dateB..acoff)
|
||||
print("\nFooter:")
|
||||
else
|
||||
print(value)
|
||||
end
|
||||
end
|
||||
print("\nHeader:")
|
||||
for key,value in ipairs(cdata) do
|
||||
if key == 3 then
|
||||
print(value:sub(1,28)..acmagenta..value:sub(29,32)..acoff)
|
||||
if utils.SwapEndianness(value:sub(29,32),16) == crcH then strcrc = " OK" else strcrc = acred.." CRCERROR !!" end
|
||||
print(acmagenta.."CRC16/ARC = "..string.format("0x%04X", crcH)..strcrc..acoff)
|
||||
print("\nDataA:")
|
||||
elseif key == 4 then
|
||||
print(acgreen..value:sub(1,4)..acoff..value:sub(5,16)..accyan..value:sub(17,24)..acoff..value:sub(25,26)..accyan..value:sub(27,28)..acoff..value:sub(29,32))
|
||||
versionA = utils.SwapEndianness(value:sub(1,4),16)
|
||||
dateA = string.format("%d/%02d/%02d %02d:%02d", tonumber(value:sub(17,18),10)+2000, tonumber(value:sub(19,20),10),
|
||||
tonumber(string.format("%02X", band(tonumber(value:sub(21,22),16),0x3f)),10),
|
||||
tonumber(value:sub(23,24),10), tonumber(value:sub(27,28),10))
|
||||
elseif key == 8 then
|
||||
print(acgreen..value:sub(1,4)..acoff..value:sub(5,16)..accyan..value:sub(17,24)..acoff..value:sub(25,26)..accyan..value:sub(27,28)..acoff..value:sub(29,32))
|
||||
versionB = utils.SwapEndianness(value:sub(1,4),16)
|
||||
dateB = string.format("%d/%02d/%02d %02d:%02d", tonumber(value:sub(17,18),10)+2000, tonumber(value:sub(19,20),10),
|
||||
tonumber(string.format("%02X", band(tonumber(value:sub(21,22),16),0x3f)),10),
|
||||
tonumber(value:sub(23,24),10), tonumber(value:sub(27,28),10))
|
||||
elseif key == 5 then
|
||||
print(acyellow..value:sub(1,4)..acoff..value:sub(5,32))
|
||||
creditA = utils.SwapEndianness(value:sub(1,4),16)/100
|
||||
elseif key == 9 then
|
||||
print(acyellow..value:sub(1,4)..acoff..value:sub(5,32))
|
||||
creditB = utils.SwapEndianness(value:sub(1,4),16)/100
|
||||
elseif key == 7 then
|
||||
print(value:sub(1,28)..acmagenta..value:sub(29,32)..acoff)
|
||||
print(acgreen.."Version "..string.format("0x%04X", versionA)..acoff)
|
||||
print(acyellow.."Credit : "..creditA..acoff)
|
||||
if utils.SwapEndianness(value:sub(29,32),16) == crcA then strcrc = " OK" else strcrc = acred.." CRCERROR !!" end
|
||||
print(acmagenta.."CRC16/ARC = "..string.format("0x%04X", crcA)..strcrc..acoff)
|
||||
print(accyan.."Date: "..dateA..acoff)
|
||||
print("\nDataB:")
|
||||
elseif key == 11 then
|
||||
print(value:sub(1,28)..acmagenta..value:sub(29,32)..acoff)
|
||||
print(acgreen.."Version "..string.format("0x%04X", versionB)..acoff)
|
||||
print(acyellow.."Credit : "..creditB..acoff)
|
||||
if utils.SwapEndianness(value:sub(29,32),16) == crcB then strcrc = " OK" else strcrc = acred.." CRCERROR !!" end
|
||||
print(acmagenta.."CRC16/ARC = "..string.format("0x%04X", crcB)..strcrc..acoff)
|
||||
print(accyan.."Date: "..dateB..acoff)
|
||||
print("\nFooter:")
|
||||
else
|
||||
print(value)
|
||||
end
|
||||
end
|
||||
|
||||
return
|
||||
return
|
||||
end
|
||||
|
||||
main(args)
|
||||
|
|
|
@ -34,7 +34,7 @@ version = 'v1.0.0'
|
|||
desc = [[
|
||||
This script gives you an easy way to write your *.eml dumps into normal MIFARE Classic and Magic Gen3 cards.
|
||||
|
||||
Works with both 4 and 7 bytes NXP MIFARE Classic 1K cards.
|
||||
Works with both 4 and 7 bytes NXP MIFARE Classic 1K cards.
|
||||
The script also has the possibility to change UID and permanent lock uid on magic Gen3 cards.
|
||||
|
||||
It supports the following functionality.
|
||||
|
@ -47,18 +47,18 @@ desc = [[
|
|||
|
||||
Script works in a wizard styled way.
|
||||
|
||||
Author Youtube channel: https://yev.ooo/
|
||||
Author Youtube channel: https://yev.ooo/
|
||||
|
||||
Many Thanks,
|
||||
Best Regards
|
||||
Many Thanks,
|
||||
Best Regards
|
||||
]]
|
||||
example = [[
|
||||
1. script run mfc_gen3_writer
|
||||
]]
|
||||
usage = [[
|
||||
Give script to know if you uses an Windows OS
|
||||
Give script to know if you uses an Windows OS
|
||||
Select your *.eml dump from list to write to the card.
|
||||
Follow the wizard.
|
||||
Follow the wizard.
|
||||
]]
|
||||
--
|
||||
---
|
||||
|
@ -163,9 +163,9 @@ end
|
|||
--
|
||||
local function KeyAB()
|
||||
if default_key_type == '00' then
|
||||
return 'KeyA'
|
||||
return 'KeyA'
|
||||
else
|
||||
return 'KeyB'
|
||||
return 'KeyB'
|
||||
end
|
||||
end
|
||||
--
|
||||
|
@ -265,7 +265,7 @@ local function main(args)
|
|||
eml_file_uid_end = 22
|
||||
eml_file_lengt = 31
|
||||
else
|
||||
eml_file_uid_start = 9
|
||||
eml_file_uid_start = 9
|
||||
eml_file_uid_end = 16
|
||||
eml_file_lengt = 25
|
||||
end
|
||||
|
@ -366,7 +366,7 @@ local function main(args)
|
|||
print(tab)
|
||||
--
|
||||
if checkkey() == true then
|
||||
print(tab)
|
||||
print(tab)
|
||||
if (utils.confirm(' Card is Empty. Write selected dump to card ?') == true) then
|
||||
for i = 1, #eml do
|
||||
core.console(string.format(cmd_wrbl_b, (i-1), default_key, eml[i]))
|
||||
|
|
|
@ -114,7 +114,7 @@ local function main(args)
|
|||
local c = string.format( command, n )
|
||||
print('Running: "'..c..'"')
|
||||
core.console(c)
|
||||
core.console('msleep '..timeout);
|
||||
core.console('msleep '..timeout);
|
||||
core.console('hw ping')
|
||||
end
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
176
client/luascripts/lf_em_tearoff.lua
Normal file
176
client/luascripts/lf_em_tearoff.lua
Normal file
|
@ -0,0 +1,176 @@
|
|||
local getopt = require('getopt')
|
||||
local ansicolors = require('ansicolors')
|
||||
|
||||
copyright = 'Iceman'
|
||||
author = 'Iceman'
|
||||
version = 'v0.9.9'
|
||||
desc = [[
|
||||
This is scripts loops though a tear attack and reads expected value.
|
||||
]]
|
||||
example = [[
|
||||
1. script run tearoff -n 2 -s 200 -e 400 -a 5
|
||||
]]
|
||||
usage = [[
|
||||
script run tearoff [-h] [-n <steps us>] [-a <addr>] [-p <pwd>] [-s <start us>] [-e <end us>] [-r <read>] [-w <write>]
|
||||
]]
|
||||
arguments = [[
|
||||
-h This help
|
||||
-n <steps us> steps in milliseconds for each tearoff
|
||||
-a <addr> address to target on card
|
||||
-p <pwd> (optional) use a password
|
||||
-s <delay us> initial start delay
|
||||
-e <delay us> end delay, must be larger than start delay
|
||||
-r <read value> 4 hex bytes value to be read
|
||||
-w <write value> 4 hex bytes value to be written
|
||||
end
|
||||
]]
|
||||
|
||||
---
|
||||
-- This is only meant to be used when errors occur
|
||||
local function oops(err)
|
||||
print('ERROR:', err)
|
||||
core.clearCommandBuffer()
|
||||
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
|
||||
|
||||
local function main(args)
|
||||
|
||||
--[[
|
||||
Basically do the following,
|
||||
|
||||
1. hw tear
|
||||
2. lf em 4x05_write
|
||||
3. lf em 4x05_read
|
||||
|
||||
The first two commands doesn't need a feedback from the system, so going with core.console commands.
|
||||
Since the read needs demodulation of signal I opted to add that function from cmdlfem4x.c to the core lua scripting
|
||||
core.em4x05_read(addr, password)
|
||||
|
||||
--]]
|
||||
local n, addr, password, sd, ed, wr_value, rd_value
|
||||
|
||||
for o, a in getopt.getopt(args, 'he:s:a:p:n:r:w:') do
|
||||
if o == 'h' then return help() end
|
||||
if o == 'n' then n = a end
|
||||
if o == 'a' then addr = a end
|
||||
if o == 'p' then password = a end
|
||||
if o == 'e' then ed = tonumber(a) end
|
||||
if o == 's' then sd = tonumber(a) end
|
||||
if o == 'w' then wr_value = a end
|
||||
if o == 'r' then rd_value = a end
|
||||
end
|
||||
|
||||
rd_value = rd_value or 'FFFFFFFF'
|
||||
wr_value = wr_value or 'FFFFFFFF'
|
||||
addr = addr or 5
|
||||
password = password or ''
|
||||
n = n or 2
|
||||
sd = sd or 2000
|
||||
ed = ed or 2100
|
||||
|
||||
if #password ~= 8 then
|
||||
password = ''
|
||||
end
|
||||
|
||||
if #wr_value ~= 8 then
|
||||
wr_value = 'FFFFFFFF'
|
||||
end
|
||||
|
||||
if #rd_value ~= 8 then
|
||||
rd_value = 'FFFFFFFF'
|
||||
end
|
||||
|
||||
if sd > ed then
|
||||
return oops('start delay can\'t be larger than end delay', sd, ed)
|
||||
end
|
||||
|
||||
print('Starting EM4x05 tear off')
|
||||
print('target addr', addr)
|
||||
if password then
|
||||
print('target pwd', password)
|
||||
end
|
||||
print('target stepping', n)
|
||||
print('target delay', sd ,ed)
|
||||
print('read value', rd_value)
|
||||
print('write value', wr_value)
|
||||
|
||||
local res_tear = 0
|
||||
local res_nowrite = 0
|
||||
|
||||
local set_tearoff_delay = 'hw tearoff --delay %d'
|
||||
local enable_tearoff = 'hw tearoff --on'
|
||||
|
||||
local wr_template = 'lf em 4x05_write %s %s %s'
|
||||
|
||||
-- init addr to value
|
||||
core.console(wr_template:format(addr, wr_value, password))
|
||||
|
||||
if sd == ed then
|
||||
ed = n
|
||||
n = 0
|
||||
end
|
||||
|
||||
for step = sd, ed, n do
|
||||
|
||||
io.flush()
|
||||
if core.kbd_enter_pressed() then
|
||||
print("aborted by user")
|
||||
break
|
||||
end
|
||||
|
||||
core.clearCommandBuffer()
|
||||
|
||||
-- reset addr to known value, if not locked into.
|
||||
if n ~= 0 then
|
||||
c = wr_template:format(addr, wr_value, password)
|
||||
core.console(c)
|
||||
end
|
||||
|
||||
local c = set_tearoff_delay:format(step)
|
||||
core.console(c);
|
||||
core.console(enable_tearoff)
|
||||
|
||||
c = wr_template:format(addr, wr_value, password)
|
||||
core.console(c)
|
||||
|
||||
local word, err = core.em4x05_read(addr, password)
|
||||
if err then
|
||||
return oops(err)
|
||||
end
|
||||
|
||||
local wordstr = ('%08X'):format(word)
|
||||
|
||||
if wordstr ~= wr_value then
|
||||
if wordstr ~= rd_value then
|
||||
print((ansicolors.red..'TEAR OFF occurred:'..ansicolors.reset..' %08X'):format(word))
|
||||
res_tear = res_tear + 1
|
||||
else
|
||||
print((ansicolors.cyan..'TEAR OFF occurred:'..ansicolors.reset..' %08X'):format(word))
|
||||
res_nowrite = res_nowrite + 1
|
||||
end
|
||||
else
|
||||
print((ansicolors.green..'Good write occurred:'..ansicolors.reset..' %08X'):format(word))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
In the future, we may implement so that scripts are invoked directly
|
||||
into a 'main' function, instead of being executed blindly. For future
|
||||
compatibility, I have done so, but I invoke my main from here.
|
||||
--]]
|
||||
main(args)
|
326
client/luascripts/lf_em_tearoff_protect.lua
Normal file
326
client/luascripts/lf_em_tearoff_protect.lua
Normal file
|
@ -0,0 +1,326 @@
|
|||
local getopt = require('getopt')
|
||||
local ansicolors = require('ansicolors')
|
||||
|
||||
copyright = 'Iceman'
|
||||
author = [[
|
||||
'Author Iceman
|
||||
CoAuthor Doegox
|
||||
]]
|
||||
version = 'v1.0.1'
|
||||
desc = [[
|
||||
This is scripts loops though a tear attack and reads expected value.
|
||||
]]
|
||||
example = [[
|
||||
Full automatic, with password:
|
||||
script run lf_em_tearoff_protect -p 50524F58
|
||||
|
||||
Manual fix increment over specified range:
|
||||
script run lf_em_tearoff_protect -n 2 -s 200 -e 400
|
||||
|
||||
Trying repeatedly for a fixed timing, forever or till success:
|
||||
script run lf_em_tearoff_protect -s 400 -e 400
|
||||
|
||||
Tips:
|
||||
Use a low Q antenna
|
||||
Move card somehow away from the antenna to a position where it still works
|
||||
]]
|
||||
usage = [[
|
||||
script run lf_em_tearoff_protect [-h] [-n <steps us>] [-p <pwd>] [-s <start us>] [-e <end us>]
|
||||
]]
|
||||
arguments = [[
|
||||
-h This help
|
||||
-n <steps us> steps in milliseconds for each tear-off
|
||||
-p <pwd> (optional) use a password
|
||||
-s <delay us> initial start delay
|
||||
-e <delay us> end delay, must be larger or equal to start delay
|
||||
end
|
||||
]]
|
||||
|
||||
local set_tearoff_delay = 'hw tearoff -s --on --delay %d'
|
||||
local wr_template = 'lf em 4x05_write %s %s %s'
|
||||
|
||||
---
|
||||
-- This is only meant to be used when errors occur
|
||||
local function oops(err)
|
||||
print('ERROR:', err)
|
||||
core.clearCommandBuffer()
|
||||
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
|
||||
|
||||
local function exit_msg()
|
||||
print('')
|
||||
print('================= '..ansicolors.green..'verify with'..ansicolors.reset..' =================')
|
||||
print(' lf em 4x05_dump')
|
||||
print('===============================================')
|
||||
return nil
|
||||
end
|
||||
|
||||
local function reset(wr_value, password)
|
||||
print('[=] '..ansicolors.red..'resetting the active lock block'..ansicolors.reset)
|
||||
core.console(wr_template:format(99, wr_value, password))
|
||||
end
|
||||
|
||||
local function main(args)
|
||||
|
||||
--[[
|
||||
Basically it does the following,
|
||||
|
||||
1. hw tear
|
||||
2. lf em 4x05_write
|
||||
3. lf em 4x05_read
|
||||
|
||||
The first two commands dont need a feedback from the system, so going with core.console commands.
|
||||
Since the read needs demodulation of signal I opted to add that function from cmdlfem4x.c to the core lua scripting
|
||||
core.em4x05_read(addr, password)
|
||||
|
||||
--]]
|
||||
local n, password, sd, ed
|
||||
|
||||
for o, a in getopt.getopt(args, 'he:s:p:n:') do
|
||||
if o == 'h' then return help() end
|
||||
if o == 'n' then n = tonumber(a) end
|
||||
if o == 'p' then password = a end
|
||||
if o == 'e' then ed = tonumber(a) end
|
||||
if o == 's' then sd = tonumber(a) end
|
||||
end
|
||||
|
||||
password = password or ''
|
||||
if #password ~= 8 then
|
||||
password = ''
|
||||
end
|
||||
|
||||
local word14, err14 = core.em4x05_read(14, password)
|
||||
if err14 then
|
||||
return oops(err14)
|
||||
end
|
||||
local word15, err15 = core.em4x05_read(15, password)
|
||||
if err15 then
|
||||
return oops(err15)
|
||||
end
|
||||
local bit15 = bit.band(0x00008000, word15)
|
||||
if bit15 == 0x00008000 then
|
||||
rd_value = ('%08X'):format(word15)
|
||||
reset(wr_value, password)
|
||||
else
|
||||
rd_value = ('%08X'):format(word14)
|
||||
end
|
||||
if rd_value == '00008000' then
|
||||
print('Tag already fully unlocked, nothing to do')
|
||||
return nil
|
||||
end
|
||||
local wr_value = '00000000'
|
||||
local auto = false
|
||||
if n == nil then
|
||||
auto = true
|
||||
sd = sd or 2000
|
||||
ed = ed or 6000
|
||||
n = (ed - sd) / 2
|
||||
else
|
||||
if sd == nil or ed == nil then
|
||||
return oops('start and stop delays need to be defined')
|
||||
end
|
||||
if sd > ed then
|
||||
return oops('start delay can\'t be larger than end delay', sd, ed)
|
||||
end
|
||||
end
|
||||
|
||||
print('==========================================')
|
||||
print('Starting EM4x05 tear-off : target PROTECT')
|
||||
|
||||
if password ~= '' then
|
||||
print('target pwd', password)
|
||||
end
|
||||
if auto then
|
||||
print('automatic mode', 'enabled')
|
||||
end
|
||||
print('target stepping', n)
|
||||
print('target delay', sd ,ed)
|
||||
print('read value', rd_value)
|
||||
print('write value', wr_value)
|
||||
print('==========================================')
|
||||
|
||||
local res_tear = 0
|
||||
local res_nowrite = 0
|
||||
|
||||
-- fix at one specific delay
|
||||
if sd == ed then
|
||||
n = 0
|
||||
end
|
||||
|
||||
local tries = 0
|
||||
local soon = 0
|
||||
local late = 0
|
||||
while sd <= ed do
|
||||
|
||||
if auto and n < 1 then -- n is a float
|
||||
print('[!] Reached n < 1 => '..ansicolors.yellow..'disabling automatic mode'..ansicolors.reset)
|
||||
ed = sd
|
||||
auto = false
|
||||
n = 0
|
||||
end
|
||||
if not auto then
|
||||
sd = sd + n
|
||||
end
|
||||
if (tries >= 5) and (n == 0) and (soon ~= late) then
|
||||
if soon > late then
|
||||
print(('[!] Tried %d times, soon:%i late:%i => '):format(tries, soon, late)..ansicolors.yellow..'adjusting delay by +1 us'..ansicolors.reset)
|
||||
sd = sd + 1
|
||||
ed = ed + 1
|
||||
else
|
||||
print(('[!] Tried %d times, soon:%i late:%i => '):format(tries, soon, late)..ansicolors.yellow..'adjusting delay by -1 us'..ansicolors.reset)
|
||||
sd = sd - 1
|
||||
ed = ed - 1
|
||||
end
|
||||
tries = 0
|
||||
soon = 0
|
||||
late = 0
|
||||
end
|
||||
|
||||
io.flush()
|
||||
if core.kbd_enter_pressed() then
|
||||
print("aborted by user")
|
||||
break
|
||||
end
|
||||
|
||||
core.clearCommandBuffer()
|
||||
|
||||
local c = set_tearoff_delay:format(sd)
|
||||
core.console(c);
|
||||
|
||||
c = wr_template:format(99, wr_value, password)
|
||||
core.console(c)
|
||||
|
||||
word14, err14 = core.em4x05_read(14, password)
|
||||
if err14 then
|
||||
return oops(err14)
|
||||
end
|
||||
|
||||
local wordstr14 = ('%08X'):format(word14)
|
||||
|
||||
word15, err15 = core.em4x05_read(15, password)
|
||||
if err15 then
|
||||
return oops(err15)
|
||||
end
|
||||
|
||||
local wordstr15 = ('%08X'):format(word15)
|
||||
|
||||
print(('[=] ref:'..rd_value..' 14:%08X 15:%08X '):format(word14, word15))
|
||||
|
||||
|
||||
if wordstr14 == rd_value and wordstr15 == '00000000' then
|
||||
print('[=] Status: Nothing happened => '..ansicolors.green..'tearing too soon'..ansicolors.reset)
|
||||
if auto then
|
||||
sd = sd + n
|
||||
n = n / 2
|
||||
print(('[+] Adjusting params: n=%i sd=%i ed=%i'):format(n, sd, ed))
|
||||
else
|
||||
soon = soon + 1
|
||||
end
|
||||
else
|
||||
if wordstr15 == rd_value then
|
||||
if wordstr14 == '00000000' then
|
||||
print('[=] Status: Protect succeeded => '..ansicolors.green..'tearing too late'..ansicolors.reset)
|
||||
else
|
||||
if wordstr14 == rd_value then
|
||||
print('[=] Status: 15 ok, 14 not yet erased => '..ansicolors.green..'tearing too late'..ansicolors.reset)
|
||||
else
|
||||
print('[=] Status: 15 ok, 14 partially erased => '..ansicolors.green..'tearing too late'..ansicolors.reset)
|
||||
end
|
||||
end
|
||||
reset(wr_value, password)
|
||||
-- it could still happen that a bitflip got committed, let's check...
|
||||
local word14b, err14b = core.em4x05_read(14, password)
|
||||
if err14b then
|
||||
return oops(err14b)
|
||||
end
|
||||
local wordstr14b = ('%08X'):format(word14b)
|
||||
if (wordstr14b == '00000000') then
|
||||
reset(wr_value, password)
|
||||
end
|
||||
if (wordstr14b ~= rd_value) then
|
||||
local word15b, err15b = core.em4x05_read(15, password)
|
||||
if err15b then
|
||||
return oops(err15b)
|
||||
end
|
||||
print(('[=] Status: new definitive value! => '..ansicolors.red..'SUCCESS: '..ansicolors.reset..'14: '..ansicolors.cyan..'%08X'..ansicolors.reset..' 15: %08X'):format(word14b, word15b))
|
||||
return exit_msg()
|
||||
end
|
||||
if auto then
|
||||
ed = sd
|
||||
sd = sd - n
|
||||
n = n / 2
|
||||
print(('[+] Adjusting params: n=%i sd=%i ed=%i'):format(n, sd, ed))
|
||||
else
|
||||
late = late + 1
|
||||
end
|
||||
else
|
||||
bit15 = bit.band(0x00008000, word15)
|
||||
if bit15 == 0x00008000 then
|
||||
print(('[=] Status: 15 bitflipped and active => '..ansicolors.red..'SUCCESS?: '..ansicolors.reset..'14: %08X 15: '..ansicolors.cyan..'%08X'..ansicolors.reset):format(word14, word15))
|
||||
print('[+] Committing results...')
|
||||
reset(wr_value, password)
|
||||
local word14b, err14b = core.em4x05_read(14, password)
|
||||
if err14b then
|
||||
return oops(err14b)
|
||||
end
|
||||
local wordstr14b = ('%08X'):format(word14b)
|
||||
local word15b, err15b = core.em4x05_read(15, password)
|
||||
if err15b then
|
||||
return oops(err15b)
|
||||
end
|
||||
local wordstr15b = ('%08X'):format(word15b)
|
||||
print(('[=] ref:'..rd_value..' 14:%08X 15:%08X '):format(word14b, word15b))
|
||||
|
||||
bit15 = bit.band(0x00008000, word14b)
|
||||
if bit15 == 0x00008000 then
|
||||
if (wordstr14b == wordstr15) then
|
||||
print(('[=] Status: confirmed => '..ansicolors.red..'SUCCESS: '..ansicolors.reset..'14: '..ansicolors.cyan..'%08X'..ansicolors.reset..' 15: %08X'):format(word14b, word15b))
|
||||
return exit_msg()
|
||||
end
|
||||
if (wordstr14b ~= rd_value) then
|
||||
print(('[=] Status: new definitive value! => '..ansicolors.red..'SUCCESS: '..ansicolors.reset..'14: '..ansicolors.cyan..'%08X'..ansicolors.reset..' 15: %08X'):format(word14b, word15b))
|
||||
return exit_msg()
|
||||
end
|
||||
print(('[=] Status: failed to commit bitflip => '..ansicolors.red..'FAIL: '..ansicolors.reset..'14: %08X 15: %08X'):format(word14b, word15b))
|
||||
else
|
||||
print(('[=] Status: failed to commit => '..ansicolors.red..'FAIL: '..ansicolors.reset..'14: %08X 15: %08X'):format(word14b, word15b))
|
||||
end
|
||||
else
|
||||
print(('[=] Status: 15 bitflipped but inactive => '..ansicolors.yellow..'PROMISING: '..ansicolors.reset..'14: %08X 15: '..ansicolors.cyan..'%08X'..ansicolors.reset):format(word14, word15))
|
||||
end
|
||||
if auto then
|
||||
n = 0
|
||||
ed = sd
|
||||
else
|
||||
tries = 0
|
||||
soon = 0
|
||||
late = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
if not auto then
|
||||
tries = tries + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--[[
|
||||
In the future, we may implement so that scripts are invoked directly
|
||||
into a 'main' function, instead of being executed blindly. For future
|
||||
compatibility, I have done so, but I invoke my main from here.
|
||||
--]]
|
||||
main(args)
|
|
@ -192,7 +192,7 @@ local function main(args)
|
|||
print('Press enter to program card '..cardnum..':'..facility..' (hex: '..card..')')
|
||||
--This would be better with 'press Enter', but we'll take what we can get.
|
||||
io.read()
|
||||
core.console( ('lf hid clone %s'):format(card) )
|
||||
core.console( ('lf hid clone -r %s'):format(card) )
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ desc = [[
|
|||
\ / \ /
|
||||
`---' `---'
|
||||
|
||||
*SUPPORTED TAGS: pyramid, awid, fdx, jablotron, noralsy, presco, visa2000, 14a, hid
|
||||
*SUPPORTED TAGS: pyramid, awid, fdxb, jablotron, noralsy, presco, visa2000, 14a, hid
|
||||
|
||||
This script uses the Proxmark3 implementations of simulation to bruteforce given ranges of id.
|
||||
It uses both LF and HF simulations.
|
||||
|
@ -42,7 +42,7 @@ arguments = [[
|
|||
-r *see below RFID Tag: the RFID tag to emulate
|
||||
pyramid
|
||||
awid
|
||||
fdx
|
||||
fdxb
|
||||
jablotron
|
||||
noralsy
|
||||
presco
|
||||
|
@ -180,8 +180,8 @@ local function main(args)
|
|||
consolecommand = 'lf awid sim'
|
||||
rfidtagname = 'AWID'
|
||||
facilityrequired = 1
|
||||
elseif rfidtag == 'fdx' then -- I'm not sure why you would need to bruteforce this ¯\_(ツ)_/¯
|
||||
consolecommand = 'lf fdx sim'
|
||||
elseif rfidtag == 'fdxb' then -- I'm not sure why you would need to bruteforce this ¯\_(ツ)_/¯
|
||||
consolecommand = 'lf fdxb sim'
|
||||
rfidtagname = 'FDX-B'
|
||||
facilityrequired = 1
|
||||
elseif rfidtag == 'jablotron' then
|
||||
|
@ -214,7 +214,7 @@ local function main(args)
|
|||
end
|
||||
facilityrequired = 0 -- Disable the FC required check, as we used it for type instead of FC
|
||||
elseif rfidtag == 'hid' then
|
||||
consolecommand = 'lf hid sim'
|
||||
consolecommand = 'lf hid sim -r'
|
||||
rfidtagname = 'HID'
|
||||
facilityrequired = 1
|
||||
else -- Display error and exit out if bad RFID tag was supplied
|
||||
|
|
|
@ -77,7 +77,7 @@ local function main(args)
|
|||
print( string.rep('--',20) )
|
||||
print( string.rep('--',20) )
|
||||
|
||||
local cmdDataLoad = 'data load %s';
|
||||
local cmdDataLoad = 'data load -f %s';
|
||||
local cwd = core.cwd();
|
||||
|
||||
local tracesEM = "find '"..cwd.."/traces/ ' -iname 'em*.pm3' -type f"
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "reveng.h"
|
||||
#include "ui.h"
|
||||
#include "util.h"
|
||||
#include "pm3_cmd.h"
|
||||
|
||||
#define MAX_ARGS 20
|
||||
|
||||
|
@ -253,7 +254,6 @@ int RunModel(char *inModel, char *inHexStr, bool reverse, char endian, char *res
|
|||
|
||||
int ibperhx = 8, obperhx = 8;
|
||||
// int rflags = 0; // search flags
|
||||
int c;
|
||||
poly_t apoly, crc;
|
||||
|
||||
char *string;
|
||||
|
@ -265,7 +265,7 @@ int RunModel(char *inModel, char *inHexStr, bool reverse, char endian, char *res
|
|||
|
||||
SETBMP();
|
||||
//set model
|
||||
c = mbynam(&model, inModel);
|
||||
int c = mbynam(&model, inModel);
|
||||
if (!c) {
|
||||
PrintAndLogEx(ERR, "error: preset model '%s' not found. Use reveng -D to list presets. [%d]", inModel, c);
|
||||
return 0;
|
||||
|
@ -405,7 +405,7 @@ static int CmdrevengSearch(const char *Cmd) {
|
|||
|
||||
#define NMODELS 106
|
||||
|
||||
char inHexStr[100] = {0x00};
|
||||
char inHexStr[256] = {0x00};
|
||||
int dataLen = param_getstr(Cmd, 0, inHexStr, sizeof(inHexStr));
|
||||
if (dataLen < 4) return 0;
|
||||
|
||||
|
@ -418,7 +418,12 @@ static int CmdrevengSearch(const char *Cmd) {
|
|||
char revResult[30];
|
||||
int ans = GetModels(Models, &count, width);
|
||||
bool found = false;
|
||||
if (!ans) return 0;
|
||||
if (!ans) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
free(Models[i]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// try each model and get result
|
||||
for (int i = 0; i < count; i++) {
|
||||
|
@ -429,8 +434,10 @@ static int CmdrevengSearch(const char *Cmd) {
|
|||
// round up to # of characters in this model's crc
|
||||
uint8_t crcChars = ((width[i] + 7) / 8) * 2;
|
||||
// can't test a model that has more crc digits than our data
|
||||
if (crcChars >= dataLen)
|
||||
if (crcChars >= dataLen) {
|
||||
free(Models[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
PrintAndLogEx(DEBUG
|
||||
, "DEBUG: dataLen %d, crcChars %u, width[i] %u"
|
||||
|
@ -439,8 +446,10 @@ static int CmdrevengSearch(const char *Cmd) {
|
|||
, width[i]
|
||||
);
|
||||
|
||||
if (crcChars == 0)
|
||||
if (crcChars == 0) {
|
||||
free(Models[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
memset(result, 0, 30);
|
||||
char *inCRC = calloc(crcChars + 1, sizeof(char));
|
||||
|
@ -492,26 +501,29 @@ static int CmdrevengSearch(const char *Cmd) {
|
|||
free(Models[i]);
|
||||
}
|
||||
|
||||
if (!found) PrintAndLogEx(FAILED, "\nno matches found\n");
|
||||
return 1;
|
||||
if (found == false)
|
||||
PrintAndLogEx(FAILED, "\nno matches found\n");
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int CmdCrc(const char *Cmd) {
|
||||
char name[] = {"reveng "};
|
||||
char Cmd2[100 + 7];
|
||||
memcpy(Cmd2, name, 7);
|
||||
memcpy(Cmd2 + 7, Cmd, 100);
|
||||
char c[100 + 7];
|
||||
snprintf(c, sizeof(c), "reveng ");
|
||||
snprintf(c + strlen(c), sizeof(c) - strlen(c), Cmd, strlen(Cmd));
|
||||
|
||||
char *argv[MAX_ARGS];
|
||||
int argc = split(Cmd2, argv);
|
||||
int argc = split(c, argv);
|
||||
|
||||
if (argc == 3 && memcmp(argv[1], "-g", 2) == 0) {
|
||||
CmdrevengSearch(argv[2]);
|
||||
} else {
|
||||
reveng_main(argc, argv);
|
||||
}
|
||||
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
free(argv[i]);
|
||||
}
|
||||
return 0;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,31 +27,17 @@
|
|||
#include "fileutils.h" // searchFile
|
||||
#include "mifare/ndef.h"
|
||||
#include "cliparser.h"
|
||||
#include "cmdlft55xx.h" // print...
|
||||
|
||||
uint8_t DemodBuffer[MAX_DEMOD_BUF_LEN];
|
||||
size_t DemodBufferLen = 0;
|
||||
size_t g_DemodStartIdx = 0;
|
||||
int32_t g_DemodStartIdx = 0;
|
||||
int g_DemodClock = 0;
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static int usage_data_save(void) {
|
||||
PrintAndLogEx(NORMAL, "Save trace from graph window , i.e. the GraphBuffer");
|
||||
PrintAndLogEx(NORMAL, "This is a text file with number -127 to 127. With the option `w` you can save it as wave file");
|
||||
PrintAndLogEx(NORMAL, "Filename should be without file extension");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: data save [h] [w] [f <filename w/o ext>]");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h this help");
|
||||
PrintAndLogEx(NORMAL, " w save as wave format (.wav)");
|
||||
PrintAndLogEx(NORMAL, " f <filename> save file name");
|
||||
PrintAndLogEx(NORMAL, "Samples:");
|
||||
PrintAndLogEx(NORMAL, " data save f mytrace - save graphbuffer to file");
|
||||
PrintAndLogEx(NORMAL, " data save f mytrace w - save graphbuffer to wave file");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_data_printdemodbuf(void) {
|
||||
PrintAndLogEx(NORMAL, "Usage: data printdemodbuffer x o <offset> l <length>");
|
||||
PrintAndLogEx(NORMAL, "Usage: data print x o <offset> l <length>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h this help");
|
||||
PrintAndLogEx(NORMAL, " i invert Demodbuffer before printing");
|
||||
|
@ -236,15 +222,6 @@ static int usage_data_autocorr(void) {
|
|||
PrintAndLogEx(NORMAL, " g save back to GraphBuffer (overwrite)");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_data_undecimate(void) {
|
||||
PrintAndLogEx(NORMAL, "Usage: data undec [factor]");
|
||||
PrintAndLogEx(NORMAL, "This function performs un-decimation, by repeating each sample N times");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h This help");
|
||||
PrintAndLogEx(NORMAL, " factor The number of times to repeat each sample.[default:2]");
|
||||
PrintAndLogEx(NORMAL, "Example: 'data undec 3'");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_data_detectclock(void) {
|
||||
PrintAndLogEx(NORMAL, "Usage: data detectclock [modulation] <clock>");
|
||||
PrintAndLogEx(NORMAL, " [modulation as char], specify the modulation type you want to detect the clock of");
|
||||
|
@ -269,7 +246,7 @@ static int usage_data_bin2hex(void) {
|
|||
}
|
||||
static int usage_data_buffclear(void) {
|
||||
PrintAndLogEx(NORMAL, "This function clears the bigbuff on deviceside");
|
||||
PrintAndLogEx(NORMAL, "Usage: data buffclear [h]");
|
||||
PrintAndLogEx(NORMAL, "Usage: data clear [h]");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h This help");
|
||||
return PM3_SUCCESS;
|
||||
|
@ -544,6 +521,7 @@ static int CmdConvertBitStream(const char *Cmd) {
|
|||
//emSearch will auto search for EM410x format in bitstream
|
||||
//askType switches decode: ask/raw = 0, ask/manchester = 1
|
||||
int ASKDemod_ext(int clk, int invert, int maxErr, size_t maxLen, bool amplify, bool verbose, bool emSearch, uint8_t askType, bool *stCheck) {
|
||||
PrintAndLogEx(DEBUG, "DEBUG: (ASKDemod_ext) clk %i invert %i maxErr %i maxLen %zu amplify %i verbose %i emSearch %i askType %i ", clk, invert, maxErr, maxLen, amplify, verbose, emSearch, askType);
|
||||
uint8_t askamp = 0;
|
||||
|
||||
if (!maxLen) maxLen = pm3_capabilities.bigbuf_size;
|
||||
|
@ -638,28 +616,37 @@ int ASKDemod(int clk, int invert, int maxErr, size_t maxLen, bool amplify, bool
|
|||
//attempts to demodulate ask while decoding manchester
|
||||
//prints binary found and saves in graphbuffer for further commands
|
||||
static int Cmdaskmandemod(const char *Cmd) {
|
||||
|
||||
size_t slen = strlen(Cmd);
|
||||
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) > 45 || cmdp == 'h') return usage_data_rawdemod_am();
|
||||
bool st = false;
|
||||
if (Cmd[0] == 's') {
|
||||
st = true;
|
||||
Cmd++;
|
||||
} else if (Cmd[1] == 's') {
|
||||
st = true;
|
||||
Cmd += 2;
|
||||
}
|
||||
int clk = 0;
|
||||
int invert = 0;
|
||||
int maxErr = 100;
|
||||
if (slen > 45 || cmdp == 'h') return usage_data_rawdemod_am();
|
||||
|
||||
bool st = false, amplify = false;
|
||||
int clk = 0, invert = 0, maxErr = 100;
|
||||
size_t maxLen = 0;
|
||||
bool amplify = false;
|
||||
char amp = tolower(param_getchar(Cmd, 0));
|
||||
sscanf(Cmd, "%i %i %i %zu %c", &clk, &invert, &maxErr, &maxLen, &);
|
||||
amplify = amp == 'a';
|
||||
|
||||
if (slen) {
|
||||
|
||||
if (Cmd[0] == 's') {
|
||||
st = true;
|
||||
Cmd++;
|
||||
} else if (slen > 1 && Cmd[1] == 's') {
|
||||
st = true;
|
||||
Cmd += 2;
|
||||
}
|
||||
|
||||
char amp = tolower(param_getchar(Cmd, 0));
|
||||
sscanf(Cmd, "%i %i %i %zu %c", &clk, &invert, &maxErr, &maxLen, &);
|
||||
|
||||
amplify = (amp == 'a');
|
||||
}
|
||||
|
||||
if (clk == 1) {
|
||||
invert = 1;
|
||||
clk = 0;
|
||||
}
|
||||
|
||||
if (invert != 0 && invert != 1) {
|
||||
PrintAndLogEx(WARNING, "Invalid value for invert: %i", invert);
|
||||
return PM3_EINVARG;
|
||||
|
@ -998,12 +985,29 @@ static int CmdBuffClear(const char *Cmd) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdDec(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
for (size_t i = 0; i < (GraphTraceLen / 2); ++i)
|
||||
GraphBuffer[i] = GraphBuffer[i * 2];
|
||||
GraphTraceLen /= 2;
|
||||
PrintAndLogEx(NORMAL, "decimated by 2");
|
||||
static int CmdDecimate(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "data decimate",
|
||||
"Performs decimation, by reducing samples N times in the grapbuf. Good for PSK\n",
|
||||
"data decimate\n"
|
||||
"data decimate 4"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_int0(NULL, NULL, "<dec>", "factor to reduce sample set (default 2)"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
int n = arg_get_int_def(ctx, 1, 2);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
for (size_t i = 0; i < (GraphTraceLen / n); ++i)
|
||||
GraphBuffer[i] = GraphBuffer[i * n];
|
||||
|
||||
GraphTraceLen /= n;
|
||||
PrintAndLogEx(SUCCESS, "decimated by " _GREEN_("%u"), n);
|
||||
RepaintGraphWindow();
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
@ -1014,19 +1018,34 @@ static int CmdDec(const char *Cmd) {
|
|||
* @param Cmd
|
||||
* @return
|
||||
*/
|
||||
static int CmdUndec(const char *Cmd) {
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (cmdp == 'h') return usage_data_undecimate();
|
||||
static int CmdUndecimate(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "data undecimate",
|
||||
"Performs un-decimation, by repeating each sample N times in the graphbuf",
|
||||
"data undecimate\n"
|
||||
"data undecimate 4\n"
|
||||
);
|
||||
|
||||
uint8_t factor = param_get8ex(Cmd, 0, 2, 10);
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_int0(NULL, NULL, "<dec>", "factor to repeat each sample (default 2)"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
int factor = arg_get_int_def(ctx, 1, 2);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
//We have memory, don't we?
|
||||
int swap[MAX_GRAPH_TRACE_LEN] = {0};
|
||||
uint32_t g_index = 0, s_index = 0;
|
||||
while (g_index < GraphTraceLen && s_index + factor < MAX_GRAPH_TRACE_LEN) {
|
||||
int count = 0;
|
||||
for (count = 0; count < factor && s_index + count < MAX_GRAPH_TRACE_LEN; count++)
|
||||
swap[s_index + count] = GraphBuffer[g_index];
|
||||
for (count = 0; count < factor && s_index + count < MAX_GRAPH_TRACE_LEN; count++) {
|
||||
swap[s_index + count] = (
|
||||
(double)(factor - count) / (factor - 1)) * GraphBuffer[g_index] +
|
||||
((double)count / factor) * GraphBuffer[g_index + 1]
|
||||
;
|
||||
}
|
||||
s_index += count;
|
||||
g_index++;
|
||||
}
|
||||
|
@ -1437,7 +1456,7 @@ void setClockGrid(uint32_t clk, int offset) {
|
|||
}
|
||||
|
||||
int CmdGrid(const char *Cmd) {
|
||||
sscanf(Cmd, "%i %i", &PlotGridX, &PlotGridY);
|
||||
sscanf(Cmd, "%lf %lf", &PlotGridX, &PlotGridY);
|
||||
PlotGridXdefault = PlotGridX;
|
||||
PlotGridYdefault = PlotGridY;
|
||||
RepaintGraphWindow();
|
||||
|
@ -1675,6 +1694,48 @@ int CmdTuneSamples(const char *Cmd) {
|
|||
if (package->peak_v > NON_VOLTAGE && package->peak_f > 0)
|
||||
PrintAndLogEx(SUCCESS, "LF optimal: %5.2f V - %6.2f kHz", (package->peak_v * ANTENNA_ERROR) / 1000.0, LF_DIV2FREQ(package->peak_f));
|
||||
|
||||
const double vdd_rdv4 = 9000;
|
||||
const double vdd_other = 5400; // Empirical measures in mV
|
||||
double vdd = IfPm3Rdv4Fw() ? vdd_rdv4 : vdd_other;
|
||||
if (package->peak_v > NON_VOLTAGE && package->peak_f > 0) {
|
||||
|
||||
// Q measure with Q=f/delta_f
|
||||
double v_3db_scaled = (double)(package->peak_v * 0.707) / 512; // /512 == >>9
|
||||
uint32_t s2 = 0, s4 = 0;
|
||||
for (int i = 1; i < 256; i++) {
|
||||
if ((s2 == 0) && (package->results[i] > v_3db_scaled)) {
|
||||
s2 = i;
|
||||
}
|
||||
if ((s2 != 0) && (package->results[i] < v_3db_scaled)) {
|
||||
s4 = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
double lfq1 = 0;
|
||||
if (s4 != 0) { // we got all our points of interest
|
||||
double a = package->results[s2 - 1];
|
||||
double b = package->results[s2];
|
||||
double f1 = LF_DIV2FREQ(s2 - 1 + (v_3db_scaled - a) / (b - a));
|
||||
double c = package->results[s4 - 1];
|
||||
double d = package->results[s4];
|
||||
double f2 = LF_DIV2FREQ(s4 - 1 + (c - v_3db_scaled) / (c - d));
|
||||
lfq1 = LF_DIV2FREQ(package->peak_f) / (f1 - f2);
|
||||
PrintAndLogEx(SUCCESS, "Approx. Q factor (*): %.1lf by frequency bandwidth measurement", lfq1);
|
||||
}
|
||||
|
||||
// Q measure with Vlr=Q*(2*Vdd/pi)
|
||||
double lfq2 = (double)package->peak_v * 3.14 / 2 / vdd;
|
||||
PrintAndLogEx(SUCCESS, "Approx. Q factor (*): %.1lf by peak voltage measurement", lfq2);
|
||||
// cross-check results
|
||||
if (lfq1 > 3) {
|
||||
double approx_vdd = (double)package->peak_v * 3.14 / 2 / lfq1;
|
||||
if ((approx_vdd > (vdd_rdv4 + vdd_other) / 2) && (! IfPm3Rdv4Fw()))
|
||||
PrintAndLogEx(WARNING, "Contradicting measures seem to indicate you're running a " _YELLOW_("PM3_OTHER firmware on a RDV4") ", please check your setup");
|
||||
if ((approx_vdd < (vdd_rdv4 + vdd_other) / 2) && (IfPm3Rdv4Fw()))
|
||||
PrintAndLogEx(WARNING, "Contradicting measures seem to indicate you're running a " _YELLOW_("PM3_RDV4 firmware on a non-RDV4") ", please check your setup");
|
||||
}
|
||||
}
|
||||
|
||||
char judgement[20];
|
||||
memset(judgement, 0, sizeof(judgement));
|
||||
// LF evaluation
|
||||
|
@ -1694,6 +1755,11 @@ int CmdTuneSamples(const char *Cmd) {
|
|||
|
||||
memset(judgement, 0, sizeof(judgement));
|
||||
|
||||
if (package->v_hf >= HF_UNUSABLE_V) {
|
||||
// Q measure with Vlr=Q*(2*Vdd/pi)
|
||||
double hfq = (double)package->v_hf * 3.14 / 2 / vdd;
|
||||
PrintAndLogEx(SUCCESS, "Approx. Q factor (*): %.1lf by peak voltage measurement", hfq);
|
||||
}
|
||||
if (package->v_hf < HF_UNUSABLE_V)
|
||||
sprintf(judgement, _RED_("UNUSABLE"));
|
||||
else if (package->v_hf < HF_MARGINAL_V)
|
||||
|
@ -1702,6 +1768,7 @@ int CmdTuneSamples(const char *Cmd) {
|
|||
sprintf(judgement, _GREEN_("OK"));
|
||||
|
||||
PrintAndLogEx((package->v_hf < HF_UNUSABLE_V) ? WARNING : SUCCESS, "HF antenna is %s", judgement);
|
||||
PrintAndLogEx(NORMAL, "\n(*) Q factor must be measured without tag on the antenna");
|
||||
|
||||
// graph LF measurements
|
||||
// even here, these values has 3% error.
|
||||
|
@ -1712,9 +1779,11 @@ int CmdTuneSamples(const char *Cmd) {
|
|||
}
|
||||
|
||||
if (test1 > 0) {
|
||||
PrintAndLogEx(SUCCESS, "\nDisplaying LF tuning graph. Divisor %d is %.2f kHz, %d is %.2f kHz.\n\n",
|
||||
PrintAndLogEx(SUCCESS, "\nDisplaying LF tuning graph. Divisor %d (blue) is %.2f kHz, %d (red) is %.2f kHz.\n\n",
|
||||
LF_DIVISOR_134, LF_DIV2FREQ(LF_DIVISOR_134), LF_DIVISOR_125, LF_DIV2FREQ(LF_DIVISOR_125));
|
||||
GraphTraceLen = 256;
|
||||
CursorCPos = LF_DIVISOR_125;
|
||||
CursorDPos = LF_DIVISOR_134;
|
||||
ShowGraphWindow();
|
||||
RepaintGraphWindow();
|
||||
} else {
|
||||
|
@ -1726,16 +1795,26 @@ int CmdTuneSamples(const char *Cmd) {
|
|||
}
|
||||
|
||||
static int CmdLoad(const char *Cmd) {
|
||||
char filename[FILE_PATH_SIZE] = {0x00};
|
||||
int len = 0;
|
||||
|
||||
len = strlen(Cmd);
|
||||
if (len == 0) return PM3_EFILE;
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "data load",
|
||||
"This command loads the contents of a pm3 file into graph window\n",
|
||||
"data load -f myfilename"
|
||||
);
|
||||
|
||||
if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE;
|
||||
memcpy(filename, Cmd, len);
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_strx0("f", "file", "<filename>", "file to load"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
char *path;
|
||||
int fnlen = 0;
|
||||
char filename[FILE_PATH_SIZE] = {0};
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
char *path = NULL;
|
||||
if (searchFile(&path, TRACES_SUBDIR, filename, ".pm3", true) != PM3_SUCCESS) {
|
||||
if (searchFile(&path, TRACES_SUBDIR, filename, "", false) != PM3_SUCCESS) {
|
||||
return PM3_EFILE;
|
||||
|
@ -1759,7 +1838,6 @@ static int CmdLoad(const char *Cmd) {
|
|||
if (GraphTraceLen >= MAX_GRAPH_TRACE_LEN)
|
||||
break;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
|
||||
PrintAndLogEx(SUCCESS, "loaded " _YELLOW_("%zu") " samples", GraphTraceLen);
|
||||
|
@ -1789,6 +1867,7 @@ int CmdLtrim(const char *Cmd) {
|
|||
GraphBuffer[i - ds] = GraphBuffer[i];
|
||||
|
||||
GraphTraceLen -= ds;
|
||||
g_DemodStartIdx -= ds;
|
||||
RepaintGraphWindow();
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
@ -1858,39 +1937,29 @@ int CmdPlot(const char *Cmd) {
|
|||
|
||||
int CmdSave(const char *Cmd) {
|
||||
|
||||
int len = 0;
|
||||
char filename[FILE_PATH_SIZE] = {0x00};
|
||||
uint8_t cmdp = 0;
|
||||
bool errors = false, as_wave = false, has_name = false;
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "data save",
|
||||
"Save trace from graph window , i.e. the GraphBuffer\n"
|
||||
"This is a text file with number -127 to 127. With the option `w` you can save it as wave file\n"
|
||||
"Filename should be without file extension",
|
||||
"data save -f myfilename -> save graph buffer to file\n"
|
||||
"data save --wave -f myfilename -> save graph buffer to wave file"
|
||||
);
|
||||
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
char ctmp = tolower(param_getchar(Cmd, cmdp));
|
||||
switch (ctmp) {
|
||||
case 'h':
|
||||
return usage_data_save();
|
||||
case 'f':
|
||||
len = param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE);
|
||||
if (len < 1) {
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
has_name = true;
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'w':
|
||||
as_wave = true;
|
||||
cmdp++;
|
||||
break;
|
||||
default:
|
||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("w", "wave", "save as wave format (.wav)"),
|
||||
arg_strx0("f", "file", "<fn w/o ext>", "save file name"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
if (!has_name) errors = true;
|
||||
bool as_wave = arg_get_lit(ctx, 1);
|
||||
|
||||
if (errors || cmdp == 0) return usage_data_save();
|
||||
int fnlen = 0;
|
||||
char filename[FILE_PATH_SIZE] = {0};
|
||||
CLIGetStrWithReturn(ctx, 2, (uint8_t *)filename, &fnlen);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (as_wave)
|
||||
return saveFileWAVE(filename, GraphBuffer, GraphTraceLen);
|
||||
|
@ -1898,32 +1967,32 @@ int CmdSave(const char *Cmd) {
|
|||
return saveFilePM3(filename, GraphBuffer, GraphTraceLen);
|
||||
}
|
||||
|
||||
static int CmdScale(const char *Cmd) {
|
||||
static int CmdTimeScale(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "data scale",
|
||||
"Set cursor display scale.\n"
|
||||
"Setting the scale makes the differential `dt` reading between the yellow and purple markers meaningful.\n"
|
||||
"once the scale is set, the differential reading between brackets can become a time duration.",
|
||||
"data scale --sr 125 -u ms -> for LF sampled at 125 kHz. Reading will be in milliseconds\n"
|
||||
"data scale --sr 1.695 -u us -> for HF sampled at 1.695 MHz. Reading will be in microseconds\n"
|
||||
"data scale --sr 16 -u ETU -> for HF with 16 samples per ETU. Reading will be in ETUs"
|
||||
);
|
||||
CLIParserInit(&ctx, "data timescale",
|
||||
"Set cursor display timescale.\n"
|
||||
"Setting the timescale makes the differential `dt` reading between the yellow and purple markers meaningful.\n"
|
||||
"once the timescale is set, the differential reading between brackets can become a time duration.",
|
||||
"data timescale --sr 125 -u ms -> for LF sampled at 125 kHz. Reading will be in milliseconds\n"
|
||||
"data timescale --sr 1.695 -u us -> for HF sampled at 16 * fc/128. Reading will be in microseconds\n"
|
||||
"data timescale --sr 16 -u ETU -> for HF with 16 samples per ETU (fc/128). Reading will be in ETUs"
|
||||
);
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_dbl1(NULL, "sr", "<float>", "sets scale according to sampling rate"),
|
||||
arg_dbl1(NULL, "sr", "<float>", "sets timescale factor 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");
|
||||
PrintAndLogEx(FAILED, "bad, can't have negative or zero timescale factor");
|
||||
CursorScaleFactor = 1;
|
||||
}
|
||||
int len = 0;
|
||||
CursorScaleFactorUnit[0] = '\x00';
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t*)CursorScaleFactorUnit, sizeof(CursorScaleFactorUnit), &len);
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)CursorScaleFactorUnit, sizeof(CursorScaleFactorUnit), &len);
|
||||
CLIParserFree(ctx);
|
||||
RepaintGraphWindow();
|
||||
return PM3_SUCCESS;
|
||||
|
@ -2298,45 +2367,206 @@ static int CmdDataNDEF(const char *Cmd) {
|
|||
return res;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
t55xx_modulation modulation;
|
||||
int bitrate;
|
||||
int carrier;
|
||||
uint8_t fc1;
|
||||
uint8_t fc2;
|
||||
} lf_modulation_t;
|
||||
|
||||
static int print_modulation(lf_modulation_t b) {
|
||||
PrintAndLogEx(INFO, " Modulation.... " _GREEN_("%s"), GetSelectedModulationStr(b.modulation));
|
||||
PrintAndLogEx(INFO, " Bit clock..... " _GREEN_("RF/%d"), b.bitrate);
|
||||
switch (b.modulation) {
|
||||
case DEMOD_PSK1:
|
||||
case DEMOD_PSK2:
|
||||
case DEMOD_PSK3:
|
||||
PrintAndLogEx(SUCCESS, " Carrier rate.. %d", b.carrier);
|
||||
break;
|
||||
case DEMOD_FSK:
|
||||
case DEMOD_FSK1:
|
||||
case DEMOD_FSK1a:
|
||||
case DEMOD_FSK2:
|
||||
case DEMOD_FSK2a:
|
||||
PrintAndLogEx(SUCCESS, " Field Clocks.. FC/%u, FC/%u", b.fc1, b.fc2);
|
||||
break;
|
||||
case DEMOD_NRZ:
|
||||
case DEMOD_ASK:
|
||||
case DEMOD_BI:
|
||||
case DEMOD_BIa:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int try_detect_modulation(void) {
|
||||
|
||||
lf_modulation_t tests[6];
|
||||
int clk = 0, firstClockEdge = 0;
|
||||
uint8_t hits = 0, ans = 0;
|
||||
uint8_t fc1 = 0, fc2 = 0;
|
||||
bool st = false;
|
||||
|
||||
ans = fskClocks(&fc1, &fc2, (uint8_t *)&clk, &firstClockEdge);
|
||||
|
||||
if (ans && ((fc1 == 10 && fc2 == 8) || (fc1 == 8 && fc2 == 5))) {
|
||||
|
||||
if ((FSKrawDemod(0, 0, 0, 0, false) == PM3_SUCCESS)) {
|
||||
tests[hits].modulation = DEMOD_FSK;
|
||||
if (fc1 == 8 && fc2 == 5) {
|
||||
tests[hits].modulation = DEMOD_FSK1a;
|
||||
} else if (fc1 == 10 && fc2 == 8) {
|
||||
tests[hits].modulation = DEMOD_FSK2;
|
||||
}
|
||||
|
||||
tests[hits].bitrate = clk;
|
||||
tests[hits].fc1 = fc1;
|
||||
tests[hits].fc2 = fc2;
|
||||
++hits;
|
||||
}
|
||||
|
||||
} else {
|
||||
clk = GetAskClock("", false);
|
||||
if (clk > 0) {
|
||||
// 0 = auto clock
|
||||
// 0 = no invert
|
||||
// 1 = maxError 1
|
||||
// 0 = max len
|
||||
// false = no amplify
|
||||
// false = no verbose
|
||||
// false = no emSearch
|
||||
// 1 = Ask/Man
|
||||
// st = true
|
||||
if ((ASKDemod_ext(0, 0, 1, 0, false, false, false, 1, &st) == PM3_SUCCESS)) {
|
||||
tests[hits].modulation = DEMOD_ASK;
|
||||
tests[hits].bitrate = clk;
|
||||
++hits;
|
||||
}
|
||||
// "0 0 1 " == clock auto, invert true, maxError 1.
|
||||
// false = no verbose
|
||||
// false = no emSearch
|
||||
// 1 = Ask/Man
|
||||
// st = true
|
||||
|
||||
// ASK / biphase
|
||||
if ((ASKbiphaseDemod(0, 0, 0, 2, false) == PM3_SUCCESS)) {
|
||||
tests[hits].modulation = DEMOD_BI;
|
||||
tests[hits].bitrate = clk;
|
||||
++hits;
|
||||
}
|
||||
// ASK / Diphase
|
||||
if ((ASKbiphaseDemod(0, 0, 1, 2, false) == PM3_SUCCESS)) {
|
||||
tests[hits].modulation = DEMOD_BIa;
|
||||
tests[hits].bitrate = clk;
|
||||
++hits;
|
||||
}
|
||||
}
|
||||
clk = GetNrzClock("", false);
|
||||
if ((NRZrawDemod(0, 0, 1, false) == PM3_SUCCESS)) {
|
||||
tests[hits].modulation = DEMOD_NRZ;
|
||||
tests[hits].bitrate = clk;
|
||||
++hits;
|
||||
}
|
||||
|
||||
clk = GetPskClock("", false);
|
||||
if (clk > 0) {
|
||||
// allow undo
|
||||
save_restoreGB(GRAPH_SAVE);
|
||||
// skip first 160 samples to allow antenna to settle in (psk gets inverted occasionally otherwise)
|
||||
CmdLtrim("160");
|
||||
if ((PSKDemod(0, 0, 6, false) == PM3_SUCCESS)) {
|
||||
tests[hits].modulation = DEMOD_PSK1;
|
||||
tests[hits].bitrate = clk;
|
||||
++hits;
|
||||
|
||||
// get psk carrier
|
||||
tests[hits].carrier = GetPskCarrier(false);
|
||||
}
|
||||
//undo trim samples
|
||||
save_restoreGB(GRAPH_RESTORE);
|
||||
}
|
||||
}
|
||||
|
||||
if (hits) {
|
||||
PrintAndLogEx(SUCCESS, "Found [%d] possible matches for modulation.", hits);
|
||||
for (int i = 0; i < hits; ++i) {
|
||||
PrintAndLogEx(INFO, "--[%d]---------------", i + 1);
|
||||
print_modulation(tests[i]);
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
} else {
|
||||
PrintAndLogEx(INFO, "Signal doesn't match");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
}
|
||||
|
||||
static int CmdDataModulationSearch(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "data modulation",
|
||||
"search LF signal after clock and modulation\n",
|
||||
"data modulation"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
CLIParserFree(ctx);
|
||||
return try_detect_modulation();
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"askedgedetect", CmdAskEdgeDetect, AlwaysAvailable, "[threshold] Adjust Graph for manual ASK demod using the length of sample differences to detect the edge of a wave (use 20-45, def:25)"},
|
||||
{"autocorr", CmdAutoCorr, AlwaysAvailable, "[window length] [g] -- Autocorrelation over window - g to save back to GraphBuffer (overwrite)"},
|
||||
{"biphaserawdecode", CmdBiphaseDecodeRaw, AlwaysAvailable, "[offset] [invert<0|1>] [maxErr] -- Biphase decode bin stream in DemodBuffer (offset = 0|1 bits to shift the decode start)"},
|
||||
{"bin2hex", Cmdbin2hex, AlwaysAvailable, "<digits> -- Converts binary to hexadecimal"},
|
||||
{"bitsamples", CmdBitsamples, IfPm3Present, "Get raw samples as bitstring"},
|
||||
{"buffclear", CmdBuffClear, AlwaysAvailable, "Clears bigbuff on deviceside and graph window"},
|
||||
{"convertbitstream", CmdConvertBitStream, AlwaysAvailable, "Convert GraphBuffer's 0/1 values to 127 / -127"},
|
||||
{"dec", CmdDec, AlwaysAvailable, "Decimate samples"},
|
||||
{"detectclock", CmdDetectClockRate, AlwaysAvailable, "[<a|f|n|p>] Detect ASK, FSK, NRZ, PSK clock rate of wave in GraphBuffer"},
|
||||
{"fsktonrz", CmdFSKToNRZ, AlwaysAvailable, "Convert fsk2 to nrz wave for alternate fsk demodulating (for weak fsk)"},
|
||||
{"getbitstream", CmdGetBitStream, AlwaysAvailable, "Convert GraphBuffer's >=1 values to 1 and <1 to 0"},
|
||||
{"grid", CmdGrid, AlwaysAvailable, "<x> <y> -- overlay grid on graph window, use zero value to turn off either"},
|
||||
{"hexsamples", CmdHexsamples, IfPm3Present, "<bytes> [<offset>] -- Dump big buffer as hex bytes"},
|
||||
{"hex2bin", Cmdhex2bin, AlwaysAvailable, "<hexadecimal> -- Converts hexadecimal to binary"},
|
||||
{"hide", CmdHide, AlwaysAvailable, "Hide graph window"},
|
||||
{"hpf", CmdHpf, AlwaysAvailable, "Remove DC offset from trace"},
|
||||
{"load", CmdLoad, AlwaysAvailable, "<filename> -- Load trace (to graph window"},
|
||||
{"ltrim", CmdLtrim, AlwaysAvailable, "<samples> -- Trim samples from left of trace"},
|
||||
{"rtrim", CmdRtrim, AlwaysAvailable, "<location to end trace> -- Trim samples from right of trace"},
|
||||
{"mtrim", CmdMtrim, AlwaysAvailable, "<start> <stop> -- Trim out samples from the specified start to the specified stop"},
|
||||
{"manrawdecode", Cmdmandecoderaw, AlwaysAvailable, "[invert] [maxErr] -- Manchester decode binary stream in DemodBuffer"},
|
||||
{"norm", CmdNorm, AlwaysAvailable, "Normalize max/min to +/-128"},
|
||||
{"plot", CmdPlot, AlwaysAvailable, "Show graph window (hit 'h' in window for keystroke help)"},
|
||||
{"printdemodbuffer", CmdPrintDemodBuff, AlwaysAvailable, "[x] [o] <offset> [l] <length> -- print the data in the DemodBuffer - 'x' for hex output"},
|
||||
{"rawdemod", CmdRawDemod, AlwaysAvailable, "[modulation] ... <options> -see help (h option) -- Demodulate the data in the GraphBuffer and output binary"},
|
||||
{"samples", CmdSamples, IfPm3Present, "[512 - 40000] -- Get raw samples for graph window (GraphBuffer)"},
|
||||
{"save", CmdSave, AlwaysAvailable, "Save trace (from graph window)"},
|
||||
{"setgraphmarkers", CmdSetGraphMarkers, AlwaysAvailable, "[orange_marker] [blue_marker] (in graph window)"},
|
||||
{"scale", CmdScale, AlwaysAvailable, "<int> -- Set cursor display scale in carrier frequency expressed in kHz"},
|
||||
{"setdebugmode", CmdSetDebugMode, AlwaysAvailable, "<0|1|2> -- Set Debugging Level on client side"},
|
||||
{"shiftgraphzero", CmdGraphShiftZero, AlwaysAvailable, "<shift> -- Shift 0 for Graphed wave + or - shift value"},
|
||||
{"dirthreshold", CmdDirectionalThreshold, AlwaysAvailable, "<thres up> <thres down> -- Max rising higher up-thres/ Min falling lower down-thres, keep rest as prev."},
|
||||
{"tune", CmdTuneSamples, IfPm3Present, "Get hw tune samples for graph window"},
|
||||
{"undec", CmdUndec, AlwaysAvailable, "Un-decimate samples by 2"},
|
||||
{"zerocrossings", CmdZerocrossings, AlwaysAvailable, "Count time between zero-crossings"},
|
||||
{"iir", CmdDataIIR, AlwaysAvailable, "apply IIR buttersworth filter on plotdata"},
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
|
||||
{"-----------", CmdHelp, AlwaysAvailable, "------------------------- " _CYAN_("Modulation") "-------------------------"},
|
||||
{"biphaserawdecode", CmdBiphaseDecodeRaw, AlwaysAvailable, "Biphase decode bin stream in DemodBuffer"},
|
||||
{"detectclock", CmdDetectClockRate, AlwaysAvailable, "Detect ASK, FSK, NRZ, PSK clock rate of wave in GraphBuffer"},
|
||||
{"fsktonrz", CmdFSKToNRZ, AlwaysAvailable, "Convert fsk2 to nrz wave for alternate fsk demodulating (for weak fsk)"},
|
||||
{"manrawdecode", Cmdmandecoderaw, AlwaysAvailable, "Manchester decode binary stream in DemodBuffer"},
|
||||
{"modulation", CmdDataModulationSearch, AlwaysAvailable, "Identify LF signal for clock and modulation"},
|
||||
{"rawdemod", CmdRawDemod, AlwaysAvailable, "Demodulate the data in the GraphBuffer and output binary"},
|
||||
|
||||
{"-----------", CmdHelp, AlwaysAvailable, "------------------------- " _CYAN_("Graph") "-------------------------"},
|
||||
{"askedgedetect", CmdAskEdgeDetect, AlwaysAvailable, "[threshold] Adjust Graph for manual ASK demod using the length of sample differences to detect the edge of a wave (use 20-45, def:25)"},
|
||||
{"autocorr", CmdAutoCorr, AlwaysAvailable, "Autocorrelation over window"},
|
||||
{"dirthreshold", CmdDirectionalThreshold, AlwaysAvailable, "<thres up> <thres down> -- Max rising higher up-thres/ Min falling lower down-thres, keep rest as prev."},
|
||||
{"decimate", CmdDecimate, AlwaysAvailable, "Decimate samples"},
|
||||
{"undecimate", CmdUndecimate, AlwaysAvailable, "Un-decimate samples"},
|
||||
{"hide", CmdHide, AlwaysAvailable, "Hide graph window"},
|
||||
{"hpf", CmdHpf, AlwaysAvailable, "Remove DC offset from trace"},
|
||||
{"iir", CmdDataIIR, AlwaysAvailable, "apply IIR buttersworth filter on plotdata"},
|
||||
{"grid", CmdGrid, AlwaysAvailable, "<x> <y> -- overlay grid on graph window, use zero value to turn off either"},
|
||||
{"ltrim", CmdLtrim, AlwaysAvailable, "<samples> -- Trim samples from left of trace"},
|
||||
{"mtrim", CmdMtrim, AlwaysAvailable, "<start> <stop> -- Trim out samples from the specified start to the specified stop"},
|
||||
{"norm", CmdNorm, AlwaysAvailable, "Normalize max/min to +/-128"},
|
||||
{"plot", CmdPlot, AlwaysAvailable, "Show graph window (hit 'h' in window for keystroke help)"},
|
||||
{"rtrim", CmdRtrim, AlwaysAvailable, "<location to end trace> -- Trim samples from right of trace"},
|
||||
{"setgraphmarkers", CmdSetGraphMarkers, AlwaysAvailable, "[orange_marker] [blue_marker] (in graph window)"},
|
||||
{"shiftgraphzero", CmdGraphShiftZero, AlwaysAvailable, "<shift> -- Shift 0 for Graphed wave + or - shift value"},
|
||||
{"timescale", CmdTimeScale, AlwaysAvailable, "Set a timescale to get a differential reading between the yellow and purple markers as time duration\n"},
|
||||
{"zerocrossings", CmdZerocrossings, AlwaysAvailable, "Count time between zero-crossings"},
|
||||
|
||||
{"convertbitstream", CmdConvertBitStream, AlwaysAvailable, "Convert GraphBuffer's 0/1 values to 127 / -127"},
|
||||
{"getbitstream", CmdGetBitStream, AlwaysAvailable, "Convert GraphBuffer's >=1 values to 1 and <1 to 0"},
|
||||
|
||||
|
||||
{"-----------", CmdHelp, AlwaysAvailable, "------------------------- " _CYAN_("General") "-------------------------"},
|
||||
{"bin2hex", Cmdbin2hex, AlwaysAvailable, "Converts binary to hexadecimal"},
|
||||
{"bitsamples", CmdBitsamples, IfPm3Present, "Get raw samples as bitstring"},
|
||||
{"clear", CmdBuffClear, AlwaysAvailable, "Clears bigbuf on deviceside and graph window"},
|
||||
{"hexsamples", CmdHexsamples, IfPm3Present, "<bytes> [<offset>] -- Dump big buffer as hex bytes"},
|
||||
{"hex2bin", Cmdhex2bin, AlwaysAvailable, "Converts hexadecimal to binary"},
|
||||
{"load", CmdLoad, AlwaysAvailable, "Load contents of file into graph window"},
|
||||
{"ndef", CmdDataNDEF, AlwaysAvailable, "Decode NDEF records"},
|
||||
{"print", CmdPrintDemodBuff, AlwaysAvailable, "print the data in the DemodBuffer"},
|
||||
{"samples", CmdSamples, IfPm3Present, "[512 - 40000] -- Get raw samples for graph window (GraphBuffer)"},
|
||||
{"save", CmdSave, AlwaysAvailable, "Save signal trace data (from graph window)"},
|
||||
{"setdebugmode", CmdSetDebugMode, AlwaysAvailable, "<0|1|2> -- Set Debugging Level on client side"},
|
||||
{"tune", CmdTuneSamples, IfPm3Present, "Measure tuning of device antenna. Results shown in graph window"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
|
|
@ -60,7 +60,7 @@ int CmdPlot(const char *Cmd);
|
|||
int CmdSave(const char *Cmd); // used by cmd auto
|
||||
int CmdTuneSamples(const char *Cmd); // used by cmd lf hw
|
||||
|
||||
int ASKbiphaseDemod(int offset, int clk, int invert, int maxErr, bool verbose); // used by cmd lf em4x, lf fdx, lf guard, lf jablotron, lf nedap, lf t55xx
|
||||
int ASKbiphaseDemod(int offset, int clk, int invert, int maxErr, bool verbose); // used by cmd lf em4x, lf fdxb, lf guard, lf jablotron, lf nedap, lf t55xx
|
||||
int ASKDemod(int clk, int invert, int maxErr, size_t maxLen, bool amplify, bool verbose, bool emSearch, uint8_t askType); // used by cmd lf em4x, lf t55xx, lf viking
|
||||
int ASKDemod_ext(int clk, int invert, int maxErr, size_t maxLen, bool amplify, bool verbose, bool emSearch, uint8_t askType, bool *stCheck); // used by cmd lf, lf em4x, lf noralsy, le presco, lf securekey, lf t55xx, lf visa2k
|
||||
int FSKrawDemod(uint8_t rfLen, uint8_t invert, uint8_t fchigh, uint8_t fclow, bool verbose); // used by cmd lf, lf em4x, lf t55xx
|
||||
|
@ -86,7 +86,7 @@ extern uint8_t DemodBuffer[MAX_DEMOD_BUF_LEN];
|
|||
extern size_t DemodBufferLen;
|
||||
|
||||
extern int g_DemodClock;
|
||||
extern size_t g_DemodStartIdx;
|
||||
extern int32_t g_DemodStartIdx;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ static int CmdFlashmemSpiBaudrate(const char *Cmd) {
|
|||
"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,
|
||||
|
@ -72,7 +72,7 @@ static int CmdFlashMemLoad(const char *Cmd) {
|
|||
"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,
|
||||
|
@ -91,7 +91,7 @@ static int CmdFlashMemLoad(const char *Cmd) {
|
|||
bool is_t55xx = arg_get_lit(ctx, 4);
|
||||
int fnlen = 0;
|
||||
char filename[FILE_PATH_SIZE] = {0};
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 5), (uint8_t*)filename, FILE_PATH_SIZE, &fnlen);
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 5), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
Dictionary_t d = DICTIONARY_NONE;
|
||||
|
@ -227,7 +227,7 @@ static int CmdFlashMemDump(const char *Cmd) {
|
|||
"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,
|
||||
|
@ -244,7 +244,7 @@ static int CmdFlashMemDump(const char *Cmd) {
|
|||
bool view = arg_get_lit(ctx, 3);
|
||||
int fnlen = 0;
|
||||
char filename[FILE_PATH_SIZE] = {0};
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 4), (uint8_t*)filename, FILE_PATH_SIZE, &fnlen);
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 4), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
uint8_t *dump = calloc(len, sizeof(uint8_t));
|
||||
|
@ -282,7 +282,7 @@ static int CmdFlashMemWipe(const char *Cmd) {
|
|||
_WHITE_("[ ") _RED_("!!! OBS") " ] use with caution",
|
||||
"mem wipe -p 0 -> wipes first page"
|
||||
// "mem wipe -i -> inital total wipe"
|
||||
);
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
|
@ -297,7 +297,7 @@ static int CmdFlashMemWipe(const char *Cmd) {
|
|||
// initalwipe = arg_get_lit(ctx, 2);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (page < 0 || page > 2 ) {
|
||||
if (page < 0 || page > 2) {
|
||||
PrintAndLogEx(WARNING, "page must be 0, 1 or 2");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
@ -310,7 +310,7 @@ static int CmdFlashMemWipe(const char *Cmd) {
|
|||
return PM3_ETIMEOUT;
|
||||
}
|
||||
|
||||
const char* msg = "Flash WIPE ";
|
||||
const char *msg = "Flash WIPE ";
|
||||
uint8_t isok = resp.oldarg[0] & 0xFF;
|
||||
if (isok)
|
||||
PrintAndLogEx(SUCCESS, "%s ( " _GREEN_("ok")" )", msg);
|
||||
|
@ -329,7 +329,7 @@ static int CmdFlashMemInfo(const char *Cmd) {
|
|||
"Collect signature and verify it from flash memory",
|
||||
"mem info"
|
||||
// "mem info -s"
|
||||
);
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
|
@ -459,7 +459,7 @@ static int CmdFlashMemInfo(const char *Cmd) {
|
|||
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, "Len.................. %"PRIu64, rsa.len);
|
||||
PrintAndLogEx(INFO, "Exponent............. %s", str_exp);
|
||||
PrintAndLogEx(INFO, "Public key modulus N");
|
||||
PrintAndLogEx(INFO, " %.64s", str_pk);
|
||||
|
|
|
@ -269,9 +269,13 @@ static int usage_hf_14a_reader(void) {
|
|||
}
|
||||
|
||||
static int CmdHF14AList(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
CmdTraceList("14a");
|
||||
return 0;
|
||||
char args[128] = {0};
|
||||
if (strlen(Cmd) == 0) {
|
||||
snprintf(args, sizeof(args), "-t 14a");
|
||||
} else {
|
||||
strncpy(args, Cmd, sizeof(args) - 1);
|
||||
}
|
||||
return CmdTraceList(args);
|
||||
}
|
||||
|
||||
int hf14a_getconfig(hf14a_config *config) {
|
||||
|
@ -1267,14 +1271,14 @@ static int CmdHF14ACmdRaw(const char *Cmd) {
|
|||
*buf = 0;
|
||||
if (++datalen >= sizeof(data)) {
|
||||
if (crc)
|
||||
PrintAndLogEx(NORMAL, "Buffer is full, we can't add CRC to your data");
|
||||
PrintAndLogEx(FAILED, "Buffer is full, we can't add CRC to your data");
|
||||
break;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "Invalid char on input");
|
||||
return 0;
|
||||
PrintAndLogEx(FAILED, "Invalid char on input");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
if (crc && datalen > 0 && datalen < sizeof(data) - 2) {
|
||||
|
@ -1301,7 +1305,7 @@ static int CmdHF14ACmdRaw(const char *Cmd) {
|
|||
flags |= ISO14A_SET_TIMEOUT;
|
||||
if (timeout > MAX_TIMEOUT) {
|
||||
timeout = MAX_TIMEOUT;
|
||||
PrintAndLogEx(NORMAL, "Set timeout to 40542 seconds (11.26 hours). The max we can wait for response");
|
||||
PrintAndLogEx(INFO, "Set timeout to 40542 seconds (11.26 hours). The max we can wait for response");
|
||||
}
|
||||
argtimeout = 13560000 / 1000 / (8 * 16) * timeout; // timeout in ETUs (time to transfer 1 bit, approx. 9.4 us)
|
||||
}
|
||||
|
@ -1345,18 +1349,32 @@ static int waitCmd(uint8_t iSelect, uint32_t timeout) {
|
|||
if (iSelect) {
|
||||
len = (resp.oldarg[1] & 0xFFFF);
|
||||
if (len) {
|
||||
PrintAndLogEx(NORMAL, "Card selected. UID[%i]:", len);
|
||||
PrintAndLogEx(SUCCESS, "Card selected. UID[%u]:", len);
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, "Can't select card.");
|
||||
}
|
||||
} else {
|
||||
PrintAndLogEx(NORMAL, "received %i bytes", len);
|
||||
PrintAndLogEx(SUCCESS, "received " _YELLOW_("%u") " bytes", len);
|
||||
}
|
||||
|
||||
if (!len)
|
||||
return 1;
|
||||
|
||||
PrintAndLogEx(NORMAL, "%s", sprint_hex(resp.data.asBytes, len));
|
||||
uint8_t *data = resp.data.asBytes;
|
||||
|
||||
if (len >= 3) {
|
||||
bool crc = check_crc(CRC_14443_A, data, len);
|
||||
|
||||
PrintAndLogEx(SUCCESS, "%s[%02X %02X] %s",
|
||||
sprint_hex(data, len - 2),
|
||||
data[len - 2],
|
||||
data[len - 1],
|
||||
(crc) ? _GREEN_("ok") : _RED_("fail")
|
||||
);
|
||||
} else {
|
||||
PrintAndLogEx(SUCCESS, "%s", sprint_hex(data, len));
|
||||
}
|
||||
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
||||
return 3;
|
||||
|
@ -1954,6 +1972,9 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
|||
}
|
||||
} else {
|
||||
PrintAndLogEx(INFO, "proprietary non iso14443-4 card found, RATS not supported");
|
||||
if ((card.sak & 0x20) == 0x20) {
|
||||
PrintAndLogEx(INFO, "SAK incorrectly claims that card supports RATS");
|
||||
}
|
||||
}
|
||||
|
||||
int isMagic = 0;
|
||||
|
|
|
@ -79,7 +79,8 @@ static bool wait_cmd_14b(bool verbose, bool is_select) {
|
|||
if (status == 0) {
|
||||
|
||||
if (verbose) {
|
||||
PrintAndLogEx(SUCCESS, "len %u | %s", len, sprint_hex(data, len));
|
||||
PrintAndLogEx(SUCCESS, "received " _YELLOW_("%u") " bytes", len);
|
||||
PrintAndLogEx(SUCCESS, "%s", sprint_hex(data, len));
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
|
@ -93,8 +94,8 @@ static bool wait_cmd_14b(bool verbose, bool is_select) {
|
|||
if (len >= 3) {
|
||||
bool crc = check_crc(CRC_14443_B, data, len);
|
||||
|
||||
PrintAndLogEx(SUCCESS, "len %u | %s[%02X %02X] %s",
|
||||
len,
|
||||
PrintAndLogEx(SUCCESS, "received " _YELLOW_("%u") " bytes", len);
|
||||
PrintAndLogEx(SUCCESS, "%s[%02X %02X] %s",
|
||||
sprint_hex(data, len - 2),
|
||||
data[len - 2],
|
||||
data[len - 1],
|
||||
|
@ -104,20 +105,24 @@ static bool wait_cmd_14b(bool verbose, bool is_select) {
|
|||
if (verbose)
|
||||
PrintAndLogEx(INFO, "no response from tag");
|
||||
} else {
|
||||
PrintAndLogEx(SUCCESS, "len %u | %s", len, sprint_hex(data, len));
|
||||
PrintAndLogEx(SUCCESS, "%s", sprint_hex(data, len));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, "command execution timeout");
|
||||
PrintAndLogEx(WARNING, "timeout while waiting for reply");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static int CmdHF14BList(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
CmdTraceList("14b");
|
||||
return PM3_SUCCESS;
|
||||
char args[128] = {0};
|
||||
if (strlen(Cmd) == 0) {
|
||||
snprintf(args, sizeof(args), "-t 14b");
|
||||
} else {
|
||||
strncpy(args, Cmd, sizeof(args) - 1);
|
||||
}
|
||||
return CmdTraceList(args);
|
||||
}
|
||||
|
||||
static int CmdHF14BSim(const char *Cmd) {
|
||||
|
@ -127,7 +132,7 @@ static int CmdHF14BSim(const char *Cmd) {
|
|||
"Simulate a ISO/IEC 14443 type B tag with 4 byte UID / PUPI",
|
||||
"hf 14b sim\n"
|
||||
"hf 14b sim -u 11AA33BB"
|
||||
);
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
|
@ -139,11 +144,12 @@ static int CmdHF14BSim(const char *Cmd) {
|
|||
uint8_t pupi[4];
|
||||
int n = 0;
|
||||
int res = CLIParamHexToBuf(arg_get_str(ctx, 1), pupi, sizeof(pupi), &n);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (res) {
|
||||
PrintAndLogEx(FAILED, "failed to read pupi");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
CLIParserFree(ctx);
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_HF_ISO14443B_SIMULATE, pupi, sizeof(pupi));
|
||||
return PM3_SUCCESS;
|
||||
|
@ -155,7 +161,7 @@ static int CmdHF14BSniff(const char *Cmd) {
|
|||
CLIParserInit(&ctx, "hf 14b sniff",
|
||||
"Sniff the communication reader and tag",
|
||||
"hf 14b sniff"
|
||||
);
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
|
@ -183,16 +189,16 @@ static int CmdHF14BCmdRaw(const char *Cmd) {
|
|||
"hf 14b raw -cks --data 0200a40400 -> standard select\n"
|
||||
"hf 14b raw -ck --sr --data 0200a40400 -> SRx select\n"
|
||||
"hf 14b raw -ck --cts --data 0200a40400 -> C-ticket select\n"
|
||||
);
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("k", "keep", "leave the signal field ON after receive response"),
|
||||
arg_lit0("s", "std", "activate field and select standard card"),
|
||||
arg_lit0(NULL, "sr", "activate field and select SRx ST"),
|
||||
arg_lit0(NULL, "cts", "activate field and select ASK C-ticket"),
|
||||
arg_lit0("s", "std", "activate field, use ISO14B select"),
|
||||
arg_lit0(NULL, "sr", "activate field, use SRx ST select"),
|
||||
arg_lit0(NULL, "cts", "activate field, use ASK C-ticket select"),
|
||||
arg_lit0("c", "crc", "calculate and append CRC"),
|
||||
arg_lit0("r", "noresponse", "do not read response"),
|
||||
arg_lit0("r", "noresponse", "do not read response from card"),
|
||||
arg_int0("t", "timeout", "<dec>", "timeout in ms"),
|
||||
arg_lit0("v", "verbose", "verbose"),
|
||||
arg_strx0("d", "data", "<hex>", "data, bytes to send"),
|
||||
|
@ -217,7 +223,7 @@ static int CmdHF14BCmdRaw(const char *Cmd) {
|
|||
if (select_std) {
|
||||
flags |= (ISO14B_SELECT_STD | ISO14B_CLEARTRACE);
|
||||
if (verbose)
|
||||
PrintAndLogEx(INFO, "using standard select");
|
||||
PrintAndLogEx(INFO, "using ISO14443-B select");
|
||||
} else if (select_sr) {
|
||||
flags |= (ISO14B_SELECT_SR | ISO14B_CLEARTRACE);
|
||||
if (verbose)
|
||||
|
@ -267,6 +273,7 @@ static int CmdHF14BCmdRaw(const char *Cmd) {
|
|||
}
|
||||
|
||||
bool success = true;
|
||||
|
||||
// Select, device will send back iso14b_card_select_t, don't print it.
|
||||
if (select_std) {
|
||||
success = wait_cmd_14b(verbose, true);
|
||||
|
@ -618,7 +625,7 @@ static void print_ct_general_info(void *vcard) {
|
|||
iso14b_cts_card_select_t card;
|
||||
memcpy(&card, (iso14b_cts_card_select_t *)vcard, sizeof(iso14b_cts_card_select_t));
|
||||
|
||||
uint32_t uid32 = (card.uid[0] |card.uid[1] << 8 |card.uid[2] << 16 | card.uid[3] << 24);
|
||||
uint32_t uid32 = (card.uid[0] | card.uid[1] << 8 | card.uid[2] << 16 | card.uid[3] << 24);
|
||||
PrintAndLogEx(SUCCESS, "ASK C-Ticket");
|
||||
PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s") " ( " _YELLOW_("%010u") " )", sprint_hex(card.uid, sizeof(card.uid)), uid32);
|
||||
PrintAndLogEx(SUCCESS, " Product Code: %02X", card.pc);
|
||||
|
@ -650,7 +657,7 @@ static bool HF14B_Std_Info(bool verbose) {
|
|||
SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_STD | ISO14B_DISCONNECT, 0, 0, NULL, 0);
|
||||
|
||||
if (!WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) {
|
||||
if (verbose) PrintAndLogEx(WARNING, "command execution timeout");
|
||||
if (verbose) PrintAndLogEx(WARNING, "timeout while waiting for reply");
|
||||
switch_off_field_14b();
|
||||
return is_success;
|
||||
}
|
||||
|
@ -690,7 +697,7 @@ static bool HF14B_ST_Info(bool verbose) {
|
|||
SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_SR | ISO14B_DISCONNECT, 0, 0, NULL, 0);
|
||||
|
||||
if (!WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) {
|
||||
if (verbose) PrintAndLogEx(WARNING, "command execution timeout");
|
||||
if (verbose) PrintAndLogEx(WARNING, "timeout while waiting for reply");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -711,7 +718,7 @@ static int CmdHF14Binfo(const char *Cmd) {
|
|||
CLIParserInit(&ctx, "hf 14b info",
|
||||
"Tag information for ISO/IEC 14443 type B based tags",
|
||||
"hf 14b info\n"
|
||||
);
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
|
@ -734,7 +741,7 @@ static bool HF14B_st_reader(bool verbose) {
|
|||
SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_SR | ISO14B_DISCONNECT, 0, 0, NULL, 0);
|
||||
|
||||
if (!WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) {
|
||||
if (verbose) PrintAndLogEx(WARNING, "command execution timeout");
|
||||
if (verbose) PrintAndLogEx(WARNING, "timeout while waiting for reply");
|
||||
return is_success;
|
||||
}
|
||||
|
||||
|
@ -774,7 +781,7 @@ static bool HF14B_std_reader(bool verbose) {
|
|||
SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_STD | ISO14B_DISCONNECT, 0, 0, NULL, 0);
|
||||
|
||||
if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT) == false) {
|
||||
if (verbose) PrintAndLogEx(WARNING, "command execution timeout");
|
||||
if (verbose) PrintAndLogEx(WARNING, "timeout while waiting for reply");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -817,7 +824,7 @@ static bool HF14B_ask_ct_reader(bool verbose) {
|
|||
PacketResponseNG resp;
|
||||
SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_CTS | ISO14B_DISCONNECT, 0, 0, NULL, 0);
|
||||
if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT) == false) {
|
||||
if (verbose) PrintAndLogEx(WARNING, "command execution timeout");
|
||||
if (verbose) PrintAndLogEx(WARNING, "timeout while waiting for reply");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -859,7 +866,7 @@ static bool HF14B_other_reader(bool verbose) {
|
|||
SendCommandMIX(CMD_HF_ISO14443B_COMMAND, flags, datalen, 0, data, datalen);
|
||||
|
||||
if (!WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) {
|
||||
if (verbose) PrintAndLogEx(WARNING, "command execution timeout");
|
||||
if (verbose) PrintAndLogEx(WARNING, "timeout while waiting for reply");
|
||||
switch_off_field_14b();
|
||||
return false;
|
||||
}
|
||||
|
@ -883,7 +890,7 @@ static bool HF14B_other_reader(bool verbose) {
|
|||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_HF_ISO14443B_COMMAND, flags, 1, 0, data, 1);
|
||||
if (!WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) {
|
||||
if (verbose) PrintAndLogEx(WARNING, "command execution timeout");
|
||||
if (verbose) PrintAndLogEx(WARNING, "timeout while waiting for reply");
|
||||
switch_off_field_14b();
|
||||
return false;
|
||||
}
|
||||
|
@ -907,7 +914,7 @@ static bool HF14B_other_reader(bool verbose) {
|
|||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_HF_ISO14443B_COMMAND, flags, 1, 0, data, 1);
|
||||
if (!WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) {
|
||||
if (verbose) PrintAndLogEx(WARNING, "command execution timeout");
|
||||
if (verbose) PrintAndLogEx(WARNING, "timeout while waiting for reply");
|
||||
switch_off_field_14b();
|
||||
return false;
|
||||
}
|
||||
|
@ -937,7 +944,7 @@ static int CmdHF14BReader(const char *Cmd) {
|
|||
CLIParserInit(&ctx, "hf 14b reader",
|
||||
"Act as a 14443B reader to identify a tag",
|
||||
"hf 14b reader\n"
|
||||
);
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
|
@ -960,7 +967,7 @@ static int CmdHF14BReadSri(const char *Cmd) {
|
|||
CLIParserInit(&ctx, "hf 14b sriread",
|
||||
"Read contents of a SRI512 | SRIX4K tag",
|
||||
"hf 14b sriread\n"
|
||||
);
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
|
@ -1068,7 +1075,7 @@ static int CmdHF14BDump(const char *Cmd) {
|
|||
"Tries to autodetect cardtype, memory size defaults to SRI4K",
|
||||
"hf 14b dump\n"
|
||||
"hf 14b dump -f myfilename\n"
|
||||
);
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
|
@ -1080,7 +1087,7 @@ static int CmdHF14BDump(const char *Cmd) {
|
|||
int fnlen = 0;
|
||||
char filename[FILE_PATH_SIZE] = {0};
|
||||
char *fptr = filename;
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t*)filename, FILE_PATH_SIZE, &fnlen);
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
iso14b_card_select_t card;
|
||||
|
@ -1635,11 +1642,11 @@ static int CmdHF14BAPDU(const char *Cmd) {
|
|||
CLIParserFree(ctx);
|
||||
|
||||
PrintAndLogEx(NORMAL, ">>>>[%s%s%s] %s",
|
||||
activate_field ? "sel" : "",
|
||||
leave_signal_on ? " keep" : "",
|
||||
decode_TLV ? " TLV" : "",
|
||||
sprint_hex(data, datalen)
|
||||
);
|
||||
activate_field ? "sel" : "",
|
||||
leave_signal_on ? " keep" : "",
|
||||
decode_TLV ? " TLV" : "",
|
||||
sprint_hex(data, datalen)
|
||||
);
|
||||
|
||||
if (decode_APDU) {
|
||||
APDUStruct apdu;
|
||||
|
@ -1671,7 +1678,7 @@ static int CmdHF14BNdef(const char *Cmd) {
|
|||
CLIParserInit(&ctx, "hf 14b ndef",
|
||||
"Print NFC Data Exchange Format (NDEF)",
|
||||
"hf 14b ndef"
|
||||
);
|
||||
);
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_param_end
|
||||
|
|
|
@ -60,9 +60,9 @@ typedef struct {
|
|||
uint64_t uid;
|
||||
int mask; // how many MSB bits used
|
||||
const char *desc;
|
||||
} productName;
|
||||
} productName_t;
|
||||
|
||||
const productName uidmapping[] = {
|
||||
const productName_t uidmapping[] = {
|
||||
|
||||
// UID, #significant Bits, "Vendor(+Product)"
|
||||
{ 0xE001000000000000LL, 16, "Motorola UK" },
|
||||
|
@ -1342,9 +1342,13 @@ static int CmdHF15Dump(const char *Cmd) {
|
|||
}
|
||||
|
||||
static int CmdHF15List(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
CmdTraceList("15");
|
||||
return PM3_SUCCESS;
|
||||
char args[128] = {0};
|
||||
if (strlen(Cmd) == 0) {
|
||||
snprintf(args, sizeof(args), "-t 15");
|
||||
} else {
|
||||
strncpy(args, Cmd, sizeof(args) - 1);
|
||||
}
|
||||
return CmdTraceList(args);
|
||||
}
|
||||
|
||||
static int CmdHF15Raw(const char *Cmd) {
|
||||
|
|
|
@ -115,9 +115,13 @@ static int switch_off_field_cryptorf(void) {
|
|||
}
|
||||
|
||||
static int CmdHFCryptoRFList(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
CmdTraceList("cryptorf");
|
||||
return PM3_SUCCESS;
|
||||
char args[128] = {0};
|
||||
if (strlen(Cmd) == 0) {
|
||||
snprintf(args, sizeof(args), "-t cryptorf");
|
||||
} else {
|
||||
strncpy(args, Cmd, sizeof(args) - 1);
|
||||
}
|
||||
return CmdTraceList(args);
|
||||
}
|
||||
|
||||
static int CmdHFCryptoRFSim(const char *Cmd) {
|
||||
|
|
|
@ -407,9 +407,13 @@ static bool add_last_IDm(uint8_t position, uint8_t *data) {
|
|||
}
|
||||
|
||||
static int CmdHFFelicaList(const char *Cmd) {
|
||||
(void)Cmd;
|
||||
CmdTraceList("felica");
|
||||
return PM3_SUCCESS;
|
||||
char args[128] = {0};
|
||||
if (strlen(Cmd) == 0) {
|
||||
snprintf(args, sizeof(args), "-t felica");
|
||||
} else {
|
||||
strncpy(args, Cmd, sizeof(args) - 1);
|
||||
}
|
||||
return CmdTraceList(args);
|
||||
}
|
||||
|
||||
static int CmdHFFelicaReader(const char *Cmd) {
|
||||
|
|
|
@ -36,10 +36,21 @@
|
|||
#include "emv/dump.h"
|
||||
#include "ui.h"
|
||||
#include "cmdhf14a.h"
|
||||
#include "cmdtrace.h"
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static int CmdHFFidoInfo(const char *cmd) {
|
||||
static int cmd_hf_fido_list(const char *Cmd) {
|
||||
char args[128] = {0};
|
||||
if (strlen(Cmd) == 0) {
|
||||
snprintf(args, sizeof(args), "-t 14a");
|
||||
} else {
|
||||
strncpy(args, Cmd, sizeof(args) - 1);
|
||||
}
|
||||
return CmdTraceList(args);
|
||||
}
|
||||
|
||||
static int cmd_hf_fido_info(const char *cmd) {
|
||||
|
||||
if (cmd && strlen(cmd) > 0)
|
||||
PrintAndLogEx(WARNING, "WARNING: command doesn't have any parameters.\n");
|
||||
|
@ -150,7 +161,7 @@ static json_t *OpenJson(CLIParserContext *ctx, int paramnum, char *fname, void *
|
|||
return root;
|
||||
}
|
||||
|
||||
static int CmdHFFidoRegister(const char *cmd) {
|
||||
static int cmd_hf_fido_register(const char *cmd) {
|
||||
uint8_t data[64] = {0};
|
||||
int chlen = 0;
|
||||
uint8_t cdata[250] = {0};
|
||||
|
@ -386,7 +397,7 @@ static int CmdHFFidoRegister(const char *cmd) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdHFFidoAuthenticate(const char *cmd) {
|
||||
static int cmd_hf_fido_authenticate(const char *cmd) {
|
||||
uint8_t data[512] = {0};
|
||||
uint8_t hdata[250] = {0};
|
||||
bool public_key_loaded = false;
|
||||
|
@ -652,7 +663,7 @@ static int GetExistsFileNameJson(const char *prefixDir, const char *reqestedFile
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdHFFido2MakeCredential(const char *cmd) {
|
||||
static int cmd_hf_fido_2make_credential(const char *cmd) {
|
||||
json_error_t error;
|
||||
char fname[FILE_PATH_SIZE] = {0};
|
||||
|
||||
|
@ -777,7 +788,7 @@ static int CmdHFFido2MakeCredential(const char *cmd) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdHFFido2GetAssertion(const char *cmd) {
|
||||
static int cmd_hf_fido_2get_assertion(const char *cmd) {
|
||||
json_error_t error;
|
||||
char fname[FILE_PATH_SIZE] = {0};
|
||||
|
||||
|
@ -903,13 +914,14 @@ static int CmdHFFido2GetAssertion(const char *cmd) {
|
|||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help."},
|
||||
{"info", CmdHFFidoInfo, IfPm3Iso14443a, "Info about FIDO tag."},
|
||||
{"reg", CmdHFFidoRegister, IfPm3Iso14443a, "FIDO U2F Registration Message."},
|
||||
{"auth", CmdHFFidoAuthenticate, IfPm3Iso14443a, "FIDO U2F Authentication Message."},
|
||||
{"make", CmdHFFido2MakeCredential, IfPm3Iso14443a, "FIDO2 MakeCredential command."},
|
||||
{"assert", CmdHFFido2GetAssertion, IfPm3Iso14443a, "FIDO2 GetAssertion command."},
|
||||
{NULL, NULL, 0, NULL}
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help."},
|
||||
{"info", cmd_hf_fido_list, IfPm3Iso14443a, "List ISO 14443A history"},
|
||||
{"info", cmd_hf_fido_info, IfPm3Iso14443a, "Info about FIDO tag."},
|
||||
{"reg", cmd_hf_fido_register, IfPm3Iso14443a, "FIDO U2F Registration Message."},
|
||||
{"auth", cmd_hf_fido_authenticate, IfPm3Iso14443a, "FIDO U2F Authentication Message."},
|
||||
{"make", cmd_hf_fido_2make_credential, IfPm3Iso14443a, "FIDO2 MakeCredential command."},
|
||||
{"assert", cmd_hf_fido_2get_assertion, IfPm3Iso14443a, "FIDO2 GetAssertion command."},
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
int CmdHFFido(const char *Cmd) {
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "cmdparser.h" // command_t
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "cmdtrace.h"
|
||||
#include "cliparser.h"
|
||||
#include "util_posix.h"
|
||||
#include "comms.h"
|
||||
#include "des.h"
|
||||
|
@ -224,21 +225,6 @@ static int usage_hf_iclass_readblock(void) {
|
|||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_hf_iclass_view(void) {
|
||||
PrintAndLogEx(NORMAL, "Print a iCLASS tag dump file\n");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf iClass view [f <filename>] [s <startblock>] [e <endblock>] [v]\n");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h Show this help");
|
||||
PrintAndLogEx(NORMAL, " f <filename> filename of dump");
|
||||
PrintAndLogEx(NORMAL, " s <startblock> print from this block (default block6)");
|
||||
PrintAndLogEx(NORMAL, " e <endblock> end printing at this block (default 0, ALL)");
|
||||
PrintAndLogEx(NORMAL, " v verbose output");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass view f hf-iclass-AA162D30F8FF12F1-dump.bin"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass view s 1 f hf-iclass-AA162D30F8FF12F1-dump.bin"));
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_hf_iclass_calc_newkey(void) {
|
||||
PrintAndLogEx(NORMAL, "Calculate new key for updating\n");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf iclass calc_newkey o <old key> n <new key> s [csn] e\n");
|
||||
|
@ -359,20 +345,7 @@ static int usage_hf_iclass_lookup(void) {
|
|||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_hf_iclass_permutekey(void) {
|
||||
PrintAndLogEx(NORMAL, "Permute function from 'heart of darkness' paper.\n");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf iclass permute [h] <r|f> <bytes>\n");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h Show this help");
|
||||
PrintAndLogEx(NORMAL, " r reverse permuted key");
|
||||
PrintAndLogEx(NORMAL, " f permute key");
|
||||
PrintAndLogEx(NORMAL, " <bytes> input bytes");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass permute r 0123456789abcdef"));
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static int cmp_uint32(const void *a, const void *b) {
|
||||
|
||||
|
@ -631,9 +604,13 @@ static void print_picopass_header(const picopass_hdr *hdr) {
|
|||
}
|
||||
|
||||
static int CmdHFiClassList(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
CmdTraceList("iclass");
|
||||
return PM3_SUCCESS;
|
||||
char args[128] = {0};
|
||||
if (strlen(Cmd) == 0) {
|
||||
snprintf(args, sizeof(args), "-t iclass");
|
||||
} else {
|
||||
strncpy(args, Cmd, sizeof(args) - 1);
|
||||
}
|
||||
return CmdTraceList(args);
|
||||
}
|
||||
|
||||
static int CmdHFiClassSniff(const char *Cmd) {
|
||||
|
@ -2680,43 +2657,31 @@ void printIclassDumpContents(uint8_t *iclass_dump, uint8_t startblock, uint8_t e
|
|||
}
|
||||
|
||||
static int CmdHFiClassView(const char *Cmd) {
|
||||
int startblock = 0;
|
||||
int endblock = 0;
|
||||
char filename[FILE_PATH_SIZE];
|
||||
bool errors = false, verbose = false;
|
||||
uint8_t cmdp = 0;
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
return usage_hf_iclass_view();
|
||||
case 'f':
|
||||
if (param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE) >= FILE_PATH_SIZE) {
|
||||
PrintAndLogEx(FAILED, "Filename too long");
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 's':
|
||||
startblock = param_get8ex(Cmd, cmdp + 1, 0, 10);
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'e':
|
||||
endblock = param_get8ex(Cmd, cmdp + 1, 0, 10);
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'v':
|
||||
verbose = true;
|
||||
cmdp++;
|
||||
break;
|
||||
default:
|
||||
PrintAndLogEx(WARNING, "unknown parameter '%c'\n", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf iclass view",
|
||||
"Print a iCLASS tag dump file",
|
||||
"hf iclass view -f hf-iclass-AA162D30F8FF12F1-dump.bin\n"
|
||||
"hf iclass view --startblock 1 --file hf-iclass-AA162D30F8FF12F1-dump.bin\n");
|
||||
|
||||
if (errors || (strlen(Cmd) == 0)) return usage_hf_iclass_view();
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_str1("f", "file", "<filename>", "filename of dump"),
|
||||
arg_int0("s", "startblock", "<dec>", "print from this block (default block6)"),
|
||||
arg_int0("e", "endblock", "<dec>", "end printing at this block (default 0, ALL)"),
|
||||
arg_lit0("v", "verbose", "verbose output"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
int fnlen = 0;
|
||||
char filename[FILE_PATH_SIZE];
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||
|
||||
int startblock = arg_get_int_def(ctx, 2, 0);
|
||||
int endblock = arg_get_int_def(ctx, 3, 0);
|
||||
bool verbose = arg_get_lit(ctx, 4);
|
||||
|
||||
CLIParserFree(ctx);
|
||||
|
||||
uint8_t *dump = NULL;
|
||||
size_t bytes_read = 0;
|
||||
|
@ -3522,17 +3487,26 @@ static int CmdHFiClassPermuteKey(const char *Cmd) {
|
|||
uint8_t data[16] = {0};
|
||||
bool isReverse = false;
|
||||
int len = 0;
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h')
|
||||
return usage_hf_iclass_permutekey();
|
||||
|
||||
isReverse = (cmdp == 'r');
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf iclass permute",
|
||||
"Permute function from 'heart of darkness' paper.",
|
||||
"hf iclass permute --reverse --key 0123456789abcdef\n"
|
||||
"hf iclass permute --key ff55330f0055330f\n");
|
||||
|
||||
param_gethex_ex(Cmd, 1, data, &len);
|
||||
if (len % 2)
|
||||
return usage_hf_iclass_permutekey();
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("r", "reverse", "reverse permuted key"),
|
||||
arg_str1(NULL, "key", "<bytes>", "input key"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
len >>= 1;
|
||||
isReverse = arg_get_lit(ctx, 1);
|
||||
|
||||
CLIGetHexWithReturn(ctx, 2, data, &len);
|
||||
|
||||
CLIParserFree(ctx);
|
||||
|
||||
memcpy(key, data, 8);
|
||||
|
||||
|
@ -3580,7 +3554,7 @@ static command_t CommandTable[] = {
|
|||
{"encrypt", CmdHFiClassEncryptBlk, AlwaysAvailable, "[options..] Encrypt given block data"},
|
||||
{"decrypt", CmdHFiClassDecrypt, AlwaysAvailable, "[options..] Decrypt given block data or tag dump file" },
|
||||
{"managekeys", CmdHFiClassManageKeys, AlwaysAvailable, "[options..] Manage keys to use with iclass commands"},
|
||||
{"permutekey", CmdHFiClassPermuteKey, IfPm3Iclass, " Permute function from 'heart of darkness' paper"},
|
||||
{"permute", CmdHFiClassPermuteKey, IfPm3Iclass, " Permute function from 'heart of darkness' paper"},
|
||||
{"view", CmdHFiClassView, AlwaysAvailable, "[options..] Display content from tag dump file"},
|
||||
|
||||
{NULL, NULL, NULL, NULL}
|
||||
|
|
|
@ -1401,9 +1401,13 @@ static int CmdLegicWipe(const char *Cmd) {
|
|||
}
|
||||
|
||||
static int CmdLegicList(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
CmdTraceList("legic");
|
||||
return PM3_SUCCESS;
|
||||
char args[128] = {0};
|
||||
if (strlen(Cmd) == 0) {
|
||||
snprintf(args, sizeof(args), "-t legic");
|
||||
} else {
|
||||
strncpy(args, Cmd, sizeof(args) - 1);
|
||||
}
|
||||
return CmdTraceList(args);
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
|
|
|
@ -207,9 +207,13 @@ int infoLTO(bool verbose) {
|
|||
}
|
||||
|
||||
static int CmdHfLTOList(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
CmdTraceList("lto");
|
||||
return PM3_SUCCESS;
|
||||
char args[128] = {0};
|
||||
if (strlen(Cmd) == 0) {
|
||||
snprintf(args, sizeof(args), "-t lto");
|
||||
} else {
|
||||
strncpy(args, Cmd, sizeof(args) - 1);
|
||||
}
|
||||
return CmdTraceList(args);
|
||||
}
|
||||
|
||||
static int lto_rdbl(uint8_t blk, uint8_t *block_responce, uint8_t *block_cnt_responce, bool verbose) {
|
||||
|
|
|
@ -1002,6 +1002,7 @@ static int CmdHF14AMfDump(const char *Cmd) {
|
|||
return PM3_ESOFT;
|
||||
|
||||
strcpy(keyFilename, fptr);
|
||||
free(fptr);
|
||||
}
|
||||
|
||||
if ((f = fopen(keyFilename, "rb")) == NULL) {
|
||||
|
@ -1163,6 +1164,7 @@ static int CmdHF14AMfDump(const char *Cmd) {
|
|||
return PM3_ESOFT;
|
||||
|
||||
strcpy(dataFilename, fptr);
|
||||
free(fptr);
|
||||
}
|
||||
|
||||
uint16_t bytes = 16 * (FirstBlockOfSector(numSectors - 1) + NumBlocksPerSector(numSectors - 1));
|
||||
|
@ -1226,6 +1228,7 @@ static int CmdHF14AMfRestore(const char *Cmd) {
|
|||
return 1;
|
||||
|
||||
strcpy(keyFilename, fptr);
|
||||
free(fptr);
|
||||
}
|
||||
|
||||
if ((fkeys = fopen(keyFilename, "rb")) == NULL) {
|
||||
|
@ -1260,6 +1263,7 @@ static int CmdHF14AMfRestore(const char *Cmd) {
|
|||
return 1;
|
||||
|
||||
strcpy(dataFilename, fptr);
|
||||
free(fptr);
|
||||
}
|
||||
|
||||
if ((fdump = fopen(dataFilename, "rb")) == NULL) {
|
||||
|
@ -1570,8 +1574,10 @@ jumptoend:
|
|||
if (createMfcKeyDump(fptr, SectorsCnt, e_sector) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "Failed to save keys to file");
|
||||
free(e_sector);
|
||||
free(fptr);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
free(fptr);
|
||||
}
|
||||
free(e_sector);
|
||||
}
|
||||
|
@ -1775,8 +1781,10 @@ jumptoend:
|
|||
if (createMfcKeyDump(fptr, SectorsCnt, e_sector) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "Failed to save keys to file");
|
||||
free(e_sector);
|
||||
free(fptr);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
free(fptr);
|
||||
}
|
||||
free(e_sector);
|
||||
|
||||
|
@ -2013,7 +2021,6 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
|
|||
uint8_t block[16] = {0x00};
|
||||
uint8_t *dump;
|
||||
int bytes;
|
||||
char *fnameptr = filename;
|
||||
// Settings
|
||||
bool slow = false;
|
||||
bool legacy_mfchk = false;
|
||||
|
@ -2136,7 +2143,6 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
|
|||
// read uid to generate a filename for the key file
|
||||
char *fptr = GenerateFilename("hf-mf-", "-key.bin");
|
||||
|
||||
|
||||
// check if tag doesn't have static nonce
|
||||
has_staticnonce = detect_classic_static_nonce();
|
||||
|
||||
|
@ -2146,6 +2152,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
|
|||
if (prng_type < 0) {
|
||||
PrintAndLogEx(FAILED, "\nNo tag detected or other tag communication error");
|
||||
free(e_sector);
|
||||
free(fptr);
|
||||
return prng_type;
|
||||
}
|
||||
}
|
||||
|
@ -2259,6 +2266,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
|
|||
keyBlock = calloc(ARRAYLEN(g_mifare_default_keys), 6);
|
||||
if (keyBlock == NULL) {
|
||||
free(e_sector);
|
||||
free(fptr);
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
|
||||
|
@ -2403,6 +2411,7 @@ noValidKeyFound:
|
|||
PrintAndLogEx(FAILED, "No usable key was found!");
|
||||
free(keyBlock);
|
||||
free(e_sector);
|
||||
free(fptr);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
}
|
||||
|
@ -2516,11 +2525,13 @@ tryNested:
|
|||
case PM3_ETIMEOUT: {
|
||||
PrintAndLogEx(ERR, "\nError: No response from Proxmark3.");
|
||||
free(e_sector);
|
||||
free(fptr);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
case PM3_EOPABORTED: {
|
||||
PrintAndLogEx(WARNING, "\nButton pressed. Aborted.");
|
||||
free(e_sector);
|
||||
free(fptr);
|
||||
return PM3_EOPABORTED;
|
||||
}
|
||||
case PM3_EFAILED: {
|
||||
|
@ -2551,6 +2562,7 @@ tryNested:
|
|||
default: {
|
||||
PrintAndLogEx(ERR, "unknown Error.\n");
|
||||
free(e_sector);
|
||||
free(fptr);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
}
|
||||
|
@ -2582,6 +2594,7 @@ tryHardnested: // If the nested attack fails then we try the hardnested attack
|
|||
}
|
||||
}
|
||||
free(e_sector);
|
||||
free(fptr);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
|
@ -2606,11 +2619,13 @@ tryStaticnested:
|
|||
case PM3_ETIMEOUT: {
|
||||
PrintAndLogEx(ERR, "\nError: No response from Proxmark3.");
|
||||
free(e_sector);
|
||||
free(fptr);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
case PM3_EOPABORTED: {
|
||||
PrintAndLogEx(WARNING, "\nButton pressed. Aborted.");
|
||||
free(e_sector);
|
||||
free(fptr);
|
||||
return PM3_EOPABORTED;
|
||||
}
|
||||
case PM3_SUCCESS: {
|
||||
|
@ -2676,6 +2691,7 @@ all_found:
|
|||
if (!dump) {
|
||||
PrintAndLogEx(ERR, "Fail, cannot allocate memory");
|
||||
free(e_sector);
|
||||
free(fptr);
|
||||
return PM3_EMALLOC;
|
||||
}
|
||||
memset(dump, 0, bytes);
|
||||
|
@ -2685,16 +2701,19 @@ all_found:
|
|||
PrintAndLogEx(ERR, "Fail, transfer from device time-out");
|
||||
free(e_sector);
|
||||
free(dump);
|
||||
free(fptr);
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
|
||||
fnameptr = GenerateFilename("hf-mf-", "-dump");
|
||||
char *fnameptr = GenerateFilename("hf-mf-", "-dump");
|
||||
if (fnameptr == NULL) {
|
||||
free(dump);
|
||||
free(e_sector);
|
||||
free(fptr);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
strcpy(filename, fnameptr);
|
||||
free(fnameptr);
|
||||
|
||||
saveFile(filename, ".bin", dump, bytes);
|
||||
saveFileEML(filename, dump, bytes, MFBLOCK_SIZE);
|
||||
|
@ -2706,6 +2725,7 @@ all_found:
|
|||
|
||||
free(dump);
|
||||
free(e_sector);
|
||||
free(fptr);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -2982,6 +3002,7 @@ out:
|
|||
if (createMfcKeyDump(fptr, sectorsCnt, e_sector) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "Failed to save keys to file");
|
||||
}
|
||||
free(fptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3285,6 +3306,7 @@ out:
|
|||
if (createMfcKeyDump(fptr, SectorsCnt, e_sector) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "Failed to save keys to file");
|
||||
}
|
||||
free(fptr);
|
||||
}
|
||||
|
||||
free(keyBlock);
|
||||
|
@ -4040,7 +4062,6 @@ static int CmdHF14AMfEKeyPrn(const char *Cmd) {
|
|||
char *fptr = filename;
|
||||
fptr += snprintf(fptr, sizeof(filename), "hf-mf-");
|
||||
FillFileNameByUID(fptr + strlen(fptr), uid, "-key", sizeof(uid));
|
||||
|
||||
createMfcKeyDump(filename, sectors_cnt, e_sector);
|
||||
}
|
||||
|
||||
|
@ -4732,6 +4753,7 @@ static int CmdHF14AMfice(const char *Cmd) {
|
|||
if (fptr == NULL)
|
||||
return PM3_EFILE;
|
||||
strcpy(filename, fptr);
|
||||
free(fptr);
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "Collecting "_YELLOW_("%u")" nonces \n", limit);
|
||||
|
@ -5174,8 +5196,13 @@ static int CmdHFMFPersonalize(const char *cmd) {
|
|||
}
|
||||
|
||||
static int CmdHF14AMfList(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
return CmdTraceList("mf");
|
||||
char args[128] = {0};
|
||||
if (strlen(Cmd) == 0) {
|
||||
snprintf(args, sizeof(args), "-t mf");
|
||||
} else {
|
||||
strncpy(args, Cmd, sizeof(args) - 1);
|
||||
}
|
||||
return CmdTraceList(args);
|
||||
}
|
||||
|
||||
static int CmdHf14AGen3UID(const char *Cmd) {
|
||||
|
|
|
@ -4470,8 +4470,13 @@ static int CmdHF14aDesChk(const char *Cmd) {
|
|||
}
|
||||
|
||||
static int CmdHF14ADesList(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
return CmdTraceList("des");
|
||||
char args[128] = {0};
|
||||
if (strlen(Cmd) == 0) {
|
||||
snprintf(args, sizeof(args), "-t des");
|
||||
} else {
|
||||
strncpy(args, Cmd, sizeof(args) - 1);
|
||||
}
|
||||
return CmdTraceList(args);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -143,12 +143,10 @@ static inline void clear_bitarray24(uint32_t *bitarray) {
|
|||
memset(bitarray, 0x00, sizeof(uint32_t) * (1 << 19));
|
||||
}
|
||||
|
||||
|
||||
static inline void set_bitarray24(uint32_t *bitarray) {
|
||||
memset(bitarray, 0xff, sizeof(uint32_t) * (1 << 19));
|
||||
}
|
||||
|
||||
|
||||
static inline void set_bit24(uint32_t *bitarray, uint32_t index) {
|
||||
bitarray[index >> 5] |= 0x80000000 >> (index & 0x0000001f);
|
||||
}
|
||||
|
@ -157,36 +155,46 @@ static inline uint32_t test_bit24(uint32_t *bitarray, uint32_t index) {
|
|||
return bitarray[index >> 5] & (0x80000000 >> (index & 0x0000001f));
|
||||
}
|
||||
|
||||
|
||||
static inline uint32_t next_state(uint32_t *bitarray, uint32_t state) {
|
||||
if (++state == 1 << 24) return 1 << 24;
|
||||
if (++state == (1 << 24)) {
|
||||
return (1 << 24);
|
||||
}
|
||||
|
||||
uint32_t index = state >> 5;
|
||||
uint_fast8_t bit = state & 0x1f;
|
||||
uint_fast8_t bit = state & 0x1F;
|
||||
uint32_t line = bitarray[index] << bit;
|
||||
while (bit <= 0x1f) {
|
||||
if (line & 0x80000000) return state;
|
||||
|
||||
while (bit <= 0x1F) {
|
||||
if (line & 0x80000000) {
|
||||
return state;
|
||||
}
|
||||
state++;
|
||||
bit++;
|
||||
line <<= 1;
|
||||
}
|
||||
index++;
|
||||
while (bitarray[index] == 0x00000000 && state < 1 << 24) {
|
||||
while (state < (1 << 24) && bitarray[index] == 0x00000000) {
|
||||
index++;
|
||||
state += 0x20;
|
||||
}
|
||||
if (state >= 1 << 24) return 1 << 24;
|
||||
|
||||
if (state >= (1 << 24)) {
|
||||
return (1 << 24);
|
||||
}
|
||||
#if defined __GNUC__
|
||||
return state + __builtin_clz(bitarray[index]);
|
||||
#else
|
||||
bit = 0x00;
|
||||
line = bitarray[index];
|
||||
while (bit <= 0x1f) {
|
||||
if (line & 0x80000000) return state;
|
||||
while (bit <= 0x1F) {
|
||||
if (line & 0x80000000) {
|
||||
return state;
|
||||
}
|
||||
state++;
|
||||
bit++;
|
||||
line <<= 1;
|
||||
}
|
||||
return 1 << 24;
|
||||
return (1 << 24);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
|
||||
#define MAX_UL_BLOCKS 0x0F
|
||||
#define MAX_ULC_BLOCKS 0x2B
|
||||
#define MAX_ULC_BLOCKS 0x2F
|
||||
#define MAX_ULEV1a_BLOCKS 0x13
|
||||
#define MAX_ULEV1b_BLOCKS 0x28
|
||||
#define MAX_NTAG_203 0x29
|
||||
|
@ -168,17 +168,13 @@ static int usage_hf_mfu_sim(void) {
|
|||
}
|
||||
|
||||
static int usage_hf_mfu_ucauth(void) {
|
||||
PrintAndLogEx(NORMAL, "Usage: hf mfu cauth k <key number>");
|
||||
PrintAndLogEx(NORMAL, " 0 (default): 3DES standard key");
|
||||
PrintAndLogEx(NORMAL, " 1 : all 0x00 key");
|
||||
PrintAndLogEx(NORMAL, " 2 : 0x00-0x0F key");
|
||||
PrintAndLogEx(NORMAL, " 3 : nfc key");
|
||||
PrintAndLogEx(NORMAL, " 4 : all 0x01 key");
|
||||
PrintAndLogEx(NORMAL, " 5 : all 0xff key");
|
||||
PrintAndLogEx(NORMAL, " 6 : 0x00-0xFF key");
|
||||
PrintAndLogEx(NORMAL, "Tests 3DES password on Mifare Ultralight-C tag.");
|
||||
PrintAndLogEx(NORMAL, "If password is not specified, a set of known defaults will be tested.");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf mfu cauth <password (32 hex symbols)>");
|
||||
PrintAndLogEx(NORMAL, " [password] - (32 hex symbols)");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu cauth k"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu cauth k 3"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu cauth"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu cauth 000102030405060708090a0b0c0d0e0f"));
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
@ -244,12 +240,14 @@ static int usage_hf_mfu_otp_tearoff(void) {
|
|||
PrintAndLogEx(NORMAL, " s <time> : (optional) start time to run the test - default 0 us");
|
||||
PrintAndLogEx(NORMAL, " d <data> : (optional) data to full-write before trying the OTP test - default 0x00");
|
||||
PrintAndLogEx(NORMAL, " t <data> : (optional) data to write while running the OTP test - default 0x00");
|
||||
PrintAndLogEx(NORMAL, " m <data> : (optional) exit criteria, if block matches this value");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " hf mfu otptear b 3");
|
||||
PrintAndLogEx(NORMAL, " hf mfu otptear b 8 i 100 l 3000 s 1000");
|
||||
PrintAndLogEx(NORMAL, " hf mfu otptear b 3 i 1 l 200");
|
||||
PrintAndLogEx(NORMAL, " hf mfu otptear b 3 i 100 l 2500 s 200 d FFFFFFFF t EEEEEEEE");
|
||||
PrintAndLogEx(NORMAL, " hf mfu otptear b 3 i 100 l 2500 s 200 d FFFFFFFF t EEEEEEEE m 00000000 -> such quite when OTP is reset");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -408,6 +406,18 @@ static int ulc_authentication(uint8_t *key, bool switch_off_field) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int try_default_3des_keys(uint8_t **correct_key) {
|
||||
PrintAndLogEx(INFO, "Trying some default 3des keys");
|
||||
for (uint8_t i = 0; i < ARRAYLEN(default_3des_keys); ++i) {
|
||||
uint8_t *key = default_3des_keys[i];
|
||||
if (ulc_authentication(key, true)) {
|
||||
*correct_key = key;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ulev1_requestAuthentication(uint8_t *pwd, uint8_t *pack, uint16_t packLength) {
|
||||
|
||||
uint8_t cmd[] = {MIFARE_ULEV1_AUTH, pwd[0], pwd[1], pwd[2], pwd[3]};
|
||||
|
@ -1317,16 +1327,11 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
|
|||
if (hasAuthKey) return PM3_SUCCESS;
|
||||
|
||||
// also try to diversify default keys.. look into CmdHF14AMfGenDiverseKeys
|
||||
PrintAndLogEx(INFO, "Trying some default 3des keys");
|
||||
for (uint8_t i = 0; i < ARRAYLEN(default_3des_keys); ++i) {
|
||||
key = default_3des_keys[i];
|
||||
if (ulc_authentication(key, true)) {
|
||||
PrintAndLogEx(SUCCESS, "Found default 3des key: ");
|
||||
uint8_t keySwap[16];
|
||||
memcpy(keySwap, SwapEndian64(key, 16, 8), 16);
|
||||
ulc_print_3deskey(keySwap);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
if (try_default_3des_keys(&key)) {
|
||||
PrintAndLogEx(SUCCESS, "Found default 3des key: ");
|
||||
uint8_t keySwap[16];
|
||||
memcpy(keySwap, SwapEndian64(key, 16, 8), 16);
|
||||
ulc_print_3deskey(keySwap);
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
@ -2389,28 +2394,33 @@ static int CmdHF14AMfUSim(const char *Cmd) {
|
|||
//-------------------------------------------------------------------------------
|
||||
|
||||
//
|
||||
// Ultralight C Authentication Demo {currently uses hard-coded key}
|
||||
// Ultralight C Authentication
|
||||
//
|
||||
|
||||
static int CmdHF14AMfUCAuth(const char *Cmd) {
|
||||
|
||||
uint8_t keyNo = 3;
|
||||
bool errors = false;
|
||||
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
|
||||
//Change key to user defined one
|
||||
if (cmdp == 'k') {
|
||||
keyNo = param_get8(Cmd, 1);
|
||||
if (keyNo >= ARRAYLEN(default_3des_keys))
|
||||
errors = true;
|
||||
if (cmdp == 'h') {
|
||||
return usage_hf_mfu_ucauth();
|
||||
}
|
||||
|
||||
if (cmdp == 'h') errors = true;
|
||||
uint8_t key_buf[16];
|
||||
uint8_t *key;
|
||||
int succeeded;
|
||||
|
||||
if (errors) return usage_hf_mfu_ucauth();
|
||||
// If no hex key is specified, try all known ones
|
||||
if (strlen(Cmd) == 0) {
|
||||
succeeded = try_default_3des_keys(&key);
|
||||
// Else try user-supplied
|
||||
} else {
|
||||
if (param_gethex(Cmd, 0, key_buf, 32)) {
|
||||
PrintAndLogEx(WARNING, "Password must include 32 HEX symbols");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
succeeded = ulc_authentication(key_buf, true);
|
||||
key = key_buf;
|
||||
}
|
||||
|
||||
uint8_t *key = default_3des_keys[keyNo];
|
||||
if (ulc_authentication(key, true))
|
||||
if (succeeded)
|
||||
PrintAndLogEx(SUCCESS, "Authentication successful. 3des key: %s", sprint_hex(key, 16));
|
||||
else
|
||||
PrintAndLogEx(WARNING, "Authentication failed");
|
||||
|
@ -2809,7 +2819,8 @@ static int CmdHF14AMfUPwdGen(const char *Cmd) {
|
|||
static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
|
||||
uint8_t blockNoUint = 8;
|
||||
uint8_t cmdp = 0;
|
||||
bool errors = 0;
|
||||
bool errors = 0, use_match = false;
|
||||
uint8_t match[4] = {0x00};
|
||||
uint8_t teardata[8] = {0x00};
|
||||
uint32_t interval = 500; // time in us
|
||||
uint32_t timeLimit = 3000; // time in us
|
||||
|
@ -2821,7 +2832,6 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
|
|||
return usage_hf_mfu_otp_tearoff();
|
||||
case 'b':
|
||||
blockNoUint = param_get8(Cmd, cmdp + 1);
|
||||
//iceman, which blocks can be targeted? UID blocks?
|
||||
if (blockNoUint < 2) {
|
||||
PrintAndLogEx(WARNING, "Wrong block number");
|
||||
errors = true;
|
||||
|
@ -2830,10 +2840,6 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
|
|||
break;
|
||||
case 'i':
|
||||
interval = param_get32ex(Cmd, cmdp + 1, interval, 10);
|
||||
if (interval == 0) {
|
||||
PrintAndLogEx(WARNING, "Wrong interval number");
|
||||
errors = true;
|
||||
}
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'l':
|
||||
|
@ -2842,6 +2848,10 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
|
|||
PrintAndLogEx(WARNING, "Wrong time limit number");
|
||||
errors = true;
|
||||
}
|
||||
if (timeLimit > 43000) {
|
||||
PrintAndLogEx(WARNING, "You can't set delay out of 1..43000 range!");
|
||||
errors = true;
|
||||
}
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 's':
|
||||
|
@ -2866,6 +2876,14 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
|
|||
}
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'm':
|
||||
if (param_gethex(Cmd, cmdp + 1, match, 8)) {
|
||||
PrintAndLogEx(WARNING, "Block data must include 8 HEX symbols");
|
||||
errors = true;
|
||||
}
|
||||
use_match = true;
|
||||
cmdp += 2;
|
||||
break;
|
||||
default:
|
||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
|
@ -2875,52 +2893,112 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
|
|||
|
||||
if (errors) return usage_hf_mfu_otp_tearoff();
|
||||
|
||||
PrintAndLogEx(INFO, "Starting TearOff test - Selected Block no: %u", blockNoUint);
|
||||
|
||||
|
||||
PrintAndLogEx(INFO, "----------------- " _CYAN_("MFU Tear off") " ---------------------");
|
||||
PrintAndLogEx(INFO, "Starting Tear-off test");
|
||||
PrintAndLogEx(INFO, "Target block no: %u", blockNoUint);
|
||||
PrintAndLogEx(INFO, "Target inital block data : %s", sprint_hex_inrow(teardata, 4));
|
||||
PrintAndLogEx(INFO, "Target write block data : %s", sprint_hex_inrow(teardata + 4, 4));
|
||||
PrintAndLogEx(INFO, "----------------------------------------------------");
|
||||
uint8_t isOK;
|
||||
bool got_pre = false, got_post = false, lock_on = false;
|
||||
uint8_t pre[4] = {0};
|
||||
uint8_t post[4] = {0};
|
||||
uint32_t actualTime = startTime;
|
||||
|
||||
int phase_clear = -1;
|
||||
int phase_newwr = -1;
|
||||
|
||||
uint8_t retries = 0;
|
||||
while (actualTime <= (timeLimit - interval)) {
|
||||
PrintAndLogEx(INFO, "Using tear-off at: %" PRIu32 " us", actualTime);
|
||||
PrintAndLogEx(INFO, "Reading block BEFORE attack");
|
||||
|
||||
if (kbd_enter_pressed()) {
|
||||
PrintAndLogEx(INFO, "\naborted via keyboard!\n");
|
||||
break;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Using tear-off delay " _GREEN_("%" PRIu32) " us", actualTime);
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_HF_MIFAREU_READBL, blockNoUint, 0, 0, NULL, 0);
|
||||
PacketResponseNG resp;
|
||||
|
||||
got_pre = false;
|
||||
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
||||
uint8_t isOK = resp.oldarg[0] & 0xff;
|
||||
isOK = resp.oldarg[0] & 0xFF;
|
||||
if (isOK) {
|
||||
uint8_t *d = resp.data.asBytes;
|
||||
PrintAndLogEx(NORMAL, "\nBlock# | Data | Ascii");
|
||||
PrintAndLogEx(NORMAL, "-----------------------------");
|
||||
PrintAndLogEx(NORMAL, "%02d/0x%02X | %s| %s\n", blockNoUint, blockNoUint, sprint_hex(d, 4), sprint_ascii(d, 4));
|
||||
memcpy(pre, resp.data.asBytes, sizeof(pre));
|
||||
got_pre = true;
|
||||
}
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, ".....");
|
||||
clearCommandBuffer();
|
||||
|
||||
SendCommandMIX(CMD_HF_MFU_OTP_TEAROFF, blockNoUint, actualTime, 0, teardata, 8);
|
||||
if (!WaitForResponseTimeout(CMD_HF_MFU_OTP_TEAROFF, &resp, 4000)) {
|
||||
if (!WaitForResponseTimeout(CMD_HF_MFU_OTP_TEAROFF, &resp, 2000)) {
|
||||
PrintAndLogEx(WARNING, "Failed");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Reading block AFTER attack");
|
||||
|
||||
got_post = false;
|
||||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_HF_MIFAREU_READBL, blockNoUint, 0, 0, NULL, 0);
|
||||
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
||||
uint8_t isOK = resp.oldarg[0] & 0xff;
|
||||
isOK = resp.oldarg[0] & 0xFF;
|
||||
if (isOK) {
|
||||
uint8_t *d = resp.data.asBytes;
|
||||
PrintAndLogEx(NORMAL, "\nBlock# | Data | Ascii");
|
||||
PrintAndLogEx(NORMAL, "-----------------------------");
|
||||
PrintAndLogEx(NORMAL, "%02d/0x%02X | %s| %s\n", blockNoUint, blockNoUint, sprint_hex(d, 4), sprint_ascii(d, 4));
|
||||
memcpy(post, resp.data.asBytes, sizeof(post));
|
||||
got_post = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (got_pre && got_post) {
|
||||
|
||||
char prestr[20] = {0};
|
||||
snprintf(prestr, sizeof(prestr), "%s", sprint_hex_inrow(pre, sizeof(pre)));
|
||||
char poststr[20] = {0};
|
||||
snprintf(poststr, sizeof(poststr), "%s", sprint_hex_inrow(post, sizeof(post)));
|
||||
|
||||
if (memcmp(pre, post, sizeof(pre)) == 0) {
|
||||
|
||||
PrintAndLogEx(INFO, "Current %02d (0x%02X) %s"
|
||||
, blockNoUint
|
||||
, blockNoUint
|
||||
, poststr
|
||||
);
|
||||
} else {
|
||||
|
||||
// skip first message, since its the reset write.
|
||||
if (actualTime == startTime) {
|
||||
PrintAndLogEx(INFO, "Inital write");
|
||||
} else {
|
||||
PrintAndLogEx(INFO, _CYAN_("Tear off occured") " : %02d (0x%02X) %s vs " _RED_("%s")
|
||||
, blockNoUint
|
||||
, blockNoUint
|
||||
, prestr
|
||||
, poststr
|
||||
);
|
||||
|
||||
lock_on = true;
|
||||
|
||||
if (phase_clear == -1)
|
||||
phase_clear = actualTime;
|
||||
|
||||
// new write phase must be atleast 100us later..
|
||||
if (phase_clear > -1 && phase_newwr == -1 && actualTime > (phase_clear + 100))
|
||||
phase_newwr = actualTime;
|
||||
}
|
||||
}
|
||||
|
||||
if (use_match && memcmp(pre, match, sizeof(pre)) == 0) {
|
||||
PrintAndLogEx(SUCCESS, "Block matches!\n");
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (got_pre == false)
|
||||
PrintAndLogEx(FAILED, "Failed to read block BEFORE");
|
||||
if (got_post == false)
|
||||
PrintAndLogEx(FAILED, "Failed to read block AFTER");
|
||||
}
|
||||
|
||||
/* TEMPORALLY DISABLED
|
||||
uint8_t d0, d1, d2, d3;
|
||||
d0 = *resp.data.asBytes;
|
||||
|
@ -2933,8 +3011,29 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
|
|||
PrintAndLogEx(NORMAL, "---------------------------------\n");
|
||||
}
|
||||
*/
|
||||
actualTime += interval;
|
||||
if (startTime != timeLimit) {
|
||||
actualTime += interval;
|
||||
} else {
|
||||
if (lock_on == false) {
|
||||
if (++retries == 20) {
|
||||
actualTime++;
|
||||
timeLimit++;
|
||||
startTime++;
|
||||
retries = 0;
|
||||
PrintAndLogEx(INFO, _CYAN_("Retried %u times, increased delay with 1us"), retries);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "----------------------------------------------------");
|
||||
if (phase_clear > - 1) {
|
||||
PrintAndLogEx(INFO, "New phase boundary around " _YELLOW_("%d") " us", phase_clear);
|
||||
}
|
||||
if (phase_newwr > - 1) {
|
||||
PrintAndLogEx(INFO, "New phase boundary around " _YELLOW_("%d") " us", phase_newwr);
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
@ -299,7 +299,7 @@ static int cmd_hf_st_info(const char *Cmd) {
|
|||
CLIParserInit(&ctx, "hf st info",
|
||||
"Get info about ST25TA tag",
|
||||
"hf st info"
|
||||
);
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
|
@ -724,9 +724,13 @@ static int cmd_hf_st_pwd(const char *Cmd) {
|
|||
}
|
||||
|
||||
static int cmd_hf_st_list(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
CmdTraceList("7816");
|
||||
return PM3_SUCCESS;
|
||||
char args[128] = {0};
|
||||
if (strlen(Cmd) == 0) {
|
||||
snprintf(args, sizeof(args), "-t 7816");
|
||||
} else {
|
||||
strncpy(args, Cmd, sizeof(args) - 1);
|
||||
}
|
||||
return CmdTraceList(args);
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
|
|
|
@ -118,7 +118,6 @@ static int print_barcode(uint8_t *barcode, const size_t barcode_len, bool verbos
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static int CmdHfThinFilmInfo(const char *Cmd) {
|
||||
|
||||
uint8_t cmdp = 0;
|
||||
|
@ -226,9 +225,13 @@ static int CmdHfThinFilmSim(const char *Cmd) {
|
|||
}
|
||||
|
||||
static int CmdHfThinFilmList(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
CmdTraceList("thinfilm");
|
||||
return PM3_SUCCESS;
|
||||
char args[128] = {0};
|
||||
if (strlen(Cmd) == 0) {
|
||||
snprintf(args, sizeof(args), "-t thinfilm");
|
||||
} else {
|
||||
strncpy(args, Cmd, sizeof(args) - 1);
|
||||
}
|
||||
return CmdTraceList(args);
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
|
|
|
@ -481,9 +481,13 @@ static int CmdHFTopazCmdRaw(const char *Cmd) {
|
|||
}
|
||||
|
||||
static int CmdHFTopazList(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
CmdTraceList("topaz");
|
||||
return PM3_SUCCESS;
|
||||
char args[128] = {0};
|
||||
if (strlen(Cmd) == 0) {
|
||||
snprintf(args, sizeof(args), "-t topaz");
|
||||
} else {
|
||||
strncpy(args, Cmd, sizeof(args) - 1);
|
||||
}
|
||||
return CmdTraceList(args);
|
||||
}
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "util.h"
|
||||
#include "fileutils.h"
|
||||
#include "util_posix.h" // msleep
|
||||
#include "cliparser.h"
|
||||
|
||||
// Currently the largest pixel 880*528 only needs 58.08K bytes
|
||||
#define WSMAPSIZE 60000
|
||||
|
@ -90,23 +91,6 @@ static model_t models[] = {
|
|||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static int usage_hf_waveshare_loadbmp(void) {
|
||||
PrintAndLogEx(NORMAL, "Load BMP file to Waveshare NFC ePaper.");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf waveshare loadbmp [h] f <filename[.bmp]> m <model_nr> [s]");
|
||||
PrintAndLogEx(NORMAL, " Options :");
|
||||
PrintAndLogEx(NORMAL, " f <fn> : " _YELLOW_("filename[.bmp]") " to upload to tag");
|
||||
PrintAndLogEx(NORMAL, " m <nr> : " _YELLOW_("model number") " of your tag");
|
||||
PrintAndLogEx(NORMAL, " s : save dithered version in filename-[n].bmp, only for RGB BMP");
|
||||
for (uint8_t i = 0; i < MEND; i++) {
|
||||
PrintAndLogEx(NORMAL, " m %2i : %s", i, models[i].desc);
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf waveshare loadbmp m 0 f myfile"));
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int picture_bit_depth(const uint8_t *bmp, const size_t bmpsize, const uint8_t model_nr) {
|
||||
if (bmpsize < sizeof(BMP_HEADER))
|
||||
return PM3_ESOFT;
|
||||
|
@ -138,9 +122,15 @@ static int read_bmp_bitmap(const uint8_t *bmp, const size_t bmpsize, uint8_t mod
|
|||
uint8_t color_flag = pbmpheader->Color_1;
|
||||
// Get BMP file data pointer
|
||||
uint32_t offset = pbmpheader->offset;
|
||||
uint16_t width = pbmpheader->BMP_Width;
|
||||
uint16_t height = pbmpheader->BMP_Height;
|
||||
if ((width + 8) * height > WSMAPSIZE * 8) {
|
||||
PrintAndLogEx(WARNING, "The file is too large, aborting!");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
uint16_t X, Y;
|
||||
uint16_t Image_Width_Byte = (pbmpheader->BMP_Width % 8 == 0) ? (pbmpheader->BMP_Width / 8) : (pbmpheader->BMP_Width / 8 + 1);
|
||||
uint16_t Image_Width_Byte = (width % 8 == 0) ? (width / 8) : (width / 8 + 1);
|
||||
uint16_t Bmp_Width_Byte = (Image_Width_Byte % 4 == 0) ? Image_Width_Byte : ((Image_Width_Byte / 4 + 1) * 4);
|
||||
|
||||
*black = calloc(WSMAPSIZE, sizeof(uint8_t));
|
||||
|
@ -148,10 +138,10 @@ static int read_bmp_bitmap(const uint8_t *bmp, const size_t bmpsize, uint8_t mod
|
|||
return PM3_EMALLOC;
|
||||
}
|
||||
// Write data into RAM
|
||||
for (Y = 0; Y < pbmpheader->BMP_Height; Y++) { // columns
|
||||
for (Y = 0; Y < height; Y++) { // columns
|
||||
for (X = 0; X < Bmp_Width_Byte; X++) { // lines
|
||||
if ((X < Image_Width_Byte) && ((X + (pbmpheader->BMP_Height - Y - 1) * Image_Width_Byte) < WSMAPSIZE)) {
|
||||
(*black)[X + (pbmpheader->BMP_Height - Y - 1) * Image_Width_Byte] = color_flag ? bmp[offset] : ~bmp[offset];
|
||||
if ((X < Image_Width_Byte) && ((X + (height - Y - 1) * Image_Width_Byte) < WSMAPSIZE)) {
|
||||
(*black)[X + (height - Y - 1) * Image_Width_Byte] = color_flag ? bmp[offset] : ~bmp[offset];
|
||||
}
|
||||
offset++;
|
||||
}
|
||||
|
@ -241,7 +231,7 @@ static void dither_rgb_inplace(int16_t *chanR, int16_t *chanG, int16_t *chanB, u
|
|||
int16_t oldR = chanR[XX + Y * width];
|
||||
int16_t oldG = chanG[XX + Y * width];
|
||||
int16_t oldB = chanB[XX + Y * width];
|
||||
uint8_t newR, newG, newB;
|
||||
uint8_t newR = 0, newG = 0, newB = 0;
|
||||
nearest_color(oldR, oldG, oldB, palette, palettelen, &newR, &newG, &newB);
|
||||
chanR[XX + Y * width] = newR;
|
||||
chanG[XX + Y * width] = newG;
|
||||
|
@ -381,6 +371,10 @@ static int read_bmp_rgb(uint8_t *bmp, const size_t bmpsize, uint8_t model_nr, ui
|
|||
uint32_t offset = pbmpheader->offset;
|
||||
uint16_t width = pbmpheader->BMP_Width;
|
||||
uint16_t height = pbmpheader->BMP_Height;
|
||||
if ((width + 8) * height > WSMAPSIZE * 8) {
|
||||
PrintAndLogEx(WARNING, "The file is too large, aborting!");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
int16_t *chanR = calloc(width * height, sizeof(int16_t));
|
||||
if (chanR == NULL) {
|
||||
|
@ -565,7 +559,7 @@ static int transceive_blocking(uint8_t *txBuf, uint16_t txBufLen, uint8_t *rxBuf
|
|||
|
||||
if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
|
||||
if (resp.oldarg[0] > rxBufLen) {
|
||||
PrintAndLogEx(WARNING, "Received %"PRIu32 " bytes, rxBuf too small (%u)", resp.oldarg[0], rxBufLen);
|
||||
PrintAndLogEx(WARNING, "Received %"PRIu64 " bytes, rxBuf too small (%u)", resp.oldarg[0], rxBufLen);
|
||||
memcpy(rxBuf, resp.data.asBytes, rxBufLen);
|
||||
*actLen = rxBufLen;
|
||||
return PM3_ESOFT;
|
||||
|
@ -646,21 +640,30 @@ static int start_drawing_1in54B(uint8_t model_nr, uint8_t *black, uint8_t *red)
|
|||
static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) {
|
||||
uint8_t progress = 0;
|
||||
uint8_t step0[2] = {0xcd, 0x0d};
|
||||
uint8_t step1[3] = {0xcd, 0x00, 10}; //select e-paper type and reset e-paper 4:2.13inch e-Paper 7:2.9inch e-Paper 10:4.2inch e-Paper 14:7.5inch e-Paper
|
||||
uint8_t step2[2] = {0xcd, 0x01}; //e-paper normal mode type:
|
||||
uint8_t step3[2] = {0xcd, 0x02}; //e-paper config1
|
||||
uint8_t step4[2] = {0xcd, 0x03}; //e-paper power on
|
||||
uint8_t step5[2] = {0xcd, 0x05}; //e-paper config2
|
||||
uint8_t step6[2] = {0xcd, 0x06}; //EDP load to main
|
||||
uint8_t step7[2] = {0xcd, 0x07}; //Data preparation
|
||||
uint8_t step8[123] = {0xcd, 0x08, 0x64}; //Data start command 2.13inch(0x10:Send 16 data at a time) 2.9inch(0x10:Send 16 data at a time) 4.2inch(0x64:Send 100 data at a time) 7.5inch(0x78:Send 120 data at a time)
|
||||
uint8_t step9[2] = {0xcd, 0x18}; //e-paper power on
|
||||
uint8_t step10[2] = {0xcd, 0x09}; //Refresh e-paper
|
||||
uint8_t step11[2] = {0xcd, 0x0a}; //wait for ready
|
||||
uint8_t step12[2] = {0xcd, 0x04}; //e-paper power off command
|
||||
uint8_t step1[3] = {0xcd, 0x00, 10}; // select e-paper type and reset e-paper
|
||||
// 4 :2.13inch e-Paper
|
||||
// 7 :2.9inch e-Paper
|
||||
// 10 :4.2inch e-Paper
|
||||
// 14 :7.5inch e-Paper
|
||||
uint8_t step2[2] = {0xcd, 0x01}; // e-paper normal mode type:
|
||||
uint8_t step3[2] = {0xcd, 0x02}; // e-paper config1
|
||||
uint8_t step4[2] = {0xcd, 0x03}; // e-paper power on
|
||||
uint8_t step5[2] = {0xcd, 0x05}; // e-paper config2
|
||||
uint8_t step6[2] = {0xcd, 0x06}; // EDP load to main
|
||||
uint8_t step7[2] = {0xcd, 0x07}; // Data preparation
|
||||
|
||||
uint8_t step8[123] = {0xcd, 0x08, 0x64}; // Data start command
|
||||
// 2.13inch(0x10:Send 16 data at a time)
|
||||
// 2.9inch(0x10:Send 16 data at a time)
|
||||
// 4.2inch(0x64:Send 100 data at a time)
|
||||
// 7.5inch(0x78:Send 120 data at a time)
|
||||
uint8_t step9[2] = {0xcd, 0x18}; // e-paper power on
|
||||
uint8_t step10[2] = {0xcd, 0x09}; // Refresh e-paper
|
||||
uint8_t step11[2] = {0xcd, 0x0a}; // wait for ready
|
||||
uint8_t step12[2] = {0xcd, 0x04}; // e-paper power off command
|
||||
uint8_t step13[124] = {0xcd, 0x19, 121};
|
||||
// uint8_t step13[2]={0xcd,0x0b}; //Judge whether the power supply is turned off successfully
|
||||
// uint8_t step14[2]={0xcd,0x0c}; //The end of the transmission
|
||||
// uint8_t step13[2]={0xcd,0x0b}; // Judge whether the power supply is turned off successfully
|
||||
// uint8_t step14[2]={0xcd,0x0c}; // The end of the transmission
|
||||
uint8_t rx[20];
|
||||
uint16_t actrxlen[20], i = 0;
|
||||
|
||||
|
@ -963,53 +966,60 @@ static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static int CmdHF14AWSLoadBmp(const char *Cmd) {
|
||||
|
||||
char filename[FILE_PATH_SIZE] = {0};
|
||||
uint8_t cmdp = 0;
|
||||
bool errors = false;
|
||||
size_t filenamelen = 0;
|
||||
uint8_t model_nr = 0xff;
|
||||
bool save_conversions = false;
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
return usage_hf_waveshare_loadbmp();
|
||||
case 'f':
|
||||
filenamelen = param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE);
|
||||
if (filenamelen > FILE_PATH_SIZE - 5)
|
||||
filenamelen = FILE_PATH_SIZE - 5;
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'm':
|
||||
model_nr = param_get8(Cmd, cmdp + 1);
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 's':
|
||||
save_conversions = true;
|
||||
cmdp += 1;
|
||||
break;
|
||||
default:
|
||||
PrintAndLogEx(WARNING, "Unknown parameter: " _RED_("'%c'"), param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
char desc[800] = {0};
|
||||
for (uint8_t i = 0; i < MEND; i++) {
|
||||
snprintf(desc + strlen(desc),
|
||||
sizeof(desc) - strlen(desc),
|
||||
"hf waveshare loadbmp -f myfile -m %2u -> %s ( %u, %u )\n",
|
||||
i,
|
||||
models[i].desc,
|
||||
models[i].width,
|
||||
models[i].height
|
||||
);
|
||||
}
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hf waveshare loadbmp",
|
||||
"Load BMP file to Waveshare NFC ePaper.",
|
||||
desc
|
||||
);
|
||||
|
||||
char modeldesc[40];
|
||||
snprintf(modeldesc, sizeof(modeldesc), "model number [0 - %u] of your tag", MEND - 1);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_int1("m", NULL, "<nr>", modeldesc),
|
||||
arg_lit0("s", "save", "save dithered version in filename-[n].bmp, only for RGB BMP"),
|
||||
arg_str1("f", "file", "<filename>", "filename[.bmp] to upload to tag"),
|
||||
arg_param_end
|
||||
};
|
||||
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
int model_nr = arg_get_int_def(ctx, 1, -1);
|
||||
bool save_conversions = arg_get_lit(ctx, 2);
|
||||
|
||||
int fnlen = 0;
|
||||
char filename[FILE_PATH_SIZE] = {0};
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 3), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
//Validations
|
||||
if (filenamelen < 1) {
|
||||
if (fnlen < 1) {
|
||||
PrintAndLogEx(WARNING, "Missing filename");
|
||||
errors = true;
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
if (model_nr == 0xff) {
|
||||
if (model_nr == -1) {
|
||||
PrintAndLogEx(WARNING, "Missing model");
|
||||
errors = true;
|
||||
} else if (model_nr >= MEND) {
|
||||
PrintAndLogEx(WARNING, "Unknown model");
|
||||
errors = true;
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
if (model_nr >= MEND) {
|
||||
PrintAndLogEx(WARNING, "Unknown model");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
if (errors || cmdp == 0) return usage_hf_waveshare_loadbmp();
|
||||
|
||||
uint8_t *bmp = NULL;
|
||||
uint8_t *black = NULL;
|
||||
|
@ -1042,7 +1052,7 @@ static int CmdHF14AWSLoadBmp(const char *Cmd) {
|
|||
free(bmp);
|
||||
return PM3_ESOFT;
|
||||
} else {
|
||||
PrintAndLogEx(ERR, "Error, BMP color depth %i not supported", depth);
|
||||
PrintAndLogEx(ERR, "Error, BMP color depth %i not supported. Must be 1 (BW) or 24 (RGB)", depth);
|
||||
free(bmp);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <ctype.h>
|
||||
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "cliparser.h"
|
||||
#include "comms.h"
|
||||
#include "usart_defs.h"
|
||||
#include "ui.h"
|
||||
|
@ -515,6 +516,77 @@ static int CmdStatus(const char *Cmd) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdTearoff(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "hw tearoff",
|
||||
"Configure a tear-off hook for the next write command supporting tear-off\n"
|
||||
"After having been triggered by a write command, the tear-off hook is deactivated\n"
|
||||
"Delay (in us) must be between 1 and 43000 (43ms). Precision is about 1/3us.",
|
||||
"hw tearoff --delay 1200 --> define delay of 1200us\n"
|
||||
"hw tearoff --on --> (re)activate a previously defined delay\n"
|
||||
"hw tearoff --off --> deactivate a previously activated but not yet triggered hook\n");
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_int0(NULL, "delay", "<dec>", "Delay in us before triggering tear-off, must be between 1 and 43000"),
|
||||
arg_lit0(NULL, "on", "Activate tear-off hook"),
|
||||
arg_lit0(NULL, "off", "Deactivate tear-off hook"),
|
||||
arg_lit0("s", "silent", "less verbose output"),
|
||||
arg_param_end
|
||||
};
|
||||
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
struct {
|
||||
uint16_t delay_us;
|
||||
bool on;
|
||||
bool off;
|
||||
} PACKED params;
|
||||
int delay = arg_get_int_def(ctx, 1, -1);
|
||||
params.on = arg_get_lit(ctx, 2);
|
||||
params.off = arg_get_lit(ctx, 3);
|
||||
bool silent = arg_get_lit(ctx, 4);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (delay != -1) {
|
||||
if ((delay < 1) || (delay > 43000)) {
|
||||
PrintAndLogEx(WARNING, "You can't set delay out of 1..43000 range!");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
} else {
|
||||
delay = 0; // will be ignored by ARM
|
||||
}
|
||||
|
||||
params.delay_us = delay;
|
||||
if (params.on && params.off) {
|
||||
PrintAndLogEx(WARNING, "You can't set both --on and --off!");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_SET_TEAROFF, (uint8_t *)¶ms, sizeof(params));
|
||||
PacketResponseNG resp;
|
||||
|
||||
if (WaitForResponseTimeout(CMD_SET_TEAROFF, &resp, 500) == false) {
|
||||
PrintAndLogEx(WARNING, "Tear-off command timeout.");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
|
||||
if (resp.status == PM3_SUCCESS) {
|
||||
if (params.delay_us > 0)
|
||||
PrintAndLogEx(INFO, "Tear-off hook configured with delay of " _GREEN_("%i us"), params.delay_us);
|
||||
if (params.on && silent == false)
|
||||
PrintAndLogEx(INFO, "Tear-off hook " _GREEN_("enabled"));
|
||||
if (params.off && silent == false)
|
||||
PrintAndLogEx(INFO, "Tear-off hook " _RED_("disabled"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
if (silent == false)
|
||||
PrintAndLogEx(WARNING, "Tear-off command failed.");
|
||||
|
||||
return resp.status;
|
||||
}
|
||||
|
||||
static int CmdTia(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
PrintAndLogEx(INFO, "Triggering new Timing Interval Acquisition (TIA)...");
|
||||
|
@ -621,6 +693,7 @@ static command_t CommandTable[] = {
|
|||
{"setmux", CmdSetMux, IfPm3Present, "Set the ADC mux to a specific value"},
|
||||
{"standalone", CmdStandalone, IfPm3Present, "Jump to the standalone mode"},
|
||||
{"status", CmdStatus, IfPm3Present, "Show runtime status information about the connected Proxmark3"},
|
||||
{"tearoff", CmdTearoff, IfPm3Present, "Program a tearoff hook for the next command supporting tearoff"},
|
||||
{"tia", CmdTia, IfPm3Present, "Trigger a Timing Interval Acquisition to re-adjust the RealTimeCounter divider"},
|
||||
{"tune", CmdTune, IfPm3Present, "Measure antenna tuning"},
|
||||
{"version", CmdVersion, IfPm3Present, "Show version information about the connected Proxmark3"},
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
#include "cmdlfidteck.h" // for idteck menu
|
||||
#include "cmdlfio.h" // for ioprox menu
|
||||
#include "cmdlfcotag.h" // for COTAG meny
|
||||
#include "cmdlffdx.h" // for fdx-b menu
|
||||
#include "cmdlffdxb.h" // for FDX-B menu
|
||||
#include "cmdlfgallagher.h" // for GALLAGHER menu
|
||||
#include "cmdlfguard.h" // for gproxii menu
|
||||
#include "cmdlfindala.h" // for indala menu
|
||||
|
@ -1195,7 +1195,7 @@ int CmdLFpskSim(const char *Cmd) {
|
|||
if (clk == 0) clk = GetPskClock("", false);
|
||||
PrintAndLogEx(INFO, "clk: %d", clk);
|
||||
|
||||
if (!carrier) carrier = GetPskCarrier("", false);
|
||||
if (!carrier) carrier = GetPskCarrier(false);
|
||||
PrintAndLogEx(INFO, "carrier: %d", carrier);
|
||||
|
||||
} else {
|
||||
|
@ -1454,7 +1454,7 @@ int CmdLFfind(const char *Cmd) {
|
|||
if (demodNexWatch(true) == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("NexWatch ID") " found!"); goto out;}
|
||||
if (demodIndala(true) == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Indala ID") " found!"); goto out;}
|
||||
if (demodEM410x(true) == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("EM410x ID") " found!"); goto out;}
|
||||
if (demodFDX(true) == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("FDX-B ID") " found!"); goto out;}
|
||||
if (demodFDXB(true) == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("FDX-B ID") " found!"); goto out;}
|
||||
if (demodGuard(true) == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Guardall G-Prox II ID") " found!"); goto out; }
|
||||
if (demodIdteck(true) == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Idteck ID") " found!"); goto out;}
|
||||
if (demodJablotron(true) == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Jablotron ID") " found!"); goto out;}
|
||||
|
@ -1527,7 +1527,7 @@ static command_t CommandTable[] = {
|
|||
{"awid", CmdLFAWID, AlwaysAvailable, "{ AWID RFIDs... }"},
|
||||
{"cotag", CmdLFCOTAG, AlwaysAvailable, "{ COTAG CHIPs... }"},
|
||||
{"em", CmdLFEM4X, AlwaysAvailable, "{ EM4X CHIPs & RFIDs... }"},
|
||||
{"fdx", CmdLFFdx, AlwaysAvailable, "{ FDX-B RFIDs... }"},
|
||||
{"fdxb", CmdLFFdxB, AlwaysAvailable, "{ FDX-B RFIDs... }"},
|
||||
{"gallagher", CmdLFGallagher, AlwaysAvailable, "{ GALLAGHER RFIDs... }"},
|
||||
{"gproxii", CmdLFGuard, AlwaysAvailable, "{ Guardall Prox II RFIDs... }"},
|
||||
{"hid", CmdLFHID, AlwaysAvailable, "{ HID Prox RFIDs... }"},
|
||||
|
|
|
@ -30,6 +30,8 @@
|
|||
#include "cmddata.h"
|
||||
#include "cmdlf.h"
|
||||
#include "lfdemod.h"
|
||||
#include "generator.h"
|
||||
#include "cliparser.h"
|
||||
|
||||
static uint64_t g_em410xid = 0;
|
||||
|
||||
|
@ -164,7 +166,7 @@ static int usage_lf_em4x05_write(void) {
|
|||
PrintAndLogEx(NORMAL, "Usage: lf em 4x05_write [h] <address> <data> <pwd>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h - this help");
|
||||
PrintAndLogEx(NORMAL, " address - memory address to write to. (0-15)");
|
||||
PrintAndLogEx(NORMAL, " address - memory address to write to. (0-13, 99 for Protection Words)");
|
||||
PrintAndLogEx(NORMAL, " data - data to write (hex)");
|
||||
PrintAndLogEx(NORMAL, " pwd - password (hex) (optional)");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
|
@ -731,25 +733,30 @@ static bool downloadSamplesEM(void) {
|
|||
}
|
||||
|
||||
// em_demod
|
||||
static bool doPreambleSearch(size_t *startIdx) {
|
||||
static int doPreambleSearch(size_t *startIdx) {
|
||||
|
||||
// sanity check
|
||||
if (DemodBufferLen < EM_PREAMBLE_LEN) {
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - EM4305 demodbuffer too small");
|
||||
return false;
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
// set size to 20 to only test first 14 positions for the preamble
|
||||
size_t size = (20 > DemodBufferLen) ? DemodBufferLen : 20;
|
||||
// set size to 9 to only test first 3 positions for the preamble
|
||||
// do not set it too long else an error preamble followed by 010 could be seen as success.
|
||||
size_t size = (9 > DemodBufferLen) ? DemodBufferLen : 9;
|
||||
*startIdx = 0;
|
||||
// skip first two 0 bits as they might have been missed in the demod
|
||||
uint8_t preamble[EM_PREAMBLE_LEN] = {0, 0, 1, 0, 1, 0};
|
||||
|
||||
if (!preambleSearchEx(DemodBuffer, preamble, EM_PREAMBLE_LEN, &size, startIdx, true)) {
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - EM4305 preamble not found :: %zu", *startIdx);
|
||||
return false;
|
||||
uint8_t errpreamble[EM_PREAMBLE_LEN] = {0, 0, 0, 0, 0, 1};
|
||||
if (!preambleSearchEx(DemodBuffer, errpreamble, EM_PREAMBLE_LEN, &size, startIdx, true)) {
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - EM4305 preamble not found :: %zu", *startIdx);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
return PM3_EFAILED; // Error preamble found
|
||||
}
|
||||
return true;
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static bool detectFSK(void) {
|
||||
|
@ -793,7 +800,7 @@ static bool detectPSK(void) {
|
|||
// try manchester - NOTE: ST only applies to T55x7 tags.
|
||||
static bool detectASK_MAN(void) {
|
||||
bool stcheck = false;
|
||||
if (ASKDemod_ext(0, 0, 0, 0, false, false, false, 1, &stcheck) != PM3_SUCCESS) {
|
||||
if (ASKDemod_ext(0, 0, 50, 0, false, false, false, 1, &stcheck) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - EM: ASK/Manchester Demod failed");
|
||||
return false;
|
||||
}
|
||||
|
@ -852,35 +859,72 @@ static int setDemodBufferEM(uint32_t *word, size_t idx) {
|
|||
// FSK, PSK, ASK/MANCHESTER, ASK/BIPHASE, ASK/DIPHASE, NRZ
|
||||
// should cover 90% of known used configs
|
||||
// the rest will need to be manually demoded for now...
|
||||
static int demodEM4x05resp(uint32_t *word) {
|
||||
static int demodEM4x05resp(uint32_t *word, bool onlyPreamble) {
|
||||
size_t idx = 0;
|
||||
*word = 0;
|
||||
if (detectASK_MAN() && doPreambleSearch(&idx))
|
||||
return setDemodBufferEM(word, idx);
|
||||
bool found_err = false;
|
||||
int res = PM3_SUCCESS;
|
||||
do {
|
||||
if (detectASK_MAN()) {
|
||||
res = doPreambleSearch(&idx);
|
||||
if (res == PM3_SUCCESS)
|
||||
break;
|
||||
if (res == PM3_EFAILED)
|
||||
// go on, maybe it's false positive and another modulation will work
|
||||
found_err = true;
|
||||
}
|
||||
if (detectASK_BI()) {
|
||||
res = doPreambleSearch(&idx);
|
||||
if (res == PM3_SUCCESS)
|
||||
break;
|
||||
if (res == PM3_EFAILED)
|
||||
found_err = true;
|
||||
}
|
||||
if (detectNRZ()) {
|
||||
res = doPreambleSearch(&idx);
|
||||
if (res == PM3_SUCCESS)
|
||||
break;
|
||||
if (res == PM3_EFAILED)
|
||||
found_err = true;
|
||||
}
|
||||
if (detectFSK()) {
|
||||
res = doPreambleSearch(&idx);
|
||||
if (res == PM3_SUCCESS)
|
||||
break;
|
||||
if (res == PM3_EFAILED)
|
||||
found_err = true;
|
||||
}
|
||||
if (detectPSK()) {
|
||||
res = doPreambleSearch(&idx);
|
||||
if (res == PM3_SUCCESS)
|
||||
break;
|
||||
if (res == PM3_EFAILED)
|
||||
found_err = true;
|
||||
|
||||
if (detectASK_BI() && doPreambleSearch(&idx))
|
||||
return setDemodBufferEM(word, idx);
|
||||
|
||||
if (detectNRZ() && doPreambleSearch(&idx))
|
||||
return setDemodBufferEM(word, idx);
|
||||
|
||||
if (detectFSK() && doPreambleSearch(&idx))
|
||||
return setDemodBufferEM(word, idx);
|
||||
|
||||
if (detectPSK()) {
|
||||
if (doPreambleSearch(&idx))
|
||||
return setDemodBufferEM(word, idx);
|
||||
|
||||
psk1TOpsk2(DemodBuffer, DemodBufferLen);
|
||||
if (doPreambleSearch(&idx))
|
||||
return setDemodBufferEM(word, idx);
|
||||
}
|
||||
return PM3_ESOFT;
|
||||
psk1TOpsk2(DemodBuffer, DemodBufferLen);
|
||||
res = doPreambleSearch(&idx);
|
||||
if (res == PM3_SUCCESS)
|
||||
break;
|
||||
if (res == PM3_EFAILED)
|
||||
found_err = true;
|
||||
}
|
||||
if (found_err)
|
||||
return PM3_EFAILED;
|
||||
return PM3_ESOFT;
|
||||
} while (0);
|
||||
if (onlyPreamble)
|
||||
return PM3_SUCCESS;
|
||||
res = setDemodBufferEM(word, idx);
|
||||
if (res == PM3_SUCCESS)
|
||||
return res;
|
||||
if (found_err)
|
||||
return PM3_EFAILED;
|
||||
return res;
|
||||
}
|
||||
|
||||
//////////////// 4205 / 4305 commands
|
||||
#include "util_posix.h" // msclock
|
||||
static int EM4x05ReadWord_ext(uint8_t addr, uint32_t pwd, bool usePwd, uint32_t *word) {
|
||||
int EM4x05ReadWord_ext(uint8_t addr, uint32_t pwd, bool usePwd, uint32_t *word) {
|
||||
|
||||
struct {
|
||||
uint32_t password;
|
||||
|
@ -903,20 +947,21 @@ static int EM4x05ReadWord_ext(uint8_t addr, uint32_t pwd, bool usePwd, uint32_t
|
|||
if (downloadSamplesEM() == false) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
return demodEM4x05resp(word);
|
||||
return demodEM4x05resp(word, false);
|
||||
}
|
||||
|
||||
static int CmdEM4x05Demod(const char *Cmd) {
|
||||
// uint8_t ctmp = tolower(param_getchar(Cmd, 0));
|
||||
// if (ctmp == 'h') return usage_lf_em4x05_demod();
|
||||
uint32_t word = 0;
|
||||
return demodEM4x05resp(&word);
|
||||
uint32_t dummy = 0;
|
||||
return demodEM4x05resp(&dummy, false);
|
||||
}
|
||||
|
||||
static int CmdEM4x05Dump(const char *Cmd) {
|
||||
uint8_t addr = 0;
|
||||
uint32_t pwd = 0;
|
||||
bool usePwd = false;
|
||||
bool needReadPwd = true;
|
||||
uint8_t cmdp = 0;
|
||||
uint8_t bytes[4] = {0};
|
||||
uint32_t data[16];
|
||||
|
@ -946,40 +991,66 @@ static int CmdEM4x05Dump(const char *Cmd) {
|
|||
}
|
||||
|
||||
int success = PM3_SUCCESS;
|
||||
int status;
|
||||
int status, status14, status15;
|
||||
uint32_t lock_bits = 0x00; // no blocks locked
|
||||
|
||||
bool gotLockBits = false;
|
||||
bool lockInPW2 = false;
|
||||
uint32_t word = 0;
|
||||
const char *info[] = {"Info/User", "UID", "Password", "User", "Config", "User", "User", "User", "User", "User", "User", "User", "User", "User", "Lock", "Lock"};
|
||||
|
||||
if (usePwd) {
|
||||
// Test first if a password is required
|
||||
status = EM4x05ReadWord_ext(14, pwd, false, &word);
|
||||
if (status == PM3_SUCCESS) {
|
||||
PrintAndLogEx(INFO, "Note that password doesn't seem to be needed");
|
||||
needReadPwd = false;
|
||||
}
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "Addr | data | ascii |lck| info");
|
||||
PrintAndLogEx(NORMAL, "-----+----------+-------+---+-----");
|
||||
|
||||
// To flag any blocks locked we need to read blocks 14 and 15 first
|
||||
// dont swap endin until we get block lock flags.
|
||||
status = EM4x05ReadWord_ext(14, pwd, usePwd, &word);
|
||||
if (status != PM3_SUCCESS)
|
||||
status14 = EM4x05ReadWord_ext(14, pwd, usePwd, &word);
|
||||
if (status14 == PM3_SUCCESS) {
|
||||
if (!usePwd)
|
||||
needReadPwd = false;
|
||||
if ((word & 0x00008000) != 0x00) {
|
||||
lock_bits = word;
|
||||
gotLockBits = true;
|
||||
}
|
||||
data[14] = word;
|
||||
} else {
|
||||
success = PM3_ESOFT; // If any error ensure fail is set so not to save invalid data
|
||||
if (word != 0x00)
|
||||
lock_bits = word;
|
||||
data[14] = word;
|
||||
|
||||
status = EM4x05ReadWord_ext(15, pwd, usePwd, &word);
|
||||
if (status != PM3_SUCCESS)
|
||||
}
|
||||
status15 = EM4x05ReadWord_ext(15, pwd, usePwd, &word);
|
||||
if (status15 == PM3_SUCCESS) {
|
||||
if ((word & 0x00008000) != 0x00) { // assume block 15 is the current lock block
|
||||
lock_bits = word;
|
||||
gotLockBits = true;
|
||||
lockInPW2 = true;
|
||||
}
|
||||
data[15] = word;
|
||||
} else {
|
||||
success = PM3_ESOFT; // If any error ensure fail is set so not to save invalid data
|
||||
if (word != 0x00) // assume block 15 is the current lock block
|
||||
lock_bits = word;
|
||||
data[15] = word;
|
||||
|
||||
}
|
||||
uint32_t lockbit;
|
||||
// Now read blocks 0 - 13 as we have 14 and 15
|
||||
for (; addr < 14; addr++) {
|
||||
|
||||
lockbit = (lock_bits >> addr) & 1;
|
||||
if (addr == 2) {
|
||||
if (usePwd) {
|
||||
data[addr] = BSWAP_32(pwd);
|
||||
num_to_bytes(pwd, 4, bytes);
|
||||
PrintAndLogEx(NORMAL, " %02u | %08X | %s | %c | password", addr, pwd, sprint_ascii(bytes, 4), ((lock_bits >> addr) & 1) ? 'x' : ' ');
|
||||
if ((needReadPwd) && (success != PM3_ESOFT)) {
|
||||
data[addr] = BSWAP_32(pwd);
|
||||
num_to_bytes(pwd, 4, bytes);
|
||||
PrintAndLogEx(NORMAL, " %02u | %08X | %s | %s | %s", addr, pwd, sprint_ascii(bytes, 4), gotLockBits ? (lockbit ? _RED_("x") : " ") : _YELLOW_("?"), info[addr]);
|
||||
} else {
|
||||
// The pwd is not needed for Login so we're not sure what's the actual content of that block
|
||||
PrintAndLogEx(NORMAL, " %02u | | | | %-10s " _YELLOW_("write only"), addr, info[addr]);
|
||||
}
|
||||
} else {
|
||||
data[addr] = 0x00; // Unknown password, but not used to set to zeros
|
||||
PrintAndLogEx(NORMAL, " 02 | | | | " _RED_("cannot read"));
|
||||
PrintAndLogEx(NORMAL, " %02u | | | | %-10s " _YELLOW_("write only"), addr, info[addr]);
|
||||
}
|
||||
} else {
|
||||
// success &= EM4x05ReadWord_ext(addr, pwd, usePwd, &word);
|
||||
|
@ -989,15 +1060,27 @@ static int CmdEM4x05Dump(const char *Cmd) {
|
|||
data[addr] = BSWAP_32(word);
|
||||
if (status == PM3_SUCCESS) {
|
||||
num_to_bytes(word, 4, bytes);
|
||||
PrintAndLogEx(NORMAL, " %02d | %08X | %s | %c |", addr, word, sprint_ascii(bytes, 4), ((lock_bits >> addr) & 1) ? 'x' : ' ');
|
||||
PrintAndLogEx(NORMAL, " %02u | %08X | %s | %s | %s", addr, word, sprint_ascii(bytes, 4), gotLockBits ? (lockbit ? _RED_("x") : " ") : _YELLOW_("?"), info[addr]);
|
||||
} else
|
||||
PrintAndLogEx(NORMAL, " %02d | | | | " _RED_("Fail"), addr);
|
||||
PrintAndLogEx(NORMAL, " %02u | | | | %-10s %s", addr, info[addr], status == PM3_EFAILED ? _RED_("read denied") : _RED_("read failed"));
|
||||
}
|
||||
}
|
||||
// Print blocks 14 and 15
|
||||
// Both lock bits are protected with bit idx 14 (special case)
|
||||
PrintAndLogEx(NORMAL, " %02d | %08X | %s | %c | Lock", 14, data[14], sprint_ascii(bytes, 4), ((lock_bits >> 14) & 1) ? 'x' : ' ');
|
||||
PrintAndLogEx(NORMAL, " %02d | %08X | %s | %c | Lock", 15, data[15], sprint_ascii(bytes, 4), ((lock_bits >> 14) & 1) ? 'x' : ' ');
|
||||
addr = 14;
|
||||
if (status14 == PM3_SUCCESS) {
|
||||
lockbit = (lock_bits >> addr) & 1;
|
||||
PrintAndLogEx(NORMAL, " %02u | %08X | %s | %s | %-10s %s", addr, data[addr], sprint_ascii(bytes, 4), gotLockBits ? (lockbit ? _RED_("x") : " ") : _YELLOW_("?"), info[addr], lockInPW2 ? "" : _GREEN_("active"));
|
||||
} else {
|
||||
PrintAndLogEx(NORMAL, " %02u | | | | %-10s %s", addr, info[addr], status14 == PM3_EFAILED ? _RED_("read denied") : _RED_("read failed"));
|
||||
}
|
||||
addr = 15;
|
||||
if (status15 == PM3_SUCCESS) {
|
||||
lockbit = (lock_bits >> 14) & 1; // beware lock bit of word15 is pr14
|
||||
PrintAndLogEx(NORMAL, " %02u | %08X | %s | %s | %-10s %s", addr, data[addr], sprint_ascii(bytes, 4), gotLockBits ? (lockbit ? _RED_("x") : " ") : _YELLOW_("?"), info[addr], lockInPW2 ? _GREEN_("active") : "");
|
||||
} else {
|
||||
PrintAndLogEx(NORMAL, " %02u | | | | %-10s %s", addr, info[addr], status15 == PM3_EFAILED ? _RED_("read denied") : _RED_("read failed"));
|
||||
}
|
||||
// Update endian for files
|
||||
data[14] = BSWAP_32(data[14]);
|
||||
data[15] = BSWAP_32(data[15]);
|
||||
|
@ -1027,22 +1110,24 @@ static int CmdEM4x05Read(const char *Cmd) {
|
|||
pwd = param_get32ex(Cmd, 1, 0xFFFFFFFF, 16);
|
||||
|
||||
if (addr > 15) {
|
||||
PrintAndLogEx(NORMAL, "Address must be between 0 and 15");
|
||||
PrintAndLogEx(WARNING, "Address must be between 0 and 15");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
if (pwd == 0xFFFFFFFF) {
|
||||
PrintAndLogEx(NORMAL, "Reading address %02u", addr);
|
||||
PrintAndLogEx(INFO, "Reading address %02u", addr);
|
||||
} else {
|
||||
usePwd = true;
|
||||
PrintAndLogEx(NORMAL, "Reading address %02u | password %08X", addr, pwd);
|
||||
PrintAndLogEx(INFO, "Reading address %02u using password %08X", addr, pwd);
|
||||
}
|
||||
|
||||
uint32_t word = 0;
|
||||
int status = EM4x05ReadWord_ext(addr, pwd, usePwd, &word);
|
||||
if (status == PM3_SUCCESS)
|
||||
PrintAndLogEx(NORMAL, "Address %02d | %08X - %s", addr, word, (addr > 13) ? "Lock" : "");
|
||||
PrintAndLogEx(SUCCESS, "Address %02d | %08X - %s", addr, word, (addr > 13) ? "Lock" : "");
|
||||
else if (status == PM3_EFAILED)
|
||||
PrintAndLogEx(ERR, "Tag denied Read operation");
|
||||
else
|
||||
PrintAndLogEx(NORMAL, "Read Address %02d | " _RED_("Fail"), addr);
|
||||
PrintAndLogEx(WARNING, "No answer from tag");
|
||||
return status;
|
||||
}
|
||||
|
||||
|
@ -1057,48 +1142,76 @@ static int CmdEM4x05Write(const char *Cmd) {
|
|||
addr = param_get8ex(Cmd, 0, 50, 10);
|
||||
data = param_get32ex(Cmd, 1, 0, 16);
|
||||
pwd = param_get32ex(Cmd, 2, 0xFFFFFFFF, 16);
|
||||
bool protectOperation = addr == 99; // will do better with cliparser...
|
||||
|
||||
if (addr > 15) {
|
||||
PrintAndLogEx(NORMAL, "Address must be between 0 and 15");
|
||||
if ((addr > 13) && (!protectOperation)) {
|
||||
PrintAndLogEx(WARNING, "Address must be between 0 and 13");
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
if (pwd == 0xFFFFFFFF)
|
||||
PrintAndLogEx(NORMAL, "Writing address %d data %08X", addr, data);
|
||||
else {
|
||||
if (pwd == 0xFFFFFFFF) {
|
||||
if (protectOperation)
|
||||
PrintAndLogEx(INFO, "Writing protection words data %08X", data);
|
||||
else
|
||||
PrintAndLogEx(INFO, "Writing address %d data %08X", addr, data);
|
||||
} else {
|
||||
usePwd = true;
|
||||
PrintAndLogEx(NORMAL, "Writing address %d data %08X using password %08X", addr, data, pwd);
|
||||
if (protectOperation)
|
||||
PrintAndLogEx(INFO, "Writing protection words data %08X using password %08X", data, pwd);
|
||||
else
|
||||
PrintAndLogEx(INFO, "Writing address %d data %08X using password %08X", addr, data, pwd);
|
||||
}
|
||||
|
||||
struct {
|
||||
uint32_t password;
|
||||
uint32_t data;
|
||||
uint8_t address;
|
||||
uint8_t usepwd;
|
||||
} PACKED payload;
|
||||
if (protectOperation) { // set Protect Words
|
||||
struct {
|
||||
uint32_t password;
|
||||
uint32_t data;
|
||||
uint8_t usepwd;
|
||||
} PACKED payload;
|
||||
|
||||
payload.password = pwd;
|
||||
payload.data = data;
|
||||
payload.address = addr;
|
||||
payload.usepwd = usePwd;
|
||||
payload.password = pwd;
|
||||
payload.data = data;
|
||||
payload.usepwd = usePwd;
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_LF_EM4X_WRITEWORD, (uint8_t *)&payload, sizeof(payload));
|
||||
PacketResponseNG resp;
|
||||
if (!WaitForResponseTimeout(CMD_LF_EM4X_WRITEWORD, &resp, 2000)) {
|
||||
PrintAndLogEx(ERR, "Error occurred, device did not respond during write operation.");
|
||||
return PM3_ETIMEOUT;
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_LF_EM4X_PROTECTWORD, (uint8_t *)&payload, sizeof(payload));
|
||||
PacketResponseNG resp;
|
||||
if (!WaitForResponseTimeout(CMD_LF_EM4X_PROTECTWORD, &resp, 2000)) {
|
||||
PrintAndLogEx(ERR, "Error occurred, device did not respond during write operation.");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
} else {
|
||||
struct {
|
||||
uint32_t password;
|
||||
uint32_t data;
|
||||
uint8_t address;
|
||||
uint8_t usepwd;
|
||||
} PACKED payload;
|
||||
|
||||
payload.password = pwd;
|
||||
payload.data = data;
|
||||
payload.address = addr;
|
||||
payload.usepwd = usePwd;
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_LF_EM4X_WRITEWORD, (uint8_t *)&payload, sizeof(payload));
|
||||
PacketResponseNG resp;
|
||||
if (!WaitForResponseTimeout(CMD_LF_EM4X_WRITEWORD, &resp, 2000)) {
|
||||
PrintAndLogEx(ERR, "Error occurred, device did not respond during write operation.");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
if (!downloadSamplesEM())
|
||||
return PM3_ENODATA;
|
||||
|
||||
//need 0 bits demoded (after preamble) to verify write cmd
|
||||
uint32_t dummy = 0;
|
||||
int status = demodEM4x05resp(&dummy);
|
||||
int status = demodEM4x05resp(&dummy, true);
|
||||
if (status == PM3_SUCCESS)
|
||||
PrintAndLogEx(SUCCESS, "Success writing to tag");
|
||||
else if (status == PM3_EFAILED)
|
||||
PrintAndLogEx(ERR, "Tag denied %s operation", protectOperation ? "Protect" : "Write");
|
||||
else
|
||||
PrintAndLogEx(DEBUG, "No answer from tag");
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf em 4x05_read`") " to verify");
|
||||
return status;
|
||||
}
|
||||
|
@ -1263,8 +1376,10 @@ static void printEM4x05config(uint32_t wordData) {
|
|||
uint8_t disable = (wordData & EM4x05_DISABLE_ALLOWED) >> 23;
|
||||
uint8_t rtf = (wordData & EM4x05_READER_TALK_FIRST) >> 24;
|
||||
uint8_t pigeon = (wordData & (1 << 26)) >> 26;
|
||||
PrintAndLogEx(INFO, "ConfigWord: %08X (Word 4)\n", wordData);
|
||||
PrintAndLogEx(INFO, "Config Breakdown:");
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "--- " _CYAN_("Config Information") " ---------------------------");
|
||||
PrintAndLogEx(INFO, "ConfigWord: %08X (Word 4)", wordData);
|
||||
PrintAndLogEx(INFO, " Data Rate: %02u | "_YELLOW_("RF/%u"), wordData & 0x3F, datarate);
|
||||
PrintAndLogEx(INFO, " Encoder: %u | " _YELLOW_("%s"), encoder, enc);
|
||||
PrintAndLogEx(INFO, " PSK CF: %u | %s", PSKcf, cf);
|
||||
|
@ -1277,30 +1392,50 @@ static void printEM4x05config(uint32_t wordData) {
|
|||
PrintAndLogEx(INFO, " R.A.W.: %u | Read after write is %s", raw, raw ? "on" : "off");
|
||||
PrintAndLogEx(INFO, " Disable: %u | Disable command is %s", disable, disable ? "accepted" : "not accepted");
|
||||
PrintAndLogEx(INFO, " R.T.F.: %u | Reader talk first is %s", rtf, rtf ? _YELLOW_("enabled") : "disabled");
|
||||
PrintAndLogEx(INFO, " Pigeon: %u | Pigeon mode is %s\n", pigeon, pigeon ? _YELLOW_("enabled") : "disabled");
|
||||
PrintAndLogEx(INFO, " Pigeon: %u | Pigeon mode is %s", pigeon, pigeon ? _YELLOW_("enabled") : "disabled");
|
||||
}
|
||||
|
||||
static void printEM4x05info(uint32_t block0, uint32_t serial) {
|
||||
|
||||
uint8_t chipType = (block0 >> 1) & 0xF;
|
||||
uint8_t cap = (block0 >> 5) & 3;
|
||||
uint16_t custCode = (block0 >> 9) & 0x3FF;
|
||||
uint16_t custCode = (block0 >> 9) & 0x2FF;
|
||||
|
||||
PrintAndLogEx(INFO, " block0: %X", block0);
|
||||
PrintAndLogEx(INFO, " chiptype: %X", chipType);
|
||||
PrintAndLogEx(INFO, "capacitor: %X", cap);
|
||||
PrintAndLogEx(INFO, " custcode: %X", custCode);
|
||||
|
||||
/* bits
|
||||
// 0, rfu
|
||||
// 1,2,3,4 chip type
|
||||
// 5,6 resonant cap
|
||||
// 7,8, rfu
|
||||
// 9 - 18 customer code
|
||||
// 19, rfu
|
||||
|
||||
98765432109876543210
|
||||
001000000000
|
||||
// 00100000000001111000
|
||||
// 1100
|
||||
// 011
|
||||
// 00100000000
|
||||
*/
|
||||
|
||||
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------");
|
||||
|
||||
char ctstr[50];
|
||||
snprintf(ctstr, sizeof(ctstr), "\n Chip Type: %u | ", chipType);
|
||||
snprintf(ctstr, sizeof(ctstr), " Chip Type: %u | ", chipType);
|
||||
switch (chipType) {
|
||||
case 9:
|
||||
snprintf(ctstr + strlen(ctstr), sizeof(ctstr) - strlen(ctstr), _YELLOW_("%s"), "EM4305");
|
||||
break;
|
||||
case 4:
|
||||
snprintf(ctstr + strlen(ctstr), sizeof(ctstr) - strlen(ctstr), _YELLOW_("%s"), "EM4469");
|
||||
break;
|
||||
case 8:
|
||||
snprintf(ctstr + strlen(ctstr), sizeof(ctstr) - strlen(ctstr), _YELLOW_("%s"), "EM4205");
|
||||
break;
|
||||
case 4:
|
||||
snprintf(ctstr + strlen(ctstr), sizeof(ctstr) - strlen(ctstr), _YELLOW_("%s"), "Unknown");
|
||||
break;
|
||||
case 2:
|
||||
snprintf(ctstr + strlen(ctstr), sizeof(ctstr) - strlen(ctstr), _YELLOW_("%s"), "EM4469");
|
||||
break;
|
||||
//add more here when known
|
||||
default:
|
||||
snprintf(ctstr + strlen(ctstr), sizeof(ctstr) - strlen(ctstr), _YELLOW_("%s"), "Unknown");
|
||||
|
@ -1328,14 +1463,17 @@ static void printEM4x05info(uint32_t block0, uint32_t serial) {
|
|||
|
||||
PrintAndLogEx(SUCCESS, " Cust Code: %03u | %s", custCode, (custCode == 0x200) ? "Default" : "Unknown");
|
||||
if (serial != 0)
|
||||
PrintAndLogEx(SUCCESS, "\n Serial #: " _YELLOW_("%08X"), serial);
|
||||
PrintAndLogEx(SUCCESS, " Serial #: " _YELLOW_("%08X"), serial);
|
||||
}
|
||||
|
||||
static void printEM4x05ProtectionBits(uint32_t word) {
|
||||
static void printEM4x05ProtectionBits(uint32_t word, uint8_t addr) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "--- " _CYAN_("Protection") " ---------------------------");
|
||||
PrintAndLogEx(INFO, "ProtectionWord: %08X (Word %i)", word, addr);
|
||||
for (uint8_t i = 0; i < 15; i++) {
|
||||
PrintAndLogEx(INFO, " Word: %02u | %s", i, (((1 << i) & word) || i < 2) ? _RED_("write Locked") : "unlocked");
|
||||
PrintAndLogEx(INFO, " Word: %02u | %s", i, ((1 << i) & word) ? _RED_("write Locked") : "unlocked");
|
||||
if (i == 14)
|
||||
PrintAndLogEx(INFO, " Word: %02u | %s", i + 1, (((1 << i) & word) || i < 2) ? _RED_("write locked") : "unlocked");
|
||||
PrintAndLogEx(INFO, " Word: %02u | %s", i + 1, ((1 << i) & word) ? _RED_("write locked") : "unlocked");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1382,18 +1520,126 @@ static int CmdEM4x05Info(const char *Cmd) {
|
|||
if (EM4x05ReadWord_ext(EM_PROT1_BLOCK, pwd, usePwd, &word) != PM3_SUCCESS) {
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
// if status bit says this is not the used protection word
|
||||
if (!(word & 0x8000)) {
|
||||
if (word & 0x8000) {
|
||||
printEM4x05ProtectionBits(word, EM_PROT1_BLOCK);
|
||||
return PM3_SUCCESS;
|
||||
} else { // if status bit says this is not the used protection word
|
||||
if (EM4x05ReadWord_ext(EM_PROT2_BLOCK, pwd, usePwd, &word) != PM3_SUCCESS)
|
||||
return PM3_ESOFT;
|
||||
if (word & 0x8000) {
|
||||
printEM4x05ProtectionBits(word, EM_PROT2_BLOCK);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
}
|
||||
//something went wrong
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
static bool is_cancelled(void) {
|
||||
if (kbd_enter_pressed()) {
|
||||
PrintAndLogEx(WARNING, "\naborted via keyboard!\n");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// load a default pwd file.
|
||||
static int CmdEM4x05Chk(const char *Cmd) {
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf em 4x05_chk",
|
||||
"This command uses a dictionary attack against EM4205/4305/4469/4569",
|
||||
"lf em 4x05_chk\n"
|
||||
"lf em 4x05_chk -e 0x00000022B8 -> remember to use 0x for hex\n"
|
||||
"lf em 4x05_chk -f t55xx_default_pwds -> use T55xx default dictionary"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_strx0("f", "file", "<*.dic>", "loads a default keys dictionary file <*.dic>"),
|
||||
arg_u64_0("e", "em", "<EM4100>", "try the calculated password from some cloners based on EM4100 ID"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
int fnlen = 0;
|
||||
char filename[FILE_PATH_SIZE] = {0};
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||
uint64_t card_id = arg_get_u64_def(ctx, 2, 0);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (strlen(filename) == 0) {
|
||||
snprintf(filename, sizeof(filename), "t55xx_default_pwds");
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
|
||||
uint8_t addr = 4;
|
||||
uint32_t word = 0;
|
||||
bool found = false;
|
||||
uint64_t t1 = msclock();
|
||||
|
||||
// White cloner password based on EM4100 ID
|
||||
if ( card_id > 0 ) {
|
||||
|
||||
uint32_t pwd = lf_t55xx_white_pwdgen(card_id & 0xFFFFFFFF);
|
||||
PrintAndLogEx(INFO, "testing %08"PRIX32" generated ", pwd);
|
||||
|
||||
int status = EM4x05ReadWord_ext(addr, pwd, true, &word);
|
||||
if (status == PM3_SUCCESS) {
|
||||
PrintAndLogEx(SUCCESS, "found valid password [ " _GREEN_("%08"PRIX32) " ]", pwd);
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
//something went wrong
|
||||
if (!(word & 0x8000))
|
||||
return PM3_ESOFT;
|
||||
// Loop dictionary
|
||||
uint8_t *keyBlock = NULL;
|
||||
if (found == false) {
|
||||
|
||||
printEM4x05ProtectionBits(word);
|
||||
PrintAndLogEx(INFO, "press " _YELLOW_("'enter'") " to cancel the command");
|
||||
|
||||
word = 0;
|
||||
uint32_t keycount = 0;
|
||||
|
||||
int res = loadFileDICTIONARY_safe(filename, (void **) &keyBlock, 4, &keycount);
|
||||
if (res != PM3_SUCCESS || keycount == 0 || keyBlock == NULL) {
|
||||
PrintAndLogEx(WARNING, "no keys found in file");
|
||||
if (keyBlock != NULL)
|
||||
free(keyBlock);
|
||||
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
for (uint32_t c = 0; c < keycount; ++c) {
|
||||
|
||||
if (!session.pm3_present) {
|
||||
PrintAndLogEx(WARNING, "device offline\n");
|
||||
free(keyBlock);
|
||||
return PM3_ENODATA;
|
||||
}
|
||||
|
||||
if (is_cancelled()) {
|
||||
free(keyBlock);
|
||||
return PM3_EOPABORTED;
|
||||
}
|
||||
|
||||
uint32_t curr_password = bytes_to_num(keyBlock + 4 * c, 4);
|
||||
|
||||
PrintAndLogEx(INFO, "testing %08"PRIX32, curr_password);
|
||||
|
||||
int status = EM4x05ReadWord_ext(addr, curr_password, 1, &word);
|
||||
if (status == PM3_SUCCESS) {
|
||||
PrintAndLogEx(SUCCESS, "found valid password [ " _GREEN_("%08"PRIX32) " ]", curr_password);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found == false)
|
||||
PrintAndLogEx(WARNING, "check pwd failed");
|
||||
|
||||
free(keyBlock);
|
||||
|
||||
t1 = msclock() - t1;
|
||||
PrintAndLogEx(SUCCESS, "\ntime in check pwd " _YELLOW_("%.0f") " seconds\n", (float)t1 / 1000.0);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -1409,6 +1655,7 @@ static command_t CommandTable[] = {
|
|||
{"410x_spoof", CmdEM410xWatchnSpoof, IfPm3Lf, "watches for EM410x 125/134 kHz tags, and replays them. (option 'h' for 134)" },
|
||||
{"410x_clone", CmdEM410xClone, IfPm3Lf, "write EM410x UID to T55x7 or Q5/T5555 tag"},
|
||||
{"----------", CmdHelp, AlwaysAvailable, "-------------------- " _CYAN_("EM 4x05 / 4x69") " -------------------"},
|
||||
{"4x05_chk", CmdEM4x05Chk, IfPm3Lf, "Check passwords from dictionary"},
|
||||
{"4x05_demod", CmdEM4x05Demod, AlwaysAvailable, "demodulate a EM4x05/EM4x69 tag from the GraphBuffer"},
|
||||
{"4x05_dump", CmdEM4x05Dump, IfPm3Lf, "dump EM4x05/EM4x69 tag"},
|
||||
{"4x05_wipe", CmdEM4x05Wipe, IfPm3Lf, "wipe EM4x05/EM4x69 tag"},
|
||||
|
|
|
@ -17,6 +17,7 @@ int CmdLFEM4X(const char *Cmd);
|
|||
|
||||
int demodEM410x(bool verbose);
|
||||
bool EM4x05IsBlock0(uint32_t *word);
|
||||
int EM4x05ReadWord_ext(uint8_t addr, uint32_t pwd, bool usePwd, uint32_t *word);
|
||||
|
||||
void printEM410x(uint32_t hi, uint64_t id);
|
||||
int AskEm410xDecode(bool verbose, uint32_t *hi, uint64_t *lo);
|
||||
|
|
|
@ -93,7 +93,7 @@ static int usage_lf_em4x50_wipe(void) {
|
|||
PrintAndLogEx(NORMAL, " h - this help");
|
||||
PrintAndLogEx(NORMAL, " p <pwd> - password (hex)");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_wwipe p 11223344"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_wipe p 11223344"));
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
// Differential Biphase, rf/32, 128 bits (known)
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "cmdlffdx.h"
|
||||
#include "cmdlffdxb.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
|
@ -48,9 +48,9 @@
|
|||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static int usage_lf_fdx_clone(void) {
|
||||
static int usage_lf_fdxb_clone(void) {
|
||||
PrintAndLogEx(NORMAL, "Clone a FDX-B animal tag to a T55x7 or Q5/T5555 tag.");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf fdx clone [h] [c <country code>] [a <national code>] [e <extended>] <s> <Q5>");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf fdxb clone [h] [c <country code>] [a <national code>] [e <extended>] <s> <Q5>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : This help");
|
||||
PrintAndLogEx(NORMAL, " c <country> : (dec) Country code");
|
||||
|
@ -60,15 +60,15 @@ static int usage_lf_fdx_clone(void) {
|
|||
PrintAndLogEx(NORMAL, " <Q5> : Specify writing to Q5/T5555 tag");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf fdx clone c 999 n 112233 s"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf fdx clone c 999 n 112233 e 16a"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf fdxb clone c 999 n 112233 s"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf fdxb clone c 999 n 112233 e 16a"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int usage_lf_fdx_read(void) {
|
||||
static int usage_lf_fdxb_read(void) {
|
||||
PrintAndLogEx(NORMAL, "Read FDX-B animal tag");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf fdx read [h] [@]");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf fdxb read [h] [@]");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : This help");
|
||||
PrintAndLogEx(NORMAL, " @ : run continuously until a key is pressed (optional)");
|
||||
|
@ -76,11 +76,11 @@ static int usage_lf_fdx_read(void) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int usage_lf_fdx_sim(void) {
|
||||
static int usage_lf_fdxb_sim(void) {
|
||||
PrintAndLogEx(NORMAL, "Enables simulation of FDX-B animal tag");
|
||||
PrintAndLogEx(NORMAL, "Simulation runs until the button is pressed or another USB command is issued.");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf fdx sim [h] [c <country code>] [n <national code>] [e <extended>] <s> <Q5>");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf fdxb sim [h] [c <country code>] [n <national code>] [e <extended>] <s> <Q5>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : This help");
|
||||
PrintAndLogEx(NORMAL, " c <country> : (dec) Country code");
|
||||
|
@ -90,8 +90,8 @@ static int usage_lf_fdx_sim(void) {
|
|||
PrintAndLogEx(NORMAL, " <Q5> : Specify writing to Q5/T5555 tag");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf fdx sim c 999 n 112233 s"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf fdx sim c 999 n 112233 e 16a"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf fdxb sim c 999 n 112233 s"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf fdxb sim c 999 n 112233 e 16a"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -215,9 +215,275 @@ static int CmdFDXBdemodBI(const char *Cmd) {
|
|||
}
|
||||
*/
|
||||
|
||||
// For the country part:
|
||||
// wget -q -O - "https://en.wikipedia.org/w/index.php?title=List_of_ISO_3166_country_codes&action=raw" | awk '/id=/{match($0, /\[\[([^\]|]*)/, a); name=a[1];getline;getline;getline;getline;getline;match($0, /numeric#([0-9]*)/, a);num=a[1]; if (num != "") {printf " { %3u, \"%s\" },\n", num, name}}'
|
||||
// Beware the bottom of the list contains also Manufacturers list
|
||||
const fdxbCountryMapping_t fdxbCountryMapping[] = {
|
||||
{ 4, "Afghanistan" },
|
||||
{ 8, "Albania" },
|
||||
{ 12, "Algeria" },
|
||||
{ 16, "American Samoa" },
|
||||
{ 20, "Andorra" },
|
||||
{ 24, "Angola" },
|
||||
{ 660, "Anguilla" },
|
||||
{ 10, "Antarctica" },
|
||||
{ 28, "Antigua and Barbuda" },
|
||||
{ 32, "Argentina" },
|
||||
{ 51, "Armenia" },
|
||||
{ 533, "Aruba" },
|
||||
{ 40, "Austria" },
|
||||
{ 31, "Azerbaijan" },
|
||||
{ 44, "The Bahamas" },
|
||||
{ 48, "Bahrain" },
|
||||
{ 50, "Bangladesh" },
|
||||
{ 52, "Barbados" },
|
||||
{ 112, "Belarus" },
|
||||
{ 56, "Belgium" },
|
||||
{ 84, "Belize" },
|
||||
{ 204, "Benin" },
|
||||
{ 60, "Bermuda" },
|
||||
{ 64, "Bhutan" },
|
||||
{ 68, "Bolivia" },
|
||||
{ 535, "Bonaire" },
|
||||
{ 70, "Bosnia and Herzegovina" },
|
||||
{ 72, "Botswana" },
|
||||
{ 74, "Bouvet Island" },
|
||||
{ 76, "Brazil" },
|
||||
{ 86, "British Indian Ocean Territory" },
|
||||
{ 100, "Bulgaria" },
|
||||
{ 854, "Burkina Faso" },
|
||||
{ 132, "Cape Verde" },
|
||||
{ 116, "Cambodia" },
|
||||
{ 120, "Cameroon" },
|
||||
{ 124, "Canada" },
|
||||
{ 140, "Central African Republic" },
|
||||
{ 148, "Chad" },
|
||||
{ 152, "Chile" },
|
||||
{ 156, "China" },
|
||||
{ 170, "Colombia" },
|
||||
{ 174, "Comoros" },
|
||||
{ 180, "Democratic Republic of the Congo" },
|
||||
{ 178, "Republic of the Congo" },
|
||||
{ 184, "Cook Islands" },
|
||||
{ 384, "Ivory Coast" },
|
||||
{ 191, "Croatia" },
|
||||
{ 192, "Cuba" },
|
||||
{ 531, "Curaçao" },
|
||||
{ 196, "Cyprus" },
|
||||
{ 203, "Czech Republic" },
|
||||
{ 262, "Djibouti" },
|
||||
{ 212, "Dominica" },
|
||||
{ 214, "Dominican Republic" },
|
||||
{ 818, "Egypt" },
|
||||
{ 222, "El Salvador" },
|
||||
{ 232, "Eritrea" },
|
||||
{ 233, "Estonia" },
|
||||
{ 748, "Eswatini" },
|
||||
{ 231, "Ethiopia" },
|
||||
{ 238, "Falkland Islands" },
|
||||
{ 234, "Faroe Islands" },
|
||||
{ 242, "Fiji" },
|
||||
{ 246, "Finland" },
|
||||
{ 250, "France" },
|
||||
{ 254, "French Guiana" },
|
||||
{ 258, "French Polynesia" },
|
||||
{ 260, "French Southern Territories" },
|
||||
{ 266, "Gabon" },
|
||||
{ 270, "The Gambia" },
|
||||
{ 268, "Georgia (country)" },
|
||||
{ 276, "Germany" },
|
||||
{ 288, "Ghana" },
|
||||
{ 292, "Gibraltar" },
|
||||
{ 304, "Greenland" },
|
||||
{ 308, "Grenada" },
|
||||
{ 312, "Guadeloupe" },
|
||||
{ 316, "Guam" },
|
||||
{ 320, "Guatemala" },
|
||||
{ 831, "Bailiwick of Guernsey" },
|
||||
{ 324, "Guinea" },
|
||||
{ 624, "Guinea-Bissau" },
|
||||
{ 328, "Guyana" },
|
||||
{ 332, "Haiti" },
|
||||
{ 336, "Holy See" },
|
||||
{ 340, "Honduras" },
|
||||
{ 344, "Hong Kong" },
|
||||
{ 348, "Hungary" },
|
||||
{ 352, "Iceland" },
|
||||
{ 356, "India" },
|
||||
{ 360, "Indonesia" },
|
||||
{ 364, "Iran (Islamic Republic of)" },
|
||||
{ 368, "Iraq" },
|
||||
{ 372, "Republic of Ireland" },
|
||||
{ 833, "Isle of Man" },
|
||||
{ 376, "Israel" },
|
||||
{ 380, "Italy" },
|
||||
{ 832, "Jersey" },
|
||||
{ 400, "Jordan" },
|
||||
{ 398, "Kazakhstan" },
|
||||
{ 404, "Kenya" },
|
||||
{ 296, "Kiribati" },
|
||||
{ 408, "North Korea" },
|
||||
{ 410, "South Korea" },
|
||||
{ 414, "Kuwait" },
|
||||
{ 417, "Kyrgyzstan" },
|
||||
{ 418, "Laos" },
|
||||
{ 428, "Latvia" },
|
||||
{ 422, "Lebanon" },
|
||||
{ 426, "Lesotho" },
|
||||
{ 430, "Liberia" },
|
||||
{ 434, "Libya" },
|
||||
{ 438, "Liechtenstein" },
|
||||
{ 440, "Lithuania" },
|
||||
{ 442, "Luxembourg" },
|
||||
{ 446, "Macau" },
|
||||
{ 807, "North Macedonia" },
|
||||
{ 450, "Madagascar" },
|
||||
{ 454, "Malawi" },
|
||||
{ 458, "Malaysia" },
|
||||
{ 462, "Maldives" },
|
||||
{ 466, "Mali" },
|
||||
{ 470, "Malta" },
|
||||
{ 584, "Marshall Islands" },
|
||||
{ 474, "Martinique" },
|
||||
{ 478, "Mauritania" },
|
||||
{ 480, "Mauritius" },
|
||||
{ 175, "Mayotte" },
|
||||
{ 484, "Mexico" },
|
||||
{ 583, "Federated States of Micronesia" },
|
||||
{ 498, "Moldova" },
|
||||
{ 492, "Monaco" },
|
||||
{ 496, "Mongolia" },
|
||||
{ 499, "Montenegro" },
|
||||
{ 500, "Montserrat" },
|
||||
{ 504, "Morocco" },
|
||||
{ 508, "Mozambique" },
|
||||
{ 104, "Myanmar" },
|
||||
{ 516, "Namibia" },
|
||||
{ 520, "Nauru" },
|
||||
{ 524, "Nepal" },
|
||||
{ 528, "Kingdom of the Netherlands" },
|
||||
{ 540, "New Caledonia" },
|
||||
{ 554, "New Zealand" },
|
||||
{ 558, "Nicaragua" },
|
||||
{ 562, "Niger" },
|
||||
{ 566, "Nigeria" },
|
||||
{ 570, "Niue" },
|
||||
{ 574, "Norfolk Island" },
|
||||
{ 578, "Norway" },
|
||||
{ 512, "Oman" },
|
||||
{ 586, "Pakistan" },
|
||||
{ 585, "Palau" },
|
||||
{ 275, "State of Palestine" },
|
||||
{ 591, "Panama" },
|
||||
{ 598, "Papua New Guinea" },
|
||||
{ 600, "Paraguay" },
|
||||
{ 608, "Philippines" },
|
||||
{ 612, "Pitcairn Islands" },
|
||||
{ 616, "Poland" },
|
||||
{ 620, "Portugal" },
|
||||
{ 630, "Puerto Rico" },
|
||||
{ 634, "Qatar" },
|
||||
{ 638, "Réunion" },
|
||||
{ 642, "Romania" },
|
||||
{ 643, "Russia" },
|
||||
{ 646, "Rwanda" },
|
||||
{ 654, "Saint Helena" },
|
||||
{ 659, "Saint Kitts and Nevis" },
|
||||
{ 662, "Saint Lucia" },
|
||||
{ 663, "Collectivity of Saint Martin" },
|
||||
{ 666, "Saint Pierre and Miquelon" },
|
||||
{ 670, "Saint Vincent and the Grenadines" },
|
||||
{ 882, "Samoa" },
|
||||
{ 674, "San Marino" },
|
||||
{ 678, "São Tomé and Príncipe" },
|
||||
{ 682, "Saudi Arabia" },
|
||||
{ 688, "Serbia" },
|
||||
{ 690, "Seychelles" },
|
||||
{ 694, "Sierra Leone" },
|
||||
{ 702, "Singapore" },
|
||||
{ 703, "Slovakia" },
|
||||
{ 705, "Slovenia" },
|
||||
{ 90, "Solomon Islands" },
|
||||
{ 706, "Somalia" },
|
||||
{ 710, "South Africa" },
|
||||
{ 239, "South Georgia and the South Sandwich Islands" },
|
||||
{ 724, "Spain" },
|
||||
{ 144, "Sri Lanka" },
|
||||
{ 729, "Sudan" },
|
||||
{ 740, "Suriname" },
|
||||
{ 744, "Svalbard" },
|
||||
{ 752, "Sweden" },
|
||||
{ 756, "Switzerland" },
|
||||
{ 760, "Syria" },
|
||||
{ 158, "Taiwan" },
|
||||
{ 762, "Tajikistan" },
|
||||
{ 834, "Tanzania" },
|
||||
{ 764, "Thailand" },
|
||||
{ 626, "East Timor" },
|
||||
{ 768, "Togo" },
|
||||
{ 772, "Tokelau" },
|
||||
{ 776, "Tonga" },
|
||||
{ 780, "Trinidad and Tobago" },
|
||||
{ 788, "Tunisia" },
|
||||
{ 792, "Turkey" },
|
||||
{ 795, "Turkmenistan" },
|
||||
{ 796, "Turks and Caicos Islands" },
|
||||
{ 798, "Tuvalu" },
|
||||
{ 800, "Uganda" },
|
||||
{ 804, "Ukraine" },
|
||||
{ 784, "United Arab Emirates" },
|
||||
{ 826, "United Kingdom" },
|
||||
{ 581, "United States Minor Outlying Islands" },
|
||||
{ 840, "United States" },
|
||||
{ 860, "Uzbekistan" },
|
||||
{ 548, "Vanuatu" },
|
||||
{ 704, "Vietnam" },
|
||||
{ 92, "British Virgin Islands" },
|
||||
{ 850, "United States Virgin Islands" },
|
||||
{ 732, "Western Sahara" },
|
||||
{ 887, "Yemen" },
|
||||
{ 894, "Zambia" },
|
||||
{ 716, "Zimbabwe" },
|
||||
|
||||
// Manufacturers list:
|
||||
{ 952, "JECTA" },
|
||||
{ 953, "Cromasa Identificacion electronica S.A."},
|
||||
{ 955, "Reseaumatique" },
|
||||
{ 956, "Trovan Ltd. (ACK Reunite)" },
|
||||
{ 958, "Pet ID" },
|
||||
{ 959, "Global ID Technologies" },
|
||||
{ 961, "Mannings I.A.I.D." },
|
||||
{ 963, "Korth Eletro Mecanica LTDA" },
|
||||
{ 965, "4D Technology Co. Ltd" },
|
||||
{ 966, "PetCode" },
|
||||
{ 967, "Rfdynamics / M4S ID in Canada" },
|
||||
{ 968, "AEG / EIDAP in Canada" },
|
||||
{ 972, "Planet ID" },
|
||||
{ 975, "Sokymat" },
|
||||
{ 977, "AVID" },
|
||||
{ 978, "Ordicam" },
|
||||
{ 981, "Microfindr, Datamars, Found Animals, Crystal Tag, Banfield, Bayer resQ, Peeva" },
|
||||
{ 982, "24 Pet Watch (Allflex)" },
|
||||
{ 985, "HomeAgain (Destron Fearing/Digital Angel)" },
|
||||
{ 991, "Peeva" },
|
||||
{ 999, "Test range" },
|
||||
{ 0, "N/A" } // must be the last entry
|
||||
};
|
||||
|
||||
static const char* mapFDBX(uint16_t countryCode) {
|
||||
uint16_t i = 0;
|
||||
while (fdxbCountryMapping[i].code > 0) {
|
||||
if (countryCode == fdxbCountryMapping[i].code) {
|
||||
return fdxbCountryMapping[i].desc;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return fdxbCountryMapping[i].desc;
|
||||
}
|
||||
|
||||
//see ASKDemod for what args are accepted
|
||||
//almost the same demod as cmddata.c/CmdFDXBdemodBI
|
||||
int demodFDX(bool verbose) {
|
||||
int demodFDXB(bool verbose) {
|
||||
//Differential Biphase / di-phase (inverted biphase)
|
||||
//get binary from ask wave
|
||||
if (ASKbiphaseDemod(0, 32, 1, 100, false) != PM3_SUCCESS) {
|
||||
|
@ -253,18 +519,34 @@ int demodFDX(bool verbose) {
|
|||
|
||||
//got a good demod
|
||||
uint8_t offset;
|
||||
// ISO: bits 27..64
|
||||
uint64_t NationalCode = ((uint64_t)(bytebits_to_byteLSBF(DemodBuffer + 32, 6)) << 32) | bytebits_to_byteLSBF(DemodBuffer, 32);
|
||||
|
||||
offset = 38;
|
||||
// ISO: bits 17..26
|
||||
uint16_t countryCode = bytebits_to_byteLSBF(DemodBuffer + offset, 10);
|
||||
|
||||
offset += 10;
|
||||
// ISO: bits 16
|
||||
uint8_t dataBlockBit = DemodBuffer[offset];
|
||||
|
||||
offset++;
|
||||
uint32_t reservedCode = bytebits_to_byteLSBF(DemodBuffer + offset, 14);
|
||||
// ISO: bits 15
|
||||
uint8_t rudiBit = DemodBuffer[offset];
|
||||
|
||||
offset += 14;
|
||||
offset++;
|
||||
// ISO: bits 10..14
|
||||
uint32_t reservedCode = bytebits_to_byteLSBF(DemodBuffer + offset, 5);
|
||||
|
||||
offset += 5;
|
||||
// ISO: bits 5..9
|
||||
uint32_t userInfo = bytebits_to_byteLSBF(DemodBuffer + offset, 5);
|
||||
|
||||
offset += 5;
|
||||
// ISO: bits 2..4
|
||||
uint32_t replacementNr = bytebits_to_byteLSBF(DemodBuffer + offset, 3);
|
||||
|
||||
offset += 3;
|
||||
uint8_t animalBit = DemodBuffer[offset];
|
||||
|
||||
offset++;
|
||||
|
@ -283,12 +565,15 @@ int demodFDX(bool verbose) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "FDX-B / ISO 11784/5 Animal");
|
||||
PrintAndLogEx(SUCCESS, "Animal ID " _GREEN_("%04u-%012"PRIu64), countryCode, NationalCode);
|
||||
PrintAndLogEx(SUCCESS, "Animal ID " _GREEN_("%03u-%012"PRIu64), countryCode, NationalCode);
|
||||
PrintAndLogEx(SUCCESS, "National Code " _GREEN_("%012" PRIu64) " (0x%" PRIX64 ")", NationalCode, NationalCode);
|
||||
PrintAndLogEx(SUCCESS, "Country Code " _GREEN_("%04u"), countryCode);
|
||||
PrintAndLogEx(SUCCESS, "Country Code " _GREEN_("%03u") " - %s", countryCode, mapFDBX(countryCode));
|
||||
PrintAndLogEx(SUCCESS, "Reserved/RFU %u (0x%04X)", reservedCode, reservedCode);
|
||||
PrintAndLogEx(SUCCESS, " Animal bit set? %s", animalBit ? _YELLOW_("True") : "False");
|
||||
PrintAndLogEx(SUCCESS, " Data block? %s [value 0x%X]", dataBlockBit ? _YELLOW_("True") : "False", extended);
|
||||
PrintAndLogEx(SUCCESS, " RUDI bit? %s", rudiBit ? _YELLOW_("True") " (advanced transponder)" : "False");
|
||||
PrintAndLogEx(SUCCESS, " User Info? %u %s", userInfo, userInfo == 0 ? "(RFU)":"");
|
||||
PrintAndLogEx(SUCCESS, " Replacement No? %u %s", replacementNr, replacementNr == 0 ? "(RFU)":"");
|
||||
|
||||
uint8_t c[] = {0, 0};
|
||||
compute_crc(CRC_11784, raw, sizeof(raw), &c[0], &c[1]);
|
||||
|
@ -321,12 +606,12 @@ int demodFDX(bool verbose) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdFdxDemod(const char *Cmd) {
|
||||
static int CmdFdxBDemod(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
return demodFDX(true);
|
||||
return demodFDXB(true);
|
||||
}
|
||||
|
||||
static int CmdFdxRead(const char *Cmd) {
|
||||
static int CmdFdxBRead(const char *Cmd) {
|
||||
sample_config config;
|
||||
memset(&config, 0, sizeof(sample_config));
|
||||
int retval = lf_getconfig(&config);
|
||||
|
@ -341,7 +626,7 @@ static int CmdFdxRead(const char *Cmd) {
|
|||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
return usage_lf_fdx_read();
|
||||
return usage_lf_fdxb_read();
|
||||
case '@':
|
||||
continuous = true;
|
||||
cmdp++;
|
||||
|
@ -354,7 +639,7 @@ static int CmdFdxRead(const char *Cmd) {
|
|||
}
|
||||
|
||||
//Validations
|
||||
if (errors) return usage_lf_fdx_read();
|
||||
if (errors) return usage_lf_fdxb_read();
|
||||
int16_t tmp_div = config.divisor;
|
||||
if (tmp_div != LF_DIVISOR_134) {
|
||||
config.divisor = LF_DIVISOR_134;
|
||||
|
@ -375,7 +660,7 @@ static int CmdFdxRead(const char *Cmd) {
|
|||
PrintAndLogEx(ERR, "failed to get LF read from device");
|
||||
return retval;
|
||||
}
|
||||
ret = demodFDX(!continuous); // be verbose only if not in continuous mode
|
||||
ret = demodFDXB(!continuous); // be verbose only if not in continuous mode
|
||||
if (kbd_enter_pressed()) {
|
||||
break;
|
||||
}
|
||||
|
@ -392,7 +677,7 @@ static int CmdFdxRead(const char *Cmd) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int CmdFdxClone(const char *Cmd) {
|
||||
static int CmdFdxBClone(const char *Cmd) {
|
||||
|
||||
uint32_t country_code = 0, extended = 0;
|
||||
uint64_t national_code = 0;
|
||||
|
@ -402,7 +687,7 @@ static int CmdFdxClone(const char *Cmd) {
|
|||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
return usage_lf_fdx_clone();
|
||||
return usage_lf_fdxb_clone();
|
||||
case 'c': {
|
||||
country_code = param_get32ex(Cmd, cmdp + 1, 0, 10);
|
||||
cmdp += 2;
|
||||
|
@ -436,7 +721,7 @@ static int CmdFdxClone(const char *Cmd) {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (errors || strlen(Cmd) == 0) return usage_lf_fdx_clone();
|
||||
if (errors || strlen(Cmd) == 0) return usage_lf_fdxb_clone();
|
||||
|
||||
verify_values(&national_code, &country_code, &extended, &is_animal);
|
||||
|
||||
|
@ -448,7 +733,7 @@ static int CmdFdxClone(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, " RFU 0");
|
||||
|
||||
uint8_t *bits = calloc(128, sizeof(uint8_t));
|
||||
if (getFDXBits(national_code, country_code, is_animal, has_extended, extended, bits) != PM3_SUCCESS) {
|
||||
if (getFDXBBits(national_code, country_code, is_animal, has_extended, extended, bits) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "Error with tag bitstream generation.");
|
||||
free(bits);
|
||||
return PM3_ESOFT;
|
||||
|
@ -473,11 +758,11 @@ static int CmdFdxClone(const char *Cmd) {
|
|||
|
||||
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf fdx read`") " to verify");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf fdxb read`") " to verify");
|
||||
return res;
|
||||
}
|
||||
|
||||
static int CmdFdxSim(const char *Cmd) {
|
||||
static int CmdFdxBSim(const char *Cmd) {
|
||||
|
||||
uint32_t country_code = 0, extended = 0;
|
||||
uint64_t national_code = 0;
|
||||
|
@ -487,7 +772,7 @@ static int CmdFdxSim(const char *Cmd) {
|
|||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
return usage_lf_fdx_sim();
|
||||
return usage_lf_fdxb_sim();
|
||||
case 'c': {
|
||||
country_code = param_get32ex(Cmd, cmdp + 1, 0, 10);
|
||||
cmdp += 2;
|
||||
|
@ -516,7 +801,7 @@ static int CmdFdxSim(const char *Cmd) {
|
|||
}
|
||||
}
|
||||
}
|
||||
if (errors) return usage_lf_fdx_sim();
|
||||
if (errors) return usage_lf_fdxb_sim();
|
||||
|
||||
verify_values(&national_code, &country_code, &extended, &is_animal);
|
||||
|
||||
|
@ -530,7 +815,7 @@ static int CmdFdxSim(const char *Cmd) {
|
|||
PrintAndLogEx(SUCCESS, "Simulating FDX-B animal ID: " _GREEN_("%04u-%"PRIu64), country_code, national_code);
|
||||
|
||||
uint8_t *bits = calloc(128, sizeof(uint8_t));
|
||||
if (getFDXBits(national_code, country_code, is_animal, (extended > 0), extended, bits) != PM3_SUCCESS) {
|
||||
if (getFDXBBits(national_code, country_code, is_animal, (extended > 0), extended, bits) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "Error with tag bitstream generation.");
|
||||
free(bits);
|
||||
return PM3_ESOFT;
|
||||
|
@ -562,10 +847,10 @@ static int CmdFdxSim(const char *Cmd) {
|
|||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "this help"},
|
||||
{"demod", CmdFdxDemod, AlwaysAvailable, "demodulate a FDX-B ISO11784/85 tag from the GraphBuffer"},
|
||||
{"read", CmdFdxRead, IfPm3Lf, "attempt to read at 134kHz and extract tag data"},
|
||||
{"clone", CmdFdxClone, IfPm3Lf, "clone animal ID tag to T55x7 or Q5/T5555"},
|
||||
{"sim", CmdFdxSim, IfPm3Lf, "simulate Animal ID tag"},
|
||||
{"demod", CmdFdxBDemod, AlwaysAvailable, "demodulate a FDX-B ISO11784/85 tag from the GraphBuffer"},
|
||||
{"read", CmdFdxBRead, IfPm3Lf, "attempt to read at 134kHz and extract tag data"},
|
||||
{"clone", CmdFdxBClone, IfPm3Lf, "clone animal ID tag to T55x7 or Q5/T5555"},
|
||||
{"sim", CmdFdxBSim, IfPm3Lf, "simulate Animal ID tag"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
||||
|
@ -575,7 +860,7 @@ static int CmdHelp(const char *Cmd) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int CmdLFFdx(const char *Cmd) {
|
||||
int CmdLFFdxB(const char *Cmd) {
|
||||
clearCommandBuffer();
|
||||
return CmdsParse(CommandTable, Cmd);
|
||||
}
|
||||
|
@ -589,12 +874,12 @@ int detectFDXB(uint8_t *dest, size_t *size) {
|
|||
uint8_t preamble[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
|
||||
if (!preambleSearch(dest, preamble, sizeof(preamble), size, &startIdx))
|
||||
return -2; //preamble not found
|
||||
if (*size != 128) return -3; //wrong demoded size
|
||||
if (*size < 128) return -3; //wrong demoded size
|
||||
//return start position
|
||||
return (int)startIdx;
|
||||
}
|
||||
|
||||
int getFDXBits(uint64_t national_code, uint16_t country_code, uint8_t is_animal, uint8_t is_extended, uint32_t extended, uint8_t *bits) {
|
||||
int getFDXBBits(uint64_t national_code, uint16_t country_code, uint8_t is_animal, uint8_t is_extended, uint32_t extended, uint8_t *bits) {
|
||||
|
||||
// add preamble ten 0x00 and one 0x01
|
||||
memset(bits, 0x00, 10);
|
||||
|
@ -634,7 +919,7 @@ int getFDXBits(uint64_t national_code, uint16_t country_code, uint8_t is_animal,
|
|||
raw[i] = bytebits_to_byte(bits + 11 + i * 9, 8);
|
||||
|
||||
init_table(CRC_11784);
|
||||
uint16_t crc = crc16_fdx(raw, 8);
|
||||
uint16_t crc = crc16_fdxb(raw, 8);
|
||||
num_to_bytebitsLSBF(crc >> 0, 8, bits + 83);
|
||||
num_to_bytebitsLSBF(crc >> 8, 8, bits + 92);
|
||||
|
|
@ -6,15 +6,20 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Low frequency fdx-b tag commands
|
||||
//-----------------------------------------------------------------------------
|
||||
#ifndef CMDLFFDX_H__
|
||||
#define CMDLFFDX_H__
|
||||
#ifndef CMDLFFDXB_H__
|
||||
#define CMDLFFDXB_H__
|
||||
|
||||
#include "common.h"
|
||||
|
||||
int CmdLFFdx(const char *Cmd);
|
||||
typedef struct {
|
||||
uint16_t code;
|
||||
const char *desc;
|
||||
} fdxbCountryMapping_t;
|
||||
|
||||
int CmdLFFdxB(const char *Cmd);
|
||||
int detectFDXB(uint8_t *dest, size_t *size);
|
||||
int demodFDX(bool verbose);
|
||||
int getFDXBits(uint64_t national_code, uint16_t country_code, uint8_t is_animal, uint8_t is_extended, uint32_t extended, uint8_t *bits);
|
||||
int demodFDXB(bool verbose);
|
||||
int getFDXBBits(uint64_t national_code, uint16_t country_code, uint8_t is_animal, uint8_t is_extended, uint32_t extended, uint8_t *bits);
|
||||
|
||||
#endif
|
||||
|
|
@ -37,6 +37,7 @@
|
|||
#include "util_posix.h"
|
||||
#include "lfdemod.h"
|
||||
#include "wiegand_formats.h"
|
||||
#include "wiegand_formatutils.h"
|
||||
|
||||
#ifndef BITS
|
||||
# define BITS 96
|
||||
|
@ -135,61 +136,8 @@ int demodHID(bool verbose) {
|
|||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
if (hi2 != 0) { //extra large HID tags
|
||||
PrintAndLogEx(SUCCESS, "HID Prox - " _GREEN_("%x%08x%08x (%u)"), hi2, hi, lo, (lo >> 1) & 0xFFFF);
|
||||
} else { //standard HID tags <38 bits
|
||||
uint8_t fmtLen = 0;
|
||||
uint32_t cc = 0;
|
||||
uint32_t fc = 0;
|
||||
uint32_t cardnum = 0;
|
||||
uint8_t oem = 0;
|
||||
if (((hi >> 5) & 1) == 1) {//if bit 38 is set then < 37 bit format is used
|
||||
uint32_t lo2 = 0;
|
||||
lo2 = (((hi & 31) << 12) | (lo >> 20)); //get bits 21-37 to check for format len bit
|
||||
uint8_t idx3 = 1;
|
||||
while (lo2 > 1) { //find last bit set to 1 (format len bit)
|
||||
lo2 >>= 1;
|
||||
idx3++;
|
||||
}
|
||||
fmtLen = idx3 + 19;
|
||||
fc = 0;
|
||||
cardnum = 0;
|
||||
if (fmtLen == 26) {
|
||||
cardnum = (lo >> 1) & 0xFFFF;
|
||||
fc = (lo >> 17) & 0xFF;
|
||||
}
|
||||
if (fmtLen == 32 && (lo & 0x40000000)) { //if 32 bit and Kastle bit set
|
||||
cardnum = (lo >> 1) & 0xFFFF;
|
||||
fc = (lo >> 17) & 0xFF;
|
||||
cc = (lo >> 25) & 0x1F;
|
||||
}
|
||||
if (fmtLen == 34) {
|
||||
cardnum = (lo >> 1) & 0xFFFF;
|
||||
fc = ((hi & 1) << 15) | (lo >> 17);
|
||||
}
|
||||
if (fmtLen == 35) {
|
||||
cardnum = (lo >> 1) & 0xFFFFF;
|
||||
fc = ((hi & 1) << 11) | (lo >> 21);
|
||||
}
|
||||
if (fmtLen == 36) {
|
||||
oem = (lo >> 1) & 0x3;
|
||||
cardnum = (lo >> 3) & 0xFFFF;
|
||||
fc = (hi & 0x7) << 13 | ((lo >> 19) & 0xFFFF);
|
||||
}
|
||||
} else { //if bit 38 is not set then 37 bit format is used
|
||||
fmtLen = 37;
|
||||
cardnum = (lo >> 1) & 0x7FFFF;
|
||||
fc = ((hi & 0xF) << 12) | (lo >> 20);
|
||||
}
|
||||
if (fmtLen == 32 && (lo & 0x40000000)) { //if 32 bit and Kastle bit set
|
||||
PrintAndLogEx(SUCCESS,
|
||||
"HID Prox (Kastle format) - " _GREEN_("%x%08x (%u)") " - len: " _GREEN_("32") " bit CC: " _GREEN_("%u") " FC: " _GREEN_("%u") " Card: " _GREEN_("%u"), hi, lo, (lo >> 1) & 0xFFFF, cc, fc, cardnum);
|
||||
} else {
|
||||
PrintAndLogEx(SUCCESS,
|
||||
"HID Prox - " _GREEN_("%x%08x (%u)") " - len: " _GREEN_("%u") " bit - OEM: " _GREEN_("%03u") " FC: " _GREEN_("%u")" Card: " _GREEN_("%u"),
|
||||
hi, lo, cardnum, fmtLen, oem, fc, cardnum);
|
||||
}
|
||||
}
|
||||
wiegand_message_t packed = initialize_message_object(hi2, hi, lo);
|
||||
HIDTryUnpack(&packed, false);
|
||||
|
||||
PrintAndLogEx(DEBUG, "DEBUG: HID idx: %d, Len: %zu, Printing Demod Buffer: ", idx, size);
|
||||
if (g_debugMode)
|
||||
|
@ -206,7 +154,7 @@ static int CmdHIDDemod(const char *Cmd) {
|
|||
// this read is the "normal" read, which download lf signal and tries to demod here.
|
||||
static int CmdHIDRead(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
lf_read(false, 12000);
|
||||
lf_read(false, 16000);
|
||||
return demodHID(true);
|
||||
}
|
||||
|
||||
|
@ -219,7 +167,7 @@ static int CmdHIDWatch(const char *Cmd) {
|
|||
"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,
|
||||
|
@ -239,62 +187,85 @@ static int CmdHIDWatch(const char *Cmd) {
|
|||
}
|
||||
|
||||
static int CmdHIDSim(const char *Cmd) {
|
||||
int idlen = 0;
|
||||
uint8_t id[10] = {0};
|
||||
lf_hidsim_t payload;
|
||||
payload.longFMT = 0;
|
||||
uint32_t hi2 = 0, hi = 0, lo = 0;
|
||||
uint32_t i = 0;
|
||||
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "lf hid sim",
|
||||
"Enables simulation of HID card with card number.",
|
||||
"lf hid sim 2006ec0c86"
|
||||
);
|
||||
"lf hid sim -r 2006ec0c86 -> HID 10301 26 bit\n"
|
||||
"lf hid sim -r 2e0ec00c87 -> HID Corporate 35 bit\n"
|
||||
"lf hid sim -r 01f0760643c3 -> HID P10001 40 bit\n"
|
||||
"lf hid sim -r 01400076000c86 -> HID Corporate 48 bit\n"
|
||||
"lf hid sim -w H10301 --fc 118 --cn 1603 -> HID 10301 26 bit\n"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("l", "long", "Simulate HID tag with long ID"),
|
||||
arg_str1(NULL, NULL, "<hex>", "HID tag ID"),
|
||||
arg_str0("w", "wiegand", "<format>", "see " _YELLOW_("`wiegand list`") " for available formats"),
|
||||
arg_u64_0(NULL, "fc", "<dec>", "facility code"),
|
||||
arg_u64_0(NULL, "cn", "<dec>", "card number"),
|
||||
arg_int0("i", NULL, "<dec>", "issue level"),
|
||||
arg_int0("o", "oem", "<dec>", "OEM code"),
|
||||
arg_strx0("r", "raw", "<hex>", "raw bytes"),
|
||||
// arg_lit0("q", "Q5", "optional - specify writing to Q5/T5555 tag"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
bool long_id = arg_get_lit(ctx, 1);
|
||||
char format[16] = {0};
|
||||
int format_len = 0;
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)format, sizeof(format), &format_len);
|
||||
|
||||
CLIGetHexWithReturn(ctx, 2, id, &idlen);
|
||||
wiegand_card_t card;
|
||||
memset(&card, 0, sizeof(wiegand_card_t));
|
||||
card.FacilityCode = arg_get_u32_def(ctx, 2, 0);
|
||||
card.CardNumber = arg_get_u32_def(ctx, 3, 0);
|
||||
card.IssueLevel = arg_get_u32_def(ctx, 4, 0);
|
||||
card.OEM = arg_get_u32_def(ctx, 5, 0);
|
||||
|
||||
int raw_len = 0;
|
||||
char raw[40] = {0};
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 6), (uint8_t *)raw, sizeof(raw), &raw_len);
|
||||
|
||||
//bool q5 = arg_get_lit(ctx, 7);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (long_id) {
|
||||
for (i=0; i < idlen; ++i) {
|
||||
hi2 = (hi2 << 4) | (hi >> 28);
|
||||
hi = (hi << 4) | (lo >> 28);
|
||||
lo = (lo << 4) | (id[i] >> 4); //get first 4 bits
|
||||
wiegand_message_t packed;
|
||||
memset(&packed, 0, sizeof(wiegand_message_t));
|
||||
|
||||
hi2 = (hi2 << 4) | (hi >> 28);
|
||||
hi = (hi << 4) | (lo >> 28);
|
||||
lo = (lo << 4) | (id[i] & 0xf); //get last 4 bits
|
||||
}
|
||||
PrintAndLogEx(INFO, "Simulating HID tag with long ID: " _GREEN_("%x%08x%08x"), hi2, hi, lo);
|
||||
payload.longFMT = 1;
|
||||
// format validation
|
||||
int format_idx = HIDFindCardFormat((char *)format);
|
||||
if (format_idx == -1 && raw_len == 0) {
|
||||
PrintAndLogEx(WARNING, "Unknown format: " _YELLOW_("%s"), format);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (raw_len) {
|
||||
uint32_t top = 0, mid = 0, bot = 0;
|
||||
hexstring_to_u96(&top, &mid, &bot, raw);
|
||||
packed.Top = top;
|
||||
packed.Mid = mid;
|
||||
packed.Bot = bot;
|
||||
} else {
|
||||
for (i=0; i < idlen; ++i) {
|
||||
hi = (hi << 4) | (lo >> 28);
|
||||
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
|
||||
if (HIDPack(format_idx, &card, &packed) == false) {
|
||||
PrintAndLogEx(WARNING, "The card data could not be encoded in the selected format.");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
PrintAndLogEx(SUCCESS, "Simulating HID tag with ID: " _GREEN_("%x%08x"), hi, lo);
|
||||
hi2 = 0;
|
||||
}
|
||||
|
||||
if (raw_len == 0) {
|
||||
PrintAndLogEx(INFO, "Simulating HID tag");
|
||||
HIDTryUnpack(&packed, false);
|
||||
} else {
|
||||
PrintAndLogEx(INFO, "Simulating HID tag using raw " _GREEN_("%s"), raw);
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Press pm3-button to abort simulation");
|
||||
|
||||
payload.hi2 = hi2;
|
||||
payload.hi = hi;
|
||||
payload.lo = lo;
|
||||
lf_hidsim_t payload;
|
||||
payload.hi2 = packed.Top;
|
||||
payload.hi = packed.Mid;
|
||||
payload.lo = packed.Bot;
|
||||
payload.longFMT = (packed.Mid > 0xFFF);
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_LF_HID_SIMULATE, (uint8_t *)&payload, sizeof(payload));
|
||||
|
@ -303,66 +274,92 @@ static int CmdHIDSim(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, "Done");
|
||||
if (resp.status != PM3_EOPABORTED)
|
||||
return resp.status;
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdHIDClone(const char *Cmd) {
|
||||
int idlen = 0;
|
||||
uint8_t id[10] = {0};
|
||||
|
||||
uint32_t hi2 = 0, hi = 0, lo = 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"
|
||||
);
|
||||
"lf hid clone -r 2006ec0c86 -> HID 10301 26 bit\n"
|
||||
"lf hid clone -r 2e0ec00c87 -> HID Corporate 35 bit\n"
|
||||
"lf hid clone -r 01f0760643c3 -> HID P10001 40 bit\n"
|
||||
"lf hid clone -r 01400076000c86 -> HID Corporate 48 bit\n"
|
||||
"lf hid clone -w H10301 --fc 118 --cn 1603 -> HID 10301 26 bit\n"
|
||||
);
|
||||
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("l", "long", "84bit HID long ID"),
|
||||
arg_str1(NULL, NULL, "<hex>", "HID tag ID"),
|
||||
arg_str0("w", "wiegand", "<format>", "see " _YELLOW_("`wiegand list`") " for available formats"),
|
||||
arg_u64_0(NULL, "fc", "<dec>", "facility code"),
|
||||
arg_u64_0(NULL, "cn", "<dec>", "card number"),
|
||||
arg_int0("i", NULL, "<dec>", "issue level"),
|
||||
arg_int0("o", "oem", "<dec>", "OEM code"),
|
||||
arg_strx0("r", "raw", "<hex>", "raw bytes"),
|
||||
// arg_lit0("q", "Q5", "optional - specify writing to Q5/T5555 tag"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
bool long_id = arg_get_lit(ctx, 1);
|
||||
char format[16] = {0};
|
||||
int format_len = 0;
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)format, sizeof(format), &format_len);
|
||||
|
||||
CLIGetHexWithReturn(ctx, 2, id, &idlen);
|
||||
wiegand_card_t card;
|
||||
memset(&card, 0, sizeof(wiegand_card_t));
|
||||
card.FacilityCode = arg_get_u32_def(ctx, 2, 0);
|
||||
card.CardNumber = arg_get_u32_def(ctx, 3, 0);
|
||||
card.IssueLevel = arg_get_u32_def(ctx, 4, 0);
|
||||
card.OEM = arg_get_u32_def(ctx, 5, 0);
|
||||
|
||||
int raw_len = 0;
|
||||
char raw[40] = {0};
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 6), (uint8_t *)raw, sizeof(raw), &raw_len);
|
||||
|
||||
//bool q5 = arg_get_lit(ctx, 7);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
uint8_t longid[1] = {0};
|
||||
wiegand_message_t packed;
|
||||
memset(&packed, 0, sizeof(wiegand_message_t));
|
||||
|
||||
if (long_id) {
|
||||
for (i=0; i < idlen; ++i) {
|
||||
hi2 = (hi2 << 4) | (hi >> 28);
|
||||
hi = (hi << 4) | (lo >> 28);
|
||||
lo = (lo << 4) | (id[i] >> 4); //get first 4 bits
|
||||
|
||||
hi2 = (hi2 << 4) | (hi >> 28);
|
||||
hi = (hi << 4) | (lo >> 28);
|
||||
lo = (lo << 4) | (id[i] & 0xf); //get last 4 bits
|
||||
}
|
||||
PrintAndLogEx(INFO, "Preparing to clone HID tag with long ID: " _GREEN_("%x%08x%08x"), hi2, hi, lo);
|
||||
|
||||
longid[0] = 1;
|
||||
} else {
|
||||
for (i=0; i < idlen; ++i) {
|
||||
hi = (hi << 4) | (lo >> 28);
|
||||
lo = (lo << 4) | (id[i] >> 4); //get first 4 bits
|
||||
|
||||
hi = (hi << 4) | (lo >> 28);
|
||||
lo = (lo << 4) | (id[i] & 0xf); //get last 4 bits
|
||||
}
|
||||
PrintAndLogEx(INFO, "Preparing to clone HID tag with ID: " _GREEN_("%x%08x"), hi, lo);
|
||||
hi2 = 0;
|
||||
// format validation
|
||||
int format_idx = HIDFindCardFormat((char *)format);
|
||||
if (format_idx == -1 && raw_len == 0) {
|
||||
PrintAndLogEx(WARNING, "Unknown format: " _YELLOW_("%s"), format);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
if (raw_len) {
|
||||
uint32_t top = 0, mid = 0, bot = 0;
|
||||
hexstring_to_u96(&top, &mid, &bot, raw);
|
||||
packed.Top = top;
|
||||
packed.Mid = mid;
|
||||
packed.Bot = bot;
|
||||
} else {
|
||||
if (HIDPack(format_idx, &card, &packed) == false) {
|
||||
PrintAndLogEx(WARNING, "The card data could not be encoded in the selected format.");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
}
|
||||
|
||||
if (raw_len == 0) {
|
||||
PrintAndLogEx(INFO, "Preparing to clone HID tag");
|
||||
HIDTryUnpack(&packed, false);
|
||||
} else {
|
||||
PrintAndLogEx(INFO, "Preparing to clone HID tag using raw " _YELLOW_("%s"), raw);
|
||||
}
|
||||
|
||||
lf_hidsim_t payload;
|
||||
payload.hi2 = packed.Top;
|
||||
payload.hi = packed.Mid;
|
||||
payload.lo = packed.Bot;
|
||||
payload.longFMT = (packed.Mid > 0xFFF);
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_LF_HID_CLONE, hi2, hi, lo, longid, sizeof(longid));
|
||||
SendCommandNG(CMD_LF_HID_CLONE, (uint8_t *)&payload, sizeof(payload));
|
||||
PrintAndLogEx(SUCCESS, "Done");
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf hid read`") " to verify");
|
||||
return PM3_SUCCESS;
|
||||
|
@ -399,22 +396,22 @@ static int CmdHIDBrute(const char *Cmd) {
|
|||
"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"
|
||||
);
|
||||
"lf hid brute -w H10301 --fc 224\n"
|
||||
"lf hid brute -w H10301 --fc 21 -d 2000\n"
|
||||
"lf hid brute -v -w H10301 --fc 21 --cn 200 -d 2000\n"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("v", "verbose", "verbose logging, show all tries"),
|
||||
arg_str1("w", "wiegand", "format", "see " _YELLOW_("`wiegand list`") " for available formats"),
|
||||
arg_int0("f", "fn", "dec", "facility code"),
|
||||
arg_int0("c", "cn", "dec", "card number to start with"),
|
||||
arg_int0("i", NULL, "dec", "issue level"),
|
||||
arg_int0("o", "oem", "dec", "OEM code"),
|
||||
arg_int0("d", "delay", "dec", "delay betweens attempts in ms. Default 1000ms"),
|
||||
arg_lit0(NULL, "up", "direction to increment card number. (default is both directions)"),
|
||||
arg_lit0(NULL, "down", "direction to decrement card number. (default is both directions)"),
|
||||
arg_lit0("v", "verbose", "verbose logging, show all tries"),
|
||||
arg_str1("w", "wiegand", "<format>", "see " _YELLOW_("`wiegand list`") " for available formats"),
|
||||
arg_int0(NULL, "fn", "<dec>", "facility code"),
|
||||
arg_int0(NULL, "cn", "<dec>", "card number to start with"),
|
||||
arg_int0("i", "issue", "<dec>", "issue level"),
|
||||
arg_int0("o", "oem", "<dec>", "OEM code"),
|
||||
arg_int0("d", "delay", "<dec>", "delay betweens attempts in ms. Default 1000ms"),
|
||||
arg_lit0(NULL, "up", "direction to increment card number. (default is both directions)"),
|
||||
arg_lit0(NULL, "down", "direction to decrement card number. (default is both directions)"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
@ -423,9 +420,10 @@ static int CmdHIDBrute(const char *Cmd) {
|
|||
|
||||
CLIGetStrWithReturn(ctx, 2, format, &formatLen);
|
||||
|
||||
format_idx = HIDFindCardFormat((char*) format);
|
||||
format_idx = HIDFindCardFormat((char *) format);
|
||||
if (format_idx == -1) {
|
||||
PrintAndLogEx(WARNING, "Unknown format: " _YELLOW_("%s"), format);
|
||||
CLIParserFree(ctx);
|
||||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
|
@ -435,6 +433,8 @@ static int CmdHIDBrute(const char *Cmd) {
|
|||
cn_hi.OEM = arg_get_int_def(ctx, 6, 0);
|
||||
delay = arg_get_int_def(ctx, 7, 1000);
|
||||
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (arg_get_lit(ctx, 8) && arg_get_lit(ctx, 9)) {
|
||||
direction = 0;
|
||||
} else if (arg_get_lit(ctx, 8)) {
|
||||
|
|
|
@ -149,9 +149,14 @@ static int usage_hitag_checkchallenges(void) {
|
|||
}
|
||||
|
||||
static int CmdLFHitagList(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
CmdTraceList("hitag2");
|
||||
return PM3_SUCCESS;
|
||||
char args[128] = {0};
|
||||
if (strlen(Cmd) == 0) {
|
||||
snprintf(args, sizeof(args), "-t hitag2");
|
||||
} else {
|
||||
strncpy(args, Cmd, sizeof(args) - 1);
|
||||
}
|
||||
return CmdTraceList(args);
|
||||
|
||||
|
||||
/*
|
||||
uint8_t *got = calloc(PM3_CMD_DATA_SIZE, sizeof(uint8_t));
|
||||
|
|
|
@ -656,6 +656,7 @@ static int CmdIndalaClone(const char *Cmd) {
|
|||
|
||||
if (getIndalaBits(fc, cn, bits) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "Error with tag bitstream generation.");
|
||||
free(bits);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
|
|
|
@ -268,7 +268,7 @@ static int CmdKeriSim(const char *Cmd) {
|
|||
CLIParserInit(&ctx, "lf keri sim",
|
||||
"Enables simulation of KERI card with card number.",
|
||||
"lf keri sim --id 112233"
|
||||
);
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
|
|
|
@ -383,7 +383,7 @@ static int usage_t55xx_clonehelp(void) {
|
|||
// todo: implement restore
|
||||
// PrintAndLogEx(NORMAL, _GREEN_("lf em 4x05_write"));
|
||||
// PrintAndLogEx(NORMAL, _GREEN_("lf em 4x50_write"));
|
||||
PrintAndLogEx(NORMAL, _GREEN_("lf fdx clone"));
|
||||
PrintAndLogEx(NORMAL, _GREEN_("lf fdxb clone"));
|
||||
PrintAndLogEx(NORMAL, _GREEN_("lf gallagher clone"));
|
||||
PrintAndLogEx(NORMAL, _GREEN_("lf gproxii clone"));
|
||||
PrintAndLogEx(NORMAL, _GREEN_("lf hid clone"));
|
||||
|
@ -598,7 +598,7 @@ bool t55xxAquireAndDetect(bool usepwd, uint32_t password, uint32_t known_block0,
|
|||
if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password, m) == false)
|
||||
continue;
|
||||
|
||||
if (tryDetectModulationEx(m, verbose, known_block0, (usepwd) ? password : -1) == false)
|
||||
if (t55xxTryDetectModulationEx(m, verbose, known_block0, (usepwd) ? password : -1) == false)
|
||||
continue;
|
||||
|
||||
config.downlink_mode = m;
|
||||
|
@ -861,7 +861,7 @@ int T55xxReadBlockEx(uint8_t block, bool page1, bool usepwd, uint8_t override, u
|
|||
if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, false, 0, downlink_mode) == false)
|
||||
return PM3_ERFTRANS;
|
||||
|
||||
if (tryDetectModulationEx(downlink_mode, false, 0, password) == false) {
|
||||
if (t55xxTryDetectModulationEx(downlink_mode, false, 0, password) == false) {
|
||||
PrintAndLogEx(WARNING, "Safety check: Could not detect if PWD bit is set in config block. Exits.");
|
||||
return PM3_EWRONGANSWER;
|
||||
} else {
|
||||
|
@ -1081,7 +1081,7 @@ static int CmdT55xxDetect(const char *Cmd) {
|
|||
if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, (try_with_pwd && usepwd), password, m) == false)
|
||||
continue;
|
||||
|
||||
if (tryDetectModulationEx(m, T55XX_PrintConfig, 0, (try_with_pwd && usepwd) ? password : -1) == false)
|
||||
if (t55xxTryDetectModulationEx(m, T55XX_PrintConfig, 0, (try_with_pwd && usepwd) ? password : -1) == false)
|
||||
continue;
|
||||
|
||||
found = true;
|
||||
|
@ -1090,7 +1090,7 @@ static int CmdT55xxDetect(const char *Cmd) {
|
|||
}
|
||||
} else {
|
||||
if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password, downlink_mode)) {
|
||||
found = tryDetectModulationEx(downlink_mode, T55XX_PrintConfig, 0, (usepwd) ? password : -1);
|
||||
found = t55xxTryDetectModulationEx(downlink_mode, T55XX_PrintConfig, 0, (usepwd) ? password : -1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1105,7 +1105,7 @@ static int CmdT55xxDetect(const char *Cmd) {
|
|||
} while (try_with_pwd);
|
||||
|
||||
} else {
|
||||
found = tryDetectModulation(downlink_mode, T55XX_PrintConfig);
|
||||
found = t55xxTryDetectModulation(downlink_mode, T55XX_PrintConfig);
|
||||
}
|
||||
|
||||
if (found == false) {
|
||||
|
@ -1117,11 +1117,11 @@ static int CmdT55xxDetect(const char *Cmd) {
|
|||
}
|
||||
|
||||
// detect configuration?
|
||||
bool tryDetectModulation(uint8_t downlink_mode, bool print_config) {
|
||||
return tryDetectModulationEx(downlink_mode, print_config, 0, -1);
|
||||
bool t55xxTryDetectModulation(uint8_t downlink_mode, bool print_config) {
|
||||
return t55xxTryDetectModulationEx(downlink_mode, print_config, 0, -1);
|
||||
}
|
||||
|
||||
bool tryDetectModulationEx(uint8_t downlink_mode, bool print_config, uint32_t wanted_conf, uint64_t pwd) {
|
||||
bool t55xxTryDetectModulationEx(uint8_t downlink_mode, bool print_config, uint32_t wanted_conf, uint64_t pwd) {
|
||||
|
||||
t55xx_conf_block_t tests[15];
|
||||
int bitRate = 0, clk = 0, firstClockEdge = 0;
|
||||
|
@ -3079,7 +3079,7 @@ static int CmdT55xxChkPwds(const char *Cmd) {
|
|||
PrintAndLogEx(SUCCESS, "\nFound a candidate [ " _YELLOW_("%08"PRIX32) " ]", packet->candidate);
|
||||
|
||||
if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, packet->candidate, downlink_mode)) {
|
||||
found = tryDetectModulationEx(downlink_mode, T55XX_PrintConfig, 0, packet->candidate);
|
||||
found = t55xxTryDetectModulationEx(downlink_mode, T55XX_PrintConfig, 0, packet->candidate);
|
||||
if (found) {
|
||||
PrintAndLogEx(SUCCESS, "Found valid password [ " _GREEN_("%08"PRIX32) " ]", packet->candidate);
|
||||
|
||||
|
@ -3105,7 +3105,7 @@ static int CmdT55xxChkPwds(const char *Cmd) {
|
|||
continue;
|
||||
}
|
||||
|
||||
found = tryDetectModulationEx(dl_mode, T55XX_PrintConfig, 0, cardPassword);
|
||||
found = t55xxTryDetectModulationEx(dl_mode, T55XX_PrintConfig, 0, cardPassword);
|
||||
if (found) {
|
||||
PrintAndLogEx(SUCCESS, "Found valid password : [ " _GREEN_("%08"PRIX32) " ]", cardPassword);
|
||||
dl_mode = 4; // Exit other downlink mode checks
|
||||
|
@ -3150,7 +3150,7 @@ static int CmdT55xxChkPwds(const char *Cmd) {
|
|||
continue;
|
||||
}
|
||||
|
||||
found = tryDetectModulationEx(dl_mode, T55XX_PrintConfig, 0, curr_password);
|
||||
found = t55xxTryDetectModulationEx(dl_mode, T55XX_PrintConfig, 0, curr_password);
|
||||
if (found) {
|
||||
PrintAndLogEx(SUCCESS, "Found valid password: [ " _GREEN_("%08"PRIX32) " ]", curr_password);
|
||||
dl_mode = 4; // Exit other downlink mode checks
|
||||
|
@ -3267,7 +3267,7 @@ uint8_t tryOnePassword(uint32_t password, uint8_t downlink_mode) {
|
|||
if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, password, dl_mode)) {
|
||||
// if (getSignalProperties()->isnoise == false) {
|
||||
// } else {
|
||||
if (tryDetectModulationEx(dl_mode, T55XX_PrintConfig, 0, password)) {
|
||||
if (t55xxTryDetectModulationEx(dl_mode, T55XX_PrintConfig, 0, password)) {
|
||||
return 1 + (dl_mode << 1);
|
||||
}
|
||||
// }
|
||||
|
|
|
@ -105,21 +105,23 @@ typedef struct {
|
|||
uint32_t dw;
|
||||
} t5555_tracedata_t;
|
||||
|
||||
typedef enum {
|
||||
DEMOD_NRZ = 0x00,
|
||||
DEMOD_PSK1 = 0x01,
|
||||
DEMOD_PSK2 = 0x02,
|
||||
DEMOD_PSK3 = 0x03,
|
||||
DEMOD_FSK1 = 0x04,
|
||||
DEMOD_FSK1a = 0x05,
|
||||
DEMOD_FSK2 = 0x06,
|
||||
DEMOD_FSK2a = 0x07,
|
||||
DEMOD_FSK = 0xF0, //generic FSK (auto detect FCs)
|
||||
DEMOD_ASK = 0x08,
|
||||
DEMOD_BI = 0x10,
|
||||
DEMOD_BIa = 0x18,
|
||||
} t55xx_modulation;
|
||||
|
||||
typedef struct {
|
||||
enum {
|
||||
DEMOD_NRZ = 0x00,
|
||||
DEMOD_PSK1 = 0x01,
|
||||
DEMOD_PSK2 = 0x02,
|
||||
DEMOD_PSK3 = 0x03,
|
||||
DEMOD_FSK1 = 0x04,
|
||||
DEMOD_FSK1a = 0x05,
|
||||
DEMOD_FSK2 = 0x06,
|
||||
DEMOD_FSK2a = 0x07,
|
||||
DEMOD_FSK = 0xF0, //generic FSK (auto detect FCs)
|
||||
DEMOD_ASK = 0x08,
|
||||
DEMOD_BI = 0x10,
|
||||
DEMOD_BIa = 0x18,
|
||||
} modulation;
|
||||
t55xx_modulation modulation;
|
||||
bool inverted;
|
||||
uint8_t offset;
|
||||
uint32_t block0;
|
||||
|
@ -180,9 +182,9 @@ int t55xxWrite(uint8_t block, bool page1, bool usepwd, bool testMode, uint32_t p
|
|||
|
||||
bool GetT55xxBlockData(uint32_t *blockdata);
|
||||
bool DecodeT55xxBlock(void);
|
||||
bool tryDetectModulation(uint8_t downlink_mode, bool print_config);
|
||||
//bool tryDetectModulationEx(uint8_t downlink_mode, bool print_config, uint32_t wanted_conf);
|
||||
bool tryDetectModulationEx(uint8_t downlink_mode, bool print_config, uint32_t wanted_conf, uint64_t pwd);
|
||||
bool t55xxTryDetectModulation(uint8_t downlink_mode, bool print_config);
|
||||
//bool t55xxTryDetectModulationEx(uint8_t downlink_mode, bool print_config, uint32_t wanted_conf);
|
||||
bool t55xxTryDetectModulationEx(uint8_t downlink_mode, bool print_config, uint32_t wanted_conf, uint64_t pwd);
|
||||
bool testKnownConfigBlock(uint32_t block0);
|
||||
|
||||
bool tryDetectP1(bool getData);
|
||||
|
|
|
@ -292,7 +292,7 @@ static int CmdScriptRun(const char *Cmd) {
|
|||
// get the top of the stack as the error and pop it off
|
||||
const char *str = lua_tostring(lua_state, lua_gettop(lua_state));
|
||||
lua_pop(lua_state, 1);
|
||||
puts(str);
|
||||
PrintAndLogEx(FAILED, _RED_("error") " - %s", str);
|
||||
}
|
||||
|
||||
//luaL_dofile(lua_state, buf);
|
||||
|
|
|
@ -844,9 +844,13 @@ static int CmdSmartSetClock(const char *Cmd) {
|
|||
}
|
||||
|
||||
static int CmdSmartList(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
CmdTraceList("7816");
|
||||
return PM3_SUCCESS;
|
||||
char args[128] = {0};
|
||||
if (strlen(Cmd) == 0) {
|
||||
snprintf(args, sizeof(args), "-t 7816");
|
||||
} else {
|
||||
strncpy(args, Cmd, sizeof(args) - 1);
|
||||
}
|
||||
return CmdTraceList(args);
|
||||
}
|
||||
|
||||
static void smart_brute_prim(void) {
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "fileutils.h" // for saveFile
|
||||
#include "cmdlfhitag.h" // annotate hitag
|
||||
#include "pm3_cmd.h" // tracelog_hdr_t
|
||||
#include "cliparser.h" // args..
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
|
@ -26,56 +27,6 @@ static int CmdHelp(const char *Cmd);
|
|||
static uint8_t *g_trace;
|
||||
static long g_traceLen = 0;
|
||||
|
||||
static int usage_trace_list(void) {
|
||||
PrintAndLogEx(NORMAL, "List protocol data in trace buffer.");
|
||||
PrintAndLogEx(NORMAL, "Usage: trace list <protocol> [f][c| <0|1>");
|
||||
PrintAndLogEx(NORMAL, " f - show frame delay times as well");
|
||||
PrintAndLogEx(NORMAL, " c - mark CRC bytes");
|
||||
PrintAndLogEx(NORMAL, " r - show relative times (gap and duration)");
|
||||
PrintAndLogEx(NORMAL, " u - display times in microseconds instead of clock cycles");
|
||||
PrintAndLogEx(NORMAL, " x - show hexdump to convert to pcap(ng) or to import into Wireshark using encapsulation type \"ISO 14443\"");
|
||||
PrintAndLogEx(NORMAL, " syntax to use: `text2pcap -t \"%%S.\" -l 264 -n <input-text-file> <output-pcapng-file>`");
|
||||
PrintAndLogEx(NORMAL, " <0|1> - use data from Tracebuffer, if not set, try to collect a trace from Proxmark3 device.");
|
||||
PrintAndLogEx(NORMAL, "Supported <protocol> values:");
|
||||
PrintAndLogEx(NORMAL, " raw - just show raw data without annotations");
|
||||
PrintAndLogEx(NORMAL, " 14a - interpret data as iso14443a communications");
|
||||
PrintAndLogEx(NORMAL, " thinfilm - interpret data as Thinfilm communications");
|
||||
PrintAndLogEx(NORMAL, " topaz - interpret data as Topaz communications");
|
||||
PrintAndLogEx(NORMAL, " mf - interpret data as iso14443a communications and decrypt crypto1 stream");
|
||||
PrintAndLogEx(NORMAL, " des - interpret data as DESFire communications");
|
||||
PrintAndLogEx(NORMAL, " 14b - interpret data as iso14443b communications");
|
||||
PrintAndLogEx(NORMAL, " 7816 - interpret data as iso7816-4 communications");
|
||||
PrintAndLogEx(NORMAL, " 15 - interpret data as iso15693 communications");
|
||||
PrintAndLogEx(NORMAL, " iclass - interpret data as iclass communications");
|
||||
PrintAndLogEx(NORMAL, " legic - interpret data as LEGIC communications");
|
||||
PrintAndLogEx(NORMAL, " felica - interpret data as ISO18092 / FeliCa communications");
|
||||
PrintAndLogEx(NORMAL, " hitag1 - interpret data as Hitag1 communications");
|
||||
PrintAndLogEx(NORMAL, " hitag2 - interpret data as Hitag2 communications");
|
||||
PrintAndLogEx(NORMAL, " hitags - interpret data as HitagS communications");
|
||||
PrintAndLogEx(NORMAL, " lto - interpret data as LTO-CM communications");
|
||||
PrintAndLogEx(NORMAL, " cryptorf - interpret data as CryptoRF communitcations");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" trace list 14a f"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" trace list iclass"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" trace list 14a 1"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_trace_load(void) {
|
||||
PrintAndLogEx(NORMAL, "Load protocol data from binary file to trace buffer");
|
||||
PrintAndLogEx(NORMAL, "Usage: trace load <filename>");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" trace load mytracefile.trace"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_trace_save(void) {
|
||||
PrintAndLogEx(NORMAL, "Save protocol data from trace buffer to binary file");
|
||||
PrintAndLogEx(NORMAL, "Usage: trace save <filename>");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" trace save mytracefile.trace"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static bool is_last_record(uint16_t tracepos, uint16_t traceLen) {
|
||||
return ((tracepos + TRACELOG_HDR_LEN) >= traceLen);
|
||||
}
|
||||
|
@ -159,10 +110,8 @@ static uint16_t printHexLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trac
|
|||
char temp_str2[3] = {0};
|
||||
|
||||
sprintf(data_len_str, "%04x", hdr->data_len);
|
||||
strncat(temp_str1, data_len_str, 2);
|
||||
temp_str1[2] = '\0';
|
||||
strncat(temp_str2, data_len_str + 2, 2);
|
||||
temp_str2[2] = '\0';
|
||||
memmove(temp_str1, data_len_str, 2);
|
||||
memmove(temp_str2, data_len_str + 2, 2);
|
||||
|
||||
PrintAndLogEx(NORMAL, "0.%010u", hdr->timestamp);
|
||||
PrintAndLogEx(NORMAL, "000000 00 %s %s %s %s",
|
||||
|
@ -203,7 +152,7 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
|
|||
data_len = hdr->data_len;
|
||||
|
||||
if (tracepos + TRACELOG_HDR_LEN + data_len + TRACELOG_PARITY_LEN(hdr) > traceLen) {
|
||||
PrintAndLogEx(DEBUG, "trace pos offset %"PRIu32 " larger than reported tracelen %u", tracepos + TRACELOG_HDR_LEN + data_len + TRACELOG_PARITY_LEN(hdr), traceLen);
|
||||
PrintAndLogEx(DEBUG, "trace pos offset %"PRIu64 " larger than reported tracelen %u", tracepos + TRACELOG_HDR_LEN + data_len + TRACELOG_PARITY_LEN(hdr), traceLen);
|
||||
return traceLen;
|
||||
}
|
||||
|
||||
|
@ -212,7 +161,6 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
|
|||
duration *= 32;
|
||||
}
|
||||
|
||||
|
||||
uint8_t *frame = hdr->frame;
|
||||
uint8_t *parityBytes = hdr->frame + data_len;
|
||||
|
||||
|
@ -568,11 +516,24 @@ static int SanityOfflineCheck( bool useTraceBuffer ){
|
|||
|
||||
static int CmdTraceLoad(const char *Cmd) {
|
||||
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) < 1 || (strlen(Cmd) == 1 && cmdp == 'h')) return usage_trace_load();
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "trace load",
|
||||
"Load protocol data from binary file to trace buffer\n"
|
||||
"File extension is (.trace)",
|
||||
"trace load -f mytracefile"
|
||||
);
|
||||
|
||||
char filename[FILE_PATH_SIZE];
|
||||
param_getstr(Cmd, 0, filename, sizeof(filename));
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_strx0("f", "file", "<filename>", "trace file to load"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
int fnlen = 0;
|
||||
char filename[FILE_PATH_SIZE] = {0};
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (g_trace)
|
||||
free(g_trace);
|
||||
|
@ -591,8 +552,24 @@ static int CmdTraceLoad(const char *Cmd) {
|
|||
|
||||
static int CmdTraceSave(const char *Cmd) {
|
||||
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) < 1 || (strlen(Cmd) == 1 && cmdp == 'h')) return usage_trace_save();
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "trace save",
|
||||
"Save protocol data from trace buffer to binary file\n"
|
||||
"File extension is (.trace)",
|
||||
"trace save -f mytracefile"
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_strx0("f", "file", "<filename>", "trace file to load"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
int fnlen = 0;
|
||||
char filename[FILE_PATH_SIZE] = {0};
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (g_traceLen == 0) {
|
||||
download_trace();
|
||||
|
@ -603,99 +580,89 @@ static int CmdTraceSave(const char *Cmd) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
char filename[FILE_PATH_SIZE];
|
||||
param_getstr(Cmd, 0, filename, sizeof(filename));
|
||||
saveFile(filename, ".trace", g_trace, g_traceLen);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
int CmdTraceList(const char *Cmd) {
|
||||
CLIParserContext *ctx;
|
||||
CLIParserInit(&ctx, "trace list",
|
||||
"Annotate trace buffer with selected protocol data\n"
|
||||
"You can load a trace from file (see `trace load -h`) or it be downloaded from device by default\n",
|
||||
"trace list -t raw -> just show raw data without annotations\n"
|
||||
"trace list -t 14a -> interpret as " _YELLOW_("ISO14443-A") " communications\n"
|
||||
"trace list -t thinfilm -> interpret as " _YELLOW_("Thinfilm") " communications\n"
|
||||
"trace list -t topaz -> interpret as " _YELLOW_("Topaz") " communications\n"
|
||||
"trace list -t mf -> interpret as " _YELLOW_("MIFARE Classic") " communications and decrypt crypto1 stream\n"
|
||||
"trace list -t des -> interpret as " _YELLOW_("MIFARE DESFire") " communications\n"
|
||||
"trace list -t 14b -> interpret as " _YELLOW_("ISO14443-B") " communications\n"
|
||||
"trace list -t 7816 -> interpret as " _YELLOW_("ISO7816-4") " communications\n"
|
||||
"trace list -t 15 -> interpret as " _YELLOW_("ISO15693") " communications\n"
|
||||
"trace list -t iclass -> interpret as " _YELLOW_("iCLASS") " communications\n"
|
||||
"trace list -t legic -> interpret as " _YELLOW_("LEGIC") " communications\n"
|
||||
"trace list -t felica -> interpret as " _YELLOW_("ISO18092 / FeliCa") " communications\n"
|
||||
"trace list -t hitag1 -> interpret as " _YELLOW_("Hitag1") " communications\n"
|
||||
"trace list -t hitag2 -> interpret as " _YELLOW_("Hitag2") " communications\n"
|
||||
"trace list -t hitags -> interpret as " _YELLOW_("HitagS") " communications\n"
|
||||
"trace list -t lto -> interpret as " _YELLOW_("LTO-CM") " communications\n"
|
||||
"trace list -t cryptorf -> interpret as " _YELLOW_("CryptoRF") " communitcations\n"
|
||||
"trace list -t 14a f -> show frame delay times\n"
|
||||
"trace list -t 14a 1 -> use trace buffer "
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
arg_lit0("1", "buffer", "use data from trace buffer"),
|
||||
arg_lit0("f", NULL, "show frame delay times"),
|
||||
arg_lit0("c", NULL, "mark CRC bytes"),
|
||||
arg_lit0("r", NULL, "show relative times (gap and duration)"),
|
||||
arg_lit0("u", NULL, "display times in microseconds instead of clock cycles"),
|
||||
arg_lit0("x", NULL, "show hexdump to convert to pcap(ng)\n"
|
||||
" or to import into Wireshark using encapsulation type \"ISO 14443\""),
|
||||
arg_strx0("t", "type", NULL, "protocol to annotate the trace"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, false);
|
||||
|
||||
bool use_buffer = arg_get_lit(ctx, 1);
|
||||
bool show_wait_cycles = arg_get_lit(ctx, 2);
|
||||
bool mark_crc = arg_get_lit(ctx, 3);
|
||||
bool use_relative = arg_get_lit(ctx, 4);
|
||||
bool use_us = arg_get_lit(ctx, 5);
|
||||
bool show_hex = arg_get_lit(ctx, 6);
|
||||
|
||||
int tlen = 0;
|
||||
char type[10] = {0};
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 7), (uint8_t *)type, sizeof(type), &tlen);
|
||||
str_lower(type);
|
||||
|
||||
CLIParserFree(ctx);
|
||||
|
||||
clearCommandBuffer();
|
||||
|
||||
bool showWaitCycles = false, markCRCBytes = false;
|
||||
bool showHex = false, isOnline = true;
|
||||
bool use_us = false, use_relative = false;
|
||||
bool errors = false;
|
||||
uint8_t protocol = 0;
|
||||
char type[10] = {0};
|
||||
char cmdp = 0;
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
// no crc, no annotations
|
||||
uint8_t protocol = -1;
|
||||
|
||||
int slen = param_getstr(Cmd, cmdp, type, sizeof(type));
|
||||
if (slen == 1) {
|
||||
// validate type of output
|
||||
if (strcmp(type, "iclass") == 0) protocol = ICLASS;
|
||||
else if (strcmp(type, "14a") == 0) protocol = ISO_14443A;
|
||||
else if (strcmp(type, "14b") == 0) protocol = ISO_14443B;
|
||||
else if (strcmp(type, "topaz") == 0) protocol = TOPAZ;
|
||||
else if (strcmp(type, "7816") == 0) protocol = ISO_7816_4;
|
||||
else if (strcmp(type, "des") == 0) protocol = MFDES;
|
||||
else if (strcmp(type, "legic") == 0) protocol = LEGIC;
|
||||
else if (strcmp(type, "15") == 0) protocol = ISO_15693;
|
||||
else if (strcmp(type, "felica") == 0) protocol = FELICA;
|
||||
else if (strcmp(type, "mf") == 0) protocol = PROTO_MIFARE;
|
||||
else if (strcmp(type, "hitag1") == 0) protocol = PROTO_HITAG1;
|
||||
else if (strcmp(type, "hitag2") == 0) protocol = PROTO_HITAG2;
|
||||
else if (strcmp(type, "hitags") == 0) protocol = PROTO_HITAGS;
|
||||
else if (strcmp(type, "thinfilm") == 0) protocol = THINFILM;
|
||||
else if (strcmp(type, "lto") == 0) protocol = LTO;
|
||||
else if (strcmp(type, "cryptorf") == 0) protocol = PROTO_CRYPTORF;
|
||||
else if (strcmp(type, "raw") == 0) protocol = -1;
|
||||
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
return usage_trace_list();
|
||||
case 'f':
|
||||
showWaitCycles = true;
|
||||
cmdp++;
|
||||
break;
|
||||
case 'c':
|
||||
markCRCBytes = true;
|
||||
cmdp++;
|
||||
break;
|
||||
case 'x':
|
||||
showHex = true;
|
||||
cmdp++;
|
||||
break;
|
||||
case '0':
|
||||
isOnline = true;
|
||||
cmdp++;
|
||||
break;
|
||||
case '1':
|
||||
isOnline = false;
|
||||
cmdp++;
|
||||
break;
|
||||
case 'r':
|
||||
use_relative = true;
|
||||
cmdp++;
|
||||
break;
|
||||
case 'u':
|
||||
use_us = true;
|
||||
cmdp++;
|
||||
break;
|
||||
default:
|
||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
str_lower(type);
|
||||
|
||||
// validate type of output
|
||||
if (strcmp(type, "iclass") == 0) protocol = ICLASS;
|
||||
else if (strcmp(type, "14a") == 0) protocol = ISO_14443A;
|
||||
else if (strcmp(type, "14b") == 0) protocol = ISO_14443B;
|
||||
else if (strcmp(type, "topaz") == 0) protocol = TOPAZ;
|
||||
else if (strcmp(type, "7816") == 0) protocol = ISO_7816_4;
|
||||
else if (strcmp(type, "des") == 0) protocol = MFDES;
|
||||
else if (strcmp(type, "legic") == 0) protocol = LEGIC;
|
||||
else if (strcmp(type, "15") == 0) protocol = ISO_15693;
|
||||
else if (strcmp(type, "felica") == 0) protocol = FELICA;
|
||||
else if (strcmp(type, "mf") == 0) protocol = PROTO_MIFARE;
|
||||
else if (strcmp(type, "hitag1") == 0) protocol = PROTO_HITAG1;
|
||||
else if (strcmp(type, "hitag2") == 0) protocol = PROTO_HITAG2;
|
||||
else if (strcmp(type, "hitags") == 0) protocol = PROTO_HITAGS;
|
||||
else if (strcmp(type, "thinfilm") == 0) protocol = THINFILM;
|
||||
else if (strcmp(type, "lto") == 0) protocol = LTO;
|
||||
else if (strcmp(type, "cryptorf") == 0) protocol = PROTO_CRYPTORF;
|
||||
else if (strcmp(type, "raw") == 0) protocol = -1; //No crc, no annotations
|
||||
else errors = true;
|
||||
|
||||
cmdp++;
|
||||
}
|
||||
}
|
||||
|
||||
//if (!SanityOfflineCheck(isOnline)) return 1;
|
||||
|
||||
//Validations
|
||||
if (errors) return usage_trace_list();
|
||||
|
||||
if (isOnline) {
|
||||
if (use_buffer == false || (g_traceLen == 0)) {
|
||||
download_trace();
|
||||
}
|
||||
|
||||
|
@ -711,7 +678,7 @@ int CmdTraceList(const char *Cmd) {
|
|||
printFelica(g_traceLen, g_trace);
|
||||
} */
|
||||
|
||||
if (showHex) {
|
||||
if (show_hex) {
|
||||
while (tracepos < g_traceLen) {
|
||||
tracepos = printHexLine(tracepos, g_traceLen, g_trace, protocol);
|
||||
}
|
||||
|
@ -788,12 +755,16 @@ int CmdTraceList(const char *Cmd) {
|
|||
}
|
||||
|
||||
while (tracepos < g_traceLen) {
|
||||
tracepos = printTraceLine(tracepos, g_traceLen, g_trace, protocol, showWaitCycles, markCRCBytes, prev_EOT, use_us);
|
||||
tracepos = printTraceLine(tracepos, g_traceLen, g_trace, protocol, show_wait_cycles, mark_crc, prev_EOT, use_us);
|
||||
|
||||
if (kbd_enter_pressed())
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (show_hex)
|
||||
PrintAndLogEx(HINT, "syntax to use: " _YELLOW_("`text2pcap -t \"%%S.\" -l 264 -n <input-text-file> <output-pcapng-file>`"));
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,20 +26,20 @@
|
|||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static void print_wiegand_code(wiegand_message_t *packed) {
|
||||
const char* s = "Encoded wiegand: ";
|
||||
const char *s = "Encoded wiegand: ";
|
||||
if (packed->Top != 0) {
|
||||
PrintAndLogEx(SUCCESS, "%s" _GREEN_("%X%08X%08X"),
|
||||
s,
|
||||
(uint32_t)packed->Top,
|
||||
(uint32_t)packed->Mid,
|
||||
(uint32_t)packed->Bot
|
||||
);
|
||||
s,
|
||||
(uint32_t)packed->Top,
|
||||
(uint32_t)packed->Mid,
|
||||
(uint32_t)packed->Bot
|
||||
);
|
||||
} else {
|
||||
PrintAndLogEx(SUCCESS, "%s" _YELLOW_("%X%08X"),
|
||||
s,
|
||||
(uint32_t)packed->Mid,
|
||||
(uint32_t)packed->Bot
|
||||
);
|
||||
s,
|
||||
(uint32_t)packed->Mid,
|
||||
(uint32_t)packed->Bot
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -49,7 +49,7 @@ int CmdWiegandList(const char *Cmd) {
|
|||
CLIParserInit(&ctx, "wiegand info",
|
||||
"List available wiegand formats",
|
||||
"wiegand list"
|
||||
);
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
|
@ -68,7 +68,7 @@ int CmdWiegandEncode(const char *Cmd) {
|
|||
CLIParserInit(&ctx, "wiegand encode",
|
||||
"Encode wiegand formatted number to raw hex",
|
||||
"wiegand encode -w H10301 --fc 101 --cn 1337"
|
||||
);
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
|
@ -76,7 +76,7 @@ int CmdWiegandEncode(const char *Cmd) {
|
|||
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_str1("w", "wiegand", "<format>", "see `wiegand list` for available formats"),
|
||||
arg_param_end
|
||||
};
|
||||
CLIExecWithReturn(ctx, Cmd, argtable, true);
|
||||
|
@ -91,7 +91,7 @@ int CmdWiegandEncode(const char *Cmd) {
|
|||
|
||||
int len = 0;
|
||||
char format[16] = {0};
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 5), (uint8_t*)format, sizeof(format), &len);
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 5), (uint8_t *)format, sizeof(format), &len);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
int idx = HIDFindCardFormat(format);
|
||||
|
@ -118,7 +118,7 @@ int CmdWiegandDecode(const char *Cmd) {
|
|||
CLIParserInit(&ctx, "wiegand decode",
|
||||
"Decode raw hex to wiegand format",
|
||||
"wiegand decode --raw 2006f623ae"
|
||||
);
|
||||
);
|
||||
|
||||
void *argtable[] = {
|
||||
arg_param_begin,
|
||||
|
@ -131,7 +131,7 @@ int CmdWiegandDecode(const char *Cmd) {
|
|||
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);
|
||||
CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)hex, sizeof(hex), &len);
|
||||
CLIParserFree(ctx);
|
||||
|
||||
if (len == 0) {
|
||||
|
|
|
@ -1772,8 +1772,13 @@ static int CmdEMVScan(const char *Cmd) {
|
|||
}
|
||||
|
||||
static int CmdEMVList(const char *Cmd) {
|
||||
(void)Cmd; // Cmd is not used so far
|
||||
return CmdTraceList("7816");
|
||||
char args[128] = {0};
|
||||
if (strlen(Cmd) == 0) {
|
||||
snprintf(args, sizeof(args), "-t 7816");
|
||||
} else {
|
||||
strncpy(args, Cmd, sizeof(args) - 1);
|
||||
}
|
||||
return CmdTraceList(args);
|
||||
}
|
||||
|
||||
static int CmdEMVTest(const char *Cmd) {
|
||||
|
|
|
@ -119,15 +119,17 @@ bool emv_rocacheck(const unsigned char *buf, size_t buflen, bool verbose) {
|
|||
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_shift_l(&g_one, mpi_get_uint(&t_temp)));
|
||||
|
||||
if (bitand_is_zero(&g_one, &prints[i])) {
|
||||
if (verbose)
|
||||
PrintAndLogEx(FAILED, "No fingerprint found.\n");
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
mbedtls_mpi_free(&g_one);
|
||||
mbedtls_mpi_free(&t_temp);
|
||||
mbedtls_mpi_free(&t_prime);
|
||||
|
||||
if (bitand_is_zero(&g_one, &prints[i])) {
|
||||
if (verbose) {
|
||||
PrintAndLogEx(FAILED, "No fingerprint found.\n");
|
||||
}
|
||||
mbedtls_mpi_free(&g_one);
|
||||
goto cleanup;
|
||||
}
|
||||
mbedtls_mpi_free(&g_one);
|
||||
}
|
||||
|
||||
ret = true;
|
||||
|
|
|
@ -9,9 +9,7 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "emvjson.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "commonutil.h" // ARRAYLEN
|
||||
#include "ui.h"
|
||||
#include "util.h"
|
||||
|
@ -75,7 +73,7 @@ int JsonSaveJsonObject(json_t *root, const char *path, json_t *value) {
|
|||
return 1;
|
||||
|
||||
if (path[0] == '$') {
|
||||
if (json_path_set(root, path, value, 0, &error)) {
|
||||
if (json_path_set_new(root, path, value, 0, &error)) {
|
||||
PrintAndLogEx(ERR, "ERROR: can't set json path: %s", error.text);
|
||||
return 2;
|
||||
} else {
|
||||
|
|
|
@ -573,16 +573,16 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data,
|
|||
int res = json_dump_file(root, fileName, JSON_INDENT(2));
|
||||
if (res) {
|
||||
PrintAndLogEx(FAILED, "error: can't save the file: " _YELLOW_("%s"), fileName);
|
||||
json_decref(root);
|
||||
retval = 200;
|
||||
goto out;
|
||||
}
|
||||
if (verbose)
|
||||
PrintAndLogEx(SUCCESS, "saved to json file " _YELLOW_("%s"), fileName);
|
||||
|
||||
json_decref(root);
|
||||
if (verbose) {
|
||||
PrintAndLogEx(SUCCESS, "saved to json file " _YELLOW_("%s"), fileName);
|
||||
}
|
||||
|
||||
out:
|
||||
json_decref(root);
|
||||
free(fileName);
|
||||
return retval;
|
||||
}
|
||||
|
|
|
@ -190,12 +190,10 @@ int GetAskClock(const char *str, bool printAns) {
|
|||
return clock1;
|
||||
}
|
||||
|
||||
uint8_t GetPskCarrier(const char *str, bool printAns) {
|
||||
int GetPskCarrier(bool verbose) {
|
||||
if (getSignalProperties()->isnoise)
|
||||
return -1;
|
||||
|
||||
uint8_t carrier = 0;
|
||||
|
||||
uint8_t *bits = calloc(MAX_GRAPH_TRACE_LEN, sizeof(uint8_t));
|
||||
if (bits == NULL) {
|
||||
PrintAndLogEx(WARNING, "Failed to allocate memory");
|
||||
|
@ -211,16 +209,18 @@ uint8_t GetPskCarrier(const char *str, bool printAns) {
|
|||
|
||||
uint16_t fc = countFC(bits, size, false);
|
||||
free(bits);
|
||||
carrier = fc & 0xFF;
|
||||
|
||||
uint8_t carrier = fc & 0xFF;
|
||||
if (carrier != 2 && carrier != 4 && carrier != 8) return 0;
|
||||
if ((fc >> 8) == 10 && carrier == 8) return 0;
|
||||
// Only print this message if we're not looping something
|
||||
if (printAns)
|
||||
if (verbose)
|
||||
PrintAndLogEx(SUCCESS, "Auto-detected PSK carrier rate: %d", carrier);
|
||||
|
||||
return carrier;
|
||||
}
|
||||
|
||||
int GetPskClock(const char *str, bool printAns) {
|
||||
int GetPskClock(const char *str, bool verbose) {
|
||||
|
||||
if (getSignalProperties()->isnoise)
|
||||
return -1;
|
||||
|
@ -251,14 +251,14 @@ int GetPskClock(const char *str, bool printAns) {
|
|||
setClockGrid(clock1, firstPhaseShiftLoc);
|
||||
|
||||
// Only print this message if we're not looping something
|
||||
if (printAns)
|
||||
if (verbose)
|
||||
PrintAndLogEx(SUCCESS, "Auto-detected clock rate: %d", clock1);
|
||||
|
||||
free(bits);
|
||||
return clock1;
|
||||
}
|
||||
|
||||
int GetNrzClock(const char *str, bool printAns) {
|
||||
int GetNrzClock(const char *str, bool verbose) {
|
||||
|
||||
if (getSignalProperties()->isnoise)
|
||||
return -1;
|
||||
|
@ -285,7 +285,7 @@ int GetNrzClock(const char *str, bool printAns) {
|
|||
clock1 = DetectNRZClock(bits, size, 0, &clkStartIdx);
|
||||
setClockGrid(clock1, clkStartIdx);
|
||||
// Only print this message if we're not looping something
|
||||
if (printAns)
|
||||
if (verbose)
|
||||
PrintAndLogEx(SUCCESS, "Auto-detected clock rate: %d", clock1);
|
||||
|
||||
free(bits);
|
||||
|
@ -294,7 +294,7 @@ int GetNrzClock(const char *str, bool printAns) {
|
|||
|
||||
//by marshmellow
|
||||
//attempt to detect the field clock and bit clock for FSK
|
||||
int GetFskClock(const char *str, bool printAns) {
|
||||
int GetFskClock(const char *str, bool verbose) {
|
||||
|
||||
int clock1 = param_get32ex(str, 0, 0, 10);
|
||||
if (clock1 != 0)
|
||||
|
@ -307,7 +307,7 @@ int GetFskClock(const char *str, bool printAns) {
|
|||
return 0;
|
||||
|
||||
if ((fc1 == 10 && fc2 == 8) || (fc1 == 8 && fc2 == 5)) {
|
||||
if (printAns)
|
||||
if (verbose)
|
||||
PrintAndLogEx(SUCCESS, "Detected Field Clocks: FC/%d, FC/%d - Bit Clock: RF/%d", fc1, fc2, rf1);
|
||||
|
||||
setClockGrid(rf1, firstClockEdge);
|
||||
|
|
|
@ -27,11 +27,11 @@ void convertGraphFromBitstream(void);
|
|||
void convertGraphFromBitstreamEx(int hi, int low);
|
||||
bool isGraphBitstream(void);
|
||||
|
||||
int GetAskClock(const char *str, bool printAns);
|
||||
int GetPskClock(const char *str, bool printAns);
|
||||
uint8_t GetPskCarrier(const char *str, bool printAns);
|
||||
int GetNrzClock(const char *str, bool printAns);
|
||||
int GetFskClock(const char *str, bool printAns);
|
||||
int GetAskClock(const char *str, bool verbose);
|
||||
int GetPskClock(const char *str, bool verbose);
|
||||
int GetPskCarrier(bool verbose);
|
||||
int GetNrzClock(const char *str, bool verbose);
|
||||
int GetFskClock(const char *str, bool verbose);
|
||||
bool fskClocks(uint8_t *fc1, uint8_t *fc2, uint8_t *rf1, int *firstClockEdge);
|
||||
|
||||
#define MAX_GRAPH_TRACE_LEN (40000 * 8)
|
||||
|
|
|
@ -38,9 +38,7 @@ static void jsonp_free(void *ptr) {
|
|||
}
|
||||
|
||||
static char *jsonp_strndup(const char *str, size_t len) {
|
||||
char *new_str;
|
||||
|
||||
new_str = jsonp_malloc(len + 1);
|
||||
char *new_str = jsonp_malloc(len + 1);
|
||||
if (!new_str)
|
||||
return NULL;
|
||||
|
||||
|
|
|
@ -816,14 +816,16 @@ int mfEmlSetMem_xt(uint8_t *data, int blockNum, int blocksCount, int blockBtWidt
|
|||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
struct p *payload = calloc(1, sizeof(struct p) + size);
|
||||
size_t paylen = sizeof(struct p) + size;
|
||||
struct p *payload = calloc(1, paylen);
|
||||
|
||||
payload->blockno = blockNum;
|
||||
payload->blockcnt = blocksCount;
|
||||
payload->blockwidth = blockBtWidth;
|
||||
memcpy(payload->data, data, size);
|
||||
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_HF_MIFARE_EML_MEMSET, (uint8_t *)payload, sizeof(payload) + size);
|
||||
SendCommandNG(CMD_HF_MIFARE_EML_MEMSET, (uint8_t *)payload, paylen);
|
||||
free(payload);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
@ -1178,7 +1180,7 @@ int detect_mf_magic(bool is_mfc) {
|
|||
PrintAndLogEx(SUCCESS, "Magic capabilities : " _GREEN_("Gen 2 / CUID"));
|
||||
break;
|
||||
case MAGIC_GEN_3:
|
||||
PrintAndLogEx(SUCCESS, "Magic capabilities : " _GREEN_("Gen 3 / APDU"));
|
||||
PrintAndLogEx(SUCCESS, "Magic capabilities : possibly " _GREEN_("Gen 3 / APDU"));
|
||||
break;
|
||||
case MAGIC_GEN_UNFUSED:
|
||||
PrintAndLogEx(SUCCESS, "Magic capabilities : " _GREEN_("Write Once / FUID"));
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
// Add the new setting to the session_arg_t; in ui.h
|
||||
// Add the default value for the setting in the settings_load page below
|
||||
// Update the preferences_load_callback to load your setting into the stucture
|
||||
// Update the preferences_save_callback to enusre your setting gets saved when needed.
|
||||
// Update the preferences_save_callback to ensure your setting gets saved when needed.
|
||||
// use the preference as needed : session.<preference name>
|
||||
// Can use (session.preferences_loaded) to check if json settings file was used
|
||||
//-----------------------------------------------------------------------------
|
||||
|
@ -52,6 +52,7 @@ int preferences_load(void) {
|
|||
session.overlay.y = 60 + session.plot.y + session.plot.h;
|
||||
session.overlay.h = 200;
|
||||
session.overlay.w = session.plot.w;
|
||||
session.overlay_sliders = true;
|
||||
session.show_hints = false;
|
||||
|
||||
// setDefaultPath (spDefault, "");
|
||||
|
@ -78,6 +79,11 @@ int preferences_load(void) {
|
|||
setDefaultPath (spTrace, ".");
|
||||
*/
|
||||
|
||||
if (session.incognito) {
|
||||
PrintAndLogEx(INFO, "No preferences file will be loaded");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
// loadFileJson wants these, so pass in place holder values, though not used
|
||||
// in settings load;
|
||||
uint8_t dummyData = 0x00;
|
||||
|
@ -100,7 +106,10 @@ int preferences_load(void) {
|
|||
// Save all settings from memory (struct) to file
|
||||
int preferences_save(void) {
|
||||
// Note sure if backup has value ?
|
||||
|
||||
if (session.incognito) {
|
||||
PrintAndLogEx(INFO, "No preferences file will be saved");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
PrintAndLogEx(INFO, "Saving preferences...");
|
||||
|
||||
char *fn = prefGetFilename();
|
||||
|
@ -185,6 +194,7 @@ void preferences_save_callback(json_t *root) {
|
|||
JsonSaveInt(root, "window.overlay.ypos", session.overlay.y);
|
||||
JsonSaveInt(root, "window.overlay.hsize", session.overlay.h);
|
||||
JsonSaveInt(root, "window.overlay.wsize", session.overlay.w);
|
||||
JsonSaveBoolean(root, "window.overlay.sliders", session.overlay_sliders);
|
||||
|
||||
// Log level, convert to text
|
||||
switch (session.client_debug_level) {
|
||||
|
@ -225,7 +235,7 @@ void preferences_save_callback(json_t *root) {
|
|||
|
||||
void preferences_load_callback(json_t *root) {
|
||||
json_error_t up_error = {0};
|
||||
bool b1;
|
||||
int b1;
|
||||
int i1;
|
||||
const char *s1;
|
||||
char tempStr [500]; // to use str_lower() since json unpack uses const char *
|
||||
|
@ -270,6 +280,8 @@ void preferences_load_callback(json_t *root) {
|
|||
session.overlay.h = i1;
|
||||
if (json_unpack_ex(root, &up_error, 0, "{s:i}", "window.overlay.wsize", &i1) == 0)
|
||||
session.overlay.w = i1;
|
||||
if (json_unpack_ex(root, &up_error, 0, "{s:b}", "window.overlay.sliders", &b1) == 0)
|
||||
session.overlay_sliders = (bool)b1;
|
||||
|
||||
// show options
|
||||
if (json_unpack_ex(root, &up_error, 0, "{s:s}", "show.emoji", &s1) == 0) {
|
||||
|
@ -282,10 +294,10 @@ void preferences_load_callback(json_t *root) {
|
|||
}
|
||||
|
||||
if (json_unpack_ex(root, &up_error, 0, "{s:b}", "show.hints", &b1) == 0)
|
||||
session.show_hints = b1;
|
||||
session.show_hints = (bool)b1;
|
||||
|
||||
if (json_unpack_ex(root, &up_error, 0, "{s:b}", "os.supports.colors", &b1) == 0)
|
||||
session.supports_colors = b1;
|
||||
session.supports_colors = (bool)b1;
|
||||
/*
|
||||
// Logging Level
|
||||
if (json_unpack_ex(root, &up_error, 0, "{s:s}", "device.debug.level", &s1) == 0) {
|
||||
|
@ -353,6 +365,16 @@ static int usage_set_hints(void) {
|
|||
PrintAndLogEx(NORMAL, " "_GREEN_("on")" - Display hints");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int usage_set_plotsliders(void) {
|
||||
PrintAndLogEx(NORMAL, "Usage: pref set plotsliders <on | off>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " "_GREEN_("help")" - This help");
|
||||
PrintAndLogEx(NORMAL, " "_GREEN_("on")" - show plot slider controls");
|
||||
PrintAndLogEx(NORMAL, " "_GREEN_("off")" - hide plot slider controls");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
static int usage_set_savePaths(void) {
|
||||
PrintAndLogEx(NORMAL, "Usage: pref set savepaths [help] [create] [default <path>] [dump <path>] [trace <path>]");
|
||||
|
@ -492,6 +514,13 @@ static void showHintsState(prefShowOpt_t opt) {
|
|||
PrintAndLogEx(INFO, " %s hints.................. "_WHITE_("off"), prefShowMsg(opt));
|
||||
}
|
||||
|
||||
static void showPlotSliderState(prefShowOpt_t opt) {
|
||||
if (session.overlay_sliders)
|
||||
PrintAndLogEx(INFO, " %s show plot sliders...... "_GREEN_("on"), prefShowMsg(opt));
|
||||
else
|
||||
PrintAndLogEx(INFO, " %s show plot sliders...... "_WHITE_("off"), prefShowMsg(opt));
|
||||
}
|
||||
|
||||
|
||||
static int setCmdEmoji(const char *Cmd) {
|
||||
uint8_t cmdp = 0;
|
||||
|
@ -688,7 +717,7 @@ static int setCmdDeviceDebug (const char *Cmd)
|
|||
showDeviceDebugState (prefShowOLD);
|
||||
session.device_debug_level = newValue;
|
||||
showDeviceDebugState (prefShowNEW);
|
||||
preferences_save ();
|
||||
preferences_save();
|
||||
} else {
|
||||
PrintAndLogEx(INFO,"nothing changed");
|
||||
showDeviceDebugState (prefShowNone);
|
||||
|
@ -755,6 +784,52 @@ static int setCmdHint(const char *Cmd) {
|
|||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int setCmdPlotSliders(const char *Cmd) {
|
||||
uint8_t cmdp = 0;
|
||||
bool errors = false;
|
||||
bool validValue = false;
|
||||
char strOpt[50];
|
||||
bool newValue = session.overlay_sliders;
|
||||
|
||||
if (param_getchar(Cmd, cmdp) == 0x00)
|
||||
return usage_set_plotsliders();
|
||||
|
||||
while ((param_getchar(Cmd, cmdp) != 0x00) && !errors) {
|
||||
|
||||
if (param_getstr(Cmd, cmdp++, strOpt, sizeof(strOpt)) != 0) {
|
||||
str_lower(strOpt); // convert to lowercase
|
||||
|
||||
if (strncmp(strOpt, "help", 4) == 0)
|
||||
return usage_set_plotsliders();
|
||||
if (strncmp(strOpt, "off", 3) == 0) {
|
||||
validValue = true;
|
||||
newValue = false;
|
||||
}
|
||||
if (strncmp(strOpt, "on", 2) == 0) {
|
||||
validValue = true;
|
||||
newValue = true;
|
||||
}
|
||||
|
||||
if (validValue) {
|
||||
if (session.overlay_sliders != newValue) {// changed
|
||||
showPlotSliderState(prefShowOLD);
|
||||
session.overlay_sliders = newValue;
|
||||
showPlotSliderState(prefShowNEW);
|
||||
preferences_save();
|
||||
} else {
|
||||
PrintAndLogEx(INFO, "nothing changed");
|
||||
showPlotSliderState(prefShowNone);
|
||||
}
|
||||
} else {
|
||||
PrintAndLogEx(ERR, "invalid option");
|
||||
return usage_set_plotsliders();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
static int setCmdSavePaths (const char *Cmd) {
|
||||
uint8_t cmdp = 0;
|
||||
|
@ -866,6 +941,11 @@ static int getCmdDebug(const char *Cmd) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int getCmdPlotSlider(const char *Cmd) {
|
||||
showPlotSliderState(prefShowNone);
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static command_t getCommandTable[] = {
|
||||
// {"help", getCmdHelp, AlwaysAvailable, "This help"},
|
||||
{"emoji", getCmdEmoji, AlwaysAvailable, "Get emoji display preference"},
|
||||
|
@ -873,6 +953,7 @@ static command_t getCommandTable[] = {
|
|||
{"color", getCmdColor, AlwaysAvailable, "Get color support preference"},
|
||||
// {"defaultsavepaths", getCmdSavePaths, AlwaysAvailable, "... to be adjusted next ... "},
|
||||
{"clientdebug", getCmdDebug, AlwaysAvailable, "Get client debug level preference"},
|
||||
{"plotsliders", getCmdPlotSlider, AlwaysAvailable, "Get plot slider display preference"},
|
||||
// {"devicedebug", getCmdDeviceDebug, AlwaysAvailable, "Get device debug level"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
@ -884,6 +965,7 @@ static command_t setCommandTable[] = {
|
|||
{"color", setCmdColor, AlwaysAvailable, "Set color support"},
|
||||
// {"defaultsavepaths", setCmdSavePaths, AlwaysAvailable, "... to be adjusted next ... "},
|
||||
{"clientdebug", setCmdDebug, AlwaysAvailable, "Set client debug level"},
|
||||
{"plotsliders", setCmdPlotSliders, AlwaysAvailable, "Set plot slider display"},
|
||||
// {"devicedebug", setCmdDeviceDebug, AlwaysAvailable, "Set device debug level"},
|
||||
{NULL, NULL, NULL, NULL}
|
||||
};
|
||||
|
@ -912,8 +994,7 @@ static int CmdPrefShow(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, "Using "_YELLOW_("%s"), fn);
|
||||
free(fn);
|
||||
} else {
|
||||
PrintAndLogEx(ERR, "Preferences not loaded");
|
||||
return PM3_ESOFT;
|
||||
PrintAndLogEx(WARNING, "Preferences file not loaded");
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Current settings");
|
||||
|
@ -925,8 +1006,8 @@ static int CmdPrefShow(const char *Cmd) {
|
|||
// showSavePathState(spDefault, prefShowNone);
|
||||
// showSavePathState(spDump, prefShowNone);
|
||||
// showSavePathState(spTrace, prefShowNone);
|
||||
|
||||
showClientDebugState(prefShowNone);
|
||||
showPlotSliderState(prefShowNone);
|
||||
// showDeviceDebugState(prefShowNone);
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return PM3_SUCCESS;
|
||||
|
|
|
@ -28,7 +28,7 @@ void ExitGraphics(void);
|
|||
|
||||
extern double CursorScaleFactor;
|
||||
extern char CursorScaleFactorUnit[11];
|
||||
extern int PlotGridX, PlotGridY, PlotGridXdefault, PlotGridYdefault, GridOffset;
|
||||
extern double PlotGridX, PlotGridY, PlotGridXdefault, PlotGridYdefault, GridOffset;
|
||||
extern uint32_t CursorCPos, CursorDPos;
|
||||
extern int CommandFinished;
|
||||
extern int offline;
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// GUI (QT)
|
||||
//-----------------------------------------------------------------------------
|
||||
#define __STDC_FORMAT_MACROS
|
||||
#include "proxguiqt.h"
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
|
@ -251,7 +252,8 @@ ProxWidget::ProxWidget(QWidget *parent, ProxGuiQT *master) : QWidget(parent) {
|
|||
QString ct = QString("[*]Slider [ %1 ]").arg(conn.serial_port_name);
|
||||
controlWidget->setWindowTitle(ct);
|
||||
|
||||
controlWidget->show();
|
||||
// The hide/show event functions should take care of this.
|
||||
// controlWidget->show();
|
||||
|
||||
// now that is up, reset pos/size change flags
|
||||
session.window_changed = false;
|
||||
|
@ -289,7 +291,10 @@ void ProxWidget::hideEvent(QHideEvent *event) {
|
|||
plot->hide();
|
||||
}
|
||||
void ProxWidget::showEvent(QShowEvent *event) {
|
||||
controlWidget->show();
|
||||
if (session.overlay_sliders)
|
||||
controlWidget->show();
|
||||
else
|
||||
controlWidget->hide();
|
||||
plot->show();
|
||||
}
|
||||
void ProxWidget::moveEvent(QMoveEvent *event) {
|
||||
|
@ -498,17 +503,17 @@ void Plot::plotGridLines(QPainter *painter, QRect r) {
|
|||
// set GridOffset
|
||||
if (PlotGridX <= 0) return;
|
||||
|
||||
int offset = GridOffset;
|
||||
double offset = GridOffset;
|
||||
if (GridLocked && PlotGridX) {
|
||||
offset = GridOffset + PlotGridX - (GraphStart % PlotGridX);
|
||||
offset = GridOffset + PlotGridX - fmod(GraphStart, PlotGridX);
|
||||
} else if (!GridLocked && GraphStart > 0 && PlotGridX) {
|
||||
offset = PlotGridX - ((GraphStart - offset) % PlotGridX) + GraphStart - unlockStart;
|
||||
offset = PlotGridX - fmod(GraphStart - offset, PlotGridX) + GraphStart - unlockStart;
|
||||
}
|
||||
offset %= PlotGridX;
|
||||
offset = fmod(offset, PlotGridX);
|
||||
if (offset < 0) offset += PlotGridX;
|
||||
|
||||
int i;
|
||||
int grid_delta_x = (int)(PlotGridX * GraphPixelsPerPoint);
|
||||
double i;
|
||||
double grid_delta_x = PlotGridX * GraphPixelsPerPoint;
|
||||
int grid_delta_y = PlotGridY;
|
||||
|
||||
if ((PlotGridX > 0) && ((PlotGridX * GraphPixelsPerPoint) > 1)) {
|
||||
|
@ -591,7 +596,7 @@ void Plot::paintEvent(QPaintEvent *event) {
|
|||
painter.drawLine(xCoordOf(CursorCPos, plotRect), plotRect.top(), xCoordOf(CursorCPos, plotRect), plotRect.bottom());
|
||||
}
|
||||
if (CursorDPos > GraphStart && xCoordOf(CursorDPos, plotRect) < plotRect.right()) {
|
||||
painter.setPen(QColor(0, 0, 205)); //light blue
|
||||
painter.setPen(QColor(100, 209, 246)); //light blue
|
||||
painter.drawLine(xCoordOf(CursorDPos, plotRect), plotRect.top(), xCoordOf(CursorDPos, plotRect), plotRect.bottom());
|
||||
}
|
||||
|
||||
|
@ -605,7 +610,7 @@ void Plot::paintEvent(QPaintEvent *event) {
|
|||
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",
|
||||
sprintf(str, "@%u..%u dt=%i %szoom=%2.2f CursorAPos=%u CursorBPos=%u GridX=%lf GridY=%lf (%s) GridXoffset=%lf",
|
||||
GraphStart,
|
||||
GraphStop,
|
||||
CursorBPos - CursorAPos,
|
||||
|
@ -633,11 +638,12 @@ Plot::Plot(QWidget *parent) : QWidget(parent), GraphStart(0), GraphPixelsPerPoin
|
|||
palette.setColor(QPalette::Button, QColor(100, 100, 100));
|
||||
setPalette(palette);
|
||||
setAutoFillBackground(true);
|
||||
|
||||
CursorAPos = 0;
|
||||
CursorBPos = 0;
|
||||
GraphStop = 0;
|
||||
|
||||
setWindowTitle(tr("Sliders"));
|
||||
|
||||
master = parent;
|
||||
}
|
||||
|
||||
|
@ -647,19 +653,23 @@ void Plot::closeEvent(QCloseEvent *event) {
|
|||
g_useOverlays = false;
|
||||
}
|
||||
|
||||
void Plot::Zoom(double factor, int refX) {
|
||||
void Plot::Zoom(double factor, uint32_t refX) {
|
||||
if (factor >= 1) { // Zoom in
|
||||
if (GraphPixelsPerPoint <= 25 * factor) {
|
||||
GraphPixelsPerPoint *= factor;
|
||||
GraphStart += (refX - GraphStart) - ((refX - GraphStart) / factor);
|
||||
if (refX > GraphStart) {
|
||||
GraphStart += (refX - GraphStart) - ((refX - GraphStart) / factor);
|
||||
}
|
||||
}
|
||||
} else { // Zoom out
|
||||
if (GraphPixelsPerPoint >= 0.01 / factor) {
|
||||
GraphPixelsPerPoint *= factor;
|
||||
if (GraphStart >= ((refX - GraphStart) / factor) - (refX - GraphStart)) {
|
||||
GraphStart -= ((refX - GraphStart) / factor) - (refX - GraphStart);
|
||||
} else {
|
||||
GraphStart = 0;
|
||||
if (refX > GraphStart) {
|
||||
if (GraphStart >= ((refX - GraphStart) / factor) - (refX - GraphStart)) {
|
||||
GraphStart -= ((refX - GraphStart) / factor) - (refX - GraphStart);
|
||||
} else {
|
||||
GraphStart = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -693,6 +703,16 @@ void Plot::Trim(void) {
|
|||
if ((CursorAPos == 0) || (CursorBPos == 0)) { // if we don't have both cursors set
|
||||
lref = GraphStart;
|
||||
rref = GraphStop;
|
||||
if (CursorAPos >= lref) {
|
||||
CursorAPos -= lref;
|
||||
} else {
|
||||
CursorAPos = 0;
|
||||
}
|
||||
if (CursorBPos >= lref) {
|
||||
CursorBPos -= lref;
|
||||
} else {
|
||||
CursorBPos = 0;
|
||||
}
|
||||
} else {
|
||||
lref = CursorAPos < CursorBPos ? CursorAPos : CursorBPos;
|
||||
rref = CursorAPos < CursorBPos ? CursorBPos : CursorAPos;
|
||||
|
@ -705,6 +725,7 @@ void Plot::Trim(void) {
|
|||
CursorAPos -= lref;
|
||||
CursorBPos -= lref;
|
||||
}
|
||||
g_DemodStartIdx -= lref;
|
||||
for (uint32_t i = lref; i < rref; ++i)
|
||||
GraphBuffer[i - lref] = GraphBuffer[i];
|
||||
GraphTraceLen = rref - lref;
|
||||
|
@ -722,9 +743,9 @@ void Plot::wheelEvent(QWheelEvent *event) {
|
|||
if (event->modifiers() & Qt::ShiftModifier) {
|
||||
// event->position doesn't exist in QT5.12.8, both exist in 5.14.2 and event->x doesn't exist in 5.15.0
|
||||
#if QT_VERSION >= 0x050d00
|
||||
int x = event->position().x();
|
||||
uint32_t x = event->position().x();
|
||||
#else
|
||||
int x = event->x();
|
||||
uint32_t x = event->x();
|
||||
#endif
|
||||
x -= WIDTH_AXES;
|
||||
x = (int)(x / GraphPixelsPerPoint);
|
||||
|
@ -765,10 +786,11 @@ void Plot::mouseMoveEvent(QMouseEvent *event) {
|
|||
|
||||
void Plot::keyPressEvent(QKeyEvent *event) {
|
||||
uint32_t offset; // Left/right movement offset (in sample size)
|
||||
const double zoom_offset = 1.148698354997035; // 2**(1/5)
|
||||
|
||||
if (event->modifiers() & Qt::ShiftModifier) {
|
||||
if (PlotGridX)
|
||||
offset = PageWidth - (PageWidth % PlotGridX);
|
||||
offset = PageWidth - fmod(PageWidth, PlotGridX);
|
||||
else
|
||||
offset = PageWidth;
|
||||
} else {
|
||||
|
@ -781,17 +803,33 @@ void Plot::keyPressEvent(QKeyEvent *event) {
|
|||
switch (event->key()) {
|
||||
case Qt::Key_Down:
|
||||
if (event->modifiers() & Qt::ShiftModifier) {
|
||||
Zoom(2, CursorBPos);
|
||||
if (event->modifiers() & Qt::ControlModifier) {
|
||||
Zoom(zoom_offset, CursorBPos);
|
||||
} else {
|
||||
Zoom(2, CursorBPos);
|
||||
}
|
||||
} else {
|
||||
Zoom(2, CursorAPos);
|
||||
if (event->modifiers() & Qt::ControlModifier) {
|
||||
Zoom(zoom_offset, CursorAPos);
|
||||
} else {
|
||||
Zoom(2, CursorAPos);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::Key_Up:
|
||||
if (event->modifiers() & Qt::ShiftModifier) {
|
||||
Zoom(0.5, CursorBPos);
|
||||
if (event->modifiers() & Qt::ControlModifier) {
|
||||
Zoom(1.0 / zoom_offset, CursorBPos);
|
||||
} else {
|
||||
Zoom(0.5, CursorBPos);
|
||||
}
|
||||
} else {
|
||||
Zoom(0.5, CursorAPos);
|
||||
if (event->modifiers() & Qt::ControlModifier) {
|
||||
Zoom(1.0 / zoom_offset, CursorAPos);
|
||||
} else {
|
||||
Zoom(0.5, CursorAPos);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -803,6 +841,14 @@ void Plot::keyPressEvent(QKeyEvent *event) {
|
|||
Move(-offset);
|
||||
break;
|
||||
|
||||
case Qt::Key_Greater:
|
||||
g_DemodStartIdx += 1;
|
||||
break;
|
||||
|
||||
case Qt::Key_Less:
|
||||
g_DemodStartIdx -= 1;
|
||||
break;
|
||||
|
||||
case Qt::Key_G:
|
||||
if (PlotGridX || PlotGridY) {
|
||||
PlotGridX = 0;
|
||||
|
@ -819,36 +865,33 @@ void Plot::keyPressEvent(QKeyEvent *event) {
|
|||
break;
|
||||
|
||||
case Qt::Key_H:
|
||||
puts("\n-----------------------------------------------------------------------");
|
||||
puts("PLOT window keystrokes");
|
||||
puts("\tKey Action");
|
||||
puts("-----------------------------------------------------------------------");
|
||||
puts("\tUP Zoom out around yellow cursor");
|
||||
puts("\t<SHIFT> UP Zoom out around purple cursor");
|
||||
puts("\t<SHIFT> WHEEL MOUSE UP Zoom out around mouse cursor");
|
||||
puts("\tDOWN Zoom in around yellow cursor");
|
||||
puts("\t<SHIFT> DOWN Zoom in around purple cursor");
|
||||
puts("\t<SHIFT> WHEEL MOUSE DOWN Zoom in around mouse cursor");
|
||||
puts("\tG Toggle grid display");
|
||||
puts("\tH Show help");
|
||||
puts("\tL Toggle lock grid relative to samples");
|
||||
puts("\tQ Hide window");
|
||||
puts("\tT Trim data on displayed window or on cursors if defined");
|
||||
puts("\tHOME Move to the start of the graph");
|
||||
puts("\tEND Move to the end of the graph");
|
||||
puts("\tPGUP Page left");
|
||||
puts("\tPGDOWN Page right");
|
||||
puts("\tLEFT Move left");
|
||||
puts("\tRIGHT Move right");
|
||||
puts("\tWHEEL MOUSE UP Move left");
|
||||
puts("\tWHEEL MOUSE DOWN Move right");
|
||||
puts("\t<CTLR> LEFT Move left 1 sample");
|
||||
puts("\t<CTLR> RIGHT Move right 1 sample");
|
||||
puts("\t<SHIFT> LEFT Page left");
|
||||
puts("\t<SHIFT> RIGHT Page right");
|
||||
puts("\tLEFT MOUSE CLICK Set yellow cursor");
|
||||
puts("\tRIGHT MOUSE CLICK Set purple cursor");
|
||||
puts("-----------------------------------------------------------------------");
|
||||
g_printAndLog = PRINTANDLOG_PRINT;
|
||||
PrintAndLogEx(NORMAL, "\n\n" _CYAN_("PLOT window keystrokes and mouse events"));
|
||||
PrintAndLogEx(NORMAL, "\n" _GREEN_("Move:"));
|
||||
PrintAndLogEx(NORMAL, " %-*s%s", 25 + 9 + 9, _RED_("Home") "/" _RED_("End"), "Move to the start/end of the graph");
|
||||
PrintAndLogEx(NORMAL, " %-*s%s", 25 + 9, _YELLOW_("Mouse wheel"), "Move left/right");
|
||||
PrintAndLogEx(NORMAL, " %-*s%s", 25 + 9 + 9, _RED_("Left") "/" _RED_("Right"), "Move left/right");
|
||||
PrintAndLogEx(NORMAL, " %-*s%s", 25 + 9, " + " _RED_("Ctrl"), "... by 1 sample");
|
||||
PrintAndLogEx(NORMAL, " %-*s%s", 25 + 9, " + " _RED_("Shift"), "... by 1 window");
|
||||
PrintAndLogEx(NORMAL, " %-*s%s", 25 + 9 + 9, _RED_("PgUp") "/" _RED_("PgDown"), "Move left/right by 1 window");
|
||||
PrintAndLogEx(NORMAL, "\n" _GREEN_("Zoom:"));
|
||||
PrintAndLogEx(NORMAL, " %-*s%s", 25 + 9 + 9, _RED_("Shift") " + " _YELLOW_("Mouse wheel"), "Zoom in/out around mouse cursor");
|
||||
PrintAndLogEx(NORMAL, " %-*s%s", 25 + 9 + 9, _RED_("Down") "/" _RED_("Up"), "Zoom in/out around yellow cursor");
|
||||
PrintAndLogEx(NORMAL, " %-*s%s", 25 + 9, " + " _RED_("Ctrl"), "... with smaller increment");
|
||||
PrintAndLogEx(NORMAL, " %-*s%s", 25 + 9, " + " _RED_("Shift"), "... around purple cursor");
|
||||
PrintAndLogEx(NORMAL, " %-*s%s", 25 + 9, _RED_("h"), "Show this help");
|
||||
PrintAndLogEx(NORMAL, "\n" _GREEN_("Trim:"));
|
||||
PrintAndLogEx(NORMAL, " %-*s%s", 25 + 9, _RED_("t"), "Trim data on window or on cursors if defined");
|
||||
PrintAndLogEx(NORMAL, "\n" _GREEN_("Grid and demod:"));
|
||||
PrintAndLogEx(NORMAL, " %-*s%s", 25 + 9, _RED_("g"), "Toggle grid and demodulation plot display");
|
||||
PrintAndLogEx(NORMAL, " %-*s%s", 25 + 9, _RED_("l"), "Toggle lock grid relative to samples");
|
||||
PrintAndLogEx(NORMAL, " %-*s%s", 25 + 9 + 9, _RED_("<") "/" _RED_(">"), "Move demodulation left/right relative to samples");
|
||||
PrintAndLogEx(NORMAL, "\n" _GREEN_("Misc:"));
|
||||
PrintAndLogEx(NORMAL, " %-*s%s", 25 + 9, _YELLOW_("Left mouse click"), "Set yellow cursor");
|
||||
PrintAndLogEx(NORMAL, " %-*s%s", 25 + 9, _YELLOW_("Right mouse click"), "Set purple cursor");
|
||||
PrintAndLogEx(NORMAL, " %-*s%s", 25 + 9, _RED_("h"), "Show this help");
|
||||
PrintAndLogEx(NORMAL, " %-*s%s", 25 + 9, _RED_("q"), "Close plot window");
|
||||
g_printAndLog = PRINTANDLOG_PRINT | PRINTANDLOG_LOG;
|
||||
break;
|
||||
|
||||
case Qt::Key_L:
|
||||
|
|
|
@ -51,7 +51,7 @@ class Plot: public QWidget {
|
|||
protected:
|
||||
void paintEvent(QPaintEvent *event);
|
||||
void closeEvent(QCloseEvent *event);
|
||||
void Zoom(double factor, int refX);
|
||||
void Zoom(double factor, uint32_t refX);
|
||||
void Move(int offset);
|
||||
void Trim(void);
|
||||
void wheelEvent(QWheelEvent *event);
|
||||
|
|
|
@ -245,22 +245,26 @@ main_loop(char *script_cmds_file, char *script_cmd, bool stayInCommandLoop) {
|
|||
|
||||
#ifdef HAVE_READLINE
|
||||
session.history_path = NULL;
|
||||
if (searchHomeFilePath(&session.history_path, NULL, PROXHISTORY, true) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "No history will be recorded");
|
||||
session.history_path = NULL;
|
||||
if (session.incognito) {
|
||||
PrintAndLogEx(INFO, "No history will be recorded");
|
||||
} else {
|
||||
if (searchHomeFilePath(&session.history_path, NULL, PROXHISTORY, true) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "No history will be recorded");
|
||||
session.history_path = NULL;
|
||||
} else {
|
||||
|
||||
# if defined(_WIN32)
|
||||
// SetConsoleCtrlHandler((PHANDLER_ROUTINE)terminate_handler, true);
|
||||
// SetConsoleCtrlHandler((PHANDLER_ROUTINE)terminate_handler, true);
|
||||
# else
|
||||
struct sigaction action;
|
||||
memset(&action, 0, sizeof(action));
|
||||
action.sa_handler = &terminate_handler;
|
||||
sigaction(SIGINT, &action, &old_action);
|
||||
struct sigaction action;
|
||||
memset(&action, 0, sizeof(action));
|
||||
action.sa_handler = &terminate_handler;
|
||||
sigaction(SIGINT, &action, &old_action);
|
||||
# endif
|
||||
rl_catch_signals = 1;
|
||||
rl_set_signals();
|
||||
read_history(session.history_path);
|
||||
rl_catch_signals = 1;
|
||||
rl_set_signals();
|
||||
read_history(session.history_path);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -565,6 +569,7 @@ static void show_help(bool showFullHelp, char *exec_name) {
|
|||
PrintAndLogEx(NORMAL, " -l/--lua <lua script file> execute lua script.");
|
||||
PrintAndLogEx(NORMAL, " -s/--script-file <cmd_script_file> script file with one Proxmark3 command per line");
|
||||
PrintAndLogEx(NORMAL, " -i/--interactive enter interactive mode after executing the script or the command");
|
||||
PrintAndLogEx(NORMAL, " --incognito do not use history, prefs file nor log files");
|
||||
PrintAndLogEx(NORMAL, "\nOptions in flasher mode:");
|
||||
PrintAndLogEx(NORMAL, " --flash flash Proxmark3, requires at least one --image");
|
||||
PrintAndLogEx(NORMAL, " --unlock-bootloader Enable flashing of bootloader area *DANGEROUS* (need --flash or --flash-info)");
|
||||
|
@ -698,6 +703,7 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
session.pm3_present = false;
|
||||
session.help_dump_mode = false;
|
||||
session.incognito = false;
|
||||
bool waitCOMPort = false;
|
||||
bool addLuaExec = false;
|
||||
bool stayInCommandLoop = false;
|
||||
|
@ -903,6 +909,12 @@ int main(int argc, char *argv[]) {
|
|||
continue;
|
||||
}
|
||||
|
||||
// do not use history nor log files
|
||||
if (strcmp(argv[i], "--incognito") == 0) {
|
||||
session.incognito = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// go to flash mode
|
||||
if (strcmp(argv[i], "--flash") == 0) {
|
||||
flash_mode = true;
|
||||
|
@ -1008,7 +1020,7 @@ int main(int argc, char *argv[]) {
|
|||
// Save settings if not loaded from settings json file.
|
||||
// Doing this here will ensure other checks and updates are saved to over rule default
|
||||
// e.g. Linux color use check
|
||||
if (!session.preferences_loaded) {
|
||||
if ((!session.preferences_loaded) && (!session.incognito)) {
|
||||
PrintAndLogEx(INFO, "Creating initial preferences file"); // json save reports file name, so just info msg here
|
||||
preferences_save(); // Save defaults
|
||||
session.preferences_loaded = true;
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include "fileutils.h" // searchfile
|
||||
#include "cmdlf.h" // lf_config
|
||||
#include "generator.h"
|
||||
#include "cmdlfem4x.h" // read 4305
|
||||
|
||||
static int returnToLuaWithError(lua_State *L, const char *fmt, ...) {
|
||||
char buffer[200];
|
||||
|
@ -1001,7 +1002,7 @@ static int l_T55xx_readblock(lua_State *L) {
|
|||
return returnToLuaWithError(L, "Failed to read config block");
|
||||
}
|
||||
|
||||
if (!tryDetectModulation(0, true)) { // Default to prev. behaviour (default dl mode and print config)
|
||||
if (!t55xxTryDetectModulation(0, true)) { // Default to prev. behaviour (default dl mode and print config)
|
||||
PrintAndLogEx(NORMAL, "Safety Check: Could not detect if PWD bit is set in config block. Exits.");
|
||||
return 0;
|
||||
} else {
|
||||
|
@ -1077,7 +1078,7 @@ static int l_T55xx_detect(lua_State *L) {
|
|||
}
|
||||
}
|
||||
|
||||
isok = tryDetectModulation(0, true); // Default to prev. behaviour (default dl mode and print config)
|
||||
isok = t55xxTryDetectModulation(0, true); // Default to prev. behaviour (default dl mode and print config)
|
||||
if (isok == false) {
|
||||
return returnToLuaWithError(L, "Could not detect modulation automatically. Try setting it manually with \'lf t55xx config\'");
|
||||
}
|
||||
|
@ -1087,6 +1088,46 @@ static int l_T55xx_detect(lua_State *L) {
|
|||
return 2;
|
||||
}
|
||||
|
||||
//
|
||||
static int l_em4x05_read(lua_State *L) {
|
||||
|
||||
bool use_pwd = false;
|
||||
uint32_t addr, password = 0;
|
||||
|
||||
//Check number of arguments
|
||||
//int n = lua_gettop(L);
|
||||
|
||||
// get addr
|
||||
size_t size = 0;
|
||||
const char *p_addr = luaL_checklstring(L, 1, &size);
|
||||
sscanf(p_addr, "%u", &addr);
|
||||
|
||||
// get password
|
||||
const char *p_pwd = luaL_checklstring(L, 2, &size);
|
||||
if (size == 0) {
|
||||
use_pwd = false;
|
||||
} else {
|
||||
if (size != 8)
|
||||
return returnToLuaWithError(L, "Wrong size of password, got %zu , expected 8", size);
|
||||
|
||||
sscanf(p_pwd, "%08x", &password);
|
||||
use_pwd = true;
|
||||
}
|
||||
|
||||
PrintAndLogEx(DEBUG, "Addr %u", addr);
|
||||
if (use_pwd)
|
||||
PrintAndLogEx(DEBUG, " Pwd %08X", password);
|
||||
|
||||
uint32_t word = 0;
|
||||
int res = EM4x05ReadWord_ext(addr, password, use_pwd, &word);
|
||||
if (res != PM3_SUCCESS) {
|
||||
return returnToLuaWithError(L, "Failed to read EM4x05 data");
|
||||
}
|
||||
|
||||
lua_pushinteger(L, word);
|
||||
return 1;
|
||||
}
|
||||
|
||||
//
|
||||
static int l_ndefparse(lua_State *L) {
|
||||
|
||||
|
@ -1203,13 +1244,13 @@ static int l_cwd(lua_State *L) {
|
|||
// ref: https://github.com/RfidResearchGroup/proxmark3/issues/891
|
||||
// redirect LUA's print to Proxmark3 PrintAndLogEx
|
||||
static int l_printandlogex(lua_State *L) {
|
||||
|
||||
int n = lua_gettop(L);
|
||||
for (int i = 1; i <= n; i++) {
|
||||
if (lua_isstring(L, i)) {
|
||||
PrintAndLogEx(NORMAL, "%s", lua_tostring(L, i));
|
||||
PrintAndLogEx(NORMAL, "%s\t" NOLF, lua_tostring(L, i));
|
||||
}
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1278,6 +1319,7 @@ int set_pm3_libraries(lua_State *L) {
|
|||
{"ewd", l_ewd},
|
||||
{"ud", l_ud},
|
||||
{"rem", l_remark},
|
||||
{"em4x05_read", l_em4x05_read},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
|
|
|
@ -39,11 +39,11 @@ session_arg_t session;
|
|||
|
||||
double CursorScaleFactor = 1;
|
||||
char CursorScaleFactorUnit[11] = {0};
|
||||
int PlotGridX = 0, PlotGridY = 0, PlotGridXdefault = 64, PlotGridYdefault = 64;
|
||||
double PlotGridX = 0, PlotGridY = 0, PlotGridXdefault = 64, PlotGridYdefault = 64;
|
||||
uint32_t CursorCPos = 0, CursorDPos = 0;
|
||||
double GraphPixelsPerPoint = 1.f; // How many visual pixels are between each sample point (x axis)
|
||||
static bool flushAfterWrite = 0;
|
||||
int GridOffset = 0;
|
||||
double GridOffset = 0;
|
||||
bool GridLocked = false;
|
||||
bool showDemod = true;
|
||||
|
||||
|
@ -305,6 +305,9 @@ static void fPrintAndLog(FILE *stream, const char *fmt, ...) {
|
|||
pthread_mutex_lock(&print_lock);
|
||||
bool linefeed = true;
|
||||
|
||||
if (logging && session.incognito) {
|
||||
logging = 0;
|
||||
}
|
||||
if ((g_printAndLog & PRINTANDLOG_LOG) && logging && !logfile) {
|
||||
char *my_logfile_path = NULL;
|
||||
char filename[40];
|
||||
|
@ -356,7 +359,7 @@ static void fPrintAndLog(FILE *stream, const char *fmt, ...) {
|
|||
va_start(argptr, fmt);
|
||||
vsnprintf(buffer, sizeof(buffer), fmt, argptr);
|
||||
va_end(argptr);
|
||||
if (buffer[strlen(buffer) - 1] == NOLF[0]) {
|
||||
if (strlen(buffer) > 0 && buffer[strlen(buffer) - 1] == NOLF[0]) {
|
||||
linefeed = false;
|
||||
buffer[strlen(buffer) - 1] = 0;
|
||||
}
|
||||
|
|
|
@ -40,6 +40,8 @@ typedef struct {
|
|||
bool window_changed; // track if plot/overlay pos/size changed to save on exit
|
||||
qtWindow_t plot;
|
||||
qtWindow_t overlay;
|
||||
bool overlay_sliders;
|
||||
bool incognito;
|
||||
// char *defaultPaths[spItemCount]; // Array should allow loop searching for files
|
||||
clientdebugLevel_t client_debug_level;
|
||||
// uint8_t device_debug_level;
|
||||
|
|
|
@ -708,7 +708,7 @@ bool HIDTryUnpack(wiegand_message_t *packed, bool ignore_parity) {
|
|||
}
|
||||
++i;
|
||||
}
|
||||
if (result == false) {
|
||||
if (result == false && packed->Length) {
|
||||
PrintAndLogEx(SUCCESS, "Unknown. Bit len %d", packed->Length);
|
||||
}
|
||||
|
||||
|
|
|
@ -191,7 +191,7 @@ void compute_crc(CrcType_t ct, const uint8_t *d, size_t n, uint8_t *first, uint8
|
|||
crc = crc16_kermit(d, n);
|
||||
break;
|
||||
case CRC_11784:
|
||||
crc = crc16_fdx(d, n);
|
||||
crc = crc16_fdxb(d, n);
|
||||
break;
|
||||
case CRC_LEGIC:
|
||||
// TODO
|
||||
|
@ -225,7 +225,7 @@ uint16_t Crc16ex(CrcType_t ct, const uint8_t *d, size_t n) {
|
|||
case CRC_KERMIT:
|
||||
return crc16_kermit(d, n);
|
||||
case CRC_11784:
|
||||
return crc16_fdx(d, n);
|
||||
return crc16_fdxb(d, n);
|
||||
case CRC_LEGIC:
|
||||
// TODO
|
||||
return 0;
|
||||
|
@ -270,7 +270,7 @@ bool check_crc(CrcType_t ct, const uint8_t *d, size_t n) {
|
|||
case CRC_KERMIT:
|
||||
return (crc16_kermit(d, n) == 0);
|
||||
case CRC_11784:
|
||||
return (crc16_fdx(d, n) == 0);
|
||||
return (crc16_fdxb(d, n) == 0);
|
||||
case CRC_LEGIC:
|
||||
// TODO
|
||||
return false;
|
||||
|
@ -288,7 +288,7 @@ uint16_t crc16_ccitt(uint8_t const *d, size_t n) {
|
|||
|
||||
// FDX-B ISO11784/85) uses KERMIT/CCITT
|
||||
// poly 0x xx init=0x000 refin=false refout=true xorout=0x0000 ...
|
||||
uint16_t crc16_fdx(uint8_t const *d, size_t n) {
|
||||
uint16_t crc16_fdxb(uint8_t const *d, size_t n) {
|
||||
return crc16_fast(d, n, 0x0000, false, true);
|
||||
}
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ bool check_crc(CrcType_t ct, const uint8_t *d, size_t n);
|
|||
uint16_t crc16_ccitt(uint8_t const *d, size_t n);
|
||||
|
||||
// Calculate CRC-16/KERMIT (FDX-B ISO11784/85) LF
|
||||
uint16_t crc16_fdx(uint8_t const *d, size_t n);
|
||||
uint16_t crc16_fdxb(uint8_t const *d, size_t n);
|
||||
|
||||
// Calculate CRC-16/KERMIT
|
||||
uint16_t crc16_kermit(uint8_t const *d, size_t n);
|
||||
|
|
|
@ -1663,6 +1663,7 @@ int askdemod_ext(uint8_t *bits, size_t *size, int *clk, int *invert, int maxErr,
|
|||
return errCnt;
|
||||
}
|
||||
|
||||
*startIdx = start - (*clk / 2);
|
||||
if (g_debugMode == 2) prnt("DEBUG: (askdemod_ext) Weak wave detected: startIdx %i", *startIdx);
|
||||
|
||||
int lastBit; //set first clock check - can go negative
|
||||
|
|
|
@ -247,6 +247,7 @@ static int g_debuglog_enable = 1;
|
|||
/*-************************************
|
||||
* Types
|
||||
**************************************/
|
||||
#include <limits.h>
|
||||
#if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
|
||||
# include <stdint.h>
|
||||
typedef uint8_t BYTE;
|
||||
|
@ -256,7 +257,6 @@ typedef int32_t S32;
|
|||
typedef uint64_t U64;
|
||||
typedef uintptr_t uptrval;
|
||||
#else
|
||||
# include <limits.h>
|
||||
# if UINT_MAX != 4294967295UL
|
||||
# error "LZ4 code (when not C++ or C99) assumes that sizeof(int) == 4"
|
||||
# endif
|
||||
|
@ -322,6 +322,8 @@ static void LZ4_write32(void *memPtr, U32 value) { *(U32 *)memPtr = value; }
|
|||
typedef union { U16 u16; U32 u32; reg_t uArch; } __attribute__((packed)) unalign;
|
||||
|
||||
static U16 LZ4_read16(const void *ptr) { return ((const unalign *)ptr)->u16; }
|
||||
// Tolerate reads on buffer boundary
|
||||
ATTRIBUTE_NO_SANITIZE_ADDRESS
|
||||
static U32 LZ4_read32(const void *ptr) { return ((const unalign *)ptr)->u32; }
|
||||
static reg_t LZ4_read_ARCH(const void *ptr) { return ((const unalign *)ptr)->uArch; }
|
||||
|
||||
|
@ -1182,13 +1184,14 @@ _last_literals:
|
|||
if (outputDirective == fillOutput) {
|
||||
/* adapt lastRun to fill 'dst' */
|
||||
assert(olimit >= op);
|
||||
lastRun = (size_t)(olimit - op) - 1;
|
||||
lastRun -= (lastRun + 240) / 255;
|
||||
lastRun = (size_t)(olimit - op) - 1/*token*/;
|
||||
lastRun -= (lastRun + 256 - RUN_MASK) / 256; /*additional length tokens*/
|
||||
} else {
|
||||
assert(outputDirective == limitedOutput);
|
||||
return 0; /* cannot compress within `dst` budget. Stored indexes in hash table are nonetheless fine */
|
||||
}
|
||||
}
|
||||
DEBUGLOG(6, "Final literal run : %i literals", (int)lastRun);
|
||||
if (lastRun >= RUN_MASK) {
|
||||
size_t accumulator = lastRun - RUN_MASK;
|
||||
*op++ = RUN_MASK << ML_BITS;
|
||||
|
@ -1666,7 +1669,9 @@ typedef enum { decode_full_block = 0, partial_decode = 1 } earlyEnd_directive;
|
|||
*/
|
||||
typedef enum { loop_error = -2, initial_error = -1, ok = 0 } variable_length_error;
|
||||
LZ4_FORCE_INLINE unsigned
|
||||
read_variable_length(const BYTE **ip, const BYTE *lencheck, int loop_check, int initial_check, variable_length_error *error) {
|
||||
read_variable_length(const BYTE **ip, const BYTE *lencheck,
|
||||
int loop_check, int initial_check,
|
||||
variable_length_error *error) {
|
||||
U32 length = 0;
|
||||
U32 s;
|
||||
if (initial_check && unlikely((*ip) >= lencheck)) { /* overflow detection */
|
||||
|
@ -1767,7 +1772,7 @@ LZ4_decompress_generic(
|
|||
/* decode literal length */
|
||||
if (length == RUN_MASK) {
|
||||
variable_length_error error = ok;
|
||||
length += read_variable_length(&ip, iend - RUN_MASK, endOnInput, endOnInput, &error);
|
||||
length += read_variable_length(&ip, iend - RUN_MASK, (int)endOnInput, (int)endOnInput, &error);
|
||||
if (error == initial_error) { goto _output_error; }
|
||||
if ((safeDecode) && unlikely((uptrval)(op) + length < (uptrval)(op))) { goto _output_error; } /* overflow detection */
|
||||
if ((safeDecode) && unlikely((uptrval)(ip) + length < (uptrval)(ip))) { goto _output_error; } /* overflow detection */
|
||||
|
@ -1815,7 +1820,7 @@ LZ4_decompress_generic(
|
|||
if (length == ML_MASK) {
|
||||
variable_length_error error = ok;
|
||||
if ((checkOffset) && (unlikely(match + dictSize < lowPrefix))) { goto _output_error; } /* Error : offset outside buffers */
|
||||
length += read_variable_length(&ip, iend - LASTLITERALS + 1, endOnInput, 0, &error);
|
||||
length += read_variable_length(&ip, iend - LASTLITERALS + 1, (int)endOnInput, 0, &error);
|
||||
if (error != ok) { goto _output_error; }
|
||||
if ((safeDecode) && unlikely((uptrval)(op) + length < (uptrval)op)) { goto _output_error; } /* overflow detection */
|
||||
length += MINMATCH;
|
||||
|
@ -1844,7 +1849,7 @@ LZ4_decompress_generic(
|
|||
}
|
||||
}
|
||||
|
||||
if ((checkOffset) && (unlikely(match + dictSize < lowPrefix))) { goto _output_error; } /* Error : offset outside buffers */
|
||||
if (checkOffset && (unlikely(match + dictSize < lowPrefix))) { goto _output_error; } /* Error : offset outside buffers */
|
||||
/* match starting within external dictionary */
|
||||
if ((dict == usingExtDict) && (match < lowPrefix)) {
|
||||
if (unlikely(op + length > oend - LASTLITERALS)) {
|
||||
|
@ -1946,7 +1951,7 @@ safe_decode:
|
|||
/* decode literal length */
|
||||
if (length == RUN_MASK) {
|
||||
variable_length_error error = ok;
|
||||
length += read_variable_length(&ip, iend - RUN_MASK, endOnInput, endOnInput, &error);
|
||||
length += read_variable_length(&ip, iend - RUN_MASK, (int)endOnInput, (int)endOnInput, &error);
|
||||
if (error == initial_error) { goto _output_error; }
|
||||
if ((safeDecode) && unlikely((uptrval)(op) + length < (uptrval)(op))) { goto _output_error; } /* overflow detection */
|
||||
if ((safeDecode) && unlikely((uptrval)(ip) + length < (uptrval)(ip))) { goto _output_error; } /* overflow detection */
|
||||
|
@ -1997,7 +2002,12 @@ safe_literal_copy:
|
|||
/* We must be on the last sequence (or invalid) because of the parsing limitations
|
||||
* so check that we exactly consume the input and don't overrun the output buffer.
|
||||
*/
|
||||
if ((endOnInput) && ((ip + length != iend) || (cpy > oend))) { goto _output_error; }
|
||||
if ((endOnInput) && ((ip + length != iend) || (cpy > oend))) {
|
||||
DEBUGLOG(6, "should have been last run of literals")
|
||||
DEBUGLOG(6, "ip(%p) + length(%i) = %p != iend (%p)", ip, (int)length, ip + length, iend);
|
||||
DEBUGLOG(6, "or cpy(%p) > oend(%p)", cpy, oend);
|
||||
goto _output_error;
|
||||
}
|
||||
}
|
||||
memmove(op, ip, length); /* supports overlapping memory regions; only matters for in-place decompression scenarios */
|
||||
ip += length;
|
||||
|
@ -2027,7 +2037,7 @@ safe_literal_copy:
|
|||
_copy_match:
|
||||
if (length == ML_MASK) {
|
||||
variable_length_error error = ok;
|
||||
length += read_variable_length(&ip, iend - LASTLITERALS + 1, endOnInput, 0, &error);
|
||||
length += read_variable_length(&ip, iend - LASTLITERALS + 1, (int)endOnInput, 0, &error);
|
||||
if (error != ok) goto _output_error;
|
||||
if ((safeDecode) && unlikely((uptrval)(op) + length < (uptrval)op)) goto _output_error; /* overflow detection */
|
||||
}
|
||||
|
|
|
@ -42,6 +42,11 @@ extern "C" {
|
|||
/* --- Dependency --- */
|
||||
#include <stddef.h> /* size_t */
|
||||
|
||||
#if defined(__clang__) || defined (__GNUC__)
|
||||
# define ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address))
|
||||
#else
|
||||
# define ATTRIBUTE_NO_SANITIZE_ADDRESS
|
||||
#endif
|
||||
|
||||
/**
|
||||
Introduction
|
||||
|
@ -100,7 +105,7 @@ extern "C" {
|
|||
/*------ Version ------*/
|
||||
#define LZ4_VERSION_MAJOR 1 /* for breaking interface changes */
|
||||
#define LZ4_VERSION_MINOR 9 /* for new (non-breaking) interface capabilities */
|
||||
#define LZ4_VERSION_RELEASE 2 /* for tweaks, bug-fixes, or development */
|
||||
#define LZ4_VERSION_RELEASE 3 /* for tweaks, bug-fixes, or development */
|
||||
|
||||
#define LZ4_VERSION_NUMBER (LZ4_VERSION_MAJOR *100*100 + LZ4_VERSION_MINOR *100 + LZ4_VERSION_RELEASE)
|
||||
|
||||
|
|
|
@ -268,7 +268,7 @@ LZ4HC_InsertAndGetWiderMatch(
|
|||
DEBUGLOG(7, "First match at index %u / %u (lowestMatchIndex)",
|
||||
matchIndex, lowestMatchIndex);
|
||||
|
||||
while ((matchIndex >= lowestMatchIndex) && (nbAttempts)) {
|
||||
while ((matchIndex >= lowestMatchIndex) && (nbAttempts > 0)) {
|
||||
int matchLength = 0;
|
||||
nbAttempts--;
|
||||
assert(matchIndex < ipIndex);
|
||||
|
@ -424,7 +424,7 @@ LZ4HC_InsertAndGetWiderMatch(
|
|||
} /* while ((matchIndex>=lowestMatchIndex) && (nbAttempts)) */
|
||||
|
||||
if (dict == usingDictCtxHc
|
||||
&& nbAttempts
|
||||
&& nbAttempts > 0
|
||||
&& ipIndex - lowestMatchIndex < LZ4_DISTANCE_MAX) {
|
||||
size_t const dictEndOffset = (size_t)(dictCtx->end - dictCtx->base);
|
||||
U32 dictMatchIndex = dictCtx->hashTable[LZ4HC_hashPtr(ip)];
|
||||
|
@ -497,7 +497,7 @@ LZ4_FORCE_INLINE int LZ4HC_encodeSequence(
|
|||
U32 const cost = 1 + llAdd + ll + 2 + mlAdd;
|
||||
if (start == NULL) start = *anchor; /* only works for single segment */
|
||||
/* g_debuglog_enable = (pos >= 2228) & (pos <= 2262); */
|
||||
DEBUGLOG(6, "pos:%7u -- literals:%3u, match:%4i, offset:%5u, cost:%3u + %u",
|
||||
DEBUGLOG(6, "pos:%7u -- literals:%4u, match:%4i, offset:%5u, cost:%4u + %5u",
|
||||
pos,
|
||||
(U32)(*ip - *anchor), matchLength, (U32)(*ip - match),
|
||||
cost, totalCost);
|
||||
|
@ -506,7 +506,13 @@ LZ4_FORCE_INLINE int LZ4HC_encodeSequence(
|
|||
|
||||
/* Encode Literal length */
|
||||
length = (size_t)(*ip - *anchor);
|
||||
if ((limit) && ((*op + (length / 255) + length + (2 + 1 + LASTLITERALS)) > oend)) return 1; /* Check output limit */
|
||||
LZ4_STATIC_ASSERT(notLimited == 0);
|
||||
/* Check output limit */
|
||||
if (limit && ((*op + (length / 255) + length + (2 + 1 + LASTLITERALS)) > oend)) {
|
||||
DEBUGLOG(6, "Not enough room to write %i literals (%i bytes remaining)",
|
||||
(int)length, (int)(oend - *op));
|
||||
return 1;
|
||||
}
|
||||
if (length >= RUN_MASK) {
|
||||
size_t len = length - RUN_MASK;
|
||||
*token = (RUN_MASK << ML_BITS);
|
||||
|
@ -528,7 +534,10 @@ LZ4_FORCE_INLINE int LZ4HC_encodeSequence(
|
|||
/* Encode MatchLength */
|
||||
assert(matchLength >= MINMATCH);
|
||||
length = (size_t)matchLength - MINMATCH;
|
||||
if ((limit) && (*op + (length / 255) + (1 + LASTLITERALS) > oend)) return 1; /* Check output limit */
|
||||
if (limit && (*op + (length / 255) + (1 + LASTLITERALS) > oend)) {
|
||||
DEBUGLOG(6, "Not enough room to write match length");
|
||||
return 1; /* Check output limit */
|
||||
}
|
||||
if (length >= ML_MASK) {
|
||||
*token += ML_MASK;
|
||||
length -= ML_MASK;
|
||||
|
@ -552,7 +561,7 @@ LZ4_FORCE_INLINE int LZ4HC_compress_hashChain(
|
|||
char *const dest,
|
||||
int *srcSizePtr,
|
||||
int const maxOutputSize,
|
||||
unsigned maxNbAttempts,
|
||||
int maxNbAttempts,
|
||||
const limitedOutput_directive limit,
|
||||
const dictCtx_directive dict
|
||||
) {
|
||||
|
@ -581,7 +590,7 @@ LZ4_FORCE_INLINE int LZ4HC_compress_hashChain(
|
|||
/* init */
|
||||
*srcSizePtr = 0;
|
||||
if (limit == fillOutput) oend -= LASTLITERALS; /* Hack for support LZ4 format restriction */
|
||||
if (inputSize < LZ4_minLength) goto _last_literals; /* Input too small, no compression (all literals) */
|
||||
if (inputSize < LZ4_minLength) goto _last_literals; /* Input too small, no compression (all literals) */
|
||||
|
||||
/* Main Loop */
|
||||
while (ip <= mflimit) {
|
||||
|
@ -658,7 +667,11 @@ _Search3:
|
|||
if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow;
|
||||
ip = start2;
|
||||
optr = op;
|
||||
if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml2, ref2, limit, oend)) goto _dest_overflow;
|
||||
if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml2, ref2, limit, oend)) {
|
||||
ml = ml2;
|
||||
ref = ref2;
|
||||
goto _dest_overflow;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -735,17 +748,18 @@ _last_literals:
|
|||
/* Encode Last Literals */
|
||||
{
|
||||
size_t lastRunSize = (size_t)(iend - anchor); /* literals */
|
||||
size_t litLength = (lastRunSize + 255 - RUN_MASK) / 255;
|
||||
size_t const totalSize = 1 + litLength + lastRunSize;
|
||||
size_t llAdd = (lastRunSize + 255 - RUN_MASK) / 255;
|
||||
size_t const totalSize = 1 + llAdd + lastRunSize;
|
||||
if (limit == fillOutput) oend += LASTLITERALS; /* restore correct value */
|
||||
if (limit && (op + totalSize > oend)) {
|
||||
if (limit == limitedOutput) return 0; /* Check output limit */
|
||||
if (limit == limitedOutput) return 0;
|
||||
/* adapt lastRunSize to fill 'dest' */
|
||||
lastRunSize = (size_t)(oend - op) - 1;
|
||||
litLength = (lastRunSize + 255 - RUN_MASK) / 255;
|
||||
lastRunSize -= litLength;
|
||||
lastRunSize = (size_t)(oend - op) - 1 /*token*/;
|
||||
llAdd = (lastRunSize + 256 - RUN_MASK) / 256;
|
||||
lastRunSize -= llAdd;
|
||||
}
|
||||
ip = anchor + lastRunSize;
|
||||
DEBUGLOG(6, "Final literal run : %i literals", (int)lastRunSize);
|
||||
ip = anchor + lastRunSize; /* can be != iend if limit==fillOutput */
|
||||
|
||||
if (lastRunSize >= RUN_MASK) {
|
||||
size_t accumulator = lastRunSize - RUN_MASK;
|
||||
|
@ -765,9 +779,27 @@ _last_literals:
|
|||
|
||||
_dest_overflow:
|
||||
if (limit == fillOutput) {
|
||||
/* Assumption : ip, anchor, ml and ref must be set correctly */
|
||||
size_t const ll = (size_t)(ip - anchor);
|
||||
size_t const ll_addbytes = (ll + 240) / 255;
|
||||
size_t const ll_totalCost = 1 + ll_addbytes + ll;
|
||||
BYTE *const maxLitPos = oend - 3; /* 2 for offset, 1 for token */
|
||||
DEBUGLOG(6, "Last sequence overflowing");
|
||||
op = optr; /* restore correct out pointer */
|
||||
if (op + ll_totalCost <= maxLitPos) {
|
||||
/* ll validated; now adjust match length */
|
||||
size_t const bytesLeftForMl = (size_t)(maxLitPos - (op + ll_totalCost));
|
||||
size_t const maxMlSize = MINMATCH + (ML_MASK - 1) + (bytesLeftForMl * 255);
|
||||
assert(maxMlSize < INT_MAX);
|
||||
assert(ml >= 0);
|
||||
if ((size_t)ml > maxMlSize) ml = (int)maxMlSize;
|
||||
if ((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1 + ml >= MFLIMIT) {
|
||||
LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, notLimited, oend);
|
||||
}
|
||||
}
|
||||
goto _last_literals;
|
||||
}
|
||||
/* compression failed */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -794,7 +826,7 @@ LZ4_FORCE_INLINE int LZ4HC_compress_generic_internal(
|
|||
typedef enum { lz4hc, lz4opt } lz4hc_strat_e;
|
||||
typedef struct {
|
||||
lz4hc_strat_e strat;
|
||||
U32 nbSearches;
|
||||
int nbSearches;
|
||||
U32 targetLength;
|
||||
} cParams_t;
|
||||
static const cParams_t clTable[LZ4HC_CLEVEL_MAX + 1] = {
|
||||
|
@ -813,7 +845,8 @@ LZ4_FORCE_INLINE int LZ4HC_compress_generic_internal(
|
|||
{ lz4opt, 16384, LZ4_OPT_NUM }, /* 12==LZ4HC_CLEVEL_MAX */
|
||||
};
|
||||
|
||||
DEBUGLOG(4, "LZ4HC_compress_generic(ctx=%p, src=%p, srcSize=%d)", ctx, src, *srcSizePtr);
|
||||
DEBUGLOG(4, "LZ4HC_compress_generic(ctx=%p, src=%p, srcSize=%d, limit=%d)",
|
||||
ctx, src, *srcSizePtr, limit);
|
||||
|
||||
if (limit == fillOutput && dstCapacity < 1) return 0; /* Impossible to store anything */
|
||||
if ((U32)*srcSizePtr > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported input size (too large or negative) */
|
||||
|
@ -834,7 +867,7 @@ LZ4_FORCE_INLINE int LZ4HC_compress_generic_internal(
|
|||
assert(cParam.strat == lz4opt);
|
||||
result = LZ4HC_compress_optimal(ctx,
|
||||
src, dst, srcSizePtr, dstCapacity,
|
||||
(int)cParam.nbSearches, cParam.targetLength, limit,
|
||||
cParam.nbSearches, cParam.targetLength, limit,
|
||||
cLevel == LZ4HC_CLEVEL_MAX, /* ultra mode */
|
||||
dict, favor);
|
||||
}
|
||||
|
@ -967,10 +1000,12 @@ int LZ4_compress_HC_destSize(void *state, const char *source, char *dest, int *s
|
|||
**************************************/
|
||||
/* allocation */
|
||||
LZ4_streamHC_t *LZ4_createStreamHC(void) {
|
||||
LZ4_streamHC_t *const LZ4_streamHCPtr = (LZ4_streamHC_t *)ALLOC(sizeof(LZ4_streamHC_t));
|
||||
if (LZ4_streamHCPtr == NULL) return NULL;
|
||||
LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr)); /* full initialization, malloc'ed buffer can be full of garbage */
|
||||
return LZ4_streamHCPtr;
|
||||
LZ4_streamHC_t *const state = (LZ4_streamHC_t *)ALLOC(sizeof(LZ4_streamHC_t));
|
||||
if (LZ4_initStreamHC(state, sizeof(*state)) == NULL) {
|
||||
free(state);
|
||||
return NULL;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
int LZ4_freeStreamHC(LZ4_streamHC_t *LZ4_streamHCPtr) {
|
||||
|
@ -980,7 +1015,10 @@ int LZ4_freeStreamHC(LZ4_streamHC_t *LZ4_streamHCPtr) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// Skip AddressSanitizer which breaks compilation strangely on
|
||||
// lz4/lz4hc.c: error: writing 2 bytes into a region of size 1 [-Werror=stringop-overflow=]
|
||||
// | LZ4_streamHCPtr->internal_donotuse.favorDecSpeed = 0;
|
||||
ATTRIBUTE_NO_SANITIZE_ADDRESS
|
||||
LZ4_streamHC_t *LZ4_initStreamHC(void *buffer, size_t size) {
|
||||
LZ4_streamHC_t *const LZ4_streamHCPtr = (LZ4_streamHC_t *)buffer;
|
||||
if (buffer == NULL) return NULL;
|
||||
|
@ -1084,8 +1122,8 @@ static int LZ4_compressHC_continue_generic(LZ4_streamHC_t *LZ4_streamHCPtr,
|
|||
int *srcSizePtr, int dstCapacity,
|
||||
limitedOutput_directive limit) {
|
||||
LZ4HC_CCtx_internal *const ctxPtr = &LZ4_streamHCPtr->internal_donotuse;
|
||||
DEBUGLOG(4, "LZ4_compressHC_continue_generic(ctx=%p, src=%p, srcSize=%d)",
|
||||
LZ4_streamHCPtr, src, *srcSizePtr);
|
||||
DEBUGLOG(5, "LZ4_compressHC_continue_generic(ctx=%p, src=%p, srcSize=%d, limit=%d)",
|
||||
LZ4_streamHCPtr, src, *srcSizePtr, limit);
|
||||
assert(ctxPtr != NULL);
|
||||
/* auto-init if forgotten */
|
||||
if (ctxPtr->base == NULL) LZ4HC_init_internal(ctxPtr, (const BYTE *) src);
|
||||
|
@ -1301,6 +1339,8 @@ static int LZ4HC_compress_optimal(LZ4HC_CCtx_internal *ctx,
|
|||
BYTE *op = (BYTE *) dst;
|
||||
BYTE *opSaved = (BYTE *) dst;
|
||||
BYTE *oend = op + dstCapacity;
|
||||
int ovml = MINMATCH; /* overflow - last sequence */
|
||||
const BYTE *ovref = NULL;
|
||||
|
||||
/* init */
|
||||
#ifdef LZ4HC_HEAPMODE
|
||||
|
@ -1312,7 +1352,6 @@ static int LZ4HC_compress_optimal(LZ4HC_CCtx_internal *ctx,
|
|||
if (sufficient_len >= LZ4_OPT_NUM) sufficient_len = LZ4_OPT_NUM - 1;
|
||||
|
||||
/* Main Loop */
|
||||
assert(ip - anchor < LZ4_MAX_INPUT_SIZE);
|
||||
while (ip <= mflimit) {
|
||||
int const llen = (int)(ip - anchor);
|
||||
int best_mlen, best_off;
|
||||
|
@ -1326,8 +1365,11 @@ static int LZ4HC_compress_optimal(LZ4HC_CCtx_internal *ctx,
|
|||
int const firstML = firstMatch.len;
|
||||
const BYTE *const matchPos = ip - firstMatch.off;
|
||||
opSaved = op;
|
||||
if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), firstML, matchPos, limit, oend)) /* updates ip, op and anchor */
|
||||
if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), firstML, matchPos, limit, oend)) { /* updates ip, op and anchor */
|
||||
ovml = firstML;
|
||||
ovref = matchPos;
|
||||
goto _dest_overflow;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1516,8 +1558,11 @@ encode: /* cur, last_match_pos, best_mlen, best_off must be set */
|
|||
assert(ml >= MINMATCH);
|
||||
assert((offset >= 1) && (offset <= LZ4_DISTANCE_MAX));
|
||||
opSaved = op;
|
||||
if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ip - offset, limit, oend)) /* updates ip, op and anchor */
|
||||
if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ip - offset, limit, oend)) { /* updates ip, op and anchor */
|
||||
ovml = ml;
|
||||
ovref = ip - offset;
|
||||
goto _dest_overflow;
|
||||
}
|
||||
}
|
||||
}
|
||||
} /* while (ip <= mflimit) */
|
||||
|
@ -1526,8 +1571,8 @@ _last_literals:
|
|||
/* Encode Last Literals */
|
||||
{
|
||||
size_t lastRunSize = (size_t)(iend - anchor); /* literals */
|
||||
size_t litLength = (lastRunSize + 255 - RUN_MASK) / 255;
|
||||
size_t const totalSize = 1 + litLength + lastRunSize;
|
||||
size_t llAdd = (lastRunSize + 255 - RUN_MASK) / 255;
|
||||
size_t const totalSize = 1 + llAdd + lastRunSize;
|
||||
if (limit == fillOutput) oend += LASTLITERALS; /* restore correct value */
|
||||
if (limit && (op + totalSize > oend)) {
|
||||
if (limit == limitedOutput) { /* Check output limit */
|
||||
|
@ -1535,11 +1580,12 @@ _last_literals:
|
|||
goto _return_label;
|
||||
}
|
||||
/* adapt lastRunSize to fill 'dst' */
|
||||
lastRunSize = (size_t)(oend - op) - 1;
|
||||
litLength = (lastRunSize + 255 - RUN_MASK) / 255;
|
||||
lastRunSize -= litLength;
|
||||
lastRunSize = (size_t)(oend - op) - 1 /*token*/;
|
||||
llAdd = (lastRunSize + 256 - RUN_MASK) / 256;
|
||||
lastRunSize -= llAdd;
|
||||
}
|
||||
ip = anchor + lastRunSize;
|
||||
DEBUGLOG(6, "Final literal run : %i literals", (int)lastRunSize);
|
||||
ip = anchor + lastRunSize; /* can be != iend if limit==fillOutput */
|
||||
|
||||
if (lastRunSize >= RUN_MASK) {
|
||||
size_t accumulator = lastRunSize - RUN_MASK;
|
||||
|
@ -1560,7 +1606,27 @@ _last_literals:
|
|||
|
||||
_dest_overflow:
|
||||
if (limit == fillOutput) {
|
||||
/* Assumption : ip, anchor, ovml and ovref must be set correctly */
|
||||
size_t const ll = (size_t)(ip - anchor);
|
||||
size_t const ll_addbytes = (ll + 240) / 255;
|
||||
size_t const ll_totalCost = 1 + ll_addbytes + ll;
|
||||
BYTE *const maxLitPos = oend - 3; /* 2 for offset, 1 for token */
|
||||
DEBUGLOG(6, "Last sequence overflowing (only %i bytes remaining)", (int)(oend - 1 - opSaved));
|
||||
op = opSaved; /* restore correct out pointer */
|
||||
if (op + ll_totalCost <= maxLitPos) {
|
||||
/* ll validated; now adjust match length */
|
||||
size_t const bytesLeftForMl = (size_t)(maxLitPos - (op + ll_totalCost));
|
||||
size_t const maxMlSize = MINMATCH + (ML_MASK - 1) + (bytesLeftForMl * 255);
|
||||
assert(maxMlSize < INT_MAX);
|
||||
assert(ovml >= 0);
|
||||
if ((size_t)ovml > maxMlSize) ovml = (int)maxMlSize;
|
||||
if ((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1 + ovml >= MFLIMIT) {
|
||||
DEBUGLOG(6, "Space to end : %i + ml (%i)", (int)((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1), ovml);
|
||||
DEBUGLOG(6, "Before : ip = %p, anchor = %p", ip, anchor);
|
||||
LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ovml, ovref, notLimited, oend);
|
||||
DEBUGLOG(6, "After : ip = %p, anchor = %p", ip, anchor);
|
||||
}
|
||||
}
|
||||
goto _last_literals;
|
||||
}
|
||||
_return_label:
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue