Merge pull request #54 from RfidResearchGroup/master

Update
This commit is contained in:
mwalker33 2020-10-12 15:26:15 +11:00 committed by GitHub
commit 46fe7d1292
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
139 changed files with 25421 additions and 23275 deletions

1
.lsan_suppressions Normal file
View file

@ -0,0 +1 @@
leak:libfontconfig.so

View file

@ -248,7 +248,7 @@ print-%: ; @echo $* = $($*)
style: style:
# Make sure astyle is installed # Make sure astyle is installed
@which astyle >/dev/null || ( echo "Please install 'astyle' package first" ; exit 1 ) @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" \) \) \ 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 perl -pi -e 's/[ \t]+$$//' {} \; \
-exec sh -c "tail -c1 {} | xxd -p | tail -1 | grep -q -v 0a$$" \; \ -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 \ --keep-one-line-blocks --max-instatement-indent=60 \
--style=google --pad-oper --unpad-paren --pad-header \ --style=google --pad-oper --unpad-paren --pad-header \
--align-pointer=name {} \; --align-pointer=name {} \;
# Update commands.md
[ -x client/proxmark3 ] && client/proxmark3 -m > doc/commands.md
# Detecting weird codepages and tabs. # 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: miscchecks:
# Make sure recode is installed # Make sure recode is installed
@which recode >/dev/null || ( echo "Please install 'recode' package first" ; exit 1 ) @which recode >/dev/null || ( echo "Please install 'recode' package first" ; exit 1 )
@echo "Files with suspicious chars:" @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 {}" \; -exec sh -c "cat {} |recode utf8.. >/dev/null || echo {}" \;
@echo "Files with tabs:" ifneq (,$(EDIT))
# to remove tabs within lines, one can try with: vi $file -c ':set tabstop=4' -c ':set et|retab' -c ':wq' @echo "Files with tabs: (EDIT enabled, files will be rewritten!)"
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' {} \;
else 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" \) \ @echo "Files with tabs: (rerun with EDIT=1 if you want to convert them with vim)"
-exec grep -lP '\t' {} \;
endif 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:" # @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" \) \ # @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' {} \; # -exec grep -lP '\\t' {} \;

View file

@ -50,6 +50,13 @@ endif
DEFCXXFLAGS = -Wall -Werror -O3 -pipe DEFCXXFLAGS = -Wall -Werror -O3 -pipe
DEFCFLAGS = -Wall -Werror -O3 -fstrict-aliasing -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: # 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 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: # Some more warnings we need first to eliminate, so temporarely tolerated:

View file

@ -19,6 +19,7 @@ CFLAGS ?= $(DEFCFLAGS)
CFLAGS += $(MYDEFS) $(MYCFLAGS) $(MYINCLUDES) CFLAGS += $(MYDEFS) $(MYCFLAGS) $(MYINCLUDES)
CXXFLAGS ?= $(DEFCXXFLAGS) CXXFLAGS ?= $(DEFCXXFLAGS)
CXXFLAGS += $(MYDEFS) $(MYCXXFLAGS) $(MYINCLUDES) CXXFLAGS += $(MYDEFS) $(MYCXXFLAGS) $(MYINCLUDES)
LDFLAGS ?= $(DEFLDFLAGS)
LDFLAGS += $(MYLDFLAGS) LDFLAGS += $(MYLDFLAGS)
LDLIBS += $(MYLDLIBS) LDLIBS += $(MYLDLIBS)

View file

@ -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 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 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)| |[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)| |[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)| |[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 This repo compiles nicely on
- Proxspace v3.x - 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 - Windows/mingw environment with Qt5.6.1 & GCC 4.9
- Ubuntu 16.04 -> 20.04 - Ubuntu 16.04 -> 20.04
- ParrotOS, Gentoo, Pentoo, Kali, Nethunter, Archlinux, Fedora, Debian - ParrotOS, Gentoo, Pentoo, Kali, Nethunter, Archlinux, Fedora, Debian

View file

@ -2,14 +2,14 @@ version: 3.0.1.{build}
image: Visual Studio 2019 image: Visual Studio 2019
clone_folder: C:\ProxSpace\pm3\proxmark clone_folder: C:\ProxSpace\pm3\proxmark
cache: cache:
- C:\cache -> appveyor.yml - C:\ps-cache -> appveyor.yml
environment: environment:
proxspace_url: https://github.com/Gator96100/ProxSpace/archive/master.zip proxspace_url: https://github.com/Gator96100/ProxSpace/archive/master.zip
proxspace_zip_file: \proxspace.zip proxspace_zip_file: \proxspace.zip
proxspace_zip_folder_name: ProxSpace-* proxspace_zip_folder_name: ProxSpace-*
proxspace_path: C:\ProxSpace proxspace_path: C:\ProxSpace
proxspace_home_path: \ProxSpace\pm3 proxspace_home_path: \ProxSpace\pm3
proxspace_cache_path: C:\cache proxspace_cache_path: C:\ps-cache
wsl_git_path: C:\proxmark wsl_git_path: C:\proxmark
APPVEYOR_SAVE_CACHE_ON_ERROR: true APPVEYOR_SAVE_CACHE_ON_ERROR: true
@ -29,7 +29,6 @@ init:
$releasename+=$env:APPVEYOR_BUILD_VERSION + " [" + $env:APPVEYOR_REPO_COMMIT_SHORT + "]" $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 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" 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 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" 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 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 $env:PSInstallTime=[System.Environment]::TickCount
@ -154,8 +154,9 @@ install:
} }
Start-Sleep -s 5 Start-Sleep -s 5
Receive-Job -Name WSLInstall Receive-Job -Name WSLInstall -ErrorAction SilentlyContinue
} }
#Receive-Job -Wait -Name PSInstall
} }
Function GitClone($Text, $Folder) { Function GitClone($Text, $Folder) {
@ -175,7 +176,9 @@ install:
Write-Host "ProxSpace: move cache..." -NoNewLine 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 Write-Host "[ OK ]" -ForegroundColor Gree
@ -212,6 +215,7 @@ build_script:
$WSLjob = Start-Job -Name WSLCompile -ScriptBlock { $WSLjob = Start-Job -Name WSLCompile -ScriptBlock {
Function ExecWSLCmd($Cmd) { Function ExecWSLCmd($Cmd) {
cd $env:wsl_git_path
wsl -- bash -c $Cmd wsl -- bash -c $Cmd
} }
@ -231,11 +235,17 @@ build_script:
} }
#WSL: wait for installation to finish #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) #Windows Subsystem for Linux (WSL)
Write-Host "---------- WSL make ----------" -ForegroundColor Yellow Write-Host "---------- WSL make ----------" -ForegroundColor Yellow
cd $env:wsl_git_path
$TestTime=[System.Environment]::TickCount $TestTime=[System.Environment]::TickCount
ExecWSLCmd "make clean;make V=1" ExecWSLCmd "make clean;make V=1"
#some checks #some checks
@ -266,7 +276,9 @@ build_script:
Write-Host "ProxSpace: create new cache..." -NoNewLine 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 Remove-Item -Recurse -Force -Path "$env:proxspace_cache_path" -ErrorAction SilentlyContinue
@ -316,8 +328,9 @@ build_script:
ExecCheck "PS cmake Tests" ExecCheck "PS cmake Tests"
Receive-Job -Wait -Job $WSLjob Receive-Job -Wait -Name WSLInstall -ErrorAction SilentlyContinue
Receive-Job -Wait -Job $WSLjob
test_script: test_script:
- ps: >- - ps: >-

View file

@ -147,14 +147,18 @@ void RunMod(void) {
int state = STATE_SEARCH; int state = STATE_SEARCH;
DbpString("Scanning..."); DbpString("Scanning...");
int button_pressed = BUTTON_NO_CLICK;
for (;;) { for (;;) {
// Was our button held down or pressed? // 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()) if (button_pressed != BUTTON_NO_CLICK || data_available())
break; break;
else if (state == STATE_SEARCH) { else if (state == STATE_SEARCH) {
if (!iso14443a_select_card(NULL, &card, NULL, true, 0, true)) { if (!iso14443a_select_card(NULL, &card, NULL, true, 0, true)) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LED_D_OFF();
SpinDelay(500);
continue; continue;
} else { } else {
if (card.sak == SAK && card.atqa[0] == ATQA0 && card.atqa[1] == ATQA1 && card.uidlen == 7) { 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; state = STATE_SEARCH;
} }
} }
if (button_pressed == BUTTON_HOLD) //Holding down the button
break;
} }
DbpString("exiting"); DbpString("exiting");

View file

@ -484,22 +484,18 @@ failtag:
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
SpinOff(50); SpinOff(50);
LED_A_ON(); LED_A_ON();
uint8_t ticker = 0;
while (!iso14443a_select_card(cjuid, &p_card, &cjcuid, true, 0, true)) { while (!iso14443a_select_card(cjuid, &p_card, &cjcuid, true, 0, true)) {
WDT_HIT(); WDT_HIT();
ticker++;
if (ticker % 64 == 0) {
LED_A_INV();
}
if (BUTTON_HELD(10) == BUTTON_HOLD) { if (BUTTON_HELD(10) == BUTTON_HOLD) {
WDT_HIT(); WDT_HIT();
DbprintfEx(FLAG_NEWLINE, "\t\t\t[ READING FLASH ]"); DbprintfEx(FLAG_NEWLINE, "\t\t\t[ READING FLASH ]");
ReadLastTagFromFlash(); ReadLastTagFromFlash();
goto readysim; goto readysim;
} }
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
SpinDelay(500);
LED_A_INV();
} }
SpinOff(50); SpinOff(50);

View file

@ -125,7 +125,7 @@ static void download_instructions(uint8_t t) {
case ICE_STATE_FULLSIM: { case ICE_STATE_FULLSIM: {
DbpString("The emulator memory was saved to SPIFFS"); 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("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; break;
} }
case ICE_STATE_ATTACK: { case ICE_STATE_ATTACK: {

View file

@ -575,4 +575,5 @@ void RunMod(void) {
} }
} }
} }
LEDsoff();
} }

View file

@ -305,6 +305,8 @@ void RunMod(void) {
DbpString("\n"_YELLOW_("!!") "Waiting for a card reader..."); DbpString("\n"_YELLOW_("!!") "Waiting for a card reader...");
} }
} }
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LED_D_OFF();
} else if (state == STATE_EMU) { } else if (state == STATE_EMU) {
LED_A_OFF(); LED_A_OFF();
LED_C_ON(); LED_C_ON();

View file

@ -54,7 +54,7 @@ void RunMod(void) {
for (;;) { for (;;) {
WDT_HIT(); WDT_HIT();
// exit from Standalone Mode, send a usbcommand. // exit from Standalone Mode, send a usbcommand.
if (data_available()) return; if (data_available()) break;
SpinDelay(300); SpinDelay(300);
@ -72,7 +72,7 @@ void RunMod(void) {
for (;;) { for (;;) {
// exit from Standalone Mode, send a usbcommand. // exit from Standalone Mode, send a usbcommand.
if (data_available()) return; if (data_available()) break;
if (BUTTON_PRESS()) { if (BUTTON_PRESS()) {
if (cardRead[selected]) { if (cardRead[selected]) {
@ -89,6 +89,9 @@ void RunMod(void) {
} }
if (!iso14443a_select_card(NULL, &card[selected], NULL, true, 0, true)) { if (!iso14443a_select_card(NULL, &card[selected], NULL, true, 0, true)) {
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
LED_D_OFF();
SpinDelay(500);
continue; continue;
} else { } else {
Dbprintf("Read UID:"); Dbprintf("Read UID:");
@ -220,7 +223,7 @@ void RunMod(void) {
DbpString("Playing"); DbpString("Playing");
for (; ;) { for (; ;) {
// exit from Standalone Mode, send a usbcommand. // exit from Standalone Mode, send a usbcommand.
if (data_available()) return; if (data_available()) break;
int button_pressed = BUTTON_HELD(1000); int button_pressed = BUTTON_HELD(1000);
if (button_pressed == BUTTON_NO_CLICK) { // No button action, proceed with sim if (button_pressed == BUTTON_NO_CLICK) { // No button action, proceed with sim
@ -277,4 +280,6 @@ void RunMod(void) {
LED(selected + 1, 0); LED(selected + 1, 0);
} }
} }
DbpString(_YELLOW_("[=]") "exiting");
LEDsoff();
} }

View file

@ -68,6 +68,24 @@ extern uint32_t _stack_start, _stack_end;
struct common_area common_area __attribute__((section(".commonarea"))); struct common_area common_area __attribute__((section(".commonarea")));
static int button_status = BUTTON_NO_CLICK; static int button_status = BUTTON_NO_CLICK;
static bool allow_send_wtx = false; 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) { void send_wtx(uint16_t wtx) {
if (allow_send_wtx) { if (allow_send_wtx) {
@ -731,6 +749,24 @@ static void PacketReceived(PacketCommandNG *packet) {
reply_ng(CMD_SET_DBGMODE, PM3_SUCCESS, NULL, 0); reply_ng(CMD_SET_DBGMODE, PM3_SUCCESS, NULL, 0);
break; 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 // always available
case CMD_HF_DROPFIELD: { case CMD_HF_DROPFIELD: {
hf_field_off(); hf_field_off();
@ -827,7 +863,8 @@ static void PacketReceived(PacketCommandNG *packet) {
break; break;
} }
case CMD_LF_HID_CLONE: { 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; break;
} }
case CMD_LF_IO_WATCH: { case CMD_LF_IO_WATCH: {
@ -954,6 +991,16 @@ static void PacketReceived(PacketCommandNG *packet) {
EM4xWriteWord(payload->address, payload->data, payload->password, payload->usepwd); EM4xWriteWord(payload->address, payload->data, payload->password, payload->usepwd);
break; 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: { case CMD_LF_AWID_WATCH: {
uint32_t high, low; uint32_t high, low;
int res = lf_awid_watch(0, &high, &low); int res = lf_awid_watch(0, &high, &low);

View file

@ -16,6 +16,8 @@
extern int g_rsamples; // = 0; extern int g_rsamples; // = 0;
extern uint8_t g_trigger; 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 // 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 #define MAX_ADC_HF_VOLTAGE 36300
// ADC Vref = 3300mV, (240k-10M):240k voltage divider, 140800 mV // ADC Vref = 3300mV, (240k-10M):240k voltage divider, 140800 mV

View file

@ -134,11 +134,36 @@ static hf14a_config hf14aconfig = { 0, 0, 0, 0, 0 } ;
void printHf14aConfig(void) { void printHf14aConfig(void) {
DbpString(_CYAN_("HF 14a config")); 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(" [a] Anticol override....%i %s%s%s",
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") : ""); hf14aconfig.forceanticol,
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") : ""); (hf14aconfig.forceanticol == 0) ? "( " _GREEN_("No") " ) follow standard " : "",
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") : ""); (hf14aconfig.forceanticol == 1) ? "( " _RED_("Yes") " ) always do anticol" : "",
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") : ""); (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" : ""
);
} }
/** /**

View file

@ -996,7 +996,7 @@ static int Get14443bAnswerFromTag(uint8_t *response, uint16_t max_len, int timeo
if (Handle14443bSamplesFromTag(ci, cq)) { 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) { if (Demod.len > Demod.max_len) {
ret = -2; // overflow ret = -2; // overflow
@ -1854,7 +1854,7 @@ void SendRawCommand14443B_Ex(PacketCommandNG *c) {
int status; int status;
uint32_t sendlen = sizeof(iso14b_card_select_t); uint32_t sendlen = sizeof(iso14b_card_select_t);
iso14b_card_select_t card; iso14b_card_select_t card;
memset((void*)&card, 0x00, sizeof(card)); memset((void *)&card, 0x00, sizeof(card));
if ((param & ISO14B_SELECT_STD) == ISO14B_SELECT_STD) { if ((param & ISO14B_SELECT_STD) == ISO14B_SELECT_STD) {
status = iso14443b_select_card(&card); status = iso14443b_select_card(&card);

View file

@ -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_LOGIN 0xC
#define FWD_CMD_WRITE 0xA #define FWD_CMD_WRITE 0xA
#define FWD_CMD_READ 0x9 #define FWD_CMD_READ 0x9
#define FWD_CMD_PROTECT 0x3
#define FWD_CMD_DISABLE 0x5 #define FWD_CMD_DISABLE 0x5
static uint8_t forwardLink_data[64]; //array of forwarded bits 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); SendForward(len);
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? // Wait 20ms for write to complete?
WaitMS(7); // 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); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
reply_ng(CMD_LF_EM4X_WRITEWORD, PM3_SUCCESS, NULL, 0); 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);
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(); LEDsoff();
} }

View file

@ -58,6 +58,7 @@ void TurnReadLFOn(uint32_t delay);
void EM4xReadWord(uint8_t addr, uint32_t pwd, uint8_t usepwd); 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 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 Cotag(uint32_t arg0);
void setT55xxConfig(uint8_t arg0, t55xx_configurations_t *c); void setT55xxConfig(uint8_t arg0, t55xx_configurations_t *c);

View file

@ -2702,25 +2702,24 @@ void MifareU_Otp_Tearoff(uint8_t arg0, uint32_t arg1, uint8_t *datain) {
uint8_t data_testwrite[4] = {0x00}; uint8_t data_testwrite[4] = {0x00};
memcpy(data_fullwrite, datain, 4); memcpy(data_fullwrite, datain, 4);
memcpy(data_testwrite, datain + 4, 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(); LEDsoff();
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
clear_trace(); clear_trace();
set_tracing(true); set_tracing(true);
StartTicks();
// write cmd to send, include CRC // write cmd to send, include CRC
// 1b write, 1b block, 4b data, 2 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}; 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); AddCrc14A(cmd, sizeof(cmd) - 2);
if (DBGLEVEL >= DBG_ERROR) DbpString("Transmitting");
// anticollision / select card // anticollision / select card
if (!iso14443a_select_card(NULL, NULL, NULL, true, 0, true)) { if (!iso14443a_select_card(NULL, NULL, NULL, true, 0, true)) {
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card"); 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 // Wait before cutting power. aka tear-off
LED_D_ON(); LED_D_ON();
WaitUS(tearOffTime);
SpinDelayUsPrecision(tearOffTime);
if (DBGLEVEL >= DBG_DEBUG) Dbprintf(_YELLOW_("OTP tear-off triggered!"));
switch_off(); switch_off();
reply_ng(CMD_HF_MFU_OTP_TEAROFF, PM3_SUCCESS, NULL, 0); reply_ng(CMD_HF_MFU_OTP_TEAROFF, PM3_SUCCESS, NULL, 0);
StopTicks();
if (DBGLEVEL >= DBG_ERROR) DbpString("Done");
} }

View file

@ -13,6 +13,31 @@
#include "proxmark3_arm.h" #include "proxmark3_arm.h"
#include "dbprint.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 // timer counts in 21.3us increments (1024/48MHz), rounding applies
// WARNING: timer can't measure more than 1.39s (21.3us * 0xffff) // WARNING: timer can't measure more than 1.39s (21.3us * 0xffff)
void SpinDelayUs(int us) { void SpinDelayUs(int us) {

View file

@ -20,6 +20,7 @@
void SpinDelay(int ms); void SpinDelay(int ms);
void SpinDelayUs(int us); void SpinDelayUs(int us);
void SpinDelayUsPrecision(int us); // precision 0.6us , running for 43ms before
void StartTickCount(void); void StartTickCount(void);
uint32_t RAMFUNC GetTickCount(void); uint32_t RAMFUNC GetTickCount(void);

View file

@ -248,7 +248,7 @@ set (TARGET_SOURCES
${PM3_ROOT}/client/src/cmdlfcotag.c ${PM3_ROOT}/client/src/cmdlfcotag.c
${PM3_ROOT}/client/src/cmdlfem4x.c ${PM3_ROOT}/client/src/cmdlfem4x.c
${PM3_ROOT}/client/src/cmdlfem4x50.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/cmdlfgallagher.c
${PM3_ROOT}/client/src/cmdlfguard.c ${PM3_ROOT}/client/src/cmdlfguard.c
${PM3_ROOT}/client/src/cmdlfhid.c ${PM3_ROOT}/client/src/cmdlfhid.c

View file

@ -309,6 +309,7 @@ ifeq ($(QT_FOUND),1)
endif endif
endif endif
LDFLAGS ?= $(DEFLDFLAGS)
PM3LDFLAGS = $(LDFLAGS) PM3LDFLAGS = $(LDFLAGS)
ifeq ($(platform),Darwin) ifeq ($(platform),Darwin)
PM3LDFLAGS += -framework Foundation -framework AppKit PM3LDFLAGS += -framework Foundation -framework AppKit
@ -442,7 +443,7 @@ SRCS = aidsearch.c \
cmdlfcotag.c \ cmdlfcotag.c \
cmdlfem4x.c \ cmdlfem4x.c \
cmdlfem4x50.c \ cmdlfem4x50.c \
cmdlffdx.c \ cmdlffdxb.c \
cmdlfguard.c \ cmdlfguard.c \
cmdlfgallagher.c \ cmdlfgallagher.c \
cmdlfhid.c \ cmdlfhid.c \

View file

@ -127,7 +127,7 @@ add_library(pm3rrg_rdv4 SHARED
${PM3_ROOT}/client/src/cmdlfcotag.c ${PM3_ROOT}/client/src/cmdlfcotag.c
${PM3_ROOT}/client/src/cmdlfem4x.c ${PM3_ROOT}/client/src/cmdlfem4x.c
${PM3_ROOT}/client/src/cmdlfem4x50.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/cmdlfgallagher.c
${PM3_ROOT}/client/src/cmdlfguard.c ${PM3_ROOT}/client/src/cmdlfguard.c
${PM3_ROOT}/client/src/cmdlfhid.c ${PM3_ROOT}/client/src/cmdlfhid.c

View file

@ -4529,11 +4529,11 @@ static void arg_cat_optionv(char *dest,
} }
if (datatype) { if (datatype) {
/* if (longopts) /* if (longopts)
arg_cat(&dest, "=", &ndest); arg_cat(&dest, "=", &ndest);
else if (shortopts) else if (shortopts)
arg_cat(&dest, " ", &ndest); arg_cat(&dest, " ", &ndest);
*/ */
if (longopts) if (longopts)
arg_cat(&dest, " ", &ndest); arg_cat(&dest, " ", &ndest);
else if (shortopts) else if (shortopts)

View file

@ -740,8 +740,12 @@ static int unpack(scanner_t *s, json_t *root, va_list *ap) {
case 'b': case 'b':
if (root && !json_is_boolean(root)) { if (root && !json_is_boolean(root)) {
set_error(s, "<validation>", json_error_wrong_type, "Expected true or false, got %s", set_error(s,
type_name(root)); "<validation>",
json_error_wrong_type,
"Expected true or false, got %s",
type_name(root)
);
return -1; return -1;
} }

View file

@ -167,8 +167,9 @@ int reveng_main(int argc, char *argv[]) {
pkchop(&model.spoly); pkchop(&model.spoly);
width = plen(model.spoly); width = plen(model.spoly);
rflags |= R_HAVEP; rflags |= R_HAVEP;
if (c == 'P') if (c == 'P') {
prcp(&model.spoly); prcp(&model.spoly);
}
mnovel(&model); mnovel(&model);
break; break;
case 'l': /* l little-endian input and output */ case 'l': /* l little-endian input and output */
@ -332,6 +333,7 @@ ipqx:
mbynum(&model, --args); mbynum(&model, --args);
ufound(&model); ufound(&model);
} while (args); } while (args);
mfree(&model);
break; break;
case 'd': /* d dump CRC model */ case 'd': /* d dump CRC model */
/* maybe we don't want to do this: /* maybe we don't want to do this:
@ -387,6 +389,10 @@ ipqx:
apolys = calloc(args * sizeof(poly_t), sizeof(char)); apolys = calloc(args * sizeof(poly_t), sizeof(char));
if (!apolys) { if (!apolys) {
uerror("cannot allocate memory for argument list"); uerror("cannot allocate memory for argument list");
pfree(&model.spoly);
pfree(&model.init);
pfree(&model.xorout);
mfree(&model);
return 0; return 0;
} }
@ -421,17 +427,21 @@ ipqx:
continue; continue;
if (rflags & R_HAVEX && psncmp(&model.xorout, &pset.xorout)) if (rflags & R_HAVEX && psncmp(&model.xorout, &pset.xorout))
continue; continue;
apoly = pclone(pset.xorout); apoly = pclone(pset.xorout);
if (pset.flags & P_REFOUT) if (pset.flags & P_REFOUT) {
prev(&apoly); prev(&apoly);
}
for (qptr = apolys; qptr < pptr; ++qptr) { for (qptr = apolys; qptr < pptr; ++qptr) {
crc = pcrc(*qptr, pset.spoly, pset.init, apoly, 0); crc = pcrc(*qptr, pset.spoly, pset.init, apoly, 0);
if (ptst(crc)) { if (ptst(crc)) {
pfree(&crc); pfree(&crc);
break; break;
} else } else {
pfree(&crc); pfree(&crc);
} }
}
pfree(&apoly); pfree(&apoly);
if (qptr == pptr) { if (qptr == pptr) {
/* the selected model solved all arguments */ /* the selected model solved all arguments */
@ -444,14 +454,19 @@ ipqx:
/* toggle refIn/refOut and reflect arguments */ /* toggle refIn/refOut and reflect arguments */
if (~rflags & R_HAVERI) { if (~rflags & R_HAVERI) {
model.flags ^= P_REFIN | P_REFOUT; model.flags ^= P_REFIN | P_REFOUT;
for (qptr = apolys; qptr < pptr; ++qptr) for (qptr = apolys; qptr < pptr; ++qptr) {
prevch(qptr, ibperhx); prevch(qptr, ibperhx);
} }
}
} while (~rflags & R_HAVERI && ++pass < 2); } while (~rflags & R_HAVERI && ++pass < 2);
} }
if (uflags & C_RESULT) { if (uflags & C_RESULT) {
for (qptr = apolys; qptr < pptr; ++qptr) for (qptr = apolys; qptr < pptr; ++qptr) {
pfree(qptr); pfree(qptr);
}
free(apolys);
mfree(&model);
return 1; return 1;
//exit(EXIT_SUCCESS); //exit(EXIT_SUCCESS);
} }
@ -467,8 +482,10 @@ ipqx:
pass = 0; pass = 0;
do { do {
mptr = candmods = reveng(&model, qpoly, rflags, args, apolys); mptr = candmods = reveng(&model, qpoly, rflags, args, apolys);
if (mptr && plen(mptr->spoly)) if (mptr && plen(mptr->spoly)) {
uflags |= C_RESULT; uflags |= C_RESULT;
}
while (mptr && plen(mptr->spoly)) { while (mptr && plen(mptr->spoly)) {
/* results were printed by the callback /* results were printed by the callback
* string = mtostr(mptr); * string = mtostr(mptr);
@ -478,26 +495,31 @@ ipqx:
mfree(mptr++); mfree(mptr++);
} }
free(candmods); free(candmods);
if (~rflags & R_HAVERI) { if (~rflags & R_HAVERI) {
model.flags ^= P_REFIN | P_REFOUT; model.flags ^= P_REFIN | P_REFOUT;
for (qptr = apolys; qptr < pptr; ++qptr) for (qptr = apolys; qptr < pptr; ++qptr) {
prevch(qptr, ibperhx); prevch(qptr, ibperhx);
} }
}
} while (~rflags & R_HAVERI && ++pass < 2); } while (~rflags & R_HAVERI && ++pass < 2);
for (qptr = apolys; qptr < pptr; ++qptr)
for (qptr = apolys; qptr < pptr; ++qptr) {
pfree(qptr); pfree(qptr);
}
free(apolys); free(apolys);
if (~uflags & C_RESULT) if (~uflags & C_RESULT)
uerror("no models found"); uerror("no models found");
break; break;
default: /* no mode specified */ default: /* no mode specified */
fprintf(stderr, "%s: no mode switch specified. Use %s -h for help.\n", myname, myname); fprintf(stderr, "%s: no mode switch specified. Use %s -h for help.\n", myname, myname);
return 0; return 0;
//exit(EXIT_FAILURE);
} }
return 1; return 1;
//exit(EXIT_SUCCESS);
} }
void void

View 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)

View 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)

View file

@ -192,7 +192,7 @@ local function main(args)
print('Press enter to program card '..cardnum..':'..facility..' (hex: '..card..')') 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. --This would be better with 'press Enter', but we'll take what we can get.
io.read() io.read()
core.console( ('lf hid clone %s'):format(card) ) core.console( ('lf hid clone -r %s'):format(card) )
end end
end end

View file

@ -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. This script uses the Proxmark3 implementations of simulation to bruteforce given ranges of id.
It uses both LF and HF simulations. It uses both LF and HF simulations.
@ -42,7 +42,7 @@ arguments = [[
-r *see below RFID Tag: the RFID tag to emulate -r *see below RFID Tag: the RFID tag to emulate
pyramid pyramid
awid awid
fdx fdxb
jablotron jablotron
noralsy noralsy
presco presco
@ -180,8 +180,8 @@ local function main(args)
consolecommand = 'lf awid sim' consolecommand = 'lf awid sim'
rfidtagname = 'AWID' rfidtagname = 'AWID'
facilityrequired = 1 facilityrequired = 1
elseif rfidtag == 'fdx' then -- I'm not sure why you would need to bruteforce this ¯\_(ツ)_/¯ elseif rfidtag == 'fdxb' then -- I'm not sure why you would need to bruteforce this ¯\_(ツ)_/¯
consolecommand = 'lf fdx sim' consolecommand = 'lf fdxb sim'
rfidtagname = 'FDX-B' rfidtagname = 'FDX-B'
facilityrequired = 1 facilityrequired = 1
elseif rfidtag == 'jablotron' then elseif rfidtag == 'jablotron' then
@ -214,7 +214,7 @@ local function main(args)
end end
facilityrequired = 0 -- Disable the FC required check, as we used it for type instead of FC facilityrequired = 0 -- Disable the FC required check, as we used it for type instead of FC
elseif rfidtag == 'hid' then elseif rfidtag == 'hid' then
consolecommand = 'lf hid sim' consolecommand = 'lf hid sim -r'
rfidtagname = 'HID' rfidtagname = 'HID'
facilityrequired = 1 facilityrequired = 1
else -- Display error and exit out if bad RFID tag was supplied else -- Display error and exit out if bad RFID tag was supplied

View file

@ -77,7 +77,7 @@ local function main(args)
print( string.rep('--',20) ) print( string.rep('--',20) )
print( string.rep('--',20) ) print( string.rep('--',20) )
local cmdDataLoad = 'data load %s'; local cmdDataLoad = 'data load -f %s';
local cwd = core.cwd(); local cwd = core.cwd();
local tracesEM = "find '"..cwd.."/traces/ ' -iname 'em*.pm3' -type f" local tracesEM = "find '"..cwd.."/traces/ ' -iname 'em*.pm3' -type f"

View file

@ -25,6 +25,7 @@
#include "reveng.h" #include "reveng.h"
#include "ui.h" #include "ui.h"
#include "util.h" #include "util.h"
#include "pm3_cmd.h"
#define MAX_ARGS 20 #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 ibperhx = 8, obperhx = 8;
// int rflags = 0; // search flags // int rflags = 0; // search flags
int c;
poly_t apoly, crc; poly_t apoly, crc;
char *string; char *string;
@ -265,7 +265,7 @@ int RunModel(char *inModel, char *inHexStr, bool reverse, char endian, char *res
SETBMP(); SETBMP();
//set model //set model
c = mbynam(&model, inModel); int c = mbynam(&model, inModel);
if (!c) { if (!c) {
PrintAndLogEx(ERR, "error: preset model '%s' not found. Use reveng -D to list presets. [%d]", inModel, c); PrintAndLogEx(ERR, "error: preset model '%s' not found. Use reveng -D to list presets. [%d]", inModel, c);
return 0; return 0;
@ -405,7 +405,7 @@ static int CmdrevengSearch(const char *Cmd) {
#define NMODELS 106 #define NMODELS 106
char inHexStr[100] = {0x00}; char inHexStr[256] = {0x00};
int dataLen = param_getstr(Cmd, 0, inHexStr, sizeof(inHexStr)); int dataLen = param_getstr(Cmd, 0, inHexStr, sizeof(inHexStr));
if (dataLen < 4) return 0; if (dataLen < 4) return 0;
@ -418,7 +418,12 @@ static int CmdrevengSearch(const char *Cmd) {
char revResult[30]; char revResult[30];
int ans = GetModels(Models, &count, width); int ans = GetModels(Models, &count, width);
bool found = false; 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 // try each model and get result
for (int i = 0; i < count; i++) { 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 // round up to # of characters in this model's crc
uint8_t crcChars = ((width[i] + 7) / 8) * 2; uint8_t crcChars = ((width[i] + 7) / 8) * 2;
// can't test a model that has more crc digits than our data // can't test a model that has more crc digits than our data
if (crcChars >= dataLen) if (crcChars >= dataLen) {
free(Models[i]);
continue; continue;
}
PrintAndLogEx(DEBUG PrintAndLogEx(DEBUG
, "DEBUG: dataLen %d, crcChars %u, width[i] %u" , "DEBUG: dataLen %d, crcChars %u, width[i] %u"
@ -439,8 +446,10 @@ static int CmdrevengSearch(const char *Cmd) {
, width[i] , width[i]
); );
if (crcChars == 0) if (crcChars == 0) {
free(Models[i]);
continue; continue;
}
memset(result, 0, 30); memset(result, 0, 30);
char *inCRC = calloc(crcChars + 1, sizeof(char)); char *inCRC = calloc(crcChars + 1, sizeof(char));
@ -492,26 +501,29 @@ static int CmdrevengSearch(const char *Cmd) {
free(Models[i]); free(Models[i]);
} }
if (!found) PrintAndLogEx(FAILED, "\nno matches found\n"); if (found == false)
return 1; PrintAndLogEx(FAILED, "\nno matches found\n");
return PM3_SUCCESS;
} }
int CmdCrc(const char *Cmd) { int CmdCrc(const char *Cmd) {
char name[] = {"reveng "}; char c[100 + 7];
char Cmd2[100 + 7]; snprintf(c, sizeof(c), "reveng ");
memcpy(Cmd2, name, 7); snprintf(c + strlen(c), sizeof(c) - strlen(c), Cmd, strlen(Cmd));
memcpy(Cmd2 + 7, Cmd, 100);
char *argv[MAX_ARGS]; char *argv[MAX_ARGS];
int argc = split(Cmd2, argv); int argc = split(c, argv);
if (argc == 3 && memcmp(argv[1], "-g", 2) == 0) { if (argc == 3 && memcmp(argv[1], "-g", 2) == 0) {
CmdrevengSearch(argv[2]); CmdrevengSearch(argv[2]);
} else { } else {
reveng_main(argc, argv); reveng_main(argc, argv);
} }
for (int i = 0; i < argc; ++i) { for (int i = 0; i < argc; ++i) {
free(argv[i]); free(argv[i]);
} }
return 0; return PM3_SUCCESS;
} }

View file

@ -27,31 +27,17 @@
#include "fileutils.h" // searchFile #include "fileutils.h" // searchFile
#include "mifare/ndef.h" #include "mifare/ndef.h"
#include "cliparser.h" #include "cliparser.h"
#include "cmdlft55xx.h" // print...
uint8_t DemodBuffer[MAX_DEMOD_BUF_LEN]; uint8_t DemodBuffer[MAX_DEMOD_BUF_LEN];
size_t DemodBufferLen = 0; size_t DemodBufferLen = 0;
size_t g_DemodStartIdx = 0; int32_t g_DemodStartIdx = 0;
int g_DemodClock = 0; int g_DemodClock = 0;
static int CmdHelp(const char *Cmd); 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) { 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, "Options:");
PrintAndLogEx(NORMAL, " h this help"); PrintAndLogEx(NORMAL, " h this help");
PrintAndLogEx(NORMAL, " i invert Demodbuffer before printing"); 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)"); PrintAndLogEx(NORMAL, " g save back to GraphBuffer (overwrite)");
return PM3_SUCCESS; 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) { static int usage_data_detectclock(void) {
PrintAndLogEx(NORMAL, "Usage: data detectclock [modulation] <clock>"); PrintAndLogEx(NORMAL, "Usage: data detectclock [modulation] <clock>");
PrintAndLogEx(NORMAL, " [modulation as char], specify the modulation type you want to detect the clock of"); 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) { static int usage_data_buffclear(void) {
PrintAndLogEx(NORMAL, "This function clears the bigbuff on deviceside"); 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, "Options:");
PrintAndLogEx(NORMAL, " h This help"); PrintAndLogEx(NORMAL, " h This help");
return PM3_SUCCESS; return PM3_SUCCESS;
@ -544,6 +521,7 @@ static int CmdConvertBitStream(const char *Cmd) {
//emSearch will auto search for EM410x format in bitstream //emSearch will auto search for EM410x format in bitstream
//askType switches decode: ask/raw = 0, ask/manchester = 1 //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) { 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; uint8_t askamp = 0;
if (!maxLen) maxLen = pm3_capabilities.bigbuf_size; 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 //attempts to demodulate ask while decoding manchester
//prints binary found and saves in graphbuffer for further commands //prints binary found and saves in graphbuffer for further commands
static int Cmdaskmandemod(const char *Cmd) { static int Cmdaskmandemod(const char *Cmd) {
size_t slen = strlen(Cmd);
char cmdp = tolower(param_getchar(Cmd, 0)); char cmdp = tolower(param_getchar(Cmd, 0));
if (strlen(Cmd) > 45 || cmdp == 'h') return usage_data_rawdemod_am(); if (slen > 45 || cmdp == 'h') return usage_data_rawdemod_am();
bool st = false;
bool st = false, amplify = false;
int clk = 0, invert = 0, maxErr = 100;
size_t maxLen = 0;
if (slen) {
if (Cmd[0] == 's') { if (Cmd[0] == 's') {
st = true; st = true;
Cmd++; Cmd++;
} else if (Cmd[1] == 's') { } else if (slen > 1 && Cmd[1] == 's') {
st = true; st = true;
Cmd += 2; Cmd += 2;
} }
int clk = 0;
int invert = 0;
int maxErr = 100;
size_t maxLen = 0;
bool amplify = false;
char amp = tolower(param_getchar(Cmd, 0)); char amp = tolower(param_getchar(Cmd, 0));
sscanf(Cmd, "%i %i %i %zu %c", &clk, &invert, &maxErr, &maxLen, &amp); sscanf(Cmd, "%i %i %i %zu %c", &clk, &invert, &maxErr, &maxLen, &amp);
amplify = amp == 'a';
amplify = (amp == 'a');
}
if (clk == 1) { if (clk == 1) {
invert = 1; invert = 1;
clk = 0; clk = 0;
} }
if (invert != 0 && invert != 1) { if (invert != 0 && invert != 1) {
PrintAndLogEx(WARNING, "Invalid value for invert: %i", invert); PrintAndLogEx(WARNING, "Invalid value for invert: %i", invert);
return PM3_EINVARG; return PM3_EINVARG;
@ -998,12 +985,29 @@ static int CmdBuffClear(const char *Cmd) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int CmdDec(const char *Cmd) { static int CmdDecimate(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
for (size_t i = 0; i < (GraphTraceLen / 2); ++i) CLIParserContext *ctx;
GraphBuffer[i] = GraphBuffer[i * 2]; CLIParserInit(&ctx, "data decimate",
GraphTraceLen /= 2; "Performs decimation, by reducing samples N times in the grapbuf. Good for PSK\n",
PrintAndLogEx(NORMAL, "decimated by 2"); "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(); RepaintGraphWindow();
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -1014,19 +1018,34 @@ static int CmdDec(const char *Cmd) {
* @param Cmd * @param Cmd
* @return * @return
*/ */
static int CmdUndec(const char *Cmd) { static int CmdUndecimate(const char *Cmd) {
char cmdp = tolower(param_getchar(Cmd, 0)); CLIParserContext *ctx;
if (cmdp == 'h') return usage_data_undecimate(); 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? //We have memory, don't we?
int swap[MAX_GRAPH_TRACE_LEN] = {0}; int swap[MAX_GRAPH_TRACE_LEN] = {0};
uint32_t g_index = 0, s_index = 0; uint32_t g_index = 0, s_index = 0;
while (g_index < GraphTraceLen && s_index + factor < MAX_GRAPH_TRACE_LEN) { while (g_index < GraphTraceLen && s_index + factor < MAX_GRAPH_TRACE_LEN) {
int count = 0; int count = 0;
for (count = 0; count < factor && s_index + count < MAX_GRAPH_TRACE_LEN; count++) for (count = 0; count < factor && s_index + count < MAX_GRAPH_TRACE_LEN; count++) {
swap[s_index + count] = GraphBuffer[g_index]; swap[s_index + count] = (
(double)(factor - count) / (factor - 1)) * GraphBuffer[g_index] +
((double)count / factor) * GraphBuffer[g_index + 1]
;
}
s_index += count; s_index += count;
g_index++; g_index++;
} }
@ -1437,7 +1456,7 @@ void setClockGrid(uint32_t clk, int offset) {
} }
int CmdGrid(const char *Cmd) { int CmdGrid(const char *Cmd) {
sscanf(Cmd, "%i %i", &PlotGridX, &PlotGridY); sscanf(Cmd, "%lf %lf", &PlotGridX, &PlotGridY);
PlotGridXdefault = PlotGridX; PlotGridXdefault = PlotGridX;
PlotGridYdefault = PlotGridY; PlotGridYdefault = PlotGridY;
RepaintGraphWindow(); RepaintGraphWindow();
@ -1675,6 +1694,48 @@ int CmdTuneSamples(const char *Cmd) {
if (package->peak_v > NON_VOLTAGE && package->peak_f > 0) 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)); 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]; char judgement[20];
memset(judgement, 0, sizeof(judgement)); memset(judgement, 0, sizeof(judgement));
// LF evaluation // LF evaluation
@ -1694,6 +1755,11 @@ int CmdTuneSamples(const char *Cmd) {
memset(judgement, 0, sizeof(judgement)); 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) if (package->v_hf < HF_UNUSABLE_V)
sprintf(judgement, _RED_("UNUSABLE")); sprintf(judgement, _RED_("UNUSABLE"));
else if (package->v_hf < HF_MARGINAL_V) else if (package->v_hf < HF_MARGINAL_V)
@ -1702,6 +1768,7 @@ int CmdTuneSamples(const char *Cmd) {
sprintf(judgement, _GREEN_("OK")); sprintf(judgement, _GREEN_("OK"));
PrintAndLogEx((package->v_hf < HF_UNUSABLE_V) ? WARNING : SUCCESS, "HF antenna is %s", judgement); 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 // graph LF measurements
// even here, these values has 3% error. // even here, these values has 3% error.
@ -1712,9 +1779,11 @@ int CmdTuneSamples(const char *Cmd) {
} }
if (test1 > 0) { 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)); LF_DIVISOR_134, LF_DIV2FREQ(LF_DIVISOR_134), LF_DIVISOR_125, LF_DIV2FREQ(LF_DIVISOR_125));
GraphTraceLen = 256; GraphTraceLen = 256;
CursorCPos = LF_DIVISOR_125;
CursorDPos = LF_DIVISOR_134;
ShowGraphWindow(); ShowGraphWindow();
RepaintGraphWindow(); RepaintGraphWindow();
} else { } else {
@ -1726,16 +1795,26 @@ int CmdTuneSamples(const char *Cmd) {
} }
static int CmdLoad(const char *Cmd) { static int CmdLoad(const char *Cmd) {
char filename[FILE_PATH_SIZE] = {0x00};
int len = 0;
len = strlen(Cmd); CLIParserContext *ctx;
if (len == 0) return PM3_EFILE; 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; void *argtable[] = {
memcpy(filename, Cmd, len); 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, ".pm3", true) != PM3_SUCCESS) {
if (searchFile(&path, TRACES_SUBDIR, filename, "", false) != PM3_SUCCESS) { if (searchFile(&path, TRACES_SUBDIR, filename, "", false) != PM3_SUCCESS) {
return PM3_EFILE; return PM3_EFILE;
@ -1759,7 +1838,6 @@ static int CmdLoad(const char *Cmd) {
if (GraphTraceLen >= MAX_GRAPH_TRACE_LEN) if (GraphTraceLen >= MAX_GRAPH_TRACE_LEN)
break; break;
} }
fclose(f); fclose(f);
PrintAndLogEx(SUCCESS, "loaded " _YELLOW_("%zu") " samples", GraphTraceLen); PrintAndLogEx(SUCCESS, "loaded " _YELLOW_("%zu") " samples", GraphTraceLen);
@ -1789,6 +1867,7 @@ int CmdLtrim(const char *Cmd) {
GraphBuffer[i - ds] = GraphBuffer[i]; GraphBuffer[i - ds] = GraphBuffer[i];
GraphTraceLen -= ds; GraphTraceLen -= ds;
g_DemodStartIdx -= ds;
RepaintGraphWindow(); RepaintGraphWindow();
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -1858,39 +1937,29 @@ int CmdPlot(const char *Cmd) {
int CmdSave(const char *Cmd) { int CmdSave(const char *Cmd) {
int len = 0; CLIParserContext *ctx;
char filename[FILE_PATH_SIZE] = {0x00}; CLIParserInit(&ctx, "data save",
uint8_t cmdp = 0; "Save trace from graph window , i.e. the GraphBuffer\n"
bool errors = false, as_wave = false, has_name = false; "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) { void *argtable[] = {
char ctmp = tolower(param_getchar(Cmd, cmdp)); arg_param_begin,
switch (ctmp) { arg_lit0("w", "wave", "save as wave format (.wav)"),
case 'h': arg_strx0("f", "file", "<fn w/o ext>", "save file name"),
return usage_data_save(); arg_param_end
case 'f': };
len = param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE); CLIExecWithReturn(ctx, Cmd, argtable, false);
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;
}
}
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) if (as_wave)
return saveFileWAVE(filename, GraphBuffer, GraphTraceLen); return saveFileWAVE(filename, GraphBuffer, GraphTraceLen);
@ -1898,32 +1967,32 @@ int CmdSave(const char *Cmd) {
return saveFilePM3(filename, GraphBuffer, GraphTraceLen); return saveFilePM3(filename, GraphBuffer, GraphTraceLen);
} }
static int CmdScale(const char *Cmd) { static int CmdTimeScale(const char *Cmd) {
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "data scale", CLIParserInit(&ctx, "data timescale",
"Set cursor display scale.\n" "Set cursor display timescale.\n"
"Setting the scale makes the differential `dt` reading between the yellow and purple markers meaningful.\n" "Setting the timescale 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.", "once the timescale 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 timescale --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 timescale --sr 1.695 -u us -> for HF sampled at 16 * fc/128. Reading will be in microseconds\n"
"data scale --sr 16 -u ETU -> for HF with 16 samples per ETU. Reading will be in ETUs" "data timescale --sr 16 -u ETU -> for HF with 16 samples per ETU (fc/128). Reading will be in ETUs"
); );
void *argtable[] = { void *argtable[] = {
arg_param_begin, 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_str0("u", "unit", "<string>", "time unit to display (max 10 chars)"),
arg_param_end arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, false); CLIExecWithReturn(ctx, Cmd, argtable, false);
CursorScaleFactor = arg_get_dbl_def(ctx, 1, 1); CursorScaleFactor = arg_get_dbl_def(ctx, 1, 1);
if (CursorScaleFactor <= 0) { 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; CursorScaleFactor = 1;
} }
int len = 0; int len = 0;
CursorScaleFactorUnit[0] = '\x00'; 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); CLIParserFree(ctx);
RepaintGraphWindow(); RepaintGraphWindow();
return PM3_SUCCESS; return PM3_SUCCESS;
@ -2298,45 +2367,206 @@ static int CmdDataNDEF(const char *Cmd) {
return res; 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[] = { static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"}, {"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)"}, {"-----------", CmdHelp, AlwaysAvailable, "------------------------- " _CYAN_("Modulation") "-------------------------"},
{"biphaserawdecode", CmdBiphaseDecodeRaw, AlwaysAvailable, "[offset] [invert<0|1>] [maxErr] -- Biphase decode bin stream in DemodBuffer (offset = 0|1 bits to shift the decode start)"}, {"biphaserawdecode", CmdBiphaseDecodeRaw, AlwaysAvailable, "Biphase decode bin stream in DemodBuffer"},
{"bin2hex", Cmdbin2hex, AlwaysAvailable, "<digits> -- Converts binary to hexadecimal"}, {"detectclock", CmdDetectClockRate, AlwaysAvailable, "Detect ASK, FSK, NRZ, PSK clock rate of wave in GraphBuffer"},
{"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)"}, {"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"}, {"manrawdecode", Cmdmandecoderaw, AlwaysAvailable, "Manchester decode binary stream in DemodBuffer"},
{"grid", CmdGrid, AlwaysAvailable, "<x> <y> -- overlay grid on graph window, use zero value to turn off either"}, {"modulation", CmdDataModulationSearch, AlwaysAvailable, "Identify LF signal for clock and modulation"},
{"hexsamples", CmdHexsamples, IfPm3Present, "<bytes> [<offset>] -- Dump big buffer as hex bytes"}, {"rawdemod", CmdRawDemod, AlwaysAvailable, "Demodulate the data in the GraphBuffer and output binary"},
{"hex2bin", Cmdhex2bin, AlwaysAvailable, "<hexadecimal> -- Converts hexadecimal to 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"}, {"hide", CmdHide, AlwaysAvailable, "Hide graph window"},
{"hpf", CmdHpf, AlwaysAvailable, "Remove DC offset from trace"}, {"hpf", CmdHpf, AlwaysAvailable, "Remove DC offset from trace"},
{"load", CmdLoad, AlwaysAvailable, "<filename> -- Load trace (to graph window"}, {"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"}, {"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"}, {"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"}, {"norm", CmdNorm, AlwaysAvailable, "Normalize max/min to +/-128"},
{"plot", CmdPlot, AlwaysAvailable, "Show graph window (hit 'h' in window for keystroke help)"}, {"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"}, {"rtrim", CmdRtrim, AlwaysAvailable, "<location to end trace> -- Trim samples from right of trace"},
{"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)"}, {"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"}, {"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."}, {"timescale", CmdTimeScale, AlwaysAvailable, "Set a timescale to get a differential reading between the yellow and purple markers as time duration\n"},
{"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"}, {"zerocrossings", CmdZerocrossings, AlwaysAvailable, "Count time between zero-crossings"},
{"iir", CmdDataIIR, AlwaysAvailable, "apply IIR buttersworth filter on plotdata"},
{"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"}, {"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} {NULL, NULL, NULL, NULL}
}; };

View file

@ -60,7 +60,7 @@ int CmdPlot(const char *Cmd);
int CmdSave(const char *Cmd); // used by cmd auto int CmdSave(const char *Cmd); // used by cmd auto
int CmdTuneSamples(const char *Cmd); // used by cmd lf hw 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(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 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 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 size_t DemodBufferLen;
extern int g_DemodClock; extern int g_DemodClock;
extern size_t g_DemodStartIdx; extern int32_t g_DemodStartIdx;
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -91,7 +91,7 @@ static int CmdFlashMemLoad(const char *Cmd) {
bool is_t55xx = arg_get_lit(ctx, 4); bool is_t55xx = arg_get_lit(ctx, 4);
int fnlen = 0; int fnlen = 0;
char filename[FILE_PATH_SIZE] = {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); CLIParserFree(ctx);
Dictionary_t d = DICTIONARY_NONE; Dictionary_t d = DICTIONARY_NONE;
@ -244,7 +244,7 @@ static int CmdFlashMemDump(const char *Cmd) {
bool view = arg_get_lit(ctx, 3); bool view = arg_get_lit(ctx, 3);
int fnlen = 0; int fnlen = 0;
char filename[FILE_PATH_SIZE] = {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); CLIParserFree(ctx);
uint8_t *dump = calloc(len, sizeof(uint8_t)); uint8_t *dump = calloc(len, sizeof(uint8_t));
@ -297,7 +297,7 @@ static int CmdFlashMemWipe(const char *Cmd) {
// initalwipe = arg_get_lit(ctx, 2); // initalwipe = arg_get_lit(ctx, 2);
CLIParserFree(ctx); CLIParserFree(ctx);
if (page < 0 || page > 2 ) { if (page < 0 || page > 2) {
PrintAndLogEx(WARNING, "page must be 0, 1 or 2"); PrintAndLogEx(WARNING, "page must be 0, 1 or 2");
return PM3_EINVARG; return PM3_EINVARG;
} }
@ -310,7 +310,7 @@ static int CmdFlashMemWipe(const char *Cmd) {
return PM3_ETIMEOUT; return PM3_ETIMEOUT;
} }
const char* msg = "Flash WIPE "; const char *msg = "Flash WIPE ";
uint8_t isok = resp.oldarg[0] & 0xFF; uint8_t isok = resp.oldarg[0] & 0xFF;
if (isok) if (isok)
PrintAndLogEx(SUCCESS, "%s ( " _GREEN_("ok")" )", msg); PrintAndLogEx(SUCCESS, "%s ( " _GREEN_("ok")" )", msg);
@ -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.E, 16, str_exp, sizeof(str_exp), &exlen);
mbedtls_mpi_write_string(&rsa.N, 16, str_pk, sizeof(str_pk), &pklen); 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, "Exponent............. %s", str_exp);
PrintAndLogEx(INFO, "Public key modulus N"); PrintAndLogEx(INFO, "Public key modulus N");
PrintAndLogEx(INFO, " %.64s", str_pk); PrintAndLogEx(INFO, " %.64s", str_pk);

View file

@ -269,9 +269,13 @@ static int usage_hf_14a_reader(void) {
} }
static int CmdHF14AList(const char *Cmd) { static int CmdHF14AList(const char *Cmd) {
(void)Cmd; // Cmd is not used so far char args[128] = {0};
CmdTraceList("14a"); if (strlen(Cmd) == 0) {
return 0; snprintf(args, sizeof(args), "-t 14a");
} else {
strncpy(args, Cmd, sizeof(args) - 1);
}
return CmdTraceList(args);
} }
int hf14a_getconfig(hf14a_config *config) { int hf14a_getconfig(hf14a_config *config) {
@ -1267,14 +1271,14 @@ static int CmdHF14ACmdRaw(const char *Cmd) {
*buf = 0; *buf = 0;
if (++datalen >= sizeof(data)) { if (++datalen >= sizeof(data)) {
if (crc) 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; break;
} }
} }
continue; continue;
} }
PrintAndLogEx(NORMAL, "Invalid char on input"); PrintAndLogEx(FAILED, "Invalid char on input");
return 0; return PM3_ESOFT;
} }
if (crc && datalen > 0 && datalen < sizeof(data) - 2) { if (crc && datalen > 0 && datalen < sizeof(data) - 2) {
@ -1301,7 +1305,7 @@ static int CmdHF14ACmdRaw(const char *Cmd) {
flags |= ISO14A_SET_TIMEOUT; flags |= ISO14A_SET_TIMEOUT;
if (timeout > MAX_TIMEOUT) { if (timeout > MAX_TIMEOUT) {
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) 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) { if (iSelect) {
len = (resp.oldarg[1] & 0xFFFF); len = (resp.oldarg[1] & 0xFFFF);
if (len) { if (len) {
PrintAndLogEx(NORMAL, "Card selected. UID[%i]:", len); PrintAndLogEx(SUCCESS, "Card selected. UID[%u]:", len);
} else { } else {
PrintAndLogEx(WARNING, "Can't select card."); PrintAndLogEx(WARNING, "Can't select card.");
} }
} else { } else {
PrintAndLogEx(NORMAL, "received %i bytes", len); PrintAndLogEx(SUCCESS, "received " _YELLOW_("%u") " bytes", len);
} }
if (!len) if (!len)
return 1; 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 { } else {
PrintAndLogEx(WARNING, "timeout while waiting for reply."); PrintAndLogEx(WARNING, "timeout while waiting for reply.");
return 3; return 3;
@ -1954,6 +1972,9 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
} }
} else { } else {
PrintAndLogEx(INFO, "proprietary non iso14443-4 card found, RATS not supported"); 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; int isMagic = 0;

View file

@ -79,7 +79,8 @@ static bool wait_cmd_14b(bool verbose, bool is_select) {
if (status == 0) { if (status == 0) {
if (verbose) { 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; return true;
} else { } else {
@ -93,8 +94,8 @@ static bool wait_cmd_14b(bool verbose, bool is_select) {
if (len >= 3) { if (len >= 3) {
bool crc = check_crc(CRC_14443_B, data, len); bool crc = check_crc(CRC_14443_B, data, len);
PrintAndLogEx(SUCCESS, "len %u | %s[%02X %02X] %s", PrintAndLogEx(SUCCESS, "received " _YELLOW_("%u") " bytes", len);
len, PrintAndLogEx(SUCCESS, "%s[%02X %02X] %s",
sprint_hex(data, len - 2), sprint_hex(data, len - 2),
data[len - 2], data[len - 2],
data[len - 1], data[len - 1],
@ -104,20 +105,24 @@ static bool wait_cmd_14b(bool verbose, bool is_select) {
if (verbose) if (verbose)
PrintAndLogEx(INFO, "no response from tag"); PrintAndLogEx(INFO, "no response from tag");
} else { } else {
PrintAndLogEx(SUCCESS, "len %u | %s", len, sprint_hex(data, len)); PrintAndLogEx(SUCCESS, "%s", sprint_hex(data, len));
} }
} }
return true; return true;
} else { } else {
PrintAndLogEx(WARNING, "command execution timeout"); PrintAndLogEx(WARNING, "timeout while waiting for reply");
return false; return false;
} }
} }
static int CmdHF14BList(const char *Cmd) { static int CmdHF14BList(const char *Cmd) {
(void)Cmd; // Cmd is not used so far char args[128] = {0};
CmdTraceList("14b"); if (strlen(Cmd) == 0) {
return PM3_SUCCESS; snprintf(args, sizeof(args), "-t 14b");
} else {
strncpy(args, Cmd, sizeof(args) - 1);
}
return CmdTraceList(args);
} }
static int CmdHF14BSim(const char *Cmd) { static int CmdHF14BSim(const char *Cmd) {
@ -139,11 +144,12 @@ static int CmdHF14BSim(const char *Cmd) {
uint8_t pupi[4]; uint8_t pupi[4];
int n = 0; int n = 0;
int res = CLIParamHexToBuf(arg_get_str(ctx, 1), pupi, sizeof(pupi), &n); int res = CLIParamHexToBuf(arg_get_str(ctx, 1), pupi, sizeof(pupi), &n);
CLIParserFree(ctx);
if (res) { if (res) {
PrintAndLogEx(FAILED, "failed to read pupi"); PrintAndLogEx(FAILED, "failed to read pupi");
return PM3_EINVARG; return PM3_EINVARG;
} }
CLIParserFree(ctx);
clearCommandBuffer(); clearCommandBuffer();
SendCommandNG(CMD_HF_ISO14443B_SIMULATE, pupi, sizeof(pupi)); SendCommandNG(CMD_HF_ISO14443B_SIMULATE, pupi, sizeof(pupi));
return PM3_SUCCESS; return PM3_SUCCESS;
@ -188,11 +194,11 @@ static int CmdHF14BCmdRaw(const char *Cmd) {
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_lit0("k", "keep", "leave the signal field ON after receive response"), arg_lit0("k", "keep", "leave the signal field ON after receive response"),
arg_lit0("s", "std", "activate field and select standard card"), arg_lit0("s", "std", "activate field, use ISO14B select"),
arg_lit0(NULL, "sr", "activate field and select SRx ST"), arg_lit0(NULL, "sr", "activate field, use SRx ST select"),
arg_lit0(NULL, "cts", "activate field and select ASK C-ticket"), arg_lit0(NULL, "cts", "activate field, use ASK C-ticket select"),
arg_lit0("c", "crc", "calculate and append CRC"), arg_lit0("c", "crc", "calculate and append CRC"),
arg_lit0("r", "noresponse", "do not read response"), arg_lit0("r", "noresponse", "do not read response from card"),
arg_int0("t", "timeout", "<dec>", "timeout in ms"), arg_int0("t", "timeout", "<dec>", "timeout in ms"),
arg_lit0("v", "verbose", "verbose"), arg_lit0("v", "verbose", "verbose"),
arg_strx0("d", "data", "<hex>", "data, bytes to send"), arg_strx0("d", "data", "<hex>", "data, bytes to send"),
@ -217,7 +223,7 @@ static int CmdHF14BCmdRaw(const char *Cmd) {
if (select_std) { if (select_std) {
flags |= (ISO14B_SELECT_STD | ISO14B_CLEARTRACE); flags |= (ISO14B_SELECT_STD | ISO14B_CLEARTRACE);
if (verbose) if (verbose)
PrintAndLogEx(INFO, "using standard select"); PrintAndLogEx(INFO, "using ISO14443-B select");
} else if (select_sr) { } else if (select_sr) {
flags |= (ISO14B_SELECT_SR | ISO14B_CLEARTRACE); flags |= (ISO14B_SELECT_SR | ISO14B_CLEARTRACE);
if (verbose) if (verbose)
@ -267,6 +273,7 @@ static int CmdHF14BCmdRaw(const char *Cmd) {
} }
bool success = true; bool success = true;
// Select, device will send back iso14b_card_select_t, don't print it. // Select, device will send back iso14b_card_select_t, don't print it.
if (select_std) { if (select_std) {
success = wait_cmd_14b(verbose, true); success = wait_cmd_14b(verbose, true);
@ -618,7 +625,7 @@ static void print_ct_general_info(void *vcard) {
iso14b_cts_card_select_t card; iso14b_cts_card_select_t card;
memcpy(&card, (iso14b_cts_card_select_t *)vcard, sizeof(iso14b_cts_card_select_t)); 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, "ASK C-Ticket");
PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s") " ( " _YELLOW_("%010u") " )", sprint_hex(card.uid, sizeof(card.uid)), uid32); PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s") " ( " _YELLOW_("%010u") " )", sprint_hex(card.uid, sizeof(card.uid)), uid32);
PrintAndLogEx(SUCCESS, " Product Code: %02X", card.pc); 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); 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 (!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(); switch_off_field_14b();
return is_success; 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); 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 (!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; return false;
} }
@ -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); 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 (!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; 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); 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 (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; return false;
} }
@ -817,7 +824,7 @@ static bool HF14B_ask_ct_reader(bool verbose) {
PacketResponseNG resp; PacketResponseNG resp;
SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_CTS | ISO14B_DISCONNECT, 0, 0, NULL, 0); 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 (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; return false;
} }
@ -859,7 +866,7 @@ static bool HF14B_other_reader(bool verbose) {
SendCommandMIX(CMD_HF_ISO14443B_COMMAND, flags, datalen, 0, data, datalen); SendCommandMIX(CMD_HF_ISO14443B_COMMAND, flags, datalen, 0, data, datalen);
if (!WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) { 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(); switch_off_field_14b();
return false; return false;
} }
@ -883,7 +890,7 @@ static bool HF14B_other_reader(bool verbose) {
clearCommandBuffer(); clearCommandBuffer();
SendCommandMIX(CMD_HF_ISO14443B_COMMAND, flags, 1, 0, data, 1); SendCommandMIX(CMD_HF_ISO14443B_COMMAND, flags, 1, 0, data, 1);
if (!WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) { 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(); switch_off_field_14b();
return false; return false;
} }
@ -907,7 +914,7 @@ static bool HF14B_other_reader(bool verbose) {
clearCommandBuffer(); clearCommandBuffer();
SendCommandMIX(CMD_HF_ISO14443B_COMMAND, flags, 1, 0, data, 1); SendCommandMIX(CMD_HF_ISO14443B_COMMAND, flags, 1, 0, data, 1);
if (!WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) { 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(); switch_off_field_14b();
return false; return false;
} }
@ -1080,7 +1087,7 @@ static int CmdHF14BDump(const char *Cmd) {
int fnlen = 0; int fnlen = 0;
char filename[FILE_PATH_SIZE] = {0}; char filename[FILE_PATH_SIZE] = {0};
char *fptr = filename; 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); CLIParserFree(ctx);
iso14b_card_select_t card; iso14b_card_select_t card;

View file

@ -60,9 +60,9 @@ typedef struct {
uint64_t uid; uint64_t uid;
int mask; // how many MSB bits used int mask; // how many MSB bits used
const char *desc; const char *desc;
} productName; } productName_t;
const productName uidmapping[] = { const productName_t uidmapping[] = {
// UID, #significant Bits, "Vendor(+Product)" // UID, #significant Bits, "Vendor(+Product)"
{ 0xE001000000000000LL, 16, "Motorola UK" }, { 0xE001000000000000LL, 16, "Motorola UK" },
@ -1342,9 +1342,13 @@ static int CmdHF15Dump(const char *Cmd) {
} }
static int CmdHF15List(const char *Cmd) { static int CmdHF15List(const char *Cmd) {
(void)Cmd; // Cmd is not used so far char args[128] = {0};
CmdTraceList("15"); if (strlen(Cmd) == 0) {
return PM3_SUCCESS; snprintf(args, sizeof(args), "-t 15");
} else {
strncpy(args, Cmd, sizeof(args) - 1);
}
return CmdTraceList(args);
} }
static int CmdHF15Raw(const char *Cmd) { static int CmdHF15Raw(const char *Cmd) {

View file

@ -115,9 +115,13 @@ static int switch_off_field_cryptorf(void) {
} }
static int CmdHFCryptoRFList(const char *Cmd) { static int CmdHFCryptoRFList(const char *Cmd) {
(void)Cmd; // Cmd is not used so far char args[128] = {0};
CmdTraceList("cryptorf"); if (strlen(Cmd) == 0) {
return PM3_SUCCESS; snprintf(args, sizeof(args), "-t cryptorf");
} else {
strncpy(args, Cmd, sizeof(args) - 1);
}
return CmdTraceList(args);
} }
static int CmdHFCryptoRFSim(const char *Cmd) { static int CmdHFCryptoRFSim(const char *Cmd) {

View file

@ -407,9 +407,13 @@ static bool add_last_IDm(uint8_t position, uint8_t *data) {
} }
static int CmdHFFelicaList(const char *Cmd) { static int CmdHFFelicaList(const char *Cmd) {
(void)Cmd; char args[128] = {0};
CmdTraceList("felica"); if (strlen(Cmd) == 0) {
return PM3_SUCCESS; snprintf(args, sizeof(args), "-t felica");
} else {
strncpy(args, Cmd, sizeof(args) - 1);
}
return CmdTraceList(args);
} }
static int CmdHFFelicaReader(const char *Cmd) { static int CmdHFFelicaReader(const char *Cmd) {

View file

@ -36,10 +36,21 @@
#include "emv/dump.h" #include "emv/dump.h"
#include "ui.h" #include "ui.h"
#include "cmdhf14a.h" #include "cmdhf14a.h"
#include "cmdtrace.h"
static int CmdHelp(const char *Cmd); 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) if (cmd && strlen(cmd) > 0)
PrintAndLogEx(WARNING, "WARNING: command doesn't have any parameters.\n"); 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; return root;
} }
static int CmdHFFidoRegister(const char *cmd) { static int cmd_hf_fido_register(const char *cmd) {
uint8_t data[64] = {0}; uint8_t data[64] = {0};
int chlen = 0; int chlen = 0;
uint8_t cdata[250] = {0}; uint8_t cdata[250] = {0};
@ -386,7 +397,7 @@ static int CmdHFFidoRegister(const char *cmd) {
return PM3_SUCCESS; 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 data[512] = {0};
uint8_t hdata[250] = {0}; uint8_t hdata[250] = {0};
bool public_key_loaded = false; bool public_key_loaded = false;
@ -652,7 +663,7 @@ static int GetExistsFileNameJson(const char *prefixDir, const char *reqestedFile
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int CmdHFFido2MakeCredential(const char *cmd) { static int cmd_hf_fido_2make_credential(const char *cmd) {
json_error_t error; json_error_t error;
char fname[FILE_PATH_SIZE] = {0}; char fname[FILE_PATH_SIZE] = {0};
@ -777,7 +788,7 @@ static int CmdHFFido2MakeCredential(const char *cmd) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int CmdHFFido2GetAssertion(const char *cmd) { static int cmd_hf_fido_2get_assertion(const char *cmd) {
json_error_t error; json_error_t error;
char fname[FILE_PATH_SIZE] = {0}; char fname[FILE_PATH_SIZE] = {0};
@ -904,11 +915,12 @@ static int CmdHFFido2GetAssertion(const char *cmd) {
static command_t CommandTable[] = { static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help."}, {"help", CmdHelp, AlwaysAvailable, "This help."},
{"info", CmdHFFidoInfo, IfPm3Iso14443a, "Info about FIDO tag."}, {"info", cmd_hf_fido_list, IfPm3Iso14443a, "List ISO 14443A history"},
{"reg", CmdHFFidoRegister, IfPm3Iso14443a, "FIDO U2F Registration Message."}, {"info", cmd_hf_fido_info, IfPm3Iso14443a, "Info about FIDO tag."},
{"auth", CmdHFFidoAuthenticate, IfPm3Iso14443a, "FIDO U2F Authentication Message."}, {"reg", cmd_hf_fido_register, IfPm3Iso14443a, "FIDO U2F Registration Message."},
{"make", CmdHFFido2MakeCredential, IfPm3Iso14443a, "FIDO2 MakeCredential command."}, {"auth", cmd_hf_fido_authenticate, IfPm3Iso14443a, "FIDO U2F Authentication Message."},
{"assert", CmdHFFido2GetAssertion, IfPm3Iso14443a, "FIDO2 GetAssertion command."}, {"make", cmd_hf_fido_2make_credential, IfPm3Iso14443a, "FIDO2 MakeCredential command."},
{"assert", cmd_hf_fido_2get_assertion, IfPm3Iso14443a, "FIDO2 GetAssertion command."},
{NULL, NULL, 0, NULL} {NULL, NULL, 0, NULL}
}; };

View file

@ -18,6 +18,7 @@
#include "cmdparser.h" // command_t #include "cmdparser.h" // command_t
#include "commonutil.h" // ARRAYLEN #include "commonutil.h" // ARRAYLEN
#include "cmdtrace.h" #include "cmdtrace.h"
#include "cliparser.h"
#include "util_posix.h" #include "util_posix.h"
#include "comms.h" #include "comms.h"
#include "des.h" #include "des.h"
@ -224,21 +225,6 @@ static int usage_hf_iclass_readblock(void) {
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS; 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) { static int usage_hf_iclass_calc_newkey(void) {
PrintAndLogEx(NORMAL, "Calculate new key for updating\n"); 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"); 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, ""); PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS; 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) { 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) { static int CmdHFiClassList(const char *Cmd) {
(void)Cmd; // Cmd is not used so far char args[128] = {0};
CmdTraceList("iclass"); if (strlen(Cmd) == 0) {
return PM3_SUCCESS; snprintf(args, sizeof(args), "-t iclass");
} else {
strncpy(args, Cmd, sizeof(args) - 1);
}
return CmdTraceList(args);
} }
static int CmdHFiClassSniff(const char *Cmd) { 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) { static int CmdHFiClassView(const char *Cmd) {
int startblock = 0; CLIParserContext *ctx;
int endblock = 0; CLIParserInit(&ctx, "hf iclass view",
char filename[FILE_PATH_SIZE]; "Print a iCLASS tag dump file",
bool errors = false, verbose = false; "hf iclass view -f hf-iclass-AA162D30F8FF12F1-dump.bin\n"
uint8_t cmdp = 0; "hf iclass view --startblock 1 --file hf-iclass-AA162D30F8FF12F1-dump.bin\n");
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;
}
}
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; uint8_t *dump = NULL;
size_t bytes_read = 0; size_t bytes_read = 0;
@ -3522,17 +3487,26 @@ static int CmdHFiClassPermuteKey(const char *Cmd) {
uint8_t data[16] = {0}; uint8_t data[16] = {0};
bool isReverse = false; bool isReverse = false;
int len = 0; 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); void *argtable[] = {
if (len % 2) arg_param_begin,
return usage_hf_iclass_permutekey(); 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); memcpy(key, data, 8);
@ -3580,7 +3554,7 @@ static command_t CommandTable[] = {
{"encrypt", CmdHFiClassEncryptBlk, AlwaysAvailable, "[options..] Encrypt given block data"}, {"encrypt", CmdHFiClassEncryptBlk, AlwaysAvailable, "[options..] Encrypt given block data"},
{"decrypt", CmdHFiClassDecrypt, AlwaysAvailable, "[options..] Decrypt given block data or tag dump file" }, {"decrypt", CmdHFiClassDecrypt, AlwaysAvailable, "[options..] Decrypt given block data or tag dump file" },
{"managekeys", CmdHFiClassManageKeys, AlwaysAvailable, "[options..] Manage keys to use with iclass commands"}, {"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"}, {"view", CmdHFiClassView, AlwaysAvailable, "[options..] Display content from tag dump file"},
{NULL, NULL, NULL, NULL} {NULL, NULL, NULL, NULL}

View file

@ -1401,9 +1401,13 @@ static int CmdLegicWipe(const char *Cmd) {
} }
static int CmdLegicList(const char *Cmd) { static int CmdLegicList(const char *Cmd) {
(void)Cmd; // Cmd is not used so far char args[128] = {0};
CmdTraceList("legic"); if (strlen(Cmd) == 0) {
return PM3_SUCCESS; snprintf(args, sizeof(args), "-t legic");
} else {
strncpy(args, Cmd, sizeof(args) - 1);
}
return CmdTraceList(args);
} }
static command_t CommandTable[] = { static command_t CommandTable[] = {

View file

@ -207,9 +207,13 @@ int infoLTO(bool verbose) {
} }
static int CmdHfLTOList(const char *Cmd) { static int CmdHfLTOList(const char *Cmd) {
(void)Cmd; // Cmd is not used so far char args[128] = {0};
CmdTraceList("lto"); if (strlen(Cmd) == 0) {
return PM3_SUCCESS; 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) { static int lto_rdbl(uint8_t blk, uint8_t *block_responce, uint8_t *block_cnt_responce, bool verbose) {

View file

@ -1002,6 +1002,7 @@ static int CmdHF14AMfDump(const char *Cmd) {
return PM3_ESOFT; return PM3_ESOFT;
strcpy(keyFilename, fptr); strcpy(keyFilename, fptr);
free(fptr);
} }
if ((f = fopen(keyFilename, "rb")) == NULL) { if ((f = fopen(keyFilename, "rb")) == NULL) {
@ -1163,6 +1164,7 @@ static int CmdHF14AMfDump(const char *Cmd) {
return PM3_ESOFT; return PM3_ESOFT;
strcpy(dataFilename, fptr); strcpy(dataFilename, fptr);
free(fptr);
} }
uint16_t bytes = 16 * (FirstBlockOfSector(numSectors - 1) + NumBlocksPerSector(numSectors - 1)); uint16_t bytes = 16 * (FirstBlockOfSector(numSectors - 1) + NumBlocksPerSector(numSectors - 1));
@ -1226,6 +1228,7 @@ static int CmdHF14AMfRestore(const char *Cmd) {
return 1; return 1;
strcpy(keyFilename, fptr); strcpy(keyFilename, fptr);
free(fptr);
} }
if ((fkeys = fopen(keyFilename, "rb")) == NULL) { if ((fkeys = fopen(keyFilename, "rb")) == NULL) {
@ -1260,6 +1263,7 @@ static int CmdHF14AMfRestore(const char *Cmd) {
return 1; return 1;
strcpy(dataFilename, fptr); strcpy(dataFilename, fptr);
free(fptr);
} }
if ((fdump = fopen(dataFilename, "rb")) == NULL) { if ((fdump = fopen(dataFilename, "rb")) == NULL) {
@ -1570,8 +1574,10 @@ jumptoend:
if (createMfcKeyDump(fptr, SectorsCnt, e_sector) != PM3_SUCCESS) { if (createMfcKeyDump(fptr, SectorsCnt, e_sector) != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Failed to save keys to file"); PrintAndLogEx(ERR, "Failed to save keys to file");
free(e_sector); free(e_sector);
free(fptr);
return PM3_ESOFT; return PM3_ESOFT;
} }
free(fptr);
} }
free(e_sector); free(e_sector);
} }
@ -1775,8 +1781,10 @@ jumptoend:
if (createMfcKeyDump(fptr, SectorsCnt, e_sector) != PM3_SUCCESS) { if (createMfcKeyDump(fptr, SectorsCnt, e_sector) != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Failed to save keys to file"); PrintAndLogEx(ERR, "Failed to save keys to file");
free(e_sector); free(e_sector);
free(fptr);
return PM3_ESOFT; return PM3_ESOFT;
} }
free(fptr);
} }
free(e_sector); free(e_sector);
@ -2013,7 +2021,6 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
uint8_t block[16] = {0x00}; uint8_t block[16] = {0x00};
uint8_t *dump; uint8_t *dump;
int bytes; int bytes;
char *fnameptr = filename;
// Settings // Settings
bool slow = false; bool slow = false;
bool legacy_mfchk = 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 // read uid to generate a filename for the key file
char *fptr = GenerateFilename("hf-mf-", "-key.bin"); char *fptr = GenerateFilename("hf-mf-", "-key.bin");
// check if tag doesn't have static nonce // check if tag doesn't have static nonce
has_staticnonce = detect_classic_static_nonce(); has_staticnonce = detect_classic_static_nonce();
@ -2146,6 +2152,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
if (prng_type < 0) { if (prng_type < 0) {
PrintAndLogEx(FAILED, "\nNo tag detected or other tag communication error"); PrintAndLogEx(FAILED, "\nNo tag detected or other tag communication error");
free(e_sector); free(e_sector);
free(fptr);
return prng_type; return prng_type;
} }
} }
@ -2259,6 +2266,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
keyBlock = calloc(ARRAYLEN(g_mifare_default_keys), 6); keyBlock = calloc(ARRAYLEN(g_mifare_default_keys), 6);
if (keyBlock == NULL) { if (keyBlock == NULL) {
free(e_sector); free(e_sector);
free(fptr);
return PM3_EMALLOC; return PM3_EMALLOC;
} }
@ -2403,6 +2411,7 @@ noValidKeyFound:
PrintAndLogEx(FAILED, "No usable key was found!"); PrintAndLogEx(FAILED, "No usable key was found!");
free(keyBlock); free(keyBlock);
free(e_sector); free(e_sector);
free(fptr);
return PM3_ESOFT; return PM3_ESOFT;
} }
} }
@ -2516,11 +2525,13 @@ tryNested:
case PM3_ETIMEOUT: { case PM3_ETIMEOUT: {
PrintAndLogEx(ERR, "\nError: No response from Proxmark3."); PrintAndLogEx(ERR, "\nError: No response from Proxmark3.");
free(e_sector); free(e_sector);
free(fptr);
return PM3_ESOFT; return PM3_ESOFT;
} }
case PM3_EOPABORTED: { case PM3_EOPABORTED: {
PrintAndLogEx(WARNING, "\nButton pressed. Aborted."); PrintAndLogEx(WARNING, "\nButton pressed. Aborted.");
free(e_sector); free(e_sector);
free(fptr);
return PM3_EOPABORTED; return PM3_EOPABORTED;
} }
case PM3_EFAILED: { case PM3_EFAILED: {
@ -2551,6 +2562,7 @@ tryNested:
default: { default: {
PrintAndLogEx(ERR, "unknown Error.\n"); PrintAndLogEx(ERR, "unknown Error.\n");
free(e_sector); free(e_sector);
free(fptr);
return PM3_ESOFT; return PM3_ESOFT;
} }
} }
@ -2582,6 +2594,7 @@ tryHardnested: // If the nested attack fails then we try the hardnested attack
} }
} }
free(e_sector); free(e_sector);
free(fptr);
return PM3_ESOFT; return PM3_ESOFT;
} }
@ -2606,11 +2619,13 @@ tryStaticnested:
case PM3_ETIMEOUT: { case PM3_ETIMEOUT: {
PrintAndLogEx(ERR, "\nError: No response from Proxmark3."); PrintAndLogEx(ERR, "\nError: No response from Proxmark3.");
free(e_sector); free(e_sector);
free(fptr);
return PM3_ESOFT; return PM3_ESOFT;
} }
case PM3_EOPABORTED: { case PM3_EOPABORTED: {
PrintAndLogEx(WARNING, "\nButton pressed. Aborted."); PrintAndLogEx(WARNING, "\nButton pressed. Aborted.");
free(e_sector); free(e_sector);
free(fptr);
return PM3_EOPABORTED; return PM3_EOPABORTED;
} }
case PM3_SUCCESS: { case PM3_SUCCESS: {
@ -2676,6 +2691,7 @@ all_found:
if (!dump) { if (!dump) {
PrintAndLogEx(ERR, "Fail, cannot allocate memory"); PrintAndLogEx(ERR, "Fail, cannot allocate memory");
free(e_sector); free(e_sector);
free(fptr);
return PM3_EMALLOC; return PM3_EMALLOC;
} }
memset(dump, 0, bytes); memset(dump, 0, bytes);
@ -2685,16 +2701,19 @@ all_found:
PrintAndLogEx(ERR, "Fail, transfer from device time-out"); PrintAndLogEx(ERR, "Fail, transfer from device time-out");
free(e_sector); free(e_sector);
free(dump); free(dump);
free(fptr);
return PM3_ETIMEOUT; return PM3_ETIMEOUT;
} }
fnameptr = GenerateFilename("hf-mf-", "-dump"); char *fnameptr = GenerateFilename("hf-mf-", "-dump");
if (fnameptr == NULL) { if (fnameptr == NULL) {
free(dump); free(dump);
free(e_sector); free(e_sector);
free(fptr);
return PM3_ESOFT; return PM3_ESOFT;
} }
strcpy(filename, fnameptr); strcpy(filename, fnameptr);
free(fnameptr);
saveFile(filename, ".bin", dump, bytes); saveFile(filename, ".bin", dump, bytes);
saveFileEML(filename, dump, bytes, MFBLOCK_SIZE); saveFileEML(filename, dump, bytes, MFBLOCK_SIZE);
@ -2706,6 +2725,7 @@ all_found:
free(dump); free(dump);
free(e_sector); free(e_sector);
free(fptr);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -2982,6 +3002,7 @@ out:
if (createMfcKeyDump(fptr, sectorsCnt, e_sector) != PM3_SUCCESS) { if (createMfcKeyDump(fptr, sectorsCnt, e_sector) != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Failed to save keys to file"); PrintAndLogEx(ERR, "Failed to save keys to file");
} }
free(fptr);
} }
} }
@ -3285,6 +3306,7 @@ out:
if (createMfcKeyDump(fptr, SectorsCnt, e_sector) != PM3_SUCCESS) { if (createMfcKeyDump(fptr, SectorsCnt, e_sector) != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Failed to save keys to file"); PrintAndLogEx(ERR, "Failed to save keys to file");
} }
free(fptr);
} }
free(keyBlock); free(keyBlock);
@ -4040,7 +4062,6 @@ static int CmdHF14AMfEKeyPrn(const char *Cmd) {
char *fptr = filename; char *fptr = filename;
fptr += snprintf(fptr, sizeof(filename), "hf-mf-"); fptr += snprintf(fptr, sizeof(filename), "hf-mf-");
FillFileNameByUID(fptr + strlen(fptr), uid, "-key", sizeof(uid)); FillFileNameByUID(fptr + strlen(fptr), uid, "-key", sizeof(uid));
createMfcKeyDump(filename, sectors_cnt, e_sector); createMfcKeyDump(filename, sectors_cnt, e_sector);
} }
@ -4732,6 +4753,7 @@ static int CmdHF14AMfice(const char *Cmd) {
if (fptr == NULL) if (fptr == NULL)
return PM3_EFILE; return PM3_EFILE;
strcpy(filename, fptr); strcpy(filename, fptr);
free(fptr);
} }
PrintAndLogEx(NORMAL, "Collecting "_YELLOW_("%u")" nonces \n", limit); PrintAndLogEx(NORMAL, "Collecting "_YELLOW_("%u")" nonces \n", limit);
@ -5174,8 +5196,13 @@ static int CmdHFMFPersonalize(const char *cmd) {
} }
static int CmdHF14AMfList(const char *Cmd) { static int CmdHF14AMfList(const char *Cmd) {
(void)Cmd; // Cmd is not used so far char args[128] = {0};
return CmdTraceList("mf"); 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) { static int CmdHf14AGen3UID(const char *Cmd) {

View file

@ -4470,8 +4470,13 @@ static int CmdHF14aDesChk(const char *Cmd) {
} }
static int CmdHF14ADesList(const char *Cmd) { static int CmdHF14ADesList(const char *Cmd) {
(void)Cmd; // Cmd is not used so far char args[128] = {0};
return CmdTraceList("des"); if (strlen(Cmd) == 0) {
snprintf(args, sizeof(args), "-t des");
} else {
strncpy(args, Cmd, sizeof(args) - 1);
}
return CmdTraceList(args);
} }
/* /*

View file

@ -143,12 +143,10 @@ static inline void clear_bitarray24(uint32_t *bitarray) {
memset(bitarray, 0x00, sizeof(uint32_t) * (1 << 19)); memset(bitarray, 0x00, sizeof(uint32_t) * (1 << 19));
} }
static inline void set_bitarray24(uint32_t *bitarray) { static inline void set_bitarray24(uint32_t *bitarray) {
memset(bitarray, 0xff, sizeof(uint32_t) * (1 << 19)); memset(bitarray, 0xff, sizeof(uint32_t) * (1 << 19));
} }
static inline void set_bit24(uint32_t *bitarray, uint32_t index) { static inline void set_bit24(uint32_t *bitarray, uint32_t index) {
bitarray[index >> 5] |= 0x80000000 >> (index & 0x0000001f); 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)); return bitarray[index >> 5] & (0x80000000 >> (index & 0x0000001f));
} }
static inline uint32_t next_state(uint32_t *bitarray, uint32_t state) { 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; uint32_t index = state >> 5;
uint_fast8_t bit = state & 0x1f; uint_fast8_t bit = state & 0x1F;
uint32_t line = bitarray[index] << bit; uint32_t line = bitarray[index] << bit;
while (bit <= 0x1f) {
if (line & 0x80000000) return state; while (bit <= 0x1F) {
if (line & 0x80000000) {
return state;
}
state++; state++;
bit++; bit++;
line <<= 1; line <<= 1;
} }
index++; index++;
while (bitarray[index] == 0x00000000 && state < 1 << 24) { while (state < (1 << 24) && bitarray[index] == 0x00000000) {
index++; index++;
state += 0x20; state += 0x20;
} }
if (state >= 1 << 24) return 1 << 24;
if (state >= (1 << 24)) {
return (1 << 24);
}
#if defined __GNUC__ #if defined __GNUC__
return state + __builtin_clz(bitarray[index]); return state + __builtin_clz(bitarray[index]);
#else #else
bit = 0x00; bit = 0x00;
line = bitarray[index]; line = bitarray[index];
while (bit <= 0x1f) { while (bit <= 0x1F) {
if (line & 0x80000000) return state; if (line & 0x80000000) {
return state;
}
state++; state++;
bit++; bit++;
line <<= 1; line <<= 1;
} }
return 1 << 24; return (1 << 24);
#endif #endif
} }

View file

@ -24,7 +24,7 @@
#define MAX_UL_BLOCKS 0x0F #define MAX_UL_BLOCKS 0x0F
#define MAX_ULC_BLOCKS 0x2B #define MAX_ULC_BLOCKS 0x2F
#define MAX_ULEV1a_BLOCKS 0x13 #define MAX_ULEV1a_BLOCKS 0x13
#define MAX_ULEV1b_BLOCKS 0x28 #define MAX_ULEV1b_BLOCKS 0x28
#define MAX_NTAG_203 0x29 #define MAX_NTAG_203 0x29
@ -168,17 +168,13 @@ static int usage_hf_mfu_sim(void) {
} }
static int usage_hf_mfu_ucauth(void) { static int usage_hf_mfu_ucauth(void) {
PrintAndLogEx(NORMAL, "Usage: hf mfu cauth k <key number>"); PrintAndLogEx(NORMAL, "Tests 3DES password on Mifare Ultralight-C tag.");
PrintAndLogEx(NORMAL, " 0 (default): 3DES standard key"); PrintAndLogEx(NORMAL, "If password is not specified, a set of known defaults will be tested.");
PrintAndLogEx(NORMAL, " 1 : all 0x00 key"); PrintAndLogEx(NORMAL, "Usage: hf mfu cauth <password (32 hex symbols)>");
PrintAndLogEx(NORMAL, " 2 : 0x00-0x0F key"); PrintAndLogEx(NORMAL, " [password] - (32 hex symbols)");
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, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu cauth k")); PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu cauth"));
PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu cauth k 3")); PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu cauth 000102030405060708090a0b0c0d0e0f"));
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS; 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, " 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, " 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, " 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, "");
PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " hf mfu otptear b 3"); 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 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 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");
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; return PM3_SUCCESS;
} }
@ -408,6 +406,18 @@ static int ulc_authentication(uint8_t *key, bool switch_off_field) {
return 0; 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) { 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]}; 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; if (hasAuthKey) return PM3_SUCCESS;
// also try to diversify default keys.. look into CmdHF14AMfGenDiverseKeys // also try to diversify default keys.. look into CmdHF14AMfGenDiverseKeys
PrintAndLogEx(INFO, "Trying some default 3des keys"); if (try_default_3des_keys(&key)) {
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: "); PrintAndLogEx(SUCCESS, "Found default 3des key: ");
uint8_t keySwap[16]; uint8_t keySwap[16];
memcpy(keySwap, SwapEndian64(key, 16, 8), 16); memcpy(keySwap, SwapEndian64(key, 16, 8), 16);
ulc_print_3deskey(keySwap); ulc_print_3deskey(keySwap);
return PM3_SUCCESS;
}
} }
return PM3_SUCCESS; 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) { static int CmdHF14AMfUCAuth(const char *Cmd) {
uint8_t keyNo = 3;
bool errors = false;
char cmdp = tolower(param_getchar(Cmd, 0)); char cmdp = tolower(param_getchar(Cmd, 0));
if (cmdp == 'h') {
//Change key to user defined one return usage_hf_mfu_ucauth();
if (cmdp == 'k') {
keyNo = param_get8(Cmd, 1);
if (keyNo >= ARRAYLEN(default_3des_keys))
errors = true;
} }
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 (succeeded)
if (ulc_authentication(key, true))
PrintAndLogEx(SUCCESS, "Authentication successful. 3des key: %s", sprint_hex(key, 16)); PrintAndLogEx(SUCCESS, "Authentication successful. 3des key: %s", sprint_hex(key, 16));
else else
PrintAndLogEx(WARNING, "Authentication failed"); PrintAndLogEx(WARNING, "Authentication failed");
@ -2809,7 +2819,8 @@ static int CmdHF14AMfUPwdGen(const char *Cmd) {
static int CmdHF14AMfuOtpTearoff(const char *Cmd) { static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
uint8_t blockNoUint = 8; uint8_t blockNoUint = 8;
uint8_t cmdp = 0; uint8_t cmdp = 0;
bool errors = 0; bool errors = 0, use_match = false;
uint8_t match[4] = {0x00};
uint8_t teardata[8] = {0x00}; uint8_t teardata[8] = {0x00};
uint32_t interval = 500; // time in us uint32_t interval = 500; // time in us
uint32_t timeLimit = 3000; // 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(); return usage_hf_mfu_otp_tearoff();
case 'b': case 'b':
blockNoUint = param_get8(Cmd, cmdp + 1); blockNoUint = param_get8(Cmd, cmdp + 1);
//iceman, which blocks can be targeted? UID blocks?
if (blockNoUint < 2) { if (blockNoUint < 2) {
PrintAndLogEx(WARNING, "Wrong block number"); PrintAndLogEx(WARNING, "Wrong block number");
errors = true; errors = true;
@ -2830,10 +2840,6 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
break; break;
case 'i': case 'i':
interval = param_get32ex(Cmd, cmdp + 1, interval, 10); interval = param_get32ex(Cmd, cmdp + 1, interval, 10);
if (interval == 0) {
PrintAndLogEx(WARNING, "Wrong interval number");
errors = true;
}
cmdp += 2; cmdp += 2;
break; break;
case 'l': case 'l':
@ -2842,6 +2848,10 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
PrintAndLogEx(WARNING, "Wrong time limit number"); PrintAndLogEx(WARNING, "Wrong time limit number");
errors = true; errors = true;
} }
if (timeLimit > 43000) {
PrintAndLogEx(WARNING, "You can't set delay out of 1..43000 range!");
errors = true;
}
cmdp += 2; cmdp += 2;
break; break;
case 's': case 's':
@ -2866,6 +2876,14 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
} }
cmdp += 2; cmdp += 2;
break; 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: default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true; errors = true;
@ -2875,52 +2893,112 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
if (errors) return usage_hf_mfu_otp_tearoff(); 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; uint32_t actualTime = startTime;
int phase_clear = -1;
int phase_newwr = -1;
uint8_t retries = 0;
while (actualTime <= (timeLimit - interval)) { 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(); clearCommandBuffer();
SendCommandMIX(CMD_HF_MIFAREU_READBL, blockNoUint, 0, 0, NULL, 0); SendCommandMIX(CMD_HF_MIFAREU_READBL, blockNoUint, 0, 0, NULL, 0);
PacketResponseNG resp; PacketResponseNG resp;
got_pre = false;
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
uint8_t isOK = resp.oldarg[0] & 0xff; isOK = resp.oldarg[0] & 0xFF;
if (isOK) { if (isOK) {
uint8_t *d = resp.data.asBytes; memcpy(pre, resp.data.asBytes, sizeof(pre));
PrintAndLogEx(NORMAL, "\nBlock# | Data | Ascii"); got_pre = true;
PrintAndLogEx(NORMAL, "-----------------------------");
PrintAndLogEx(NORMAL, "%02d/0x%02X | %s| %s\n", blockNoUint, blockNoUint, sprint_hex(d, 4), sprint_ascii(d, 4));
} }
} }
PrintAndLogEx(INFO, ".....");
clearCommandBuffer(); clearCommandBuffer();
SendCommandMIX(CMD_HF_MFU_OTP_TEAROFF, blockNoUint, actualTime, 0, teardata, 8); 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"); PrintAndLogEx(WARNING, "Failed");
return PM3_ESOFT; return PM3_ESOFT;
} }
PrintAndLogEx(INFO, "Reading block AFTER attack"); got_post = false;
clearCommandBuffer(); clearCommandBuffer();
SendCommandMIX(CMD_HF_MIFAREU_READBL, blockNoUint, 0, 0, NULL, 0); SendCommandMIX(CMD_HF_MIFAREU_READBL, blockNoUint, 0, 0, NULL, 0);
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) { if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
uint8_t isOK = resp.oldarg[0] & 0xff; isOK = resp.oldarg[0] & 0xFF;
if (isOK) { if (isOK) {
uint8_t *d = resp.data.asBytes; memcpy(post, resp.data.asBytes, sizeof(post));
PrintAndLogEx(NORMAL, "\nBlock# | Data | Ascii"); got_post = true;
PrintAndLogEx(NORMAL, "-----------------------------");
PrintAndLogEx(NORMAL, "%02d/0x%02X | %s| %s\n", blockNoUint, blockNoUint, sprint_hex(d, 4), sprint_ascii(d, 4));
} }
} }
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 /* TEMPORALLY DISABLED
uint8_t d0, d1, d2, d3; uint8_t d0, d1, d2, d3;
d0 = *resp.data.asBytes; d0 = *resp.data.asBytes;
@ -2933,8 +3011,29 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
PrintAndLogEx(NORMAL, "---------------------------------\n"); PrintAndLogEx(NORMAL, "---------------------------------\n");
} }
*/ */
if (startTime != timeLimit) {
actualTime += interval; 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; return PM3_SUCCESS;
} }

View file

@ -724,9 +724,13 @@ static int cmd_hf_st_pwd(const char *Cmd) {
} }
static int cmd_hf_st_list(const char *Cmd) { static int cmd_hf_st_list(const char *Cmd) {
(void)Cmd; // Cmd is not used so far char args[128] = {0};
CmdTraceList("7816"); if (strlen(Cmd) == 0) {
return PM3_SUCCESS; snprintf(args, sizeof(args), "-t 7816");
} else {
strncpy(args, Cmd, sizeof(args) - 1);
}
return CmdTraceList(args);
} }
static command_t CommandTable[] = { static command_t CommandTable[] = {

View file

@ -118,7 +118,6 @@ static int print_barcode(uint8_t *barcode, const size_t barcode_len, bool verbos
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int CmdHfThinFilmInfo(const char *Cmd) { static int CmdHfThinFilmInfo(const char *Cmd) {
uint8_t cmdp = 0; uint8_t cmdp = 0;
@ -226,9 +225,13 @@ static int CmdHfThinFilmSim(const char *Cmd) {
} }
static int CmdHfThinFilmList(const char *Cmd) { static int CmdHfThinFilmList(const char *Cmd) {
(void)Cmd; // Cmd is not used so far char args[128] = {0};
CmdTraceList("thinfilm"); if (strlen(Cmd) == 0) {
return PM3_SUCCESS; snprintf(args, sizeof(args), "-t thinfilm");
} else {
strncpy(args, Cmd, sizeof(args) - 1);
}
return CmdTraceList(args);
} }
static command_t CommandTable[] = { static command_t CommandTable[] = {

View file

@ -481,9 +481,13 @@ static int CmdHFTopazCmdRaw(const char *Cmd) {
} }
static int CmdHFTopazList(const char *Cmd) { static int CmdHFTopazList(const char *Cmd) {
(void)Cmd; // Cmd is not used so far char args[128] = {0};
CmdTraceList("topaz"); if (strlen(Cmd) == 0) {
return PM3_SUCCESS; snprintf(args, sizeof(args), "-t topaz");
} else {
strncpy(args, Cmd, sizeof(args) - 1);
}
return CmdTraceList(args);
} }
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);

View file

@ -13,6 +13,7 @@
#include "util.h" #include "util.h"
#include "fileutils.h" #include "fileutils.h"
#include "util_posix.h" // msleep #include "util_posix.h" // msleep
#include "cliparser.h"
// Currently the largest pixel 880*528 only needs 58.08K bytes // Currently the largest pixel 880*528 only needs 58.08K bytes
#define WSMAPSIZE 60000 #define WSMAPSIZE 60000
@ -90,23 +91,6 @@ static model_t models[] = {
static int CmdHelp(const char *Cmd); 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) { static int picture_bit_depth(const uint8_t *bmp, const size_t bmpsize, const uint8_t model_nr) {
if (bmpsize < sizeof(BMP_HEADER)) if (bmpsize < sizeof(BMP_HEADER))
return PM3_ESOFT; 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; uint8_t color_flag = pbmpheader->Color_1;
// Get BMP file data pointer // Get BMP file data pointer
uint32_t offset = pbmpheader->offset; 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 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); 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)); *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; return PM3_EMALLOC;
} }
// Write data into RAM // 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 for (X = 0; X < Bmp_Width_Byte; X++) { // lines
if ((X < Image_Width_Byte) && ((X + (pbmpheader->BMP_Height - Y - 1) * Image_Width_Byte) < WSMAPSIZE)) { if ((X < Image_Width_Byte) && ((X + (height - Y - 1) * Image_Width_Byte) < WSMAPSIZE)) {
(*black)[X + (pbmpheader->BMP_Height - Y - 1) * Image_Width_Byte] = color_flag ? bmp[offset] : ~bmp[offset]; (*black)[X + (height - Y - 1) * Image_Width_Byte] = color_flag ? bmp[offset] : ~bmp[offset];
} }
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 oldR = chanR[XX + Y * width];
int16_t oldG = chanG[XX + Y * width]; int16_t oldG = chanG[XX + Y * width];
int16_t oldB = chanB[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); nearest_color(oldR, oldG, oldB, palette, palettelen, &newR, &newG, &newB);
chanR[XX + Y * width] = newR; chanR[XX + Y * width] = newR;
chanG[XX + Y * width] = newG; 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; uint32_t offset = pbmpheader->offset;
uint16_t width = pbmpheader->BMP_Width; uint16_t width = pbmpheader->BMP_Width;
uint16_t height = pbmpheader->BMP_Height; 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)); int16_t *chanR = calloc(width * height, sizeof(int16_t));
if (chanR == NULL) { 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 (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
if (resp.oldarg[0] > rxBufLen) { 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); memcpy(rxBuf, resp.data.asBytes, rxBufLen);
*actLen = rxBufLen; *actLen = rxBufLen;
return PM3_ESOFT; 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) { static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) {
uint8_t progress = 0; uint8_t progress = 0;
uint8_t step0[2] = {0xcd, 0x0d}; 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 step1[3] = {0xcd, 0x00, 10}; // select e-paper type and reset e-paper
uint8_t step2[2] = {0xcd, 0x01}; //e-paper normal mode type // 4 :2.13inch e-Paper
uint8_t step3[2] = {0xcd, 0x02}; //e-paper config1 // 7 :2.9inch e-Paper
uint8_t step4[2] = {0xcd, 0x03}; //e-paper power on // 10 :4.2inch e-Paper
uint8_t step5[2] = {0xcd, 0x05}; //e-paper config2 // 14 :7.5inch e-Paper
uint8_t step6[2] = {0xcd, 0x06}; //EDP load to main uint8_t step2[2] = {0xcd, 0x01}; // e-paper normal mode type
uint8_t step7[2] = {0xcd, 0x07}; //Data preparation uint8_t step3[2] = {0xcd, 0x02}; // e-paper config1
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 step4[2] = {0xcd, 0x03}; // e-paper power on
uint8_t step9[2] = {0xcd, 0x18}; //e-paper power on uint8_t step5[2] = {0xcd, 0x05}; // e-paper config2
uint8_t step10[2] = {0xcd, 0x09}; //Refresh e-paper uint8_t step6[2] = {0xcd, 0x06}; // EDP load to main
uint8_t step11[2] = {0xcd, 0x0a}; //wait for ready uint8_t step7[2] = {0xcd, 0x07}; // Data preparation
uint8_t step12[2] = {0xcd, 0x04}; //e-paper power off command
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[124] = {0xcd, 0x19, 121};
// uint8_t step13[2]={0xcd,0x0b}; //Judge whether the power supply is turned off successfully // 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 step14[2]={0xcd,0x0c}; // The end of the transmission
uint8_t rx[20]; uint8_t rx[20];
uint16_t actrxlen[20], i = 0; 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; return PM3_SUCCESS;
} }
static int CmdHF14AWSLoadBmp(const char *Cmd) { static int CmdHF14AWSLoadBmp(const char *Cmd) {
char filename[FILE_PATH_SIZE] = {0}; char desc[800] = {0};
uint8_t cmdp = 0; for (uint8_t i = 0; i < MEND; i++) {
bool errors = false; snprintf(desc + strlen(desc),
size_t filenamelen = 0; sizeof(desc) - strlen(desc),
uint8_t model_nr = 0xff; "hf waveshare loadbmp -f myfile -m %2u -> %s ( %u, %u )\n",
bool save_conversions = false; i,
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { models[i].desc,
switch (tolower(param_getchar(Cmd, cmdp))) { models[i].width,
case 'h': models[i].height
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;
}
} }
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 //Validations
if (filenamelen < 1) { if (fnlen < 1) {
PrintAndLogEx(WARNING, "Missing filename"); PrintAndLogEx(WARNING, "Missing filename");
errors = true; return PM3_EINVARG;
} }
if (model_nr == 0xff) { if (model_nr == -1) {
PrintAndLogEx(WARNING, "Missing model"); PrintAndLogEx(WARNING, "Missing model");
errors = true; return PM3_EINVARG;
} else if (model_nr >= MEND) { }
PrintAndLogEx(WARNING, "Unknown model"); if (model_nr >= MEND) {
errors = true; PrintAndLogEx(WARNING, "Unknown model");
return PM3_EINVARG;
} }
if (errors || cmdp == 0) return usage_hf_waveshare_loadbmp();
uint8_t *bmp = NULL; uint8_t *bmp = NULL;
uint8_t *black = NULL; uint8_t *black = NULL;
@ -1042,7 +1052,7 @@ static int CmdHF14AWSLoadBmp(const char *Cmd) {
free(bmp); free(bmp);
return PM3_ESOFT; return PM3_ESOFT;
} else { } 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); free(bmp);
return PM3_ESOFT; return PM3_ESOFT;
} }

View file

@ -15,6 +15,7 @@
#include <ctype.h> #include <ctype.h>
#include "cmdparser.h" // command_t #include "cmdparser.h" // command_t
#include "cliparser.h"
#include "comms.h" #include "comms.h"
#include "usart_defs.h" #include "usart_defs.h"
#include "ui.h" #include "ui.h"
@ -515,6 +516,77 @@ static int CmdStatus(const char *Cmd) {
return PM3_SUCCESS; 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 *)&params, 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) { static int CmdTia(const char *Cmd) {
(void)Cmd; // Cmd is not used so far (void)Cmd; // Cmd is not used so far
PrintAndLogEx(INFO, "Triggering new Timing Interval Acquisition (TIA)..."); 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"}, {"setmux", CmdSetMux, IfPm3Present, "Set the ADC mux to a specific value"},
{"standalone", CmdStandalone, IfPm3Present, "Jump to the standalone mode"}, {"standalone", CmdStandalone, IfPm3Present, "Jump to the standalone mode"},
{"status", CmdStatus, IfPm3Present, "Show runtime status information about the connected Proxmark3"}, {"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"}, {"tia", CmdTia, IfPm3Present, "Trigger a Timing Interval Acquisition to re-adjust the RealTimeCounter divider"},
{"tune", CmdTune, IfPm3Present, "Measure antenna tuning"}, {"tune", CmdTune, IfPm3Present, "Measure antenna tuning"},
{"version", CmdVersion, IfPm3Present, "Show version information about the connected Proxmark3"}, {"version", CmdVersion, IfPm3Present, "Show version information about the connected Proxmark3"},

View file

@ -36,7 +36,7 @@
#include "cmdlfidteck.h" // for idteck menu #include "cmdlfidteck.h" // for idteck menu
#include "cmdlfio.h" // for ioprox menu #include "cmdlfio.h" // for ioprox menu
#include "cmdlfcotag.h" // for COTAG meny #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 "cmdlfgallagher.h" // for GALLAGHER menu
#include "cmdlfguard.h" // for gproxii menu #include "cmdlfguard.h" // for gproxii menu
#include "cmdlfindala.h" // for indala menu #include "cmdlfindala.h" // for indala menu
@ -1195,7 +1195,7 @@ int CmdLFpskSim(const char *Cmd) {
if (clk == 0) clk = GetPskClock("", false); if (clk == 0) clk = GetPskClock("", false);
PrintAndLogEx(INFO, "clk: %d", clk); PrintAndLogEx(INFO, "clk: %d", clk);
if (!carrier) carrier = GetPskCarrier("", false); if (!carrier) carrier = GetPskCarrier(false);
PrintAndLogEx(INFO, "carrier: %d", carrier); PrintAndLogEx(INFO, "carrier: %d", carrier);
} else { } 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 (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 (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 (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 (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 (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;} 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... }"}, {"awid", CmdLFAWID, AlwaysAvailable, "{ AWID RFIDs... }"},
{"cotag", CmdLFCOTAG, AlwaysAvailable, "{ COTAG CHIPs... }"}, {"cotag", CmdLFCOTAG, AlwaysAvailable, "{ COTAG CHIPs... }"},
{"em", CmdLFEM4X, AlwaysAvailable, "{ EM4X CHIPs & RFIDs... }"}, {"em", CmdLFEM4X, AlwaysAvailable, "{ EM4X CHIPs & RFIDs... }"},
{"fdx", CmdLFFdx, AlwaysAvailable, "{ FDX-B RFIDs... }"}, {"fdxb", CmdLFFdxB, AlwaysAvailable, "{ FDX-B RFIDs... }"},
{"gallagher", CmdLFGallagher, AlwaysAvailable, "{ GALLAGHER RFIDs... }"}, {"gallagher", CmdLFGallagher, AlwaysAvailable, "{ GALLAGHER RFIDs... }"},
{"gproxii", CmdLFGuard, AlwaysAvailable, "{ Guardall Prox II RFIDs... }"}, {"gproxii", CmdLFGuard, AlwaysAvailable, "{ Guardall Prox II RFIDs... }"},
{"hid", CmdLFHID, AlwaysAvailable, "{ HID Prox RFIDs... }"}, {"hid", CmdLFHID, AlwaysAvailable, "{ HID Prox RFIDs... }"},

View file

@ -30,6 +30,8 @@
#include "cmddata.h" #include "cmddata.h"
#include "cmdlf.h" #include "cmdlf.h"
#include "lfdemod.h" #include "lfdemod.h"
#include "generator.h"
#include "cliparser.h"
static uint64_t g_em410xid = 0; 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, "Usage: lf em 4x05_write [h] <address> <data> <pwd>");
PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h - this help"); 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, " data - data to write (hex)");
PrintAndLogEx(NORMAL, " pwd - password (hex) (optional)"); PrintAndLogEx(NORMAL, " pwd - password (hex) (optional)");
PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
@ -731,25 +733,30 @@ static bool downloadSamplesEM(void) {
} }
// em_demod // em_demod
static bool doPreambleSearch(size_t *startIdx) { static int doPreambleSearch(size_t *startIdx) {
// sanity check // sanity check
if (DemodBufferLen < EM_PREAMBLE_LEN) { if (DemodBufferLen < EM_PREAMBLE_LEN) {
PrintAndLogEx(DEBUG, "DEBUG: Error - EM4305 demodbuffer too small"); 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 // set size to 9 to only test first 3 positions for the preamble
size_t size = (20 > DemodBufferLen) ? DemodBufferLen : 20; // 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; *startIdx = 0;
// skip first two 0 bits as they might have been missed in the demod // 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}; uint8_t preamble[EM_PREAMBLE_LEN] = {0, 0, 1, 0, 1, 0};
if (!preambleSearchEx(DemodBuffer, preamble, EM_PREAMBLE_LEN, &size, startIdx, true)) { if (!preambleSearchEx(DemodBuffer, preamble, EM_PREAMBLE_LEN, &size, startIdx, true)) {
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); PrintAndLogEx(DEBUG, "DEBUG: Error - EM4305 preamble not found :: %zu", *startIdx);
return false; return PM3_ESOFT;
} }
return true; return PM3_EFAILED; // Error preamble found
}
return PM3_SUCCESS;
} }
static bool detectFSK(void) { static bool detectFSK(void) {
@ -793,7 +800,7 @@ static bool detectPSK(void) {
// try manchester - NOTE: ST only applies to T55x7 tags. // try manchester - NOTE: ST only applies to T55x7 tags.
static bool detectASK_MAN(void) { static bool detectASK_MAN(void) {
bool stcheck = false; 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"); PrintAndLogEx(DEBUG, "DEBUG: Error - EM: ASK/Manchester Demod failed");
return false; return false;
} }
@ -852,35 +859,72 @@ static int setDemodBufferEM(uint32_t *word, size_t idx) {
// FSK, PSK, ASK/MANCHESTER, ASK/BIPHASE, ASK/DIPHASE, NRZ // FSK, PSK, ASK/MANCHESTER, ASK/BIPHASE, ASK/DIPHASE, NRZ
// should cover 90% of known used configs // should cover 90% of known used configs
// the rest will need to be manually demoded for now... // 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; size_t idx = 0;
*word = 0; *word = 0;
if (detectASK_MAN() && doPreambleSearch(&idx)) bool found_err = false;
return setDemodBufferEM(word, idx); int res = PM3_SUCCESS;
do {
if (detectASK_BI() && doPreambleSearch(&idx)) if (detectASK_MAN()) {
return setDemodBufferEM(word, idx); res = doPreambleSearch(&idx);
if (res == PM3_SUCCESS)
if (detectNRZ() && doPreambleSearch(&idx)) break;
return setDemodBufferEM(word, idx); if (res == PM3_EFAILED)
// go on, maybe it's false positive and another modulation will work
if (detectFSK() && doPreambleSearch(&idx)) found_err = true;
return setDemodBufferEM(word, idx); }
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()) { if (detectPSK()) {
if (doPreambleSearch(&idx)) res = doPreambleSearch(&idx);
return setDemodBufferEM(word, idx); if (res == PM3_SUCCESS)
break;
if (res == PM3_EFAILED)
found_err = true;
psk1TOpsk2(DemodBuffer, DemodBufferLen); psk1TOpsk2(DemodBuffer, DemodBufferLen);
if (doPreambleSearch(&idx)) res = doPreambleSearch(&idx);
return setDemodBufferEM(word, idx); if (res == PM3_SUCCESS)
break;
if (res == PM3_EFAILED)
found_err = true;
} }
if (found_err)
return PM3_EFAILED;
return PM3_ESOFT; 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 //////////////// 4205 / 4305 commands
#include "util_posix.h" // msclock #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 { struct {
uint32_t password; uint32_t password;
@ -903,20 +947,21 @@ static int EM4x05ReadWord_ext(uint8_t addr, uint32_t pwd, bool usePwd, uint32_t
if (downloadSamplesEM() == false) { if (downloadSamplesEM() == false) {
return PM3_ESOFT; return PM3_ESOFT;
} }
return demodEM4x05resp(word); return demodEM4x05resp(word, false);
} }
static int CmdEM4x05Demod(const char *Cmd) { static int CmdEM4x05Demod(const char *Cmd) {
// uint8_t ctmp = tolower(param_getchar(Cmd, 0)); // uint8_t ctmp = tolower(param_getchar(Cmd, 0));
// if (ctmp == 'h') return usage_lf_em4x05_demod(); // if (ctmp == 'h') return usage_lf_em4x05_demod();
uint32_t word = 0; uint32_t dummy = 0;
return demodEM4x05resp(&word); return demodEM4x05resp(&dummy, false);
} }
static int CmdEM4x05Dump(const char *Cmd) { static int CmdEM4x05Dump(const char *Cmd) {
uint8_t addr = 0; uint8_t addr = 0;
uint32_t pwd = 0; uint32_t pwd = 0;
bool usePwd = false; bool usePwd = false;
bool needReadPwd = true;
uint8_t cmdp = 0; uint8_t cmdp = 0;
uint8_t bytes[4] = {0}; uint8_t bytes[4] = {0};
uint32_t data[16]; uint32_t data[16];
@ -946,40 +991,66 @@ static int CmdEM4x05Dump(const char *Cmd) {
} }
int success = PM3_SUCCESS; int success = PM3_SUCCESS;
int status; int status, status14, status15;
uint32_t lock_bits = 0x00; // no blocks locked uint32_t lock_bits = 0x00; // no blocks locked
bool gotLockBits = false;
bool lockInPW2 = false;
uint32_t word = 0; 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, "Addr | data | ascii |lck| info");
PrintAndLogEx(NORMAL, "-----+----------+-------+---+-----"); PrintAndLogEx(NORMAL, "-----+----------+-------+---+-----");
// To flag any blocks locked we need to read blocks 14 and 15 first // To flag any blocks locked we need to read blocks 14 and 15 first
// dont swap endin until we get block lock flags. // dont swap endin until we get block lock flags.
status = EM4x05ReadWord_ext(14, pwd, usePwd, &word); status14 = EM4x05ReadWord_ext(14, pwd, usePwd, &word);
if (status != PM3_SUCCESS) if (status14 == PM3_SUCCESS) {
success = PM3_ESOFT; // If any error ensure fail is set so not to save invalid data if (!usePwd)
if (word != 0x00) needReadPwd = false;
if ((word & 0x00008000) != 0x00) {
lock_bits = word; lock_bits = word;
gotLockBits = true;
}
data[14] = word; data[14] = word;
} else {
status = EM4x05ReadWord_ext(15, pwd, usePwd, &word);
if (status != PM3_SUCCESS)
success = PM3_ESOFT; // If any error ensure fail is set so not to save invalid data 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 }
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; lock_bits = word;
gotLockBits = true;
lockInPW2 = true;
}
data[15] = word; data[15] = word;
} else {
success = PM3_ESOFT; // If any error ensure fail is set so not to save invalid data
}
uint32_t lockbit;
// Now read blocks 0 - 13 as we have 14 and 15 // Now read blocks 0 - 13 as we have 14 and 15
for (; addr < 14; addr++) { for (; addr < 14; addr++) {
lockbit = (lock_bits >> addr) & 1;
if (addr == 2) { if (addr == 2) {
if (usePwd) { if (usePwd) {
if ((needReadPwd) && (success != PM3_ESOFT)) {
data[addr] = BSWAP_32(pwd); data[addr] = BSWAP_32(pwd);
num_to_bytes(pwd, 4, bytes); num_to_bytes(pwd, 4, bytes);
PrintAndLogEx(NORMAL, " %02u | %08X | %s | %c | password", addr, pwd, sprint_ascii(bytes, 4), ((lock_bits >> addr) & 1) ? 'x' : ' '); 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 { } else {
data[addr] = 0x00; // Unknown password, but not used to set to zeros 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 { } else {
// success &= EM4x05ReadWord_ext(addr, pwd, usePwd, &word); // success &= EM4x05ReadWord_ext(addr, pwd, usePwd, &word);
@ -989,15 +1060,27 @@ static int CmdEM4x05Dump(const char *Cmd) {
data[addr] = BSWAP_32(word); data[addr] = BSWAP_32(word);
if (status == PM3_SUCCESS) { if (status == PM3_SUCCESS) {
num_to_bytes(word, 4, bytes); 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 } 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 // Print blocks 14 and 15
// Both lock bits are protected with bit idx 14 (special case) // 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' : ' '); addr = 14;
PrintAndLogEx(NORMAL, " %02d | %08X | %s | %c | Lock", 15, data[15], sprint_ascii(bytes, 4), ((lock_bits >> 14) & 1) ? 'x' : ' '); 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 // Update endian for files
data[14] = BSWAP_32(data[14]); data[14] = BSWAP_32(data[14]);
data[15] = BSWAP_32(data[15]); data[15] = BSWAP_32(data[15]);
@ -1027,22 +1110,24 @@ static int CmdEM4x05Read(const char *Cmd) {
pwd = param_get32ex(Cmd, 1, 0xFFFFFFFF, 16); pwd = param_get32ex(Cmd, 1, 0xFFFFFFFF, 16);
if (addr > 15) { if (addr > 15) {
PrintAndLogEx(NORMAL, "Address must be between 0 and 15"); PrintAndLogEx(WARNING, "Address must be between 0 and 15");
return PM3_ESOFT; return PM3_ESOFT;
} }
if (pwd == 0xFFFFFFFF) { if (pwd == 0xFFFFFFFF) {
PrintAndLogEx(NORMAL, "Reading address %02u", addr); PrintAndLogEx(INFO, "Reading address %02u", addr);
} else { } else {
usePwd = true; 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; uint32_t word = 0;
int status = EM4x05ReadWord_ext(addr, pwd, usePwd, &word); int status = EM4x05ReadWord_ext(addr, pwd, usePwd, &word);
if (status == PM3_SUCCESS) 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 else
PrintAndLogEx(NORMAL, "Read Address %02d | " _RED_("Fail"), addr); PrintAndLogEx(WARNING, "No answer from tag");
return status; return status;
} }
@ -1057,18 +1142,44 @@ static int CmdEM4x05Write(const char *Cmd) {
addr = param_get8ex(Cmd, 0, 50, 10); addr = param_get8ex(Cmd, 0, 50, 10);
data = param_get32ex(Cmd, 1, 0, 16); data = param_get32ex(Cmd, 1, 0, 16);
pwd = param_get32ex(Cmd, 2, 0xFFFFFFFF, 16); pwd = param_get32ex(Cmd, 2, 0xFFFFFFFF, 16);
bool protectOperation = addr == 99; // will do better with cliparser...
if (addr > 15) { if ((addr > 13) && (!protectOperation)) {
PrintAndLogEx(NORMAL, "Address must be between 0 and 15"); PrintAndLogEx(WARNING, "Address must be between 0 and 13");
return PM3_EINVARG; return PM3_EINVARG;
} }
if (pwd == 0xFFFFFFFF) if (pwd == 0xFFFFFFFF) {
PrintAndLogEx(NORMAL, "Writing address %d data %08X", addr, data); if (protectOperation)
else { PrintAndLogEx(INFO, "Writing protection words data %08X", data);
else
PrintAndLogEx(INFO, "Writing address %d data %08X", addr, data);
} else {
usePwd = true; 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);
} }
if (protectOperation) { // set Protect Words
struct {
uint32_t password;
uint32_t data;
uint8_t usepwd;
} PACKED payload;
payload.password = pwd;
payload.data = data;
payload.usepwd = usePwd;
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 { struct {
uint32_t password; uint32_t password;
uint32_t data; uint32_t data;
@ -1088,17 +1199,19 @@ static int CmdEM4x05Write(const char *Cmd) {
PrintAndLogEx(ERR, "Error occurred, device did not respond during write operation."); PrintAndLogEx(ERR, "Error occurred, device did not respond during write operation.");
return PM3_ETIMEOUT; return PM3_ETIMEOUT;
} }
}
if (!downloadSamplesEM()) if (!downloadSamplesEM())
return PM3_ENODATA; return PM3_ENODATA;
//need 0 bits demoded (after preamble) to verify write cmd
uint32_t dummy = 0; uint32_t dummy = 0;
int status = demodEM4x05resp(&dummy); int status = demodEM4x05resp(&dummy, true);
if (status == PM3_SUCCESS) if (status == PM3_SUCCESS)
PrintAndLogEx(SUCCESS, "Success writing to tag"); 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"); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf em 4x05_read`") " to verify");
return status; return status;
} }
@ -1263,8 +1376,10 @@ static void printEM4x05config(uint32_t wordData) {
uint8_t disable = (wordData & EM4x05_DISABLE_ALLOWED) >> 23; uint8_t disable = (wordData & EM4x05_DISABLE_ALLOWED) >> 23;
uint8_t rtf = (wordData & EM4x05_READER_TALK_FIRST) >> 24; uint8_t rtf = (wordData & EM4x05_READER_TALK_FIRST) >> 24;
uint8_t pigeon = (wordData & (1 << 26)) >> 26; 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, " Data Rate: %02u | "_YELLOW_("RF/%u"), wordData & 0x3F, datarate);
PrintAndLogEx(INFO, " Encoder: %u | " _YELLOW_("%s"), encoder, enc); PrintAndLogEx(INFO, " Encoder: %u | " _YELLOW_("%s"), encoder, enc);
PrintAndLogEx(INFO, " PSK CF: %u | %s", PSKcf, cf); 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, " 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, " 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, " 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) { static void printEM4x05info(uint32_t block0, uint32_t serial) {
uint8_t chipType = (block0 >> 1) & 0xF; uint8_t chipType = (block0 >> 1) & 0xF;
uint8_t cap = (block0 >> 5) & 3; 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]; char ctstr[50];
snprintf(ctstr, sizeof(ctstr), "\n Chip Type: %u | ", chipType); snprintf(ctstr, sizeof(ctstr), " Chip Type: %u | ", chipType);
switch (chipType) { switch (chipType) {
case 9: case 9:
snprintf(ctstr + strlen(ctstr), sizeof(ctstr) - strlen(ctstr), _YELLOW_("%s"), "EM4305"); snprintf(ctstr + strlen(ctstr), sizeof(ctstr) - strlen(ctstr), _YELLOW_("%s"), "EM4305");
break; break;
case 4:
snprintf(ctstr + strlen(ctstr), sizeof(ctstr) - strlen(ctstr), _YELLOW_("%s"), "EM4469");
break;
case 8: case 8:
snprintf(ctstr + strlen(ctstr), sizeof(ctstr) - strlen(ctstr), _YELLOW_("%s"), "EM4205"); snprintf(ctstr + strlen(ctstr), sizeof(ctstr) - strlen(ctstr), _YELLOW_("%s"), "EM4205");
break; 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 //add more here when known
default: default:
snprintf(ctstr + strlen(ctstr), sizeof(ctstr) - strlen(ctstr), _YELLOW_("%s"), "Unknown"); 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"); PrintAndLogEx(SUCCESS, " Cust Code: %03u | %s", custCode, (custCode == 0x200) ? "Default" : "Unknown");
if (serial != 0) 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++) { 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) 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) { if (EM4x05ReadWord_ext(EM_PROT1_BLOCK, pwd, usePwd, &word) != PM3_SUCCESS) {
return PM3_ESOFT; 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) 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;
}
}
// Loop dictionary
uint8_t *keyBlock = NULL;
if (found == false) {
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; return PM3_ESOFT;
} }
//something went wrong for (uint32_t c = 0; c < keycount; ++c) {
if (!(word & 0x8000))
return PM3_ESOFT;
printEM4x05ProtectionBits(word); 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; 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_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"}, {"410x_clone", CmdEM410xClone, IfPm3Lf, "write EM410x UID to T55x7 or Q5/T5555 tag"},
{"----------", CmdHelp, AlwaysAvailable, "-------------------- " _CYAN_("EM 4x05 / 4x69") " -------------------"}, {"----------", 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_demod", CmdEM4x05Demod, AlwaysAvailable, "demodulate a EM4x05/EM4x69 tag from the GraphBuffer"},
{"4x05_dump", CmdEM4x05Dump, IfPm3Lf, "dump EM4x05/EM4x69 tag"}, {"4x05_dump", CmdEM4x05Dump, IfPm3Lf, "dump EM4x05/EM4x69 tag"},
{"4x05_wipe", CmdEM4x05Wipe, IfPm3Lf, "wipe EM4x05/EM4x69 tag"}, {"4x05_wipe", CmdEM4x05Wipe, IfPm3Lf, "wipe EM4x05/EM4x69 tag"},

View file

@ -17,6 +17,7 @@ int CmdLFEM4X(const char *Cmd);
int demodEM410x(bool verbose); int demodEM410x(bool verbose);
bool EM4x05IsBlock0(uint32_t *word); 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); void printEM410x(uint32_t hi, uint64_t id);
int AskEm410xDecode(bool verbose, uint32_t *hi, uint64_t *lo); int AskEm410xDecode(bool verbose, uint32_t *hi, uint64_t *lo);

View file

@ -93,7 +93,7 @@ static int usage_lf_em4x50_wipe(void) {
PrintAndLogEx(NORMAL, " h - this help"); PrintAndLogEx(NORMAL, " h - this help");
PrintAndLogEx(NORMAL, " p <pwd> - password (hex)"); PrintAndLogEx(NORMAL, " p <pwd> - password (hex)");
PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_wwipe p 11223344")); PrintAndLogEx(NORMAL, _YELLOW_(" lf em 4x50_wipe p 11223344"));
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS; return PM3_SUCCESS;
} }

View file

@ -8,7 +8,7 @@
// Differential Biphase, rf/32, 128 bits (known) // Differential Biphase, rf/32, 128 bits (known)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#include "cmdlffdx.h" #include "cmdlffdxb.h"
#include <inttypes.h> #include <inttypes.h>
#include <string.h> #include <string.h>
@ -48,9 +48,9 @@
static int CmdHelp(const char *Cmd); 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, "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, "Options:");
PrintAndLogEx(NORMAL, " h : This help"); PrintAndLogEx(NORMAL, " h : This help");
PrintAndLogEx(NORMAL, " c <country> : (dec) Country code"); 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, " <Q5> : Specify writing to Q5/T5555 tag");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" lf fdx clone c 999 n 112233 s")); PrintAndLogEx(NORMAL, _YELLOW_(" lf fdxb 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 e 16a"));
return PM3_SUCCESS; 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, "Read FDX-B animal tag");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf fdx read [h] [@]"); PrintAndLogEx(NORMAL, "Usage: lf fdxb read [h] [@]");
PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : This help"); PrintAndLogEx(NORMAL, " h : This help");
PrintAndLogEx(NORMAL, " @ : run continuously until a key is pressed (optional)"); PrintAndLogEx(NORMAL, " @ : run continuously until a key is pressed (optional)");
@ -76,11 +76,11 @@ static int usage_lf_fdx_read(void) {
return PM3_SUCCESS; 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, "Enables simulation of FDX-B animal tag");
PrintAndLogEx(NORMAL, "Simulation runs until the button is pressed or another USB command is issued."); PrintAndLogEx(NORMAL, "Simulation runs until the button is pressed or another USB command is issued.");
PrintAndLogEx(NORMAL, ""); 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, "Options:");
PrintAndLogEx(NORMAL, " h : This help"); PrintAndLogEx(NORMAL, " h : This help");
PrintAndLogEx(NORMAL, " c <country> : (dec) Country code"); 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, " <Q5> : Specify writing to Q5/T5555 tag");
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" lf fdx sim c 999 n 112233 s")); PrintAndLogEx(NORMAL, _YELLOW_(" lf fdxb 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 e 16a"));
return PM3_SUCCESS; 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 //see ASKDemod for what args are accepted
//almost the same demod as cmddata.c/CmdFDXBdemodBI //almost the same demod as cmddata.c/CmdFDXBdemodBI
int demodFDX(bool verbose) { int demodFDXB(bool verbose) {
//Differential Biphase / di-phase (inverted biphase) //Differential Biphase / di-phase (inverted biphase)
//get binary from ask wave //get binary from ask wave
if (ASKbiphaseDemod(0, 32, 1, 100, false) != PM3_SUCCESS) { if (ASKbiphaseDemod(0, 32, 1, 100, false) != PM3_SUCCESS) {
@ -253,18 +519,34 @@ int demodFDX(bool verbose) {
//got a good demod //got a good demod
uint8_t offset; uint8_t offset;
// ISO: bits 27..64
uint64_t NationalCode = ((uint64_t)(bytebits_to_byteLSBF(DemodBuffer + 32, 6)) << 32) | bytebits_to_byteLSBF(DemodBuffer, 32); uint64_t NationalCode = ((uint64_t)(bytebits_to_byteLSBF(DemodBuffer + 32, 6)) << 32) | bytebits_to_byteLSBF(DemodBuffer, 32);
offset = 38; offset = 38;
// ISO: bits 17..26
uint16_t countryCode = bytebits_to_byteLSBF(DemodBuffer + offset, 10); uint16_t countryCode = bytebits_to_byteLSBF(DemodBuffer + offset, 10);
offset += 10; offset += 10;
// ISO: bits 16
uint8_t dataBlockBit = DemodBuffer[offset]; uint8_t dataBlockBit = DemodBuffer[offset];
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]; uint8_t animalBit = DemodBuffer[offset];
offset++; offset++;
@ -283,12 +565,15 @@ int demodFDX(bool verbose) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
PrintAndLogEx(SUCCESS, "FDX-B / ISO 11784/5 Animal"); 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, "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, "Reserved/RFU %u (0x%04X)", reservedCode, reservedCode);
PrintAndLogEx(SUCCESS, " Animal bit set? %s", animalBit ? _YELLOW_("True") : "False"); 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, " 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}; uint8_t c[] = {0, 0};
compute_crc(CRC_11784, raw, sizeof(raw), &c[0], &c[1]); compute_crc(CRC_11784, raw, sizeof(raw), &c[0], &c[1]);
@ -321,12 +606,12 @@ int demodFDX(bool verbose) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int CmdFdxDemod(const char *Cmd) { static int CmdFdxBDemod(const char *Cmd) {
(void)Cmd; // Cmd is not used so far (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; sample_config config;
memset(&config, 0, sizeof(sample_config)); memset(&config, 0, sizeof(sample_config));
int retval = lf_getconfig(&config); int retval = lf_getconfig(&config);
@ -341,7 +626,7 @@ static int CmdFdxRead(const char *Cmd) {
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (tolower(param_getchar(Cmd, cmdp))) { switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h': case 'h':
return usage_lf_fdx_read(); return usage_lf_fdxb_read();
case '@': case '@':
continuous = true; continuous = true;
cmdp++; cmdp++;
@ -354,7 +639,7 @@ static int CmdFdxRead(const char *Cmd) {
} }
//Validations //Validations
if (errors) return usage_lf_fdx_read(); if (errors) return usage_lf_fdxb_read();
int16_t tmp_div = config.divisor; int16_t tmp_div = config.divisor;
if (tmp_div != LF_DIVISOR_134) { if (tmp_div != LF_DIVISOR_134) {
config.divisor = 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"); PrintAndLogEx(ERR, "failed to get LF read from device");
return retval; 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()) { if (kbd_enter_pressed()) {
break; break;
} }
@ -392,7 +677,7 @@ static int CmdFdxRead(const char *Cmd) {
return ret; return ret;
} }
static int CmdFdxClone(const char *Cmd) { static int CmdFdxBClone(const char *Cmd) {
uint32_t country_code = 0, extended = 0; uint32_t country_code = 0, extended = 0;
uint64_t national_code = 0; uint64_t national_code = 0;
@ -402,7 +687,7 @@ static int CmdFdxClone(const char *Cmd) {
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (tolower(param_getchar(Cmd, cmdp))) { switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h': case 'h':
return usage_lf_fdx_clone(); return usage_lf_fdxb_clone();
case 'c': { case 'c': {
country_code = param_get32ex(Cmd, cmdp + 1, 0, 10); country_code = param_get32ex(Cmd, cmdp + 1, 0, 10);
cmdp += 2; 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); verify_values(&national_code, &country_code, &extended, &is_animal);
@ -448,7 +733,7 @@ static int CmdFdxClone(const char *Cmd) {
PrintAndLogEx(INFO, " RFU 0"); PrintAndLogEx(INFO, " RFU 0");
uint8_t *bits = calloc(128, sizeof(uint8_t)); 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."); PrintAndLogEx(ERR, "Error with tag bitstream generation.");
free(bits); free(bits);
return PM3_ESOFT; return PM3_ESOFT;
@ -473,11 +758,11 @@ static int CmdFdxClone(const char *Cmd) {
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks)); int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
PrintAndLogEx(SUCCESS, "Done"); 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; return res;
} }
static int CmdFdxSim(const char *Cmd) { static int CmdFdxBSim(const char *Cmd) {
uint32_t country_code = 0, extended = 0; uint32_t country_code = 0, extended = 0;
uint64_t national_code = 0; uint64_t national_code = 0;
@ -487,7 +772,7 @@ static int CmdFdxSim(const char *Cmd) {
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (tolower(param_getchar(Cmd, cmdp))) { switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h': case 'h':
return usage_lf_fdx_sim(); return usage_lf_fdxb_sim();
case 'c': { case 'c': {
country_code = param_get32ex(Cmd, cmdp + 1, 0, 10); country_code = param_get32ex(Cmd, cmdp + 1, 0, 10);
cmdp += 2; 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); 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); PrintAndLogEx(SUCCESS, "Simulating FDX-B animal ID: " _GREEN_("%04u-%"PRIu64), country_code, national_code);
uint8_t *bits = calloc(128, sizeof(uint8_t)); 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."); PrintAndLogEx(ERR, "Error with tag bitstream generation.");
free(bits); free(bits);
return PM3_ESOFT; return PM3_ESOFT;
@ -562,10 +847,10 @@ static int CmdFdxSim(const char *Cmd) {
static command_t CommandTable[] = { static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "this help"}, {"help", CmdHelp, AlwaysAvailable, "this help"},
{"demod", CmdFdxDemod, AlwaysAvailable, "demodulate a FDX-B ISO11784/85 tag from the GraphBuffer"}, {"demod", CmdFdxBDemod, AlwaysAvailable, "demodulate a FDX-B ISO11784/85 tag from the GraphBuffer"},
{"read", CmdFdxRead, IfPm3Lf, "attempt to read at 134kHz and extract tag data"}, {"read", CmdFdxBRead, IfPm3Lf, "attempt to read at 134kHz and extract tag data"},
{"clone", CmdFdxClone, IfPm3Lf, "clone animal ID tag to T55x7 or Q5/T5555"}, {"clone", CmdFdxBClone, IfPm3Lf, "clone animal ID tag to T55x7 or Q5/T5555"},
{"sim", CmdFdxSim, IfPm3Lf, "simulate Animal ID tag"}, {"sim", CmdFdxBSim, IfPm3Lf, "simulate Animal ID tag"},
{NULL, NULL, NULL, NULL} {NULL, NULL, NULL, NULL}
}; };
@ -575,7 +860,7 @@ static int CmdHelp(const char *Cmd) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
int CmdLFFdx(const char *Cmd) { int CmdLFFdxB(const char *Cmd) {
clearCommandBuffer(); clearCommandBuffer();
return CmdsParse(CommandTable, Cmd); 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}; uint8_t preamble[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
if (!preambleSearch(dest, preamble, sizeof(preamble), size, &startIdx)) if (!preambleSearch(dest, preamble, sizeof(preamble), size, &startIdx))
return -2; //preamble not found 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 start position
return (int)startIdx; 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 // add preamble ten 0x00 and one 0x01
memset(bits, 0x00, 10); 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); raw[i] = bytebits_to_byte(bits + 11 + i * 9, 8);
init_table(CRC_11784); 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 >> 0, 8, bits + 83);
num_to_bytebitsLSBF(crc >> 8, 8, bits + 92); num_to_bytebitsLSBF(crc >> 8, 8, bits + 92);

View file

@ -6,15 +6,20 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Low frequency fdx-b tag commands // Low frequency fdx-b tag commands
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#ifndef CMDLFFDX_H__ #ifndef CMDLFFDXB_H__
#define CMDLFFDX_H__ #define CMDLFFDXB_H__
#include "common.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 detectFDXB(uint8_t *dest, size_t *size);
int demodFDX(bool verbose); int demodFDXB(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 getFDXBBits(uint64_t national_code, uint16_t country_code, uint8_t is_animal, uint8_t is_extended, uint32_t extended, uint8_t *bits);
#endif #endif

View file

@ -37,6 +37,7 @@
#include "util_posix.h" #include "util_posix.h"
#include "lfdemod.h" #include "lfdemod.h"
#include "wiegand_formats.h" #include "wiegand_formats.h"
#include "wiegand_formatutils.h"
#ifndef BITS #ifndef BITS
# define BITS 96 # define BITS 96
@ -135,61 +136,8 @@ int demodHID(bool verbose) {
return PM3_ESOFT; return PM3_ESOFT;
} }
if (hi2 != 0) { //extra large HID tags wiegand_message_t packed = initialize_message_object(hi2, hi, lo);
PrintAndLogEx(SUCCESS, "HID Prox - " _GREEN_("%x%08x%08x (%u)"), hi2, hi, lo, (lo >> 1) & 0xFFFF); HIDTryUnpack(&packed, false);
} 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);
}
}
PrintAndLogEx(DEBUG, "DEBUG: HID idx: %d, Len: %zu, Printing Demod Buffer: ", idx, size); PrintAndLogEx(DEBUG, "DEBUG: HID idx: %d, Len: %zu, Printing Demod Buffer: ", idx, size);
if (g_debugMode) 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. // this read is the "normal" read, which download lf signal and tries to demod here.
static int CmdHIDRead(const char *Cmd) { static int CmdHIDRead(const char *Cmd) {
(void)Cmd; // Cmd is not used so far (void)Cmd; // Cmd is not used so far
lf_read(false, 12000); lf_read(false, 16000);
return demodHID(true); return demodHID(true);
} }
@ -239,62 +187,85 @@ static int CmdHIDWatch(const char *Cmd) {
} }
static int CmdHIDSim(const char *Cmd) { static int CmdHIDSim(const char *Cmd) {
int idlen = 0;
uint8_t id[10] = {0};
lf_hidsim_t payload;
payload.longFMT = 0;
uint32_t hi2 = 0, hi = 0, lo = 0;
uint32_t i = 0;
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "lf hid sim", CLIParserInit(&ctx, "lf hid sim",
"Enables simulation of HID card with card number.", "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[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_lit0("l", "long", "Simulate HID tag with long ID"), arg_str0("w", "wiegand", "<format>", "see " _YELLOW_("`wiegand list`") " for available formats"),
arg_str1(NULL, NULL, "<hex>", "HID tag ID"), 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 arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, false); 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); CLIParserFree(ctx);
if (long_id) { wiegand_message_t packed;
for (i=0; i < idlen; ++i) { memset(&packed, 0, sizeof(wiegand_message_t));
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); // format validation
hi = (hi << 4) | (lo >> 28); int format_idx = HIDFindCardFormat((char *)format);
lo = (lo << 4) | (id[i] & 0xf); //get last 4 bits if (format_idx == -1 && raw_len == 0) {
PrintAndLogEx(WARNING, "Unknown format: " _YELLOW_("%s"), format);
return PM3_EINVARG;
} }
PrintAndLogEx(INFO, "Simulating HID tag with long ID: " _GREEN_("%x%08x%08x"), hi2, hi, lo);
payload.longFMT = 1; 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 { } else {
for (i=0; i < idlen; ++i) { if (HIDPack(format_idx, &card, &packed) == false) {
hi = (hi << 4) | (lo >> 28); PrintAndLogEx(WARNING, "The card data could not be encoded in the selected format.");
lo = (lo << 4) | (id[i] >> 4); //get first 4 bits return PM3_ESOFT;
hi = (hi << 4) | (lo >> 28);
lo = (lo << 4) | (id[i] & 0xf); //get last 4 bits
} }
PrintAndLogEx(SUCCESS, "Simulating HID tag with ID: " _GREEN_("%x%08x"), hi, lo); }
hi2 = 0;
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"); PrintAndLogEx(INFO, "Press pm3-button to abort simulation");
payload.hi2 = hi2; lf_hidsim_t payload;
payload.hi = hi; payload.hi2 = packed.Top;
payload.lo = lo; payload.hi = packed.Mid;
payload.lo = packed.Bot;
payload.longFMT = (packed.Mid > 0xFFF);
clearCommandBuffer(); clearCommandBuffer();
SendCommandNG(CMD_LF_HID_SIMULATE, (uint8_t *)&payload, sizeof(payload)); SendCommandNG(CMD_LF_HID_SIMULATE, (uint8_t *)&payload, sizeof(payload));
@ -303,66 +274,92 @@ static int CmdHIDSim(const char *Cmd) {
PrintAndLogEx(INFO, "Done"); PrintAndLogEx(INFO, "Done");
if (resp.status != PM3_EOPABORTED) if (resp.status != PM3_EOPABORTED)
return resp.status; return resp.status;
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int CmdHIDClone(const char *Cmd) { static int CmdHIDClone(const char *Cmd) {
int idlen = 0;
uint8_t id[10] = {0};
uint32_t hi2 = 0, hi = 0, lo = 0;
uint32_t i = 0;
CLIParserContext *ctx; CLIParserContext *ctx;
CLIParserInit(&ctx, "lf hid clone", CLIParserInit(&ctx, "lf hid clone",
"Clone HID to T55x7. Tag must be on antenna!", "Clone HID to T55x7. Tag must be on antenna!",
"lf hid clone 2006ec0c86\n" "lf hid clone -r 2006ec0c86 -> HID 10301 26 bit\n"
"lf hid clone -l 2006ec0c86" "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[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_lit0("l", "long", "84bit HID long ID"), arg_str0("w", "wiegand", "<format>", "see " _YELLOW_("`wiegand list`") " for available formats"),
arg_str1(NULL, NULL, "<hex>", "HID tag ID"), 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 arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, false); 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); CLIParserFree(ctx);
uint8_t longid[1] = {0}; wiegand_message_t packed;
memset(&packed, 0, sizeof(wiegand_message_t));
if (long_id) { // format validation
for (i=0; i < idlen; ++i) { int format_idx = HIDFindCardFormat((char *)format);
hi2 = (hi2 << 4) | (hi >> 28); if (format_idx == -1 && raw_len == 0) {
hi = (hi << 4) | (lo >> 28); PrintAndLogEx(WARNING, "Unknown format: " _YELLOW_("%s"), format);
lo = (lo << 4) | (id[i] >> 4); //get first 4 bits return PM3_EINVARG;
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; 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 { } else {
for (i=0; i < idlen; ++i) { if (HIDPack(format_idx, &card, &packed) == false) {
hi = (hi << 4) | (lo >> 28); PrintAndLogEx(WARNING, "The card data could not be encoded in the selected format.");
lo = (lo << 4) | (id[i] >> 4); //get first 4 bits return PM3_ESOFT;
}
}
hi = (hi << 4) | (lo >> 28); if (raw_len == 0) {
lo = (lo << 4) | (id[i] & 0xf); //get last 4 bits PrintAndLogEx(INFO, "Preparing to clone HID tag");
} HIDTryUnpack(&packed, false);
PrintAndLogEx(INFO, "Preparing to clone HID tag with ID: " _GREEN_("%x%08x"), hi, lo); } else {
hi2 = 0; 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(); 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(SUCCESS, "Done");
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf hid read`") " to verify"); PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf hid read`") " to verify");
return PM3_SUCCESS; return PM3_SUCCESS;
@ -399,20 +396,20 @@ static int CmdHIDBrute(const char *Cmd) {
"Enables bruteforce of HID readers with specified facility code.\n" "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" "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", "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 --fc 224\n"
"lf hid brute -w H10301 -f 21 -d 2000\n" "lf hid brute -w H10301 --fc 21 -d 2000\n"
"lf hid brute -v -w H10301 -f 21 -c 200 -d 2000\n" "lf hid brute -v -w H10301 --fc 21 --cn 200 -d 2000\n"
); );
void *argtable[] = { void *argtable[] = {
arg_param_begin, arg_param_begin,
arg_lit0("v", "verbose", "verbose logging, show all tries"), arg_lit0("v", "verbose", "verbose logging, show all tries"),
arg_str1("w", "wiegand", "format", "see " _YELLOW_("`wiegand list`") " for available formats"), arg_str1("w", "wiegand", "<format>", "see " _YELLOW_("`wiegand list`") " for available formats"),
arg_int0("f", "fn", "dec", "facility code"), arg_int0(NULL, "fn", "<dec>", "facility code"),
arg_int0("c", "cn", "dec", "card number to start with"), arg_int0(NULL, "cn", "<dec>", "card number to start with"),
arg_int0("i", NULL, "dec", "issue level"), arg_int0("i", "issue", "<dec>", "issue level"),
arg_int0("o", "oem", "dec", "OEM code"), arg_int0("o", "oem", "<dec>", "OEM code"),
arg_int0("d", "delay", "dec", "delay betweens attempts in ms. Default 1000ms"), 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, "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(NULL, "down", "direction to decrement card number. (default is both directions)"),
arg_param_end arg_param_end
@ -423,9 +420,10 @@ static int CmdHIDBrute(const char *Cmd) {
CLIGetStrWithReturn(ctx, 2, format, &formatLen); CLIGetStrWithReturn(ctx, 2, format, &formatLen);
format_idx = HIDFindCardFormat((char*) format); format_idx = HIDFindCardFormat((char *) format);
if (format_idx == -1) { if (format_idx == -1) {
PrintAndLogEx(WARNING, "Unknown format: " _YELLOW_("%s"), format); PrintAndLogEx(WARNING, "Unknown format: " _YELLOW_("%s"), format);
CLIParserFree(ctx);
return PM3_EINVARG; return PM3_EINVARG;
} }
@ -435,6 +433,8 @@ static int CmdHIDBrute(const char *Cmd) {
cn_hi.OEM = arg_get_int_def(ctx, 6, 0); cn_hi.OEM = arg_get_int_def(ctx, 6, 0);
delay = arg_get_int_def(ctx, 7, 1000); delay = arg_get_int_def(ctx, 7, 1000);
CLIParserFree(ctx);
if (arg_get_lit(ctx, 8) && arg_get_lit(ctx, 9)) { if (arg_get_lit(ctx, 8) && arg_get_lit(ctx, 9)) {
direction = 0; direction = 0;
} else if (arg_get_lit(ctx, 8)) { } else if (arg_get_lit(ctx, 8)) {

View file

@ -149,9 +149,14 @@ static int usage_hitag_checkchallenges(void) {
} }
static int CmdLFHitagList(const char *Cmd) { static int CmdLFHitagList(const char *Cmd) {
(void)Cmd; // Cmd is not used so far char args[128] = {0};
CmdTraceList("hitag2"); if (strlen(Cmd) == 0) {
return PM3_SUCCESS; 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)); uint8_t *got = calloc(PM3_CMD_DATA_SIZE, sizeof(uint8_t));

View file

@ -656,6 +656,7 @@ static int CmdIndalaClone(const char *Cmd) {
if (getIndalaBits(fc, cn, bits) != PM3_SUCCESS) { if (getIndalaBits(fc, cn, bits) != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Error with tag bitstream generation."); PrintAndLogEx(ERR, "Error with tag bitstream generation.");
free(bits);
return PM3_ESOFT; return PM3_ESOFT;
} }

View file

@ -383,7 +383,7 @@ static int usage_t55xx_clonehelp(void) {
// todo: implement restore // todo: implement restore
// PrintAndLogEx(NORMAL, _GREEN_("lf em 4x05_write")); // PrintAndLogEx(NORMAL, _GREEN_("lf em 4x05_write"));
// PrintAndLogEx(NORMAL, _GREEN_("lf em 4x50_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 gallagher clone"));
PrintAndLogEx(NORMAL, _GREEN_("lf gproxii clone")); PrintAndLogEx(NORMAL, _GREEN_("lf gproxii clone"));
PrintAndLogEx(NORMAL, _GREEN_("lf hid 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) if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password, m) == false)
continue; continue;
if (tryDetectModulationEx(m, verbose, known_block0, (usepwd) ? password : -1) == false) if (t55xxTryDetectModulationEx(m, verbose, known_block0, (usepwd) ? password : -1) == false)
continue; continue;
config.downlink_mode = m; 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) if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, false, 0, downlink_mode) == false)
return PM3_ERFTRANS; 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."); PrintAndLogEx(WARNING, "Safety check: Could not detect if PWD bit is set in config block. Exits.");
return PM3_EWRONGANSWER; return PM3_EWRONGANSWER;
} else { } 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) if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, (try_with_pwd && usepwd), password, m) == false)
continue; 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; continue;
found = true; found = true;
@ -1090,7 +1090,7 @@ static int CmdT55xxDetect(const char *Cmd) {
} }
} else { } else {
if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password, downlink_mode)) { 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); } while (try_with_pwd);
} else { } else {
found = tryDetectModulation(downlink_mode, T55XX_PrintConfig); found = t55xxTryDetectModulation(downlink_mode, T55XX_PrintConfig);
} }
if (found == false) { if (found == false) {
@ -1117,11 +1117,11 @@ static int CmdT55xxDetect(const char *Cmd) {
} }
// detect configuration? // detect configuration?
bool tryDetectModulation(uint8_t downlink_mode, bool print_config) { bool t55xxTryDetectModulation(uint8_t downlink_mode, bool print_config) {
return tryDetectModulationEx(downlink_mode, print_config, 0, -1); 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]; t55xx_conf_block_t tests[15];
int bitRate = 0, clk = 0, firstClockEdge = 0; 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); PrintAndLogEx(SUCCESS, "\nFound a candidate [ " _YELLOW_("%08"PRIX32) " ]", packet->candidate);
if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, packet->candidate, downlink_mode)) { 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) { if (found) {
PrintAndLogEx(SUCCESS, "Found valid password [ " _GREEN_("%08"PRIX32) " ]", packet->candidate); PrintAndLogEx(SUCCESS, "Found valid password [ " _GREEN_("%08"PRIX32) " ]", packet->candidate);
@ -3105,7 +3105,7 @@ static int CmdT55xxChkPwds(const char *Cmd) {
continue; continue;
} }
found = tryDetectModulationEx(dl_mode, T55XX_PrintConfig, 0, cardPassword); found = t55xxTryDetectModulationEx(dl_mode, T55XX_PrintConfig, 0, cardPassword);
if (found) { if (found) {
PrintAndLogEx(SUCCESS, "Found valid password : [ " _GREEN_("%08"PRIX32) " ]", cardPassword); PrintAndLogEx(SUCCESS, "Found valid password : [ " _GREEN_("%08"PRIX32) " ]", cardPassword);
dl_mode = 4; // Exit other downlink mode checks dl_mode = 4; // Exit other downlink mode checks
@ -3150,7 +3150,7 @@ static int CmdT55xxChkPwds(const char *Cmd) {
continue; continue;
} }
found = tryDetectModulationEx(dl_mode, T55XX_PrintConfig, 0, curr_password); found = t55xxTryDetectModulationEx(dl_mode, T55XX_PrintConfig, 0, curr_password);
if (found) { if (found) {
PrintAndLogEx(SUCCESS, "Found valid password: [ " _GREEN_("%08"PRIX32) " ]", curr_password); PrintAndLogEx(SUCCESS, "Found valid password: [ " _GREEN_("%08"PRIX32) " ]", curr_password);
dl_mode = 4; // Exit other downlink mode checks 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 (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, password, dl_mode)) {
// if (getSignalProperties()->isnoise == false) { // if (getSignalProperties()->isnoise == false) {
// } else { // } else {
if (tryDetectModulationEx(dl_mode, T55XX_PrintConfig, 0, password)) { if (t55xxTryDetectModulationEx(dl_mode, T55XX_PrintConfig, 0, password)) {
return 1 + (dl_mode << 1); return 1 + (dl_mode << 1);
} }
// } // }

View file

@ -105,8 +105,7 @@ typedef struct {
uint32_t dw; uint32_t dw;
} t5555_tracedata_t; } t5555_tracedata_t;
typedef struct { typedef enum {
enum {
DEMOD_NRZ = 0x00, DEMOD_NRZ = 0x00,
DEMOD_PSK1 = 0x01, DEMOD_PSK1 = 0x01,
DEMOD_PSK2 = 0x02, DEMOD_PSK2 = 0x02,
@ -119,7 +118,10 @@ typedef struct {
DEMOD_ASK = 0x08, DEMOD_ASK = 0x08,
DEMOD_BI = 0x10, DEMOD_BI = 0x10,
DEMOD_BIa = 0x18, DEMOD_BIa = 0x18,
} modulation; } t55xx_modulation;
typedef struct {
t55xx_modulation modulation;
bool inverted; bool inverted;
uint8_t offset; uint8_t offset;
uint32_t block0; 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 GetT55xxBlockData(uint32_t *blockdata);
bool DecodeT55xxBlock(void); bool DecodeT55xxBlock(void);
bool tryDetectModulation(uint8_t downlink_mode, bool print_config); bool t55xxTryDetectModulation(uint8_t downlink_mode, bool print_config);
//bool tryDetectModulationEx(uint8_t downlink_mode, bool print_config, uint32_t wanted_conf); //bool t55xxTryDetectModulationEx(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 t55xxTryDetectModulationEx(uint8_t downlink_mode, bool print_config, uint32_t wanted_conf, uint64_t pwd);
bool testKnownConfigBlock(uint32_t block0); bool testKnownConfigBlock(uint32_t block0);
bool tryDetectP1(bool getData); bool tryDetectP1(bool getData);

View file

@ -292,7 +292,7 @@ static int CmdScriptRun(const char *Cmd) {
// get the top of the stack as the error and pop it off // get the top of the stack as the error and pop it off
const char *str = lua_tostring(lua_state, lua_gettop(lua_state)); const char *str = lua_tostring(lua_state, lua_gettop(lua_state));
lua_pop(lua_state, 1); lua_pop(lua_state, 1);
puts(str); PrintAndLogEx(FAILED, _RED_("error") " - %s", str);
} }
//luaL_dofile(lua_state, buf); //luaL_dofile(lua_state, buf);

View file

@ -844,9 +844,13 @@ static int CmdSmartSetClock(const char *Cmd) {
} }
static int CmdSmartList(const char *Cmd) { static int CmdSmartList(const char *Cmd) {
(void)Cmd; // Cmd is not used so far char args[128] = {0};
CmdTraceList("7816"); if (strlen(Cmd) == 0) {
return PM3_SUCCESS; snprintf(args, sizeof(args), "-t 7816");
} else {
strncpy(args, Cmd, sizeof(args) - 1);
}
return CmdTraceList(args);
} }
static void smart_brute_prim(void) { static void smart_brute_prim(void) {

View file

@ -19,6 +19,7 @@
#include "fileutils.h" // for saveFile #include "fileutils.h" // for saveFile
#include "cmdlfhitag.h" // annotate hitag #include "cmdlfhitag.h" // annotate hitag
#include "pm3_cmd.h" // tracelog_hdr_t #include "pm3_cmd.h" // tracelog_hdr_t
#include "cliparser.h" // args..
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);
@ -26,56 +27,6 @@ static int CmdHelp(const char *Cmd);
static uint8_t *g_trace; static uint8_t *g_trace;
static long g_traceLen = 0; 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) { static bool is_last_record(uint16_t tracepos, uint16_t traceLen) {
return ((tracepos + TRACELOG_HDR_LEN) >= 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}; char temp_str2[3] = {0};
sprintf(data_len_str, "%04x", hdr->data_len); sprintf(data_len_str, "%04x", hdr->data_len);
strncat(temp_str1, data_len_str, 2); memmove(temp_str1, data_len_str, 2);
temp_str1[2] = '\0'; memmove(temp_str2, data_len_str + 2, 2);
strncat(temp_str2, data_len_str + 2, 2);
temp_str2[2] = '\0';
PrintAndLogEx(NORMAL, "0.%010u", hdr->timestamp); PrintAndLogEx(NORMAL, "0.%010u", hdr->timestamp);
PrintAndLogEx(NORMAL, "000000 00 %s %s %s %s", 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; data_len = hdr->data_len;
if (tracepos + TRACELOG_HDR_LEN + data_len + TRACELOG_PARITY_LEN(hdr) > traceLen) { 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; return traceLen;
} }
@ -212,7 +161,6 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
duration *= 32; duration *= 32;
} }
uint8_t *frame = hdr->frame; uint8_t *frame = hdr->frame;
uint8_t *parityBytes = hdr->frame + data_len; uint8_t *parityBytes = hdr->frame + data_len;
@ -568,11 +516,24 @@ static int SanityOfflineCheck( bool useTraceBuffer ){
static int CmdTraceLoad(const char *Cmd) { static int CmdTraceLoad(const char *Cmd) {
char cmdp = tolower(param_getchar(Cmd, 0)); CLIParserContext *ctx;
if (strlen(Cmd) < 1 || (strlen(Cmd) == 1 && cmdp == 'h')) return usage_trace_load(); 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]; void *argtable[] = {
param_getstr(Cmd, 0, filename, sizeof(filename)); 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) if (g_trace)
free(g_trace); free(g_trace);
@ -591,8 +552,24 @@ static int CmdTraceLoad(const char *Cmd) {
static int CmdTraceSave(const char *Cmd) { static int CmdTraceSave(const char *Cmd) {
char cmdp = tolower(param_getchar(Cmd, 0)); CLIParserContext *ctx;
if (strlen(Cmd) < 1 || (strlen(Cmd) == 1 && cmdp == 'h')) return usage_trace_save(); 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) { if (g_traceLen == 0) {
download_trace(); download_trace();
@ -603,68 +580,68 @@ static int CmdTraceSave(const char *Cmd) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
char filename[FILE_PATH_SIZE];
param_getstr(Cmd, 0, filename, sizeof(filename));
saveFile(filename, ".trace", g_trace, g_traceLen); saveFile(filename, ".trace", g_trace, g_traceLen);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
int CmdTraceList(const char *Cmd) { 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(); clearCommandBuffer();
bool showWaitCycles = false, markCRCBytes = false; // no crc, no annotations
bool showHex = false, isOnline = true; uint8_t protocol = -1;
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) {
int slen = param_getstr(Cmd, cmdp, type, sizeof(type));
if (slen == 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 // validate type of output
if (strcmp(type, "iclass") == 0) protocol = ICLASS; if (strcmp(type, "iclass") == 0) protocol = ICLASS;
@ -683,19 +660,9 @@ int CmdTraceList(const char *Cmd) {
else if (strcmp(type, "thinfilm") == 0) protocol = THINFILM; else if (strcmp(type, "thinfilm") == 0) protocol = THINFILM;
else if (strcmp(type, "lto") == 0) protocol = LTO; else if (strcmp(type, "lto") == 0) protocol = LTO;
else if (strcmp(type, "cryptorf") == 0) protocol = PROTO_CRYPTORF; else if (strcmp(type, "cryptorf") == 0) protocol = PROTO_CRYPTORF;
else if (strcmp(type, "raw") == 0) protocol = -1; //No crc, no annotations else if (strcmp(type, "raw") == 0) protocol = -1;
else errors = true;
cmdp++; if (use_buffer == false || (g_traceLen == 0)) {
}
}
//if (!SanityOfflineCheck(isOnline)) return 1;
//Validations
if (errors) return usage_trace_list();
if (isOnline) {
download_trace(); download_trace();
} }
@ -711,7 +678,7 @@ int CmdTraceList(const char *Cmd) {
printFelica(g_traceLen, g_trace); printFelica(g_traceLen, g_trace);
} */ } */
if (showHex) { if (show_hex) {
while (tracepos < g_traceLen) { while (tracepos < g_traceLen) {
tracepos = printHexLine(tracepos, g_traceLen, g_trace, protocol); tracepos = printHexLine(tracepos, g_traceLen, g_trace, protocol);
} }
@ -788,12 +755,16 @@ int CmdTraceList(const char *Cmd) {
} }
while (tracepos < g_traceLen) { 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()) if (kbd_enter_pressed())
break; 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; return PM3_SUCCESS;
} }

View file

@ -26,7 +26,7 @@
static int CmdHelp(const char *Cmd); static int CmdHelp(const char *Cmd);
static void print_wiegand_code(wiegand_message_t *packed) { static void print_wiegand_code(wiegand_message_t *packed) {
const char* s = "Encoded wiegand: "; const char *s = "Encoded wiegand: ";
if (packed->Top != 0) { if (packed->Top != 0) {
PrintAndLogEx(SUCCESS, "%s" _GREEN_("%X%08X%08X"), PrintAndLogEx(SUCCESS, "%s" _GREEN_("%X%08X%08X"),
s, s,
@ -76,7 +76,7 @@ int CmdWiegandEncode(const char *Cmd) {
arg_u64_1(NULL, "cn", "<dec>", "card number"), arg_u64_1(NULL, "cn", "<dec>", "card number"),
arg_u64_0(NULL, "issue", "<dec>", "issue level"), arg_u64_0(NULL, "issue", "<dec>", "issue level"),
arg_u64_0(NULL, "oem", "<dec>", "OEM code"), 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 arg_param_end
}; };
CLIExecWithReturn(ctx, Cmd, argtable, true); CLIExecWithReturn(ctx, Cmd, argtable, true);
@ -91,7 +91,7 @@ int CmdWiegandEncode(const char *Cmd) {
int len = 0; int len = 0;
char format[16] = {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); CLIParserFree(ctx);
int idx = HIDFindCardFormat(format); int idx = HIDFindCardFormat(format);
@ -131,7 +131,7 @@ int CmdWiegandDecode(const char *Cmd) {
bool ignore_parity = arg_get_lit(ctx, 1); bool ignore_parity = arg_get_lit(ctx, 1);
int len = 0; int len = 0;
char hex[40] = {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); CLIParserFree(ctx);
if (len == 0) { if (len == 0) {

View file

@ -1772,8 +1772,13 @@ static int CmdEMVScan(const char *Cmd) {
} }
static int CmdEMVList(const char *Cmd) { static int CmdEMVList(const char *Cmd) {
(void)Cmd; // Cmd is not used so far char args[128] = {0};
return CmdTraceList("7816"); 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) { static int CmdEMVTest(const char *Cmd) {

View file

@ -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))); 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_temp);
mbedtls_mpi_free(&t_prime); 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; ret = true;

View file

@ -9,9 +9,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#include "emvjson.h" #include "emvjson.h"
#include <string.h> #include <string.h>
#include "commonutil.h" // ARRAYLEN #include "commonutil.h" // ARRAYLEN
#include "ui.h" #include "ui.h"
#include "util.h" #include "util.h"
@ -75,7 +73,7 @@ int JsonSaveJsonObject(json_t *root, const char *path, json_t *value) {
return 1; return 1;
if (path[0] == '$') { 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); PrintAndLogEx(ERR, "ERROR: can't set json path: %s", error.text);
return 2; return 2;
} else { } else {

View file

@ -573,16 +573,16 @@ int saveFileJSONex(const char *preferredName, JSONFileType ftype, uint8_t *data,
int res = json_dump_file(root, fileName, JSON_INDENT(2)); int res = json_dump_file(root, fileName, JSON_INDENT(2));
if (res) { if (res) {
PrintAndLogEx(FAILED, "error: can't save the file: " _YELLOW_("%s"), fileName); PrintAndLogEx(FAILED, "error: can't save the file: " _YELLOW_("%s"), fileName);
json_decref(root);
retval = 200; retval = 200;
goto out; 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: out:
json_decref(root);
free(fileName); free(fileName);
return retval; return retval;
} }

View file

@ -190,12 +190,10 @@ int GetAskClock(const char *str, bool printAns) {
return clock1; return clock1;
} }
uint8_t GetPskCarrier(const char *str, bool printAns) { int GetPskCarrier(bool verbose) {
if (getSignalProperties()->isnoise) if (getSignalProperties()->isnoise)
return -1; return -1;
uint8_t carrier = 0;
uint8_t *bits = calloc(MAX_GRAPH_TRACE_LEN, sizeof(uint8_t)); uint8_t *bits = calloc(MAX_GRAPH_TRACE_LEN, sizeof(uint8_t));
if (bits == NULL) { if (bits == NULL) {
PrintAndLogEx(WARNING, "Failed to allocate memory"); 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); uint16_t fc = countFC(bits, size, false);
free(bits); free(bits);
carrier = fc & 0xFF;
uint8_t carrier = fc & 0xFF;
if (carrier != 2 && carrier != 4 && carrier != 8) return 0; if (carrier != 2 && carrier != 4 && carrier != 8) return 0;
if ((fc >> 8) == 10 && carrier == 8) return 0; if ((fc >> 8) == 10 && carrier == 8) return 0;
// Only print this message if we're not looping something // Only print this message if we're not looping something
if (printAns) if (verbose)
PrintAndLogEx(SUCCESS, "Auto-detected PSK carrier rate: %d", carrier); PrintAndLogEx(SUCCESS, "Auto-detected PSK carrier rate: %d", carrier);
return carrier; return carrier;
} }
int GetPskClock(const char *str, bool printAns) { int GetPskClock(const char *str, bool verbose) {
if (getSignalProperties()->isnoise) if (getSignalProperties()->isnoise)
return -1; return -1;
@ -251,14 +251,14 @@ int GetPskClock(const char *str, bool printAns) {
setClockGrid(clock1, firstPhaseShiftLoc); setClockGrid(clock1, firstPhaseShiftLoc);
// Only print this message if we're not looping something // Only print this message if we're not looping something
if (printAns) if (verbose)
PrintAndLogEx(SUCCESS, "Auto-detected clock rate: %d", clock1); PrintAndLogEx(SUCCESS, "Auto-detected clock rate: %d", clock1);
free(bits); free(bits);
return clock1; return clock1;
} }
int GetNrzClock(const char *str, bool printAns) { int GetNrzClock(const char *str, bool verbose) {
if (getSignalProperties()->isnoise) if (getSignalProperties()->isnoise)
return -1; return -1;
@ -285,7 +285,7 @@ int GetNrzClock(const char *str, bool printAns) {
clock1 = DetectNRZClock(bits, size, 0, &clkStartIdx); clock1 = DetectNRZClock(bits, size, 0, &clkStartIdx);
setClockGrid(clock1, clkStartIdx); setClockGrid(clock1, clkStartIdx);
// Only print this message if we're not looping something // Only print this message if we're not looping something
if (printAns) if (verbose)
PrintAndLogEx(SUCCESS, "Auto-detected clock rate: %d", clock1); PrintAndLogEx(SUCCESS, "Auto-detected clock rate: %d", clock1);
free(bits); free(bits);
@ -294,7 +294,7 @@ int GetNrzClock(const char *str, bool printAns) {
//by marshmellow //by marshmellow
//attempt to detect the field clock and bit clock for FSK //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); int clock1 = param_get32ex(str, 0, 0, 10);
if (clock1 != 0) if (clock1 != 0)
@ -307,7 +307,7 @@ int GetFskClock(const char *str, bool printAns) {
return 0; return 0;
if ((fc1 == 10 && fc2 == 8) || (fc1 == 8 && fc2 == 5)) { 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); PrintAndLogEx(SUCCESS, "Detected Field Clocks: FC/%d, FC/%d - Bit Clock: RF/%d", fc1, fc2, rf1);
setClockGrid(rf1, firstClockEdge); setClockGrid(rf1, firstClockEdge);

View file

@ -27,11 +27,11 @@ void convertGraphFromBitstream(void);
void convertGraphFromBitstreamEx(int hi, int low); void convertGraphFromBitstreamEx(int hi, int low);
bool isGraphBitstream(void); bool isGraphBitstream(void);
int GetAskClock(const char *str, bool printAns); int GetAskClock(const char *str, bool verbose);
int GetPskClock(const char *str, bool printAns); int GetPskClock(const char *str, bool verbose);
uint8_t GetPskCarrier(const char *str, bool printAns); int GetPskCarrier(bool verbose);
int GetNrzClock(const char *str, bool printAns); int GetNrzClock(const char *str, bool verbose);
int GetFskClock(const char *str, bool printAns); int GetFskClock(const char *str, bool verbose);
bool fskClocks(uint8_t *fc1, uint8_t *fc2, uint8_t *rf1, int *firstClockEdge); bool fskClocks(uint8_t *fc1, uint8_t *fc2, uint8_t *rf1, int *firstClockEdge);
#define MAX_GRAPH_TRACE_LEN (40000 * 8) #define MAX_GRAPH_TRACE_LEN (40000 * 8)

View file

@ -38,9 +38,7 @@ static void jsonp_free(void *ptr) {
} }
static char *jsonp_strndup(const char *str, size_t len) { static char *jsonp_strndup(const char *str, size_t len) {
char *new_str; char *new_str = jsonp_malloc(len + 1);
new_str = jsonp_malloc(len + 1);
if (!new_str) if (!new_str)
return NULL; return NULL;

View file

@ -816,14 +816,16 @@ int mfEmlSetMem_xt(uint8_t *data, int blockNum, int blocksCount, int blockBtWidt
return PM3_ESOFT; 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->blockno = blockNum;
payload->blockcnt = blocksCount; payload->blockcnt = blocksCount;
payload->blockwidth = blockBtWidth; payload->blockwidth = blockBtWidth;
memcpy(payload->data, data, size); memcpy(payload->data, data, size);
clearCommandBuffer(); 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); free(payload);
return PM3_SUCCESS; return PM3_SUCCESS;
} }
@ -1178,7 +1180,7 @@ int detect_mf_magic(bool is_mfc) {
PrintAndLogEx(SUCCESS, "Magic capabilities : " _GREEN_("Gen 2 / CUID")); PrintAndLogEx(SUCCESS, "Magic capabilities : " _GREEN_("Gen 2 / CUID"));
break; break;
case MAGIC_GEN_3: case MAGIC_GEN_3:
PrintAndLogEx(SUCCESS, "Magic capabilities : " _GREEN_("Gen 3 / APDU")); PrintAndLogEx(SUCCESS, "Magic capabilities : possibly " _GREEN_("Gen 3 / APDU"));
break; break;
case MAGIC_GEN_UNFUSED: case MAGIC_GEN_UNFUSED:
PrintAndLogEx(SUCCESS, "Magic capabilities : " _GREEN_("Write Once / FUID")); PrintAndLogEx(SUCCESS, "Magic capabilities : " _GREEN_("Write Once / FUID"));

View file

@ -12,7 +12,7 @@
// Add the new setting to the session_arg_t; in ui.h // 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 // 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_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> // use the preference as needed : session.<preference name>
// Can use (session.preferences_loaded) to check if json settings file was used // 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.y = 60 + session.plot.y + session.plot.h;
session.overlay.h = 200; session.overlay.h = 200;
session.overlay.w = session.plot.w; session.overlay.w = session.plot.w;
session.overlay_sliders = true;
session.show_hints = false; session.show_hints = false;
// setDefaultPath (spDefault, ""); // setDefaultPath (spDefault, "");
@ -78,6 +79,11 @@ int preferences_load(void) {
setDefaultPath (spTrace, "."); 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 // loadFileJson wants these, so pass in place holder values, though not used
// in settings load; // in settings load;
uint8_t dummyData = 0x00; uint8_t dummyData = 0x00;
@ -100,7 +106,10 @@ int preferences_load(void) {
// Save all settings from memory (struct) to file // Save all settings from memory (struct) to file
int preferences_save(void) { int preferences_save(void) {
// Note sure if backup has value ? // Note sure if backup has value ?
if (session.incognito) {
PrintAndLogEx(INFO, "No preferences file will be saved");
return PM3_SUCCESS;
}
PrintAndLogEx(INFO, "Saving preferences..."); PrintAndLogEx(INFO, "Saving preferences...");
char *fn = prefGetFilename(); 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.ypos", session.overlay.y);
JsonSaveInt(root, "window.overlay.hsize", session.overlay.h); JsonSaveInt(root, "window.overlay.hsize", session.overlay.h);
JsonSaveInt(root, "window.overlay.wsize", session.overlay.w); JsonSaveInt(root, "window.overlay.wsize", session.overlay.w);
JsonSaveBoolean(root, "window.overlay.sliders", session.overlay_sliders);
// Log level, convert to text // Log level, convert to text
switch (session.client_debug_level) { switch (session.client_debug_level) {
@ -225,7 +235,7 @@ void preferences_save_callback(json_t *root) {
void preferences_load_callback(json_t *root) { void preferences_load_callback(json_t *root) {
json_error_t up_error = {0}; json_error_t up_error = {0};
bool b1; int b1;
int i1; int i1;
const char *s1; const char *s1;
char tempStr [500]; // to use str_lower() since json unpack uses const char * 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; session.overlay.h = i1;
if (json_unpack_ex(root, &up_error, 0, "{s:i}", "window.overlay.wsize", &i1) == 0) if (json_unpack_ex(root, &up_error, 0, "{s:i}", "window.overlay.wsize", &i1) == 0)
session.overlay.w = i1; 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 // show options
if (json_unpack_ex(root, &up_error, 0, "{s:s}", "show.emoji", &s1) == 0) { 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) 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) 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 // Logging Level
if (json_unpack_ex(root, &up_error, 0, "{s:s}", "device.debug.level", &s1) == 0) { 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"); PrintAndLogEx(NORMAL, " "_GREEN_("on")" - Display hints");
return PM3_SUCCESS; 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) { static int usage_set_savePaths(void) {
PrintAndLogEx(NORMAL, "Usage: pref set savepaths [help] [create] [default <path>] [dump <path>] [trace <path>]"); 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)); 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) { static int setCmdEmoji(const char *Cmd) {
uint8_t cmdp = 0; uint8_t cmdp = 0;
@ -688,7 +717,7 @@ static int setCmdDeviceDebug (const char *Cmd)
showDeviceDebugState (prefShowOLD); showDeviceDebugState (prefShowOLD);
session.device_debug_level = newValue; session.device_debug_level = newValue;
showDeviceDebugState (prefShowNEW); showDeviceDebugState (prefShowNEW);
preferences_save (); preferences_save();
} else { } else {
PrintAndLogEx(INFO,"nothing changed"); PrintAndLogEx(INFO,"nothing changed");
showDeviceDebugState (prefShowNone); showDeviceDebugState (prefShowNone);
@ -755,6 +784,52 @@ static int setCmdHint(const char *Cmd) {
return PM3_SUCCESS; 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) { static int setCmdSavePaths (const char *Cmd) {
uint8_t cmdp = 0; uint8_t cmdp = 0;
@ -866,6 +941,11 @@ static int getCmdDebug(const char *Cmd) {
return PM3_SUCCESS; return PM3_SUCCESS;
} }
static int getCmdPlotSlider(const char *Cmd) {
showPlotSliderState(prefShowNone);
return PM3_SUCCESS;
}
static command_t getCommandTable[] = { static command_t getCommandTable[] = {
// {"help", getCmdHelp, AlwaysAvailable, "This help"}, // {"help", getCmdHelp, AlwaysAvailable, "This help"},
{"emoji", getCmdEmoji, AlwaysAvailable, "Get emoji display preference"}, {"emoji", getCmdEmoji, AlwaysAvailable, "Get emoji display preference"},
@ -873,6 +953,7 @@ static command_t getCommandTable[] = {
{"color", getCmdColor, AlwaysAvailable, "Get color support preference"}, {"color", getCmdColor, AlwaysAvailable, "Get color support preference"},
// {"defaultsavepaths", getCmdSavePaths, AlwaysAvailable, "... to be adjusted next ... "}, // {"defaultsavepaths", getCmdSavePaths, AlwaysAvailable, "... to be adjusted next ... "},
{"clientdebug", getCmdDebug, AlwaysAvailable, "Get client debug level preference"}, {"clientdebug", getCmdDebug, AlwaysAvailable, "Get client debug level preference"},
{"plotsliders", getCmdPlotSlider, AlwaysAvailable, "Get plot slider display preference"},
// {"devicedebug", getCmdDeviceDebug, AlwaysAvailable, "Get device debug level"}, // {"devicedebug", getCmdDeviceDebug, AlwaysAvailable, "Get device debug level"},
{NULL, NULL, NULL, NULL} {NULL, NULL, NULL, NULL}
}; };
@ -884,6 +965,7 @@ static command_t setCommandTable[] = {
{"color", setCmdColor, AlwaysAvailable, "Set color support"}, {"color", setCmdColor, AlwaysAvailable, "Set color support"},
// {"defaultsavepaths", setCmdSavePaths, AlwaysAvailable, "... to be adjusted next ... "}, // {"defaultsavepaths", setCmdSavePaths, AlwaysAvailable, "... to be adjusted next ... "},
{"clientdebug", setCmdDebug, AlwaysAvailable, "Set client debug level"}, {"clientdebug", setCmdDebug, AlwaysAvailable, "Set client debug level"},
{"plotsliders", setCmdPlotSliders, AlwaysAvailable, "Set plot slider display"},
// {"devicedebug", setCmdDeviceDebug, AlwaysAvailable, "Set device debug level"}, // {"devicedebug", setCmdDeviceDebug, AlwaysAvailable, "Set device debug level"},
{NULL, NULL, NULL, NULL} {NULL, NULL, NULL, NULL}
}; };
@ -912,8 +994,7 @@ static int CmdPrefShow(const char *Cmd) {
PrintAndLogEx(INFO, "Using "_YELLOW_("%s"), fn); PrintAndLogEx(INFO, "Using "_YELLOW_("%s"), fn);
free(fn); free(fn);
} else { } else {
PrintAndLogEx(ERR, "Preferences not loaded"); PrintAndLogEx(WARNING, "Preferences file not loaded");
return PM3_ESOFT;
} }
PrintAndLogEx(INFO, "Current settings"); PrintAndLogEx(INFO, "Current settings");
@ -925,8 +1006,8 @@ static int CmdPrefShow(const char *Cmd) {
// showSavePathState(spDefault, prefShowNone); // showSavePathState(spDefault, prefShowNone);
// showSavePathState(spDump, prefShowNone); // showSavePathState(spDump, prefShowNone);
// showSavePathState(spTrace, prefShowNone); // showSavePathState(spTrace, prefShowNone);
showClientDebugState(prefShowNone); showClientDebugState(prefShowNone);
showPlotSliderState(prefShowNone);
// showDeviceDebugState(prefShowNone); // showDeviceDebugState(prefShowNone);
PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS; return PM3_SUCCESS;

View file

@ -28,7 +28,7 @@ void ExitGraphics(void);
extern double CursorScaleFactor; extern double CursorScaleFactor;
extern char CursorScaleFactorUnit[11]; extern char CursorScaleFactorUnit[11];
extern int PlotGridX, PlotGridY, PlotGridXdefault, PlotGridYdefault, GridOffset; extern double PlotGridX, PlotGridY, PlotGridXdefault, PlotGridYdefault, GridOffset;
extern uint32_t CursorCPos, CursorDPos; extern uint32_t CursorCPos, CursorDPos;
extern int CommandFinished; extern int CommandFinished;
extern int offline; extern int offline;

View file

@ -7,6 +7,7 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// GUI (QT) // GUI (QT)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#define __STDC_FORMAT_MACROS
#include "proxguiqt.h" #include "proxguiqt.h"
#include <inttypes.h> #include <inttypes.h>
#include <stdbool.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); QString ct = QString("[*]Slider [ %1 ]").arg(conn.serial_port_name);
controlWidget->setWindowTitle(ct); 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 // now that is up, reset pos/size change flags
session.window_changed = false; session.window_changed = false;
@ -289,7 +291,10 @@ void ProxWidget::hideEvent(QHideEvent *event) {
plot->hide(); plot->hide();
} }
void ProxWidget::showEvent(QShowEvent *event) { void ProxWidget::showEvent(QShowEvent *event) {
if (session.overlay_sliders)
controlWidget->show(); controlWidget->show();
else
controlWidget->hide();
plot->show(); plot->show();
} }
void ProxWidget::moveEvent(QMoveEvent *event) { void ProxWidget::moveEvent(QMoveEvent *event) {
@ -498,17 +503,17 @@ void Plot::plotGridLines(QPainter *painter, QRect r) {
// set GridOffset // set GridOffset
if (PlotGridX <= 0) return; if (PlotGridX <= 0) return;
int offset = GridOffset; double offset = GridOffset;
if (GridLocked && PlotGridX) { if (GridLocked && PlotGridX) {
offset = GridOffset + PlotGridX - (GraphStart % PlotGridX); offset = GridOffset + PlotGridX - fmod(GraphStart, PlotGridX);
} else if (!GridLocked && GraphStart > 0 && 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; if (offset < 0) offset += PlotGridX;
int i; double i;
int grid_delta_x = (int)(PlotGridX * GraphPixelsPerPoint); double grid_delta_x = PlotGridX * GraphPixelsPerPoint;
int grid_delta_y = PlotGridY; int grid_delta_y = PlotGridY;
if ((PlotGridX > 0) && ((PlotGridX * GraphPixelsPerPoint) > 1)) { 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()); painter.drawLine(xCoordOf(CursorCPos, plotRect), plotRect.top(), xCoordOf(CursorCPos, plotRect), plotRect.bottom());
} }
if (CursorDPos > GraphStart && xCoordOf(CursorDPos, plotRect) < plotRect.right()) { 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()); 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(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, GraphStart,
GraphStop, GraphStop,
CursorBPos - CursorAPos, CursorBPos - CursorAPos,
@ -633,11 +638,12 @@ Plot::Plot(QWidget *parent) : QWidget(parent), GraphStart(0), GraphPixelsPerPoin
palette.setColor(QPalette::Button, QColor(100, 100, 100)); palette.setColor(QPalette::Button, QColor(100, 100, 100));
setPalette(palette); setPalette(palette);
setAutoFillBackground(true); setAutoFillBackground(true);
CursorAPos = 0; CursorAPos = 0;
CursorBPos = 0; CursorBPos = 0;
GraphStop = 0;
setWindowTitle(tr("Sliders")); setWindowTitle(tr("Sliders"));
master = parent; master = parent;
} }
@ -647,15 +653,18 @@ void Plot::closeEvent(QCloseEvent *event) {
g_useOverlays = false; g_useOverlays = false;
} }
void Plot::Zoom(double factor, int refX) { void Plot::Zoom(double factor, uint32_t refX) {
if (factor >= 1) { // Zoom in if (factor >= 1) { // Zoom in
if (GraphPixelsPerPoint <= 25 * factor) { if (GraphPixelsPerPoint <= 25 * factor) {
GraphPixelsPerPoint *= factor; GraphPixelsPerPoint *= factor;
if (refX > GraphStart) {
GraphStart += (refX - GraphStart) - ((refX - GraphStart) / factor); GraphStart += (refX - GraphStart) - ((refX - GraphStart) / factor);
} }
}
} else { // Zoom out } else { // Zoom out
if (GraphPixelsPerPoint >= 0.01 / factor) { if (GraphPixelsPerPoint >= 0.01 / factor) {
GraphPixelsPerPoint *= factor; GraphPixelsPerPoint *= factor;
if (refX > GraphStart) {
if (GraphStart >= ((refX - GraphStart) / factor) - (refX - GraphStart)) { if (GraphStart >= ((refX - GraphStart) / factor) - (refX - GraphStart)) {
GraphStart -= ((refX - GraphStart) / factor) - (refX - GraphStart); GraphStart -= ((refX - GraphStart) / factor) - (refX - GraphStart);
} else { } else {
@ -663,6 +672,7 @@ void Plot::Zoom(double factor, int refX) {
} }
} }
} }
}
} }
void Plot::Move(int offset) { void Plot::Move(int offset) {
@ -693,6 +703,16 @@ void Plot::Trim(void) {
if ((CursorAPos == 0) || (CursorBPos == 0)) { // if we don't have both cursors set if ((CursorAPos == 0) || (CursorBPos == 0)) { // if we don't have both cursors set
lref = GraphStart; lref = GraphStart;
rref = GraphStop; rref = GraphStop;
if (CursorAPos >= lref) {
CursorAPos -= lref;
} else {
CursorAPos = 0;
}
if (CursorBPos >= lref) {
CursorBPos -= lref;
} else {
CursorBPos = 0;
}
} else { } else {
lref = CursorAPos < CursorBPos ? CursorAPos : CursorBPos; lref = CursorAPos < CursorBPos ? CursorAPos : CursorBPos;
rref = CursorAPos < CursorBPos ? CursorBPos : CursorAPos; rref = CursorAPos < CursorBPos ? CursorBPos : CursorAPos;
@ -705,6 +725,7 @@ void Plot::Trim(void) {
CursorAPos -= lref; CursorAPos -= lref;
CursorBPos -= lref; CursorBPos -= lref;
} }
g_DemodStartIdx -= lref;
for (uint32_t i = lref; i < rref; ++i) for (uint32_t i = lref; i < rref; ++i)
GraphBuffer[i - lref] = GraphBuffer[i]; GraphBuffer[i - lref] = GraphBuffer[i];
GraphTraceLen = rref - lref; GraphTraceLen = rref - lref;
@ -722,9 +743,9 @@ void Plot::wheelEvent(QWheelEvent *event) {
if (event->modifiers() & Qt::ShiftModifier) { if (event->modifiers() & Qt::ShiftModifier) {
// event->position doesn't exist in QT5.12.8, both exist in 5.14.2 and event->x doesn't exist in 5.15.0 // event->position doesn't exist in QT5.12.8, both exist in 5.14.2 and event->x doesn't exist in 5.15.0
#if QT_VERSION >= 0x050d00 #if QT_VERSION >= 0x050d00
int x = event->position().x(); uint32_t x = event->position().x();
#else #else
int x = event->x(); uint32_t x = event->x();
#endif #endif
x -= WIDTH_AXES; x -= WIDTH_AXES;
x = (int)(x / GraphPixelsPerPoint); x = (int)(x / GraphPixelsPerPoint);
@ -765,10 +786,11 @@ void Plot::mouseMoveEvent(QMouseEvent *event) {
void Plot::keyPressEvent(QKeyEvent *event) { void Plot::keyPressEvent(QKeyEvent *event) {
uint32_t offset; // Left/right movement offset (in sample size) 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 (event->modifiers() & Qt::ShiftModifier) {
if (PlotGridX) if (PlotGridX)
offset = PageWidth - (PageWidth % PlotGridX); offset = PageWidth - fmod(PageWidth, PlotGridX);
else else
offset = PageWidth; offset = PageWidth;
} else { } else {
@ -781,18 +803,34 @@ void Plot::keyPressEvent(QKeyEvent *event) {
switch (event->key()) { switch (event->key()) {
case Qt::Key_Down: case Qt::Key_Down:
if (event->modifiers() & Qt::ShiftModifier) { if (event->modifiers() & Qt::ShiftModifier) {
if (event->modifiers() & Qt::ControlModifier) {
Zoom(zoom_offset, CursorBPos);
} else {
Zoom(2, CursorBPos); Zoom(2, CursorBPos);
}
} else {
if (event->modifiers() & Qt::ControlModifier) {
Zoom(zoom_offset, CursorAPos);
} else { } else {
Zoom(2, CursorAPos); Zoom(2, CursorAPos);
} }
}
break; break;
case Qt::Key_Up: case Qt::Key_Up:
if (event->modifiers() & Qt::ShiftModifier) { if (event->modifiers() & Qt::ShiftModifier) {
if (event->modifiers() & Qt::ControlModifier) {
Zoom(1.0 / zoom_offset, CursorBPos);
} else {
Zoom(0.5, CursorBPos); Zoom(0.5, CursorBPos);
}
} else {
if (event->modifiers() & Qt::ControlModifier) {
Zoom(1.0 / zoom_offset, CursorAPos);
} else { } else {
Zoom(0.5, CursorAPos); Zoom(0.5, CursorAPos);
} }
}
break; break;
case Qt::Key_Right: case Qt::Key_Right:
@ -803,6 +841,14 @@ void Plot::keyPressEvent(QKeyEvent *event) {
Move(-offset); Move(-offset);
break; break;
case Qt::Key_Greater:
g_DemodStartIdx += 1;
break;
case Qt::Key_Less:
g_DemodStartIdx -= 1;
break;
case Qt::Key_G: case Qt::Key_G:
if (PlotGridX || PlotGridY) { if (PlotGridX || PlotGridY) {
PlotGridX = 0; PlotGridX = 0;
@ -819,36 +865,33 @@ void Plot::keyPressEvent(QKeyEvent *event) {
break; break;
case Qt::Key_H: case Qt::Key_H:
puts("\n-----------------------------------------------------------------------"); g_printAndLog = PRINTANDLOG_PRINT;
puts("PLOT window keystrokes"); PrintAndLogEx(NORMAL, "\n\n" _CYAN_("PLOT window keystrokes and mouse events"));
puts("\tKey Action"); PrintAndLogEx(NORMAL, "\n" _GREEN_("Move:"));
puts("-----------------------------------------------------------------------"); PrintAndLogEx(NORMAL, " %-*s%s", 25 + 9 + 9, _RED_("Home") "/" _RED_("End"), "Move to the start/end of the graph");
puts("\tUP Zoom out around yellow cursor"); PrintAndLogEx(NORMAL, " %-*s%s", 25 + 9, _YELLOW_("Mouse wheel"), "Move left/right");
puts("\t<SHIFT> UP Zoom out around purple cursor"); PrintAndLogEx(NORMAL, " %-*s%s", 25 + 9 + 9, _RED_("Left") "/" _RED_("Right"), "Move left/right");
puts("\t<SHIFT> WHEEL MOUSE UP Zoom out around mouse cursor"); PrintAndLogEx(NORMAL, " %-*s%s", 25 + 9, " + " _RED_("Ctrl"), "... by 1 sample");
puts("\tDOWN Zoom in around yellow cursor"); PrintAndLogEx(NORMAL, " %-*s%s", 25 + 9, " + " _RED_("Shift"), "... by 1 window");
puts("\t<SHIFT> DOWN Zoom in around purple cursor"); PrintAndLogEx(NORMAL, " %-*s%s", 25 + 9 + 9, _RED_("PgUp") "/" _RED_("PgDown"), "Move left/right by 1 window");
puts("\t<SHIFT> WHEEL MOUSE DOWN Zoom in around mouse cursor"); PrintAndLogEx(NORMAL, "\n" _GREEN_("Zoom:"));
puts("\tG Toggle grid display"); PrintAndLogEx(NORMAL, " %-*s%s", 25 + 9 + 9, _RED_("Shift") " + " _YELLOW_("Mouse wheel"), "Zoom in/out around mouse cursor");
puts("\tH Show help"); PrintAndLogEx(NORMAL, " %-*s%s", 25 + 9 + 9, _RED_("Down") "/" _RED_("Up"), "Zoom in/out around yellow cursor");
puts("\tL Toggle lock grid relative to samples"); PrintAndLogEx(NORMAL, " %-*s%s", 25 + 9, " + " _RED_("Ctrl"), "... with smaller increment");
puts("\tQ Hide window"); PrintAndLogEx(NORMAL, " %-*s%s", 25 + 9, " + " _RED_("Shift"), "... around purple cursor");
puts("\tT Trim data on displayed window or on cursors if defined"); PrintAndLogEx(NORMAL, " %-*s%s", 25 + 9, _RED_("h"), "Show this help");
puts("\tHOME Move to the start of the graph"); PrintAndLogEx(NORMAL, "\n" _GREEN_("Trim:"));
puts("\tEND Move to the end of the graph"); PrintAndLogEx(NORMAL, " %-*s%s", 25 + 9, _RED_("t"), "Trim data on window or on cursors if defined");
puts("\tPGUP Page left"); PrintAndLogEx(NORMAL, "\n" _GREEN_("Grid and demod:"));
puts("\tPGDOWN Page right"); PrintAndLogEx(NORMAL, " %-*s%s", 25 + 9, _RED_("g"), "Toggle grid and demodulation plot display");
puts("\tLEFT Move left"); PrintAndLogEx(NORMAL, " %-*s%s", 25 + 9, _RED_("l"), "Toggle lock grid relative to samples");
puts("\tRIGHT Move right"); PrintAndLogEx(NORMAL, " %-*s%s", 25 + 9 + 9, _RED_("<") "/" _RED_(">"), "Move demodulation left/right relative to samples");
puts("\tWHEEL MOUSE UP Move left"); PrintAndLogEx(NORMAL, "\n" _GREEN_("Misc:"));
puts("\tWHEEL MOUSE DOWN Move right"); PrintAndLogEx(NORMAL, " %-*s%s", 25 + 9, _YELLOW_("Left mouse click"), "Set yellow cursor");
puts("\t<CTLR> LEFT Move left 1 sample"); PrintAndLogEx(NORMAL, " %-*s%s", 25 + 9, _YELLOW_("Right mouse click"), "Set purple cursor");
puts("\t<CTLR> RIGHT Move right 1 sample"); PrintAndLogEx(NORMAL, " %-*s%s", 25 + 9, _RED_("h"), "Show this help");
puts("\t<SHIFT> LEFT Page left"); PrintAndLogEx(NORMAL, " %-*s%s", 25 + 9, _RED_("q"), "Close plot window");
puts("\t<SHIFT> RIGHT Page right"); g_printAndLog = PRINTANDLOG_PRINT | PRINTANDLOG_LOG;
puts("\tLEFT MOUSE CLICK Set yellow cursor");
puts("\tRIGHT MOUSE CLICK Set purple cursor");
puts("-----------------------------------------------------------------------");
break; break;
case Qt::Key_L: case Qt::Key_L:

View file

@ -51,7 +51,7 @@ class Plot: public QWidget {
protected: protected:
void paintEvent(QPaintEvent *event); void paintEvent(QPaintEvent *event);
void closeEvent(QCloseEvent *event); void closeEvent(QCloseEvent *event);
void Zoom(double factor, int refX); void Zoom(double factor, uint32_t refX);
void Move(int offset); void Move(int offset);
void Trim(void); void Trim(void);
void wheelEvent(QWheelEvent *event); void wheelEvent(QWheelEvent *event);

View file

@ -245,13 +245,16 @@ main_loop(char *script_cmds_file, char *script_cmd, bool stayInCommandLoop) {
#ifdef HAVE_READLINE #ifdef HAVE_READLINE
session.history_path = NULL; 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) { if (searchHomeFilePath(&session.history_path, NULL, PROXHISTORY, true) != PM3_SUCCESS) {
PrintAndLogEx(ERR, "No history will be recorded"); PrintAndLogEx(ERR, "No history will be recorded");
session.history_path = NULL; session.history_path = NULL;
} else { } else {
# if defined(_WIN32) # if defined(_WIN32)
// SetConsoleCtrlHandler((PHANDLER_ROUTINE)terminate_handler, true); // SetConsoleCtrlHandler((PHANDLER_ROUTINE)terminate_handler, true);
# else # else
struct sigaction action; struct sigaction action;
memset(&action, 0, sizeof(action)); memset(&action, 0, sizeof(action));
@ -262,6 +265,7 @@ main_loop(char *script_cmds_file, char *script_cmd, bool stayInCommandLoop) {
rl_set_signals(); rl_set_signals();
read_history(session.history_path); read_history(session.history_path);
} }
}
#endif #endif
// loops every time enter is pressed... // loops every time enter is pressed...
@ -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, " -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, " -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, " -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, "\nOptions in flasher mode:");
PrintAndLogEx(NORMAL, " --flash flash Proxmark3, requires at least one --image"); 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)"); 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.pm3_present = false;
session.help_dump_mode = false; session.help_dump_mode = false;
session.incognito = false;
bool waitCOMPort = false; bool waitCOMPort = false;
bool addLuaExec = false; bool addLuaExec = false;
bool stayInCommandLoop = false; bool stayInCommandLoop = false;
@ -903,6 +909,12 @@ int main(int argc, char *argv[]) {
continue; continue;
} }
// do not use history nor log files
if (strcmp(argv[i], "--incognito") == 0) {
session.incognito = true;
continue;
}
// go to flash mode // go to flash mode
if (strcmp(argv[i], "--flash") == 0) { if (strcmp(argv[i], "--flash") == 0) {
flash_mode = true; flash_mode = true;
@ -1008,7 +1020,7 @@ int main(int argc, char *argv[]) {
// Save settings if not loaded from settings json file. // Save settings if not loaded from settings json file.
// Doing this here will ensure other checks and updates are saved to over rule default // Doing this here will ensure other checks and updates are saved to over rule default
// e.g. Linux color use check // 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 PrintAndLogEx(INFO, "Creating initial preferences file"); // json save reports file name, so just info msg here
preferences_save(); // Save defaults preferences_save(); // Save defaults
session.preferences_loaded = true; session.preferences_loaded = true;

View file

@ -36,6 +36,7 @@
#include "fileutils.h" // searchfile #include "fileutils.h" // searchfile
#include "cmdlf.h" // lf_config #include "cmdlf.h" // lf_config
#include "generator.h" #include "generator.h"
#include "cmdlfem4x.h" // read 4305
static int returnToLuaWithError(lua_State *L, const char *fmt, ...) { static int returnToLuaWithError(lua_State *L, const char *fmt, ...) {
char buffer[200]; char buffer[200];
@ -1001,7 +1002,7 @@ static int l_T55xx_readblock(lua_State *L) {
return returnToLuaWithError(L, "Failed to read config block"); 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."); PrintAndLogEx(NORMAL, "Safety Check: Could not detect if PWD bit is set in config block. Exits.");
return 0; return 0;
} else { } 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) { if (isok == false) {
return returnToLuaWithError(L, "Could not detect modulation automatically. Try setting it manually with \'lf t55xx config\'"); 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; 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) { 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 // ref: https://github.com/RfidResearchGroup/proxmark3/issues/891
// redirect LUA's print to Proxmark3 PrintAndLogEx // redirect LUA's print to Proxmark3 PrintAndLogEx
static int l_printandlogex(lua_State *L) { static int l_printandlogex(lua_State *L) {
int n = lua_gettop(L); int n = lua_gettop(L);
for (int i = 1; i <= n; i++) { for (int i = 1; i <= n; i++) {
if (lua_isstring(L, 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; return 0;
} }
@ -1278,6 +1319,7 @@ int set_pm3_libraries(lua_State *L) {
{"ewd", l_ewd}, {"ewd", l_ewd},
{"ud", l_ud}, {"ud", l_ud},
{"rem", l_remark}, {"rem", l_remark},
{"em4x05_read", l_em4x05_read},
{NULL, NULL} {NULL, NULL}
}; };

View file

@ -39,11 +39,11 @@ session_arg_t session;
double CursorScaleFactor = 1; double CursorScaleFactor = 1;
char CursorScaleFactorUnit[11] = {0}; 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; uint32_t CursorCPos = 0, CursorDPos = 0;
double GraphPixelsPerPoint = 1.f; // How many visual pixels are between each sample point (x axis) double GraphPixelsPerPoint = 1.f; // How many visual pixels are between each sample point (x axis)
static bool flushAfterWrite = 0; static bool flushAfterWrite = 0;
int GridOffset = 0; double GridOffset = 0;
bool GridLocked = false; bool GridLocked = false;
bool showDemod = true; bool showDemod = true;
@ -305,6 +305,9 @@ static void fPrintAndLog(FILE *stream, const char *fmt, ...) {
pthread_mutex_lock(&print_lock); pthread_mutex_lock(&print_lock);
bool linefeed = true; bool linefeed = true;
if (logging && session.incognito) {
logging = 0;
}
if ((g_printAndLog & PRINTANDLOG_LOG) && logging && !logfile) { if ((g_printAndLog & PRINTANDLOG_LOG) && logging && !logfile) {
char *my_logfile_path = NULL; char *my_logfile_path = NULL;
char filename[40]; char filename[40];
@ -356,7 +359,7 @@ static void fPrintAndLog(FILE *stream, const char *fmt, ...) {
va_start(argptr, fmt); va_start(argptr, fmt);
vsnprintf(buffer, sizeof(buffer), fmt, argptr); vsnprintf(buffer, sizeof(buffer), fmt, argptr);
va_end(argptr); va_end(argptr);
if (buffer[strlen(buffer) - 1] == NOLF[0]) { if (strlen(buffer) > 0 && buffer[strlen(buffer) - 1] == NOLF[0]) {
linefeed = false; linefeed = false;
buffer[strlen(buffer) - 1] = 0; buffer[strlen(buffer) - 1] = 0;
} }

View file

@ -40,6 +40,8 @@ typedef struct {
bool window_changed; // track if plot/overlay pos/size changed to save on exit bool window_changed; // track if plot/overlay pos/size changed to save on exit
qtWindow_t plot; qtWindow_t plot;
qtWindow_t overlay; qtWindow_t overlay;
bool overlay_sliders;
bool incognito;
// char *defaultPaths[spItemCount]; // Array should allow loop searching for files // char *defaultPaths[spItemCount]; // Array should allow loop searching for files
clientdebugLevel_t client_debug_level; clientdebugLevel_t client_debug_level;
// uint8_t device_debug_level; // uint8_t device_debug_level;

View file

@ -708,7 +708,7 @@ bool HIDTryUnpack(wiegand_message_t *packed, bool ignore_parity) {
} }
++i; ++i;
} }
if (result == false) { if (result == false && packed->Length) {
PrintAndLogEx(SUCCESS, "Unknown. Bit len %d", packed->Length); PrintAndLogEx(SUCCESS, "Unknown. Bit len %d", packed->Length);
} }

View file

@ -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); crc = crc16_kermit(d, n);
break; break;
case CRC_11784: case CRC_11784:
crc = crc16_fdx(d, n); crc = crc16_fdxb(d, n);
break; break;
case CRC_LEGIC: case CRC_LEGIC:
// TODO // TODO
@ -225,7 +225,7 @@ uint16_t Crc16ex(CrcType_t ct, const uint8_t *d, size_t n) {
case CRC_KERMIT: case CRC_KERMIT:
return crc16_kermit(d, n); return crc16_kermit(d, n);
case CRC_11784: case CRC_11784:
return crc16_fdx(d, n); return crc16_fdxb(d, n);
case CRC_LEGIC: case CRC_LEGIC:
// TODO // TODO
return 0; return 0;
@ -270,7 +270,7 @@ bool check_crc(CrcType_t ct, const uint8_t *d, size_t n) {
case CRC_KERMIT: case CRC_KERMIT:
return (crc16_kermit(d, n) == 0); return (crc16_kermit(d, n) == 0);
case CRC_11784: case CRC_11784:
return (crc16_fdx(d, n) == 0); return (crc16_fdxb(d, n) == 0);
case CRC_LEGIC: case CRC_LEGIC:
// TODO // TODO
return false; return false;
@ -288,7 +288,7 @@ uint16_t crc16_ccitt(uint8_t const *d, size_t n) {
// FDX-B ISO11784/85) uses KERMIT/CCITT // FDX-B ISO11784/85) uses KERMIT/CCITT
// poly 0x xx init=0x000 refin=false refout=true xorout=0x0000 ... // 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); return crc16_fast(d, n, 0x0000, false, true);
} }

View file

@ -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); uint16_t crc16_ccitt(uint8_t const *d, size_t n);
// Calculate CRC-16/KERMIT (FDX-B ISO11784/85) LF // 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 // Calculate CRC-16/KERMIT
uint16_t crc16_kermit(uint8_t const *d, size_t n); uint16_t crc16_kermit(uint8_t const *d, size_t n);

View file

@ -1663,6 +1663,7 @@ int askdemod_ext(uint8_t *bits, size_t *size, int *clk, int *invert, int maxErr,
return errCnt; return errCnt;
} }
*startIdx = start - (*clk / 2);
if (g_debugMode == 2) prnt("DEBUG: (askdemod_ext) Weak wave detected: startIdx %i", *startIdx); if (g_debugMode == 2) prnt("DEBUG: (askdemod_ext) Weak wave detected: startIdx %i", *startIdx);
int lastBit; //set first clock check - can go negative int lastBit; //set first clock check - can go negative

View file

@ -247,6 +247,7 @@ static int g_debuglog_enable = 1;
/*-************************************ /*-************************************
* Types * Types
**************************************/ **************************************/
#include <limits.h>
#if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) #if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */)
# include <stdint.h> # include <stdint.h>
typedef uint8_t BYTE; typedef uint8_t BYTE;
@ -256,7 +257,6 @@ typedef int32_t S32;
typedef uint64_t U64; typedef uint64_t U64;
typedef uintptr_t uptrval; typedef uintptr_t uptrval;
#else #else
# include <limits.h>
# if UINT_MAX != 4294967295UL # if UINT_MAX != 4294967295UL
# error "LZ4 code (when not C++ or C99) assumes that sizeof(int) == 4" # error "LZ4 code (when not C++ or C99) assumes that sizeof(int) == 4"
# endif # 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; typedef union { U16 u16; U32 u32; reg_t uArch; } __attribute__((packed)) unalign;
static U16 LZ4_read16(const void *ptr) { return ((const unalign *)ptr)->u16; } 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 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; } static reg_t LZ4_read_ARCH(const void *ptr) { return ((const unalign *)ptr)->uArch; }
@ -1182,13 +1184,14 @@ _last_literals:
if (outputDirective == fillOutput) { if (outputDirective == fillOutput) {
/* adapt lastRun to fill 'dst' */ /* adapt lastRun to fill 'dst' */
assert(olimit >= op); assert(olimit >= op);
lastRun = (size_t)(olimit - op) - 1; lastRun = (size_t)(olimit - op) - 1/*token*/;
lastRun -= (lastRun + 240) / 255; lastRun -= (lastRun + 256 - RUN_MASK) / 256; /*additional length tokens*/
} else { } else {
assert(outputDirective == limitedOutput); assert(outputDirective == limitedOutput);
return 0; /* cannot compress within `dst` budget. Stored indexes in hash table are nonetheless fine */ 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) { if (lastRun >= RUN_MASK) {
size_t accumulator = lastRun - RUN_MASK; size_t accumulator = lastRun - RUN_MASK;
*op++ = RUN_MASK << ML_BITS; *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; typedef enum { loop_error = -2, initial_error = -1, ok = 0 } variable_length_error;
LZ4_FORCE_INLINE unsigned 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 length = 0;
U32 s; U32 s;
if (initial_check && unlikely((*ip) >= lencheck)) { /* overflow detection */ if (initial_check && unlikely((*ip) >= lencheck)) { /* overflow detection */
@ -1767,7 +1772,7 @@ LZ4_decompress_generic(
/* decode literal length */ /* decode literal length */
if (length == RUN_MASK) { if (length == RUN_MASK) {
variable_length_error error = ok; 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 (error == initial_error) { goto _output_error; }
if ((safeDecode) && unlikely((uptrval)(op) + length < (uptrval)(op))) { goto _output_error; } /* overflow detection */ 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 */ if ((safeDecode) && unlikely((uptrval)(ip) + length < (uptrval)(ip))) { goto _output_error; } /* overflow detection */
@ -1815,7 +1820,7 @@ LZ4_decompress_generic(
if (length == ML_MASK) { if (length == ML_MASK) {
variable_length_error error = ok; variable_length_error error = ok;
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 */
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 (error != ok) { goto _output_error; }
if ((safeDecode) && unlikely((uptrval)(op) + length < (uptrval)op)) { goto _output_error; } /* overflow detection */ if ((safeDecode) && unlikely((uptrval)(op) + length < (uptrval)op)) { goto _output_error; } /* overflow detection */
length += MINMATCH; 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 */ /* match starting within external dictionary */
if ((dict == usingExtDict) && (match < lowPrefix)) { if ((dict == usingExtDict) && (match < lowPrefix)) {
if (unlikely(op + length > oend - LASTLITERALS)) { if (unlikely(op + length > oend - LASTLITERALS)) {
@ -1946,7 +1951,7 @@ safe_decode:
/* decode literal length */ /* decode literal length */
if (length == RUN_MASK) { if (length == RUN_MASK) {
variable_length_error error = ok; 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 (error == initial_error) { goto _output_error; }
if ((safeDecode) && unlikely((uptrval)(op) + length < (uptrval)(op))) { goto _output_error; } /* overflow detection */ 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 */ 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 /* 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. * 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 */ memmove(op, ip, length); /* supports overlapping memory regions; only matters for in-place decompression scenarios */
ip += length; ip += length;
@ -2027,7 +2037,7 @@ safe_literal_copy:
_copy_match: _copy_match:
if (length == ML_MASK) { if (length == ML_MASK) {
variable_length_error error = ok; 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 (error != ok) goto _output_error;
if ((safeDecode) && unlikely((uptrval)(op) + length < (uptrval)op)) goto _output_error; /* overflow detection */ if ((safeDecode) && unlikely((uptrval)(op) + length < (uptrval)op)) goto _output_error; /* overflow detection */
} }

View file

@ -42,6 +42,11 @@ extern "C" {
/* --- Dependency --- */ /* --- Dependency --- */
#include <stddef.h> /* size_t */ #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 Introduction
@ -100,7 +105,7 @@ extern "C" {
/*------ Version ------*/ /*------ Version ------*/
#define LZ4_VERSION_MAJOR 1 /* for breaking interface changes */ #define LZ4_VERSION_MAJOR 1 /* for breaking interface changes */
#define LZ4_VERSION_MINOR 9 /* for new (non-breaking) interface capabilities */ #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) #define LZ4_VERSION_NUMBER (LZ4_VERSION_MAJOR *100*100 + LZ4_VERSION_MINOR *100 + LZ4_VERSION_RELEASE)

View file

@ -268,7 +268,7 @@ LZ4HC_InsertAndGetWiderMatch(
DEBUGLOG(7, "First match at index %u / %u (lowestMatchIndex)", DEBUGLOG(7, "First match at index %u / %u (lowestMatchIndex)",
matchIndex, lowestMatchIndex); matchIndex, lowestMatchIndex);
while ((matchIndex >= lowestMatchIndex) && (nbAttempts)) { while ((matchIndex >= lowestMatchIndex) && (nbAttempts > 0)) {
int matchLength = 0; int matchLength = 0;
nbAttempts--; nbAttempts--;
assert(matchIndex < ipIndex); assert(matchIndex < ipIndex);
@ -424,7 +424,7 @@ LZ4HC_InsertAndGetWiderMatch(
} /* while ((matchIndex>=lowestMatchIndex) && (nbAttempts)) */ } /* while ((matchIndex>=lowestMatchIndex) && (nbAttempts)) */
if (dict == usingDictCtxHc if (dict == usingDictCtxHc
&& nbAttempts && nbAttempts > 0
&& ipIndex - lowestMatchIndex < LZ4_DISTANCE_MAX) { && ipIndex - lowestMatchIndex < LZ4_DISTANCE_MAX) {
size_t const dictEndOffset = (size_t)(dictCtx->end - dictCtx->base); size_t const dictEndOffset = (size_t)(dictCtx->end - dictCtx->base);
U32 dictMatchIndex = dictCtx->hashTable[LZ4HC_hashPtr(ip)]; 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; U32 const cost = 1 + llAdd + ll + 2 + mlAdd;
if (start == NULL) start = *anchor; /* only works for single segment */ if (start == NULL) start = *anchor; /* only works for single segment */
/* g_debuglog_enable = (pos >= 2228) & (pos <= 2262); */ /* 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, pos,
(U32)(*ip - *anchor), matchLength, (U32)(*ip - match), (U32)(*ip - *anchor), matchLength, (U32)(*ip - match),
cost, totalCost); cost, totalCost);
@ -506,7 +506,13 @@ LZ4_FORCE_INLINE int LZ4HC_encodeSequence(
/* Encode Literal length */ /* Encode Literal length */
length = (size_t)(*ip - *anchor); 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) { if (length >= RUN_MASK) {
size_t len = length - RUN_MASK; size_t len = length - RUN_MASK;
*token = (RUN_MASK << ML_BITS); *token = (RUN_MASK << ML_BITS);
@ -528,7 +534,10 @@ LZ4_FORCE_INLINE int LZ4HC_encodeSequence(
/* Encode MatchLength */ /* Encode MatchLength */
assert(matchLength >= MINMATCH); assert(matchLength >= MINMATCH);
length = (size_t)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) { if (length >= ML_MASK) {
*token += ML_MASK; *token += ML_MASK;
length -= ML_MASK; length -= ML_MASK;
@ -552,7 +561,7 @@ LZ4_FORCE_INLINE int LZ4HC_compress_hashChain(
char *const dest, char *const dest,
int *srcSizePtr, int *srcSizePtr,
int const maxOutputSize, int const maxOutputSize,
unsigned maxNbAttempts, int maxNbAttempts,
const limitedOutput_directive limit, const limitedOutput_directive limit,
const dictCtx_directive dict const dictCtx_directive dict
) { ) {
@ -658,7 +667,11 @@ _Search3:
if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow; if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow;
ip = start2; ip = start2;
optr = op; 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; continue;
} }
@ -735,17 +748,18 @@ _last_literals:
/* Encode Last Literals */ /* Encode Last Literals */
{ {
size_t lastRunSize = (size_t)(iend - anchor); /* literals */ size_t lastRunSize = (size_t)(iend - anchor); /* literals */
size_t litLength = (lastRunSize + 255 - RUN_MASK) / 255; size_t llAdd = (lastRunSize + 255 - RUN_MASK) / 255;
size_t const totalSize = 1 + litLength + lastRunSize; size_t const totalSize = 1 + llAdd + lastRunSize;
if (limit == fillOutput) oend += LASTLITERALS; /* restore correct value */ if (limit == fillOutput) oend += LASTLITERALS; /* restore correct value */
if (limit && (op + totalSize > oend)) { if (limit && (op + totalSize > oend)) {
if (limit == limitedOutput) return 0; /* Check output limit */ if (limit == limitedOutput) return 0;
/* adapt lastRunSize to fill 'dest' */ /* adapt lastRunSize to fill 'dest' */
lastRunSize = (size_t)(oend - op) - 1; lastRunSize = (size_t)(oend - op) - 1 /*token*/;
litLength = (lastRunSize + 255 - RUN_MASK) / 255; llAdd = (lastRunSize + 256 - RUN_MASK) / 256;
lastRunSize -= litLength; 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) { if (lastRunSize >= RUN_MASK) {
size_t accumulator = lastRunSize - RUN_MASK; size_t accumulator = lastRunSize - RUN_MASK;
@ -765,9 +779,27 @@ _last_literals:
_dest_overflow: _dest_overflow:
if (limit == fillOutput) { 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 */ 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; goto _last_literals;
} }
/* compression failed */
return 0; return 0;
} }
@ -794,7 +826,7 @@ LZ4_FORCE_INLINE int LZ4HC_compress_generic_internal(
typedef enum { lz4hc, lz4opt } lz4hc_strat_e; typedef enum { lz4hc, lz4opt } lz4hc_strat_e;
typedef struct { typedef struct {
lz4hc_strat_e strat; lz4hc_strat_e strat;
U32 nbSearches; int nbSearches;
U32 targetLength; U32 targetLength;
} cParams_t; } cParams_t;
static const cParams_t clTable[LZ4HC_CLEVEL_MAX + 1] = { 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 */ { 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 (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) */ 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); assert(cParam.strat == lz4opt);
result = LZ4HC_compress_optimal(ctx, result = LZ4HC_compress_optimal(ctx,
src, dst, srcSizePtr, dstCapacity, src, dst, srcSizePtr, dstCapacity,
(int)cParam.nbSearches, cParam.targetLength, limit, cParam.nbSearches, cParam.targetLength, limit,
cLevel == LZ4HC_CLEVEL_MAX, /* ultra mode */ cLevel == LZ4HC_CLEVEL_MAX, /* ultra mode */
dict, favor); dict, favor);
} }
@ -967,10 +1000,12 @@ int LZ4_compress_HC_destSize(void *state, const char *source, char *dest, int *s
**************************************/ **************************************/
/* allocation */ /* allocation */
LZ4_streamHC_t *LZ4_createStreamHC(void) { LZ4_streamHC_t *LZ4_createStreamHC(void) {
LZ4_streamHC_t *const LZ4_streamHCPtr = (LZ4_streamHC_t *)ALLOC(sizeof(LZ4_streamHC_t)); LZ4_streamHC_t *const state = (LZ4_streamHC_t *)ALLOC(sizeof(LZ4_streamHC_t));
if (LZ4_streamHCPtr == NULL) return NULL; if (LZ4_initStreamHC(state, sizeof(*state)) == NULL) {
LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr)); /* full initialization, malloc'ed buffer can be full of garbage */ free(state);
return LZ4_streamHCPtr; return NULL;
}
return state;
} }
int LZ4_freeStreamHC(LZ4_streamHC_t *LZ4_streamHCPtr) { int LZ4_freeStreamHC(LZ4_streamHC_t *LZ4_streamHCPtr) {
@ -980,7 +1015,10 @@ int LZ4_freeStreamHC(LZ4_streamHC_t *LZ4_streamHCPtr) {
return 0; 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 *LZ4_initStreamHC(void *buffer, size_t size) {
LZ4_streamHC_t *const LZ4_streamHCPtr = (LZ4_streamHC_t *)buffer; LZ4_streamHC_t *const LZ4_streamHCPtr = (LZ4_streamHC_t *)buffer;
if (buffer == NULL) return NULL; if (buffer == NULL) return NULL;
@ -1084,8 +1122,8 @@ static int LZ4_compressHC_continue_generic(LZ4_streamHC_t *LZ4_streamHCPtr,
int *srcSizePtr, int dstCapacity, int *srcSizePtr, int dstCapacity,
limitedOutput_directive limit) { limitedOutput_directive limit) {
LZ4HC_CCtx_internal *const ctxPtr = &LZ4_streamHCPtr->internal_donotuse; LZ4HC_CCtx_internal *const ctxPtr = &LZ4_streamHCPtr->internal_donotuse;
DEBUGLOG(4, "LZ4_compressHC_continue_generic(ctx=%p, src=%p, srcSize=%d)", DEBUGLOG(5, "LZ4_compressHC_continue_generic(ctx=%p, src=%p, srcSize=%d, limit=%d)",
LZ4_streamHCPtr, src, *srcSizePtr); LZ4_streamHCPtr, src, *srcSizePtr, limit);
assert(ctxPtr != NULL); assert(ctxPtr != NULL);
/* auto-init if forgotten */ /* auto-init if forgotten */
if (ctxPtr->base == NULL) LZ4HC_init_internal(ctxPtr, (const BYTE *) src); 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 *op = (BYTE *) dst;
BYTE *opSaved = (BYTE *) dst; BYTE *opSaved = (BYTE *) dst;
BYTE *oend = op + dstCapacity; BYTE *oend = op + dstCapacity;
int ovml = MINMATCH; /* overflow - last sequence */
const BYTE *ovref = NULL;
/* init */ /* init */
#ifdef LZ4HC_HEAPMODE #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; if (sufficient_len >= LZ4_OPT_NUM) sufficient_len = LZ4_OPT_NUM - 1;
/* Main Loop */ /* Main Loop */
assert(ip - anchor < LZ4_MAX_INPUT_SIZE);
while (ip <= mflimit) { while (ip <= mflimit) {
int const llen = (int)(ip - anchor); int const llen = (int)(ip - anchor);
int best_mlen, best_off; int best_mlen, best_off;
@ -1326,8 +1365,11 @@ static int LZ4HC_compress_optimal(LZ4HC_CCtx_internal *ctx,
int const firstML = firstMatch.len; int const firstML = firstMatch.len;
const BYTE *const matchPos = ip - firstMatch.off; const BYTE *const matchPos = ip - firstMatch.off;
opSaved = op; 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; goto _dest_overflow;
}
continue; continue;
} }
@ -1516,18 +1558,21 @@ encode: /* cur, last_match_pos, best_mlen, best_off must be set */
assert(ml >= MINMATCH); assert(ml >= MINMATCH);
assert((offset >= 1) && (offset <= LZ4_DISTANCE_MAX)); assert((offset >= 1) && (offset <= LZ4_DISTANCE_MAX));
opSaved = op; 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; goto _dest_overflow;
} }
} }
}
} /* while (ip <= mflimit) */ } /* while (ip <= mflimit) */
_last_literals: _last_literals:
/* Encode Last Literals */ /* Encode Last Literals */
{ {
size_t lastRunSize = (size_t)(iend - anchor); /* literals */ size_t lastRunSize = (size_t)(iend - anchor); /* literals */
size_t litLength = (lastRunSize + 255 - RUN_MASK) / 255; size_t llAdd = (lastRunSize + 255 - RUN_MASK) / 255;
size_t const totalSize = 1 + litLength + lastRunSize; size_t const totalSize = 1 + llAdd + lastRunSize;
if (limit == fillOutput) oend += LASTLITERALS; /* restore correct value */ if (limit == fillOutput) oend += LASTLITERALS; /* restore correct value */
if (limit && (op + totalSize > oend)) { if (limit && (op + totalSize > oend)) {
if (limit == limitedOutput) { /* Check output limit */ if (limit == limitedOutput) { /* Check output limit */
@ -1535,11 +1580,12 @@ _last_literals:
goto _return_label; goto _return_label;
} }
/* adapt lastRunSize to fill 'dst' */ /* adapt lastRunSize to fill 'dst' */
lastRunSize = (size_t)(oend - op) - 1; lastRunSize = (size_t)(oend - op) - 1 /*token*/;
litLength = (lastRunSize + 255 - RUN_MASK) / 255; llAdd = (lastRunSize + 256 - RUN_MASK) / 256;
lastRunSize -= litLength; 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) { if (lastRunSize >= RUN_MASK) {
size_t accumulator = lastRunSize - RUN_MASK; size_t accumulator = lastRunSize - RUN_MASK;
@ -1560,7 +1606,27 @@ _last_literals:
_dest_overflow: _dest_overflow:
if (limit == fillOutput) { 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 */ 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; goto _last_literals;
} }
_return_label: _return_label:

View file

@ -79,22 +79,20 @@ ifneq (,$(PLATFORM_EXTRAS_TMP))
endif endif
# common LF support # common LF support
PLATFORM_DEFS += \ PLATFORM_DEFS += -DWITH_LF
-DWITH_LF \ PLATFORM_DEFS += -DWITH_HITAG
-DWITH_HITAG \ PLATFORM_DEFS += -DWITH_EM4x50
-DWITH_EM4x50
# common HF support # common HF support
PLATFORM_DEFS += \ PLATFORM_DEFS += -DWITH_ISO15693
-DWITH_ISO15693 \ PLATFORM_DEFS += -DWITH_LEGICRF
-DWITH_LEGICRF \ PLATFORM_DEFS += -DWITH_ISO14443b
-DWITH_ISO14443b \ PLATFORM_DEFS += -DWITH_ISO14443a
-DWITH_ISO14443a \ PLATFORM_DEFS += -DWITH_ICLASS
-DWITH_ICLASS \ PLATFORM_DEFS += -DWITH_FELICA
-DWITH_FELICA \ PLATFORM_DEFS += -DWITH_NFCBARCODE
-DWITH_NFCBARCODE \ PLATFORM_DEFS += -DWITH_HFSNIFF
-DWITH_HFSNIFF \ PLATFORM_DEFS += -DWITH_HFPLOT
-DWITH_HFPLOT
# Standalone mode # Standalone mode

View file

@ -46,9 +46,10 @@ Reverse permute iCLASS master key
``` ```
Options Options
--- ---
r reverse permuted key -r --reverse : reverse permuted key
--key <bytes> : input key
pm3 --> hf iclass permute r 3F90EBF0910F7B6F pm3 --> hf iclass permute --reverse --key 3F90EBF0910F7B6F
``` ```
iCLASS Reader iCLASS Reader
@ -369,12 +370,14 @@ pm3 --> lf hid demod
Simulate Prox card Simulate Prox card
``` ```
pm3 --> lf hid sim 200670012d pm3 --> lf hid sim -r 200670012d
pm3 --> lf hid sim -w H10301 --fc 10 --cn 1337
``` ```
Clone Prox to T5577 card Clone Prox to T5577 card
``` ```
pm3 --> lf hid clone 200670012d pm3 --> lf hid clone -r 200670012d
pm3 --> lf hid clone -w H10301 --fc 10 --cn 1337
``` ```
Brute force HID reader Brute force HID reader
@ -538,12 +541,12 @@ pm3 --> data samples <size>
Save samples to file Save samples to file
``` ```
pm3 --> data save <filename> pm3 --> data save -f <filename>
``` ```
Load samples from file Load samples from file
``` ```
pm3 --> data load <filename> pm3 --> data load -f <filename>
``` ```
## Lua Scripts ## Lua Scripts

View file

@ -184,25 +184,37 @@ arg_get_u64_def(\<context\>, \<opt index\>, \<default value\>);
cardnumber = arg_get_u64_def(ctx, 2, 0); cardnumber = arg_get_u64_def(ctx, 2, 0);
**hex option** **hex option with return**
CLIGetHexWithReturn(\<context\>, \<opt index\>, \<store variable\>, \<ptr to stored length\>); CLIGetHexWithReturn(\<context\>, \<opt index\>, \<store variable\>, \<ptr to stored length\>);
?? as an array of uint_8 ?? ?? as an array of uint_8 ??
If failed to retrieve hexbuff, it will exit fct
uint8_t aid[2] = {0}; uint8_t aid[2] = {0};
int aidlen; int aidlen;
CLIGetHexWithReturn(ctx, 2, aid, &aidlen); CLIGetHexWithReturn(ctx, 2, aid, &aidlen);
**hex option returning ???**
**hex option**
uint8_t key[24] = {0}; uint8_t key[24] = {0};
int keylen = 0; int keylen = 0;
int res_klen = CLIParamHexToBuf(arg_get_str(ctx, 3), key, 24, &keylen); int res_klen = CLIParamHexToBuf(arg_get_str(ctx, 3), key, 24, &keylen);
quick test : seems res_keylen == 0 when ok so not key len ??? quick test : seems res_keylen == 0 when ok so not key len ???
**string option** **string option return**
CLIGetStrWithReturn(\<context\>,\<opt index\>, \<unsigned char \*\>, \<int \*\>); CLIGetStrWithReturn(\<context\>,\<opt index\>, \<unsigned char \*\>, \<int \*\>);
If failed to retrieve string, it will exit fct
uint8_t Buffer[100]; uint8_t buffer[100];
int BufLen; int slen = 0;
CLIGetStrWithReturn(ctx,7, Buffer, &BufLen); CLIGetStrWithReturn(ctx, 1, buffer, &slen);
**string option**
Getting a char array
int slen = 0;
char format[16] = {0};
int res = CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)format, sizeof(format), &slen);
quick test : seem res == 0, then ok. compare res == slen to see how many chars

View file

@ -76,11 +76,12 @@ Current usages:
* `void SpinDelayUs(int us)` * `void SpinDelayUs(int us)`
* `void SpinDelay(int ms)` based on SpinDelayUs * `void SpinDelay(int ms)` based on SpinDelayUs
* `void SpinDelayUsPrecision(int us)`
Busy wait based on 46.875 kHz PWM Channel 0, 21.3 us precision Busy wait based on 46.875 kHz PWM Channel 0
WARNING: timer can't measure more than 1.39 s
* 21.3 us precision and maximum 1.39 s
* *Precision* variant: 0.7 us precision and maximum 43 ms
## Occasional TC0+TC1 / CountUS functions ## Occasional TC0+TC1 / CountUS functions
@ -98,7 +99,7 @@ Maximal value: 0x7fffffff = 2147 s
Can't be used at the same time as CountSspClk or Ticks functions. Can't be used at the same time as CountSspClk or Ticks functions.
## Occasional TC0+TC1 SSP_CLK from FPGA / CountSspClk functions ## Occasional TC0+TC1+TC2 SSP_CLK from FPGA / CountSspClk functions
cf `armsrc/ticks.c` cf `armsrc/ticks.c`

View file

@ -72,7 +72,7 @@ lf config s 10000 t 20
lf t55xx sniff lf t55xx sniff
-- if you have a save trace from before, try -- if you have a save trace from before, try
data load xxxxxxx.pm3 data load -f xxxxxxx.pm3
lf t55xx sniff 1 lf t55xx sniff 1
``` ```

View file

@ -10,9 +10,12 @@ Check column "offline" for their availability.
|command |offline |description |command |offline |description
|------- |------- |----------- |------- |------- |-----------
|`help `|Y |`This help. Use '<command> help' for details of a particular command.`
|`auto `|N |`Automated detection process for unknown tags` |`auto `|N |`Automated detection process for unknown tags`
|`clear `|Y |`clear screen`
|`help `|Y |`This help. Use '<command> help' for details of a particular command.`
|`hints `|Y |`Turn hints on / off`
|`msleep `|Y |`Add a pause in milliseconds` |`msleep `|Y |`Add a pause in milliseconds`
|`pref `|Y |`Edit preferences`
|`rem `|Y |`Add a text line in log file` |`rem `|Y |`Add a text line in log file`
|`quit `|Y |`` |`quit `|Y |``
|`exit `|Y |`Exit program` |`exit `|Y |`Exit program`
@ -34,6 +37,7 @@ Check column "offline" for their availability.
|`analyse a `|Y |`num bits test` |`analyse a `|Y |`num bits test`
|`analyse nuid `|Y |`create NUID from 7byte UID` |`analyse nuid `|Y |`create NUID from 7byte UID`
|`analyse demodbuff `|Y |`Load binary string to demodbuffer` |`analyse demodbuff `|Y |`Load binary string to demodbuffer`
|`analyse freq `|Y |`Calc wave lengths`
### data ### data
@ -43,42 +47,45 @@ Check column "offline" for their availability.
|command |offline |description |command |offline |description
|------- |------- |----------- |------- |------- |-----------
|`data help `|Y |`This help` |`data help `|Y |`This help`
|`data askedgedetect `|Y |`[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)` |`data biphaserawdecode `|Y |`Biphase decode bin stream in DemodBuffer`
|`data autocorr `|Y |`[window length] [g] -- Autocorrelation over window - g to save back to GraphBuffer (overwrite)` |`data detectclock `|Y |`Detect ASK, FSK, NRZ, PSK clock rate of wave in GraphBuffer`
|`data biphaserawdecode `|Y |`[offset] [invert<0|1>] [maxErr] -- Biphase decode bin stream in DemodBuffer (offset = 0|1 bits to shift the decode start)`
|`data bin2hex `|Y |`<digits> -- Converts binary to hexadecimal`
|`data bitsamples `|N |`Get raw samples as bitstring`
|`data buffclear `|Y |`Clears bigbuff on deviceside and graph window`
|`data convertbitstream `|Y |`Convert GraphBuffer's 0/1 values to 127 / -127`
|`data dec `|Y |`Decimate samples`
|`data detectclock `|Y |`[<a|f|n|p>] Detect ASK, FSK, NRZ, PSK clock rate of wave in GraphBuffer`
|`data fsktonrz `|Y |`Convert fsk2 to nrz wave for alternate fsk demodulating (for weak fsk)` |`data fsktonrz `|Y |`Convert fsk2 to nrz wave for alternate fsk demodulating (for weak fsk)`
|`data getbitstream `|Y |`Convert GraphBuffer's >=1 values to 1 and <1 to 0` |`data manrawdecode `|Y |`Manchester decode binary stream in DemodBuffer`
|`data grid `|Y |`<x> <y> -- overlay grid on graph window, use zero value to turn off either` |`data modulation `|Y |`Identify LF signal for clock and modulation`
|`data hexsamples `|N |`<bytes> [<offset>] -- Dump big buffer as hex bytes` |`data rawdemod `|Y |`Demodulate the data in the GraphBuffer and output binary`
|`data hex2bin `|Y |`<hexadecimal> -- Converts hexadecimal to binary` |`data askedgedetect `|Y |`[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)`
|`data autocorr `|Y |`Autocorrelation over window`
|`data dirthreshold `|Y |`<thres up> <thres down> -- Max rising higher up-thres/ Min falling lower down-thres, keep rest as prev.`
|`data decimate `|Y |`Decimate samples`
|`data undecimate `|Y |`Un-decimate samples`
|`data hide `|Y |`Hide graph window` |`data hide `|Y |`Hide graph window`
|`data hpf `|Y |`Remove DC offset from trace` |`data hpf `|Y |`Remove DC offset from trace`
|`data load `|Y |`<filename> -- Load trace (to graph window` |`data iir `|Y |`apply IIR buttersworth filter on plotdata`
|`data grid `|Y |`<x> <y> -- overlay grid on graph window, use zero value to turn off either`
|`data ltrim `|Y |`<samples> -- Trim samples from left of trace` |`data ltrim `|Y |`<samples> -- Trim samples from left of trace`
|`data rtrim `|Y |`<location to end trace> -- Trim samples from right of trace`
|`data mtrim `|Y |`<start> <stop> -- Trim out samples from the specified start to the specified stop` |`data mtrim `|Y |`<start> <stop> -- Trim out samples from the specified start to the specified stop`
|`data manrawdecode `|Y |`[invert] [maxErr] -- Manchester decode binary stream in DemodBuffer`
|`data norm `|Y |`Normalize max/min to +/-128` |`data norm `|Y |`Normalize max/min to +/-128`
|`data plot `|Y |`Show graph window (hit 'h' in window for keystroke help)` |`data plot `|Y |`Show graph window (hit 'h' in window for keystroke help)`
|`data printdemodbuffer `|Y |`[x] [o] <offset> [l] <length> -- print the data in the DemodBuffer - 'x' for hex output` |`data rtrim `|Y |`<location to end trace> -- Trim samples from right of trace`
|`data rawdemod `|Y |`[modulation] ... <options> -see help (h option) -- Demodulate the data in the GraphBuffer and output binary`
|`data samples `|N |`[512 - 40000] -- Get raw samples for graph window (GraphBuffer)`
|`data save `|Y |`Save trace (from graph window)`
|`data setgraphmarkers `|Y |`[orange_marker] [blue_marker] (in graph window)` |`data setgraphmarkers `|Y |`[orange_marker] [blue_marker] (in graph window)`
|`data scale `|Y |`<int> -- Set cursor display scale in carrier frequency expressed in kHz`
|`data setdebugmode `|Y |`<0|1|2> -- Set Debugging Level on client side`
|`data shiftgraphzero `|Y |`<shift> -- Shift 0 for Graphed wave + or - shift value` |`data shiftgraphzero `|Y |`<shift> -- Shift 0 for Graphed wave + or - shift value`
|`data dirthreshold `|Y |`<thres up> <thres down> -- Max rising higher up-thres/ Min falling lower down-thres, keep rest as prev.` |`data timescale `|Y |`Set a timescale to get a differential reading between the yellow and purple markers as time duration
|`data tune `|N |`Get hw tune samples for graph window` `
|`data undec `|Y |`Un-decimate samples by 2`
|`data zerocrossings `|Y |`Count time between zero-crossings` |`data zerocrossings `|Y |`Count time between zero-crossings`
|`data iir `|Y |`apply IIR buttersworth filter on plotdata` |`data convertbitstream `|Y |`Convert GraphBuffer's 0/1 values to 127 / -127`
|`data getbitstream `|Y |`Convert GraphBuffer's >=1 values to 1 and <1 to 0`
|`data bin2hex `|Y |`Converts binary to hexadecimal`
|`data bitsamples `|N |`Get raw samples as bitstring`
|`data clear `|Y |`Clears bigbuf on deviceside and graph window`
|`data hexsamples `|N |`<bytes> [<offset>] -- Dump big buffer as hex bytes`
|`data hex2bin `|Y |`Converts hexadecimal to binary`
|`data load `|Y |`Load contents of file into graph window`
|`data ndef `|Y |`Decode NDEF records`
|`data print `|Y |`print the data in the DemodBuffer`
|`data samples `|N |`[512 - 40000] -- Get raw samples for graph window (GraphBuffer)`
|`data save `|Y |`Save signal trace data (from graph window)`
|`data setdebugmode `|Y |`<0|1|2> -- Set Debugging Level on client side`
|`data tune `|N |`Measure tuning of device antenna. Results shown in graph window`
### emv ### emv
@ -111,6 +118,7 @@ Check column "offline" for their availability.
|------- |------- |----------- |------- |------- |-----------
|`hf help `|Y |`This help` |`hf help `|Y |`This help`
|`hf list `|Y |`List protocol data in trace buffer` |`hf list `|Y |`List protocol data in trace buffer`
|`hf plot `|N |`Plot signal`
|`hf tune `|N |`Continuously measure HF antenna tuning` |`hf tune `|N |`Continuously measure HF antenna tuning`
|`hf search `|Y |`Search for known HF tags` |`hf search `|Y |`Search for known HF tags`
|`hf sniff `|N |`<samples to skip (10000)> <triggers to skip (1)> Generic HF Sniff` |`hf sniff `|N |`<samples to skip (10000)> <triggers to skip (1)> Generic HF Sniff`
@ -133,6 +141,7 @@ Check column "offline" for their availability.
|`hf 14a chaining `|N |`Control ISO 14443-4 input chaining` |`hf 14a chaining `|N |`Control ISO 14443-4 input chaining`
|`hf 14a raw `|N |`Send raw hex data to tag` |`hf 14a raw `|N |`Send raw hex data to tag`
|`hf 14a antifuzz `|N |`Fuzzing the anticollision phase. Warning! Readers may react strange` |`hf 14a antifuzz `|N |`Fuzzing the anticollision phase. Warning! Readers may react strange`
|`hf 14a config `|N |`Configure 14a settings (use with caution)`
### hf 14b ### hf 14b
@ -142,9 +151,11 @@ Check column "offline" for their availability.
|command |offline |description |command |offline |description
|------- |------- |----------- |------- |------- |-----------
|`hf 14b help `|Y |`This help` |`hf 14b help `|Y |`This help`
|`hf 14b apdu `|N |`Send ISO 14443-4 APDU to tag`
|`hf 14b dump `|N |`Read all memory pages of an ISO14443-B tag, save to file` |`hf 14b dump `|N |`Read all memory pages of an ISO14443-B tag, save to file`
|`hf 14b info `|N |`Tag information` |`hf 14b info `|N |`Tag information`
|`hf 14b list `|Y |`List ISO 14443B history` |`hf 14b list `|Y |`List ISO 14443B history`
|`hf 14b ndef `|N |`Read NDEF file on tag`
|`hf 14b raw `|N |`Send raw hex data to tag` |`hf 14b raw `|N |`Send raw hex data to tag`
|`hf 14b reader `|N |`Act as a 14443B reader to identify a tag` |`hf 14b reader `|N |`Act as a 14443B reader to identify a tag`
|`hf 14b sim `|N |`Fake ISO 14443B tag` |`hf 14b sim `|N |`Fake ISO 14443B tag`
@ -160,22 +171,22 @@ Check column "offline" for their availability.
|command |offline |description |command |offline |description
|------- |------- |----------- |------- |------- |-----------
|`hf 15 help `|Y |`This help` |`hf 15 help `|Y |`This help`
|`hf 15 list `|Y |`List ISO15693 history`
|`hf 15 demod `|Y |`Demodulate ISO15693 from tag` |`hf 15 demod `|Y |`Demodulate ISO15693 from tag`
|`hf 15 dump `|N |`Read all memory pages of an ISO15693 tag, save to file` |`hf 15 dump `|N |`Read all memory pages of an ISO15693 tag, save to file`
|`hf 15 info `|N |`Tag information`
|`hf 15 sniff `|N |`Sniff ISO15693 traffic`
|`hf 15 raw `|N |`Send raw hex data to tag`
|`hf 15 read `|N |`Read a block`
|`hf 15 reader `|N |`Act like an ISO15693 reader`
|`hf 15 readmulti `|N |`Reads multiple Blocks`
|`hf 15 restore `|N |`Restore from file to all memory pages of an ISO15693 tag`
|`hf 15 samples `|N |`Acquire Samples as Reader (enables carrier, sends inquiry)`
|`hf 15 sim `|N |`Fake an ISO15693 tag`
|`hf 15 write `|N |`Write a block`
|`hf 15 findafi `|N |`Brute force AFI of an ISO15693 tag` |`hf 15 findafi `|N |`Brute force AFI of an ISO15693 tag`
|`hf 15 writeafi `|N |`Writes the AFI on an ISO15693 tag` |`hf 15 writeafi `|N |`Writes the AFI on an ISO15693 tag`
|`hf 15 writedsfid `|N |`Writes the DSFID on an ISO15693 tag` |`hf 15 writedsfid `|N |`Writes the DSFID on an ISO15693 tag`
|`hf 15 info `|N |`Tag information`
|`hf 15 list `|Y |`List ISO15693 history`
|`hf 15 raw `|N |`Send raw hex data to tag`
|`hf 15 reader `|N |`Act like an ISO15693 reader`
|`hf 15 record `|N |`Record Samples (ISO15693)`
|`hf 15 restore `|N |`Restore from file to all memory pages of an ISO15693 tag`
|`hf 15 sim `|N |`Fake an ISO15693 tag`
|`hf 15 samples `|N |`Acquire Samples as Reader (enables carrier, sends inquiry)`
|`hf 15 read `|N |`Read a block`
|`hf 15 write `|N |`Write a block`
|`hf 15 readmulti `|N |`Reads multiple Blocks`
|`hf 15 csetuid `|N |`Set UID for magic Chinese card` |`hf 15 csetuid `|N |`Set UID for magic Chinese card`
@ -201,40 +212,33 @@ Check column "offline" for their availability.
|`hf felica reader `|N |`Act like an ISO18092/FeliCa reader` |`hf felica reader `|N |`Act like an ISO18092/FeliCa reader`
|`hf felica sniff `|N |`Sniff ISO 18092/FeliCa traffic` |`hf felica sniff `|N |`Sniff ISO 18092/FeliCa traffic`
|`hf felica raw `|N |`Send raw hex data to tag` |`hf felica raw `|N |`Send raw hex data to tag`
|`hf felica rqservice `|N |`verify the existence of Area and Service, and to acquire Key Version.`
|`hf felica rqresponse `|N |`verify the existence of a card and its Mode.`
|`hf felica rdunencrypted`|N |`read Block Data from authentication-not-required Service.` |`hf felica rdunencrypted`|N |`read Block Data from authentication-not-required Service.`
|`hf felica wrunencrypted`|N |`write Block Data to an authentication-not-required Service.` |`hf felica wrunencrypted`|N |`write Block Data to an authentication-not-required Service.`
|`hf felica rqservice `|N |`verify the existence of Area and Service, and to acquire Key Version.`
|`hf felica rqresponse `|N |`verify the existence of a card and its Mode.`
|`hf felica scsvcode `|N |`acquire Area Code and Service Code.` |`hf felica scsvcode `|N |`acquire Area Code and Service Code.`
|`hf felica rqsyscode `|N |`acquire System Code registered to the card.` |`hf felica rqsyscode `|N |`acquire System Code registered to the card.`
|`hf felica auth1 `|N |`authenticate a card. Start mutual authentication with Auth1` |`hf felica auth1 `|N |`authenticate a card. Start mutual authentication with Auth1`
|`hf felica auth2 `|N |`allow a card to authenticate a Reader/Writer. Complete mutual authentication` |`hf felica auth2 `|N |`allow a card to authenticate a Reader/Writer. Complete mutual authentication`
|`hf felica read `|N |`read Block Data from authentication-required Service.`
|`hf felica rqspecver `|N |`acquire the version of card OS.` |`hf felica rqspecver `|N |`acquire the version of card OS.`
|`hf felica resetmode `|N |`reset Mode to Mode 0.` |`hf felica resetmode `|N |`reset Mode to Mode 0.`
|`hf felica litesim `|N |`<NDEF2> - only reply to poll request` |`hf felica litesim `|N |`<NDEF2> - only reply to poll request`
|`hf felica litedump `|N |`Wait for and try dumping FelicaLite` |`hf felica litedump `|N |`Wait for and try dumping FelicaLite`
### hf legic ### hf fido
{ LEGIC RFIDs... } { FIDO and FIDO2 authenticators... }
|command |offline |description |command |offline |description
|------- |------- |----------- |------- |------- |-----------
|`hf legic help `|Y |`This help` |`hf fido help `|Y |`This help.`
|`hf legic reader `|N |`LEGIC Prime Reader UID and tag info` |`hf fido info `|N |`List ISO 14443A history`
|`hf legic info `|N |`Display deobfuscated and decoded LEGIC Prime tag data` |`hf fido info `|N |`Info about FIDO tag.`
|`hf legic dump `|N |`Dump LEGIC Prime tag to binary file` |`hf fido reg `|N |`FIDO U2F Registration Message.`
|`hf legic restore `|N |`Restore a dump file onto a LEGIC Prime tag` |`hf fido auth `|N |`FIDO U2F Authentication Message.`
|`hf legic rdmem `|N |`Read bytes from a LEGIC Prime tag` |`hf fido make `|N |`FIDO2 MakeCredential command.`
|`hf legic sim `|N |`Start tag simulator` |`hf fido assert `|N |`FIDO2 GetAssertion command.`
|`hf legic write `|N |`Write data to a LEGIC Prime tag`
|`hf legic crc `|Y |`Calculate Legic CRC over given bytes`
|`hf legic eload `|N |`Load binary dump to emulator memory`
|`hf legic esave `|N |`Save emulator memory to binary file`
|`hf legic list `|Y |`List LEGIC history`
|`hf legic wipe `|N |`Wipe a LEGIC Prime tag`
### hf iclass ### hf iclass
@ -244,26 +248,64 @@ Check column "offline" for their availability.
|command |offline |description |command |offline |description
|------- |------- |----------- |------- |------- |-----------
|`hf iclass help `|Y |`This help` |`hf iclass help `|Y |`This help`
|`hf iclass calcnewkey `|Y |`[options..] Calc diversified keys (blocks 3 & 4) to write new keys` |`hf iclass dump `|N |`[options..] Dump Picopass / iCLASS tag to file`
|`hf iclass chk `|Y |`[options..] Check keys`
|`hf iclass clone `|N |`[options..] Restore a dump file onto a iClass tag`
|`hf iclass decrypt `|Y |`[options..] Decrypt given block data or tag dump file`
|`hf iclass dump `|N |`[options..] Dump iClass tag to file`
|`hf iclass eload `|N |`[f <fname>] Load iClass dump file into emulator memory`
|`hf iclass encrypt `|Y |`[options..] Encrypt given block data`
|`hf iclass info `|Y |` Tag information` |`hf iclass info `|Y |` Tag information`
|`hf iclass list `|Y |` List iClass history` |`hf iclass list `|Y |` List iclass history`
|`hf iclass rdbl `|N |`[options..] Read Picopass / iCLASS block`
|`hf iclass reader `|N |` Act like an Picopass / iCLASS reader`
|`hf iclass restore `|N |`[options..] Restore a dump file onto a Picopass / iCLASS tag`
|`hf iclass sniff `|N |` Eavesdrop Picopass / iCLASS communication`
|`hf iclass wrbl `|N |`[options..] Write Picopass / iCLASS block`
|`hf iclass chk `|Y |`[options..] Check keys`
|`hf iclass loclass `|Y |`[options..] Use loclass to perform bruteforce reader attack` |`hf iclass loclass `|Y |`[options..] Use loclass to perform bruteforce reader attack`
|`hf iclass lookup `|Y |`[options..] Uses authentication trace to check for key in dictionary file` |`hf iclass lookup `|Y |`[options..] Uses authentication trace to check for key in dictionary file`
|`hf iclass managekeys `|Y |`[options..] Manage keys to use with iClass` |`hf iclass replay `|N |`<mac> Read Picopass / iCLASS tag via replay attack`
|`hf iclass permutekey `|N |` Permute function from 'heart of darkness' paper` |`hf iclass sim `|N |`[options..] Simulate iCLASS tag`
|`hf iclass rdbl `|N |`[options..] Read iClass block` |`hf iclass eload `|N |`[f <fn> ] Load Picopass / iCLASS dump file into emulator memory`
|`hf iclass reader `|N |` Act like an iClass reader` |`hf iclass esave `|N |`[f <fn> ] Save emulator memory to file`
|`hf iclass readtagfile `|Y |`[options..] Display content from tag dump file` |`hf iclass eview `|N |`[options..] View emulator memory`
|`hf iclass replay `|N |`<mac> Read iClass tag via replay attack` |`hf iclass calcnewkey `|Y |`[options..] Calc diversified keys (blocks 3 & 4) to write new keys`
|`hf iclass sim `|N |`[options..] Simulate iClass tag` |`hf iclass encrypt `|Y |`[options..] Encrypt given block data`
|`hf iclass sniff `|N |` Eavesdrop iClass communication` |`hf iclass decrypt `|Y |`[options..] Decrypt given block data or tag dump file`
|`hf iclass wrbl `|N |`[options..] Write iClass block` |`hf iclass managekeys `|Y |`[options..] Manage keys to use with iclass commands`
|`hf iclass permute `|N |` Permute function from 'heart of darkness' paper`
|`hf iclass view `|Y |`[options..] Display content from tag dump file`
### hf legic
{ LEGIC RFIDs... }
|command |offline |description
|------- |------- |-----------
|`hf legic help `|Y |`This help`
|`hf legic list `|Y |`List LEGIC history`
|`hf legic reader `|N |`LEGIC Prime Reader UID and tag info`
|`hf legic info `|N |`Display deobfuscated and decoded LEGIC Prime tag data`
|`hf legic dump `|N |`Dump LEGIC Prime tag to binary file`
|`hf legic restore `|N |`Restore a dump file onto a LEGIC Prime tag`
|`hf legic rdbl `|N |`Read bytes from a LEGIC Prime tag`
|`hf legic sim `|N |`Start tag simulator`
|`hf legic wrbl `|N |`Write data to a LEGIC Prime tag`
|`hf legic crc `|Y |`Calculate Legic CRC over given bytes`
|`hf legic eload `|Y |`Load binary dump to emulator memory`
|`hf legic esave `|Y |`Save emulator memory to binary file`
|`hf legic wipe `|N |`Wipe a LEGIC Prime tag`
### hf lto
{ LTO Cartridge Memory RFIDs... }
|command |offline |description
|------- |------- |-----------
|`hf lto help `|Y |`This help`
|`hf lto dump `|N |`Dump LTO-CM tag to file`
|`hf lto restore `|N |`Restore dump file to LTO-CM tag`
|`hf lto info `|N |`Tag information`
|`hf lto rdbl `|N |`Read block`
|`hf lto wrbl `|N |`Write block`
|`hf lto list `|Y |`List LTO-CM history`
### hf mf ### hf mf
@ -277,38 +319,43 @@ Check column "offline" for their availability.
|`hf mf darkside `|N |`Darkside attack` |`hf mf darkside `|N |`Darkside attack`
|`hf mf nested `|N |`Nested attack` |`hf mf nested `|N |`Nested attack`
|`hf mf hardnested `|Y |`Nested attack for hardened MIFARE Classic cards` |`hf mf hardnested `|Y |`Nested attack for hardened MIFARE Classic cards`
|`hf mf staticnested `|N |`Nested attack against static nonce MIFARE Classic cards`
|`hf mf autopwn `|N |`Automatic key recovery tool for MIFARE Classic` |`hf mf autopwn `|N |`Automatic key recovery tool for MIFARE Classic`
|`hf mf nack `|N |`Test for MIFARE NACK bug` |`hf mf nack `|N |`Test for MIFARE NACK bug`
|`hf mf chk `|N |`Check keys` |`hf mf chk `|N |`Check keys`
|`hf mf fchk `|N |`Check keys fast, targets all keys on card` |`hf mf fchk `|N |`Check keys fast, targets all keys on card`
|`hf mf decrypt `|Y |`[nt] [ar_enc] [at_enc] [data] - to decrypt sniff or trace` |`hf mf decrypt `|Y |`[nt] [ar_enc] [at_enc] [data] - to decrypt sniff or trace`
|`hf mf rdbl `|N |`Read MIFARE classic block`
|`hf mf rdsc `|N |`Read MIFARE classic sector`
|`hf mf dump `|N |`Dump MIFARE classic tag to binary file`
|`hf mf restore `|N |`Restore MIFARE classic binary file to BLANK tag`
|`hf mf wrbl `|N |`Write MIFARE classic block`
|`hf mf setmod `|N |`Set MIFARE Classic EV1 load modulation strength`
|`hf mf auth4 `|N |`ISO14443-4 AES authentication` |`hf mf auth4 `|N |`ISO14443-4 AES authentication`
|`hf mf dump `|N |`Dump MIFARE Classic tag to binary file`
|`hf mf mad `|N |`Checks and prints MAD`
|`hf mf ndef `|N |`Prints NDEF records from card`
|`hf mf personalize `|N |`Personalize UID (MIFARE Classic EV1 only)`
|`hf mf rdbl `|N |`Read MIFARE Classic block`
|`hf mf rdsc `|N |`Read MIFARE Classic sector`
|`hf mf restore `|N |`Restore MIFARE Classic binary file to BLANK tag`
|`hf mf setmod `|N |`Set MIFARE Classic EV1 load modulation strength`
|`hf mf wrbl `|N |`Write MIFARE Classic block`
|`hf mf sim `|N |`Simulate MIFARE card` |`hf mf sim `|N |`Simulate MIFARE card`
|`hf mf ecfill `|N |`Fill simulator memory with help of keys from simulator`
|`hf mf eclr `|N |`Clear simulator memory` |`hf mf eclr `|N |`Clear simulator memory`
|`hf mf egetblk `|N |`Get simulator memory block` |`hf mf egetblk `|N |`Get simulator memory block`
|`hf mf egetsc `|N |`Get simulator memory sector` |`hf mf egetsc `|N |`Get simulator memory sector`
|`hf mf eset `|N |`Set simulator memory block` |`hf mf ekeyprn `|N |`Print keys from simulator memory`
|`hf mf eload `|N |`Load from file emul dump` |`hf mf eload `|N |`Load from file emul dump`
|`hf mf esave `|N |`Save to file emul dump` |`hf mf esave `|N |`Save to file emul dump`
|`hf mf ecfill `|N |`Fill simulator memory with help of keys from simulator` |`hf mf eset `|N |`Set simulator memory block`
|`hf mf ekeyprn `|N |`Print keys from simulator memory` |`hf mf eview `|N |`View emul memory`
|`hf mf eview `|N |`View simulator memory` |`hf mf cgetblk `|N |`Read block`
|`hf mf csetuid `|N |`Set UID (magic chinese card)` |`hf mf cgetsc `|N |`Read sector`
|`hf mf cload `|N |`Load dump`
|`hf mf csave `|N |`Save dump from card into file or emulator`
|`hf mf csetblk `|N |`Write block`
|`hf mf csetuid `|N |`Set UID`
|`hf mf cview `|N |`view card`
|`hf mf cwipe `|N |`Wipe card to default UID/Sectors/Keys` |`hf mf cwipe `|N |`Wipe card to default UID/Sectors/Keys`
|`hf mf csetblk `|N |`Write block (magic chinese card)` |`hf mf gen3uid `|N |`Set UID without manufacturer block`
|`hf mf cgetblk `|N |`Read block (magic chinese card)` |`hf mf gen3blk `|N |`Overwrite full manufacturer block`
|`hf mf cgetsc `|N |`Read sector (magic chinese card)` |`hf mf gen3freeze `|N |`Perma lock further UID changes`
|`hf mf cload `|N |`Load dump (magic chinese card)`
|`hf mf csave `|N |`Save dump from magic chinese card into file or emulator`
|`hf mf cview `|N |`View card memory (magic chinese card)`
|`hf mf mad `|N |`Checks and prints MAD`
|`hf mf ndef `|N |`Prints NDEF records from card`
|`hf mf ice `|N |`collect MIFARE Classic nonces to file` |`hf mf ice `|N |`collect MIFARE Classic nonces to file`
@ -352,6 +399,7 @@ Check column "offline" for their availability.
|`hf mfu gen `|Y |`Generate 3des mifare diversified keys` |`hf mfu gen `|Y |`Generate 3des mifare diversified keys`
|`hf mfu pwdgen `|Y |`Generate pwd from known algos` |`hf mfu pwdgen `|Y |`Generate pwd from known algos`
|`hf mfu otptear `|N |`Tear-off test on OTP bits` |`hf mfu otptear `|N |`Tear-off test on OTP bits`
|`hf mfu ndef `|N |`Prints NDEF records from card`
### hf mfdes ### hf mfdes
@ -362,36 +410,41 @@ Check column "offline" for their availability.
|------- |------- |----------- |------- |------- |-----------
|`hf mfdes help `|Y |`This help` |`hf mfdes help `|Y |`This help`
|`hf mfdes info `|N |`Tag information` |`hf mfdes info `|N |`Tag information`
|`hf mfdes list `|Y |`List DESFire (ISO 14443A) history`
|`hf mfdes enum `|N |`Tries enumerate all applications` |`hf mfdes enum `|N |`Tries enumerate all applications`
|`hf mfdes auth `|N |`Tries a MIFARE DesFire Authentication` |`hf mfdes auth `|N |`Tries a MIFARE DesFire Authentication`
|`hf mfdes getuid `|N |`Get random uid`
|`hf mfdes selectaid `|N |`Select Application ID`
|`hf mfdes createaid `|N |`Create Application ID`
|`hf mfdes deleteaid `|N |`Delete Application ID`
|`hf mfdes createfile `|N |`Create Standard/Backup File`
|`hf mfdes createvaluefile`|N |`Create Value File`
|`hf mfdes createrecordfile`|N |`Create Linear/Cyclic Record File`
|`hf mfdes deletefile `|N |`Create Delete File`
|`hf mfdes clearfile `|N |`Clear record File`
|`hf mfdes readdata `|N |`Read data from standard/backup/record file`
|`hf mfdes writedata `|N |`Write data to standard/backup/record file`
|`hf mfdes getvalue `|N |`Get value of file`
|`hf mfdes changevalue `|N |`Write value of a value file (credit/debit/clear)`
|`hf mfdes changekey `|N |`Change Key`
|`hf mfdes formatpicc `|N |`Format PICC`
|`hf mfdes dump `|N |`Dump all files`
|`hf mfdes chk `|N |`Check keys`
### hf topaz ### hf st
{ TOPAZ (NFC Type 1) RFIDs... } { ST Rothult RFIDs... }
|command |offline |description |command |offline |description
|------- |------- |----------- |------- |------- |-----------
|`hf topaz help `|Y |`This help` |`hf st help `|Y |`This help`
|`hf topaz reader `|N |`Act like a Topaz reader` |`hf st info `|N |`Tag information`
|`hf topaz sim `|N |`<UID> -- Simulate Topaz tag` |`hf st list `|Y |`List ISO 14443A/7816 history`
|`hf topaz sniff `|N |`Sniff Topaz reader-tag communication` |`hf st ndef `|Y |`read NDEF file on tag`
|`hf topaz raw `|N |`Send raw hex data to tag` |`hf st protect `|N |`change protection on tag`
|`hf topaz list `|Y |`List Topaz history` |`hf st pwd `|N |`change password on tag`
|`hf st sim `|N |`Fake ISO 14443A/ST tag`
### hf fido
{ FIDO and FIDO2 authenticators... }
|command |offline |description
|------- |------- |-----------
|`hf fido help `|Y |`This help.`
|`hf fido info `|N |`Info about FIDO tag.`
|`hf fido reg `|N |`FIDO U2F Registration Message.`
|`hf fido auth `|N |`FIDO U2F Authentication Message.`
|`hf fido make `|N |`FIDO2 MakeCredential command.`
|`hf fido assert `|N |`FIDO2 GetAssertion command.`
### hf thinfilm ### hf thinfilm
@ -406,6 +459,31 @@ Check column "offline" for their availability.
|`hf thinfilm sim `|N |`Fake Thinfilm tag` |`hf thinfilm sim `|N |`Fake Thinfilm tag`
### hf topaz
{ TOPAZ (NFC Type 1) RFIDs... }
|command |offline |description
|------- |------- |-----------
|`hf topaz help `|Y |`This help`
|`hf topaz list `|Y |`List Topaz history`
|`hf topaz info `|N |`Tag information`
|`hf topaz reader `|N |`Act like a Topaz reader`
|`hf topaz sim `|N |`<UID> -- Simulate Topaz tag`
|`hf topaz sniff `|N |`Sniff Topaz reader-tag communication`
|`hf topaz raw `|N |`Send raw hex data to tag`
### hf waveshare
{ Waveshare NFC ePaper... }
|command |offline |description
|------- |------- |-----------
|`hf waveshare help `|Y |`This help`
|`hf waveshare loadbmp `|N |`Load BMP file to Waveshare NFC ePaper`
### hw ### hw
{ Hardware commands... } { Hardware commands... }
@ -426,6 +504,7 @@ Check column "offline" for their availability.
|`hw setmux `|N |`Set the ADC mux to a specific value` |`hw setmux `|N |`Set the ADC mux to a specific value`
|`hw standalone `|N |`Jump to the standalone mode` |`hw standalone `|N |`Jump to the standalone mode`
|`hw status `|N |`Show runtime status information about the connected Proxmark3` |`hw status `|N |`Show runtime status information about the connected Proxmark3`
|`hw tearoff `|N |`Program a tearoff hook for the next command supporting tearoff`
|`hw tia `|N |`Trigger a Timing Interval Acquisition to re-adjust the RealTimeCounter divider` |`hw tia `|N |`Trigger a Timing Interval Acquisition to re-adjust the RealTimeCounter divider`
|`hw tune `|N |`Measure antenna tuning` |`hw tune `|N |`Measure antenna tuning`
|`hw version `|N |`Show version information about the connected Proxmark3` |`hw version `|N |`Show version information about the connected Proxmark3`
@ -460,7 +539,7 @@ Check column "offline" for their availability.
|`lf awid help `|Y |`this help` |`lf awid help `|Y |`this help`
|`lf awid demod `|Y |`demodulate an AWID FSK tag from the GraphBuffer` |`lf awid demod `|Y |`demodulate an AWID FSK tag from the GraphBuffer`
|`lf awid read `|N |`attempt to read and extract tag data` |`lf awid read `|N |`attempt to read and extract tag data`
|`lf awid clone `|N |`clone AWID tag to T55x7 (or to q5/T5555)` |`lf awid clone `|N |`clone AWID tag to T55x7 or Q5/T5555`
|`lf awid sim `|N |`simulate AWID tag` |`lf awid sim `|N |`simulate AWID tag`
|`lf awid brute `|N |`Bruteforce card number against reader` |`lf awid brute `|N |`Bruteforce card number against reader`
|`lf awid watch `|N |`continuously watch for cards. Reader mode` |`lf awid watch `|N |`continuously watch for cards. Reader mode`
@ -490,30 +569,32 @@ Check column "offline" for their availability.
|`lf em 410x_brute `|N |`reader bruteforce attack by simulating EM410x tags` |`lf em 410x_brute `|N |`reader bruteforce attack by simulating EM410x tags`
|`lf em 410x_watch `|N |`watches for EM410x 125/134 kHz tags (option 'h' for 134)` |`lf em 410x_watch `|N |`watches for EM410x 125/134 kHz tags (option 'h' for 134)`
|`lf em 410x_spoof `|N |`watches for EM410x 125/134 kHz tags, and replays them. (option 'h' for 134)` |`lf em 410x_spoof `|N |`watches for EM410x 125/134 kHz tags, and replays them. (option 'h' for 134)`
|`lf em 410x_clone `|N |`write EM410x UID to T5555(Q5) or T55x7 tag` |`lf em 410x_clone `|N |`write EM410x UID to T55x7 or Q5/T5555 tag`
|`lf em 4x05_demod `|Y |`demodulate a EM4x05/EM4x69 tag from the GraphBuffer` |`lf em 4x05_demod `|Y |`demodulate a EM4x05/EM4x69 tag from the GraphBuffer`
|`lf em 4x05_dump `|N |`dump EM4x05/EM4x69 tag` |`lf em 4x05_dump `|N |`dump EM4x05/EM4x69 tag`
|`lf em 4x05_wipe `|N |`wipe EM4x05/EM4x69 tag` |`lf em 4x05_wipe `|N |`wipe EM4x05/EM4x69 tag`
|`lf em 4x05_info `|N |`tag information EM4x05/EM4x69` |`lf em 4x05_info `|N |`tag information EM4x05/EM4x69`
|`lf em 4x05_read `|N |`read word data from EM4x05/EM4x69` |`lf em 4x05_read `|N |`read word data from EM4x05/EM4x69`
|`lf em 4x05_write `|N |`write word data to EM4x05/EM4x69` |`lf em 4x05_write `|N |`write word data to EM4x05/EM4x69`
|`lf em 4x50_demod `|Y |`demodulate a EM4x50 tag from the GraphBuffer`
|`lf em 4x50_dump `|N |`dump EM4x50 tag` |`lf em 4x50_dump `|N |`dump EM4x50 tag`
|`lf em 4x50_read `|N |`read word data from EM4x50` |`lf em 4x50_info `|N |`tag information EM4x50`
|`lf em 4x50_write `|N |`write word data to EM4x50` |`lf em 4x50_write `|N |`write word data to EM4x50`
|`lf em 4x50_write_password`|N |`change passwword of EM4x50 tag`
|`lf em 4x50_read `|N |`read word data from EM4x50`
|`lf em 4x50_wipe `|N |`wipe data from EM4x50`
### lf fdx ### lf fdxb
{ FDX-B RFIDs... } { FDX-B RFIDs... }
|command |offline |description |command |offline |description
|------- |------- |----------- |------- |------- |-----------
|`lf fdx help `|Y |`this help` |`lf fdxb help `|Y |`this help`
|`lf fdx demod `|Y |`demodulate a FDX-B ISO11784/85 tag from the GraphBuffer` |`lf fdxb demod `|Y |`demodulate a FDX-B ISO11784/85 tag from the GraphBuffer`
|`lf fdx read `|N |`attempt to read and extract tag data` |`lf fdxb read `|N |`attempt to read at 134kHz and extract tag data`
|`lf fdx clone `|N |`clone animal ID tag to T55x7 (or to q5/T5555)` |`lf fdxb clone `|N |`clone animal ID tag to T55x7 or Q5/T5555`
|`lf fdx sim `|N |`simulate Animal ID tag` |`lf fdxb sim `|N |`simulate Animal ID tag`
### lf gallagher ### lf gallagher
@ -538,13 +619,13 @@ Check column "offline" for their availability.
|`lf gproxii help `|Y |`this help` |`lf gproxii help `|Y |`this help`
|`lf gproxii demod `|Y |`demodulate a G Prox II tag from the GraphBuffer` |`lf gproxii demod `|Y |`demodulate a G Prox II tag from the GraphBuffer`
|`lf gproxii read `|N |`attempt to read and extract tag data from the antenna` |`lf gproxii read `|N |`attempt to read and extract tag data from the antenna`
|`lf gproxii clone `|N |`clone Guardall tag to T55x7` |`lf gproxii clone `|N |`clone Guardall tag to T55x7 or Q5/T5555`
|`lf gproxii sim `|N |`simulate Guardall tag` |`lf gproxii sim `|N |`simulate Guardall tag`
### lf hid ### lf hid
{ HID RFIDs... } { HID Prox RFIDs... }
|command |offline |description |command |offline |description
|------- |------- |----------- |------- |------- |-----------
@ -570,9 +651,21 @@ Check column "offline" for their availability.
|`lf hitag sim `|N |`Simulate Hitag transponder` |`lf hitag sim `|N |`Simulate Hitag transponder`
|`lf hitag sniff `|N |`Eavesdrop Hitag communication` |`lf hitag sniff `|N |`Eavesdrop Hitag communication`
|`lf hitag writer `|N |`Act like a Hitag Writer` |`lf hitag writer `|N |`Act like a Hitag Writer`
|`lf hitag dump `|N |`Dump Hitag2 tag`
|`lf hitag cc `|N |`Test all challenges` |`lf hitag cc `|N |`Test all challenges`
### lf idteck
{ Idteck RFIDs... }
|command |offline |description
|------- |------- |-----------
|`lf idteck help `|Y |`This help`
|`lf idteck demod `|Y |`Demodulate an Idteck tag from the GraphBuffer`
|`lf idteck read `|N |`Attempt to read and Extract tag data from the antenna`
### lf indala ### lf indala
{ Indala RFIDs... } { Indala RFIDs... }
@ -583,7 +676,7 @@ Check column "offline" for their availability.
|`lf indala demod `|Y |`demodulate an indala tag (PSK1) from GraphBuffer` |`lf indala demod `|Y |`demodulate an indala tag (PSK1) from GraphBuffer`
|`lf indala altdemod `|Y |`alternative method to Demodulate samples for Indala 64 bit UID (option '224' for 224 bit)` |`lf indala altdemod `|Y |`alternative method to Demodulate samples for Indala 64 bit UID (option '224' for 224 bit)`
|`lf indala read `|N |`read an Indala Prox tag from the antenna` |`lf indala read `|N |`read an Indala Prox tag from the antenna`
|`lf indala clone `|N |`clone Indala tag to T55x7` |`lf indala clone `|N |`clone Indala tag to T55x7 or Q5/T5555`
|`lf indala sim `|N |`simulate Indala tag` |`lf indala sim `|N |`simulate Indala tag`
@ -596,7 +689,7 @@ Check column "offline" for their availability.
|`lf io help `|Y |`this help` |`lf io help `|Y |`this help`
|`lf io demod `|Y |`demodulate an IOProx tag from the GraphBuffer` |`lf io demod `|Y |`demodulate an IOProx tag from the GraphBuffer`
|`lf io read `|N |`attempt to read and extract tag data` |`lf io read `|N |`attempt to read and extract tag data`
|`lf io clone `|N |`clone IOProx tag to T55x7 (or to q5/T5555)` |`lf io clone `|N |`clone IOProx tag to T55x7 or Q5/T5555`
|`lf io sim `|N |`simulate IOProx tag` |`lf io sim `|N |`simulate IOProx tag`
|`lf io watch `|N |`continuously watch for cards. Reader mode` |`lf io watch `|N |`continuously watch for cards. Reader mode`
@ -610,7 +703,7 @@ Check column "offline" for their availability.
|`lf jablotron help `|Y |`This help` |`lf jablotron help `|Y |`This help`
|`lf jablotron demod `|Y |`Demodulate an Jablotron tag from the GraphBuffer` |`lf jablotron demod `|Y |`Demodulate an Jablotron tag from the GraphBuffer`
|`lf jablotron read `|N |`Attempt to read and extract tag data from the antenna` |`lf jablotron read `|N |`Attempt to read and extract tag data from the antenna`
|`lf jablotron clone `|N |`clone jablotron tag to T55x7 (or to q5/T5555)` |`lf jablotron clone `|N |`clone jablotron tag to T55x7 or Q5/T5555`
|`lf jablotron sim `|N |`simulate jablotron tag` |`lf jablotron sim `|N |`simulate jablotron tag`
@ -623,10 +716,23 @@ Check column "offline" for their availability.
|`lf keri help `|Y |`This help` |`lf keri help `|Y |`This help`
|`lf keri demod `|Y |`Demodulate an KERI tag from the GraphBuffer` |`lf keri demod `|Y |`Demodulate an KERI tag from the GraphBuffer`
|`lf keri read `|N |`Attempt to read and extract tag data from the antenna` |`lf keri read `|N |`Attempt to read and extract tag data from the antenna`
|`lf keri clone `|N |`clone KERI tag to T55x7 (or to q5/T5555)` |`lf keri clone `|N |`clone KERI tag to T55x7 or Q5/T5555`
|`lf keri sim `|N |`simulate KERI tag` |`lf keri sim `|N |`simulate KERI tag`
### lf motorola
{ Motorola RFIDs... }
|command |offline |description
|------- |------- |-----------
|`lf motorola help `|Y |`This help`
|`lf motorola demod `|Y |`Demodulate an MOTOROLA tag from the GraphBuffer`
|`lf motorola read `|N |`Attempt to read and extract tag data from the antenna`
|`lf motorola clone `|N |`clone MOTOROLA tag to T55x7`
|`lf motorola sim `|N |`simulate MOTOROLA tag`
### lf nedap ### lf nedap
{ Nedap RFIDs... } { Nedap RFIDs... }
@ -637,7 +743,7 @@ Check column "offline" for their availability.
|`lf nedap demod `|Y |`Demodulate Nedap tag from the GraphBuffer` |`lf nedap demod `|Y |`Demodulate Nedap tag from the GraphBuffer`
|`lf nedap generate `|Y |`Generate Nedap bitstream in DemodBuffer` |`lf nedap generate `|Y |`Generate Nedap bitstream in DemodBuffer`
|`lf nedap read `|N |`Attempt to read and extract tag data from the antenna` |`lf nedap read `|N |`Attempt to read and extract tag data from the antenna`
|`lf nedap clone `|N |`Clone Nedap tag to T55x7` |`lf nedap clone `|N |`Clone Nedap tag to T55x7 or Q5/T5555`
|`lf nedap sim `|N |`Simulate Nedap tag` |`lf nedap sim `|N |`Simulate Nedap tag`
@ -663,23 +769,10 @@ Check column "offline" for their availability.
|`lf noralsy help `|Y |`This help` |`lf noralsy help `|Y |`This help`
|`lf noralsy demod `|Y |`Demodulate an Noralsy tag from the GraphBuffer` |`lf noralsy demod `|Y |`Demodulate an Noralsy tag from the GraphBuffer`
|`lf noralsy read `|N |`Attempt to read and extract tag data from the antenna` |`lf noralsy read `|N |`Attempt to read and extract tag data from the antenna`
|`lf noralsy clone `|N |`clone Noralsy tag to T55x7 (or to q5/T5555)` |`lf noralsy clone `|N |`clone Noralsy tag to T55x7 or Q5/T5555`
|`lf noralsy sim `|N |`simulate Noralsy tag` |`lf noralsy sim `|N |`simulate Noralsy tag`
### lf motorola
{ Motorola RFIDs... }
|command |offline |description
|------- |------- |-----------
|`lf motorola help `|Y |`This help`
|`lf motorola demod `|Y |`Demodulate an MOTOROLA tag from the GraphBuffer`
|`lf motorola read `|N |`Attempt to read and extract tag data from the antenna`
|`lf motorola clone `|N |`clone MOTOROLA tag to T55x7`
|`lf motorola sim `|N |`simulate MOTOROLA tag`
### lf pac ### lf pac
{ PAC/Stanley RFIDs... } { PAC/Stanley RFIDs... }
@ -725,8 +818,9 @@ Check column "offline" for their availability.
|command |offline |description |command |offline |description
|------- |------- |----------- |------- |------- |-----------
|`lf presco help `|Y |`This help` |`lf presco help `|Y |`This help`
|`lf presco demod `|Y |`demodulate Presco tag from the GraphBuffer`
|`lf presco read `|N |`Attempt to read and Extract tag data` |`lf presco read `|N |`Attempt to read and Extract tag data`
|`lf presco clone `|N |`clone presco tag to T55x7 (or to q5/T5555)` |`lf presco clone `|N |`clone presco tag to T55x7 or Q5/T5555`
|`lf presco sim `|N |`simulate presco tag` |`lf presco sim `|N |`simulate presco tag`
@ -739,7 +833,7 @@ Check column "offline" for their availability.
|`lf pyramid help `|Y |`this help` |`lf pyramid help `|Y |`this help`
|`lf pyramid demod `|Y |`demodulate a Pyramid FSK tag from the GraphBuffer` |`lf pyramid demod `|Y |`demodulate a Pyramid FSK tag from the GraphBuffer`
|`lf pyramid read `|N |`attempt to read and extract tag data` |`lf pyramid read `|N |`attempt to read and extract tag data`
|`lf pyramid clone `|N |`clone pyramid tag to T55x7 (or to q5/T5555)` |`lf pyramid clone `|N |`clone pyramid tag to T55x7 or Q5/T5555`
|`lf pyramid sim `|N |`simulate pyramid tag` |`lf pyramid sim `|N |`simulate pyramid tag`
@ -775,27 +869,27 @@ Check column "offline" for their availability.
|command |offline |description |command |offline |description
|------- |------- |----------- |------- |------- |-----------
|`lf t55xx help `|Y |`This help` |`lf t55xx help `|Y |`This help`
|`lf t55xx bruteforce `|N |`<start password> <end password> Simple bruteforce attack to find password`
|`lf t55xx config `|Y |`Set/Get T55XX configuration (modulation, inverted, offset, rate)`
|`lf t55xx chk `|N |`Check passwords from dictionary/flash`
|`lf t55xx clonehelp `|N |`Shows the available clone commands` |`lf t55xx clonehelp `|N |`Shows the available clone commands`
|`lf t55xx config `|Y |`Set/Get T55XX configuration (modulation, inverted, offset, rate)`
|`lf t55xx dangerraw `|N |`Sends raw bitstream. Dangerous, do not use!! b <bitstream> t <timing>` |`lf t55xx dangerraw `|N |`Sends raw bitstream. Dangerous, do not use!! b <bitstream> t <timing>`
|`lf t55xx detect `|Y |`[1] Try detecting the tag modulation from reading the configuration block.` |`lf t55xx detect `|Y |`[1] Try detecting the tag modulation from reading the configuration block.`
|`lf t55xx deviceconfig `|N |`Set/Get T55XX device configuration (startgap, writegap, write0, write1, readgap` |`lf t55xx deviceconfig `|N |`Set/Get T55XX device configuration (startgap, writegap, write0, write1, readgap`
|`lf t55xx dump `|N |`[password] [o] Dump T55xx card Page 0 block 0-7. Optional [password], [override]` |`lf t55xx dump `|N |`[password] [o] Dump T55xx card Page 0 block 0-7. Optional [password], [override]`
|`lf t55xx restore `|N |`f <filename> [p <password>] Restore T55xx card Page 0 / Page 1 blocks`
|`lf t55xx info `|Y |`[1] Show T55x7 configuration data (page 0/ blk 0)` |`lf t55xx info `|Y |`[1] Show T55x7 configuration data (page 0/ blk 0)`
|`lf t55xx p1detect `|N |`[1] Try detecting if this is a t55xx tag by reading page 1` |`lf t55xx p1detect `|N |`[1] Try detecting if this is a t55xx tag by reading page 1`
|`lf t55xx protect `|N |`Password protect tag`
|`lf t55xx read `|N |`b <block> p [password] [o] [1] -- Read T55xx block data. Optional [p password], [override], [page1]` |`lf t55xx read `|N |`b <block> p [password] [o] [1] -- Read T55xx block data. Optional [p password], [override], [page1]`
|`lf t55xx resetread `|N |`Send Reset Cmd then lf read the stream to attempt to identify the start of it (needs a demod and/or plot after)` |`lf t55xx resetread `|N |`Send Reset Cmd then lf read the stream to attempt to identify the start of it (needs a demod and/or plot after)`
|`lf t55xx recoverpw `|N |`[password] Try to recover from bad password write from a cloner. Only use on PW protected chips!` |`lf t55xx restore `|N |`f <filename> [p <password>] Restore T55xx card Page 0 / Page 1 blocks`
|`lf t55xx sniff `|N |`Attempt to recover T55xx commands from sample buffer`
|`lf t55xx special `|N |`Show block changes with 64 different offsets`
|`lf t55xx trace `|Y |`[1] Show T55x7 traceability data (page 1/ blk 0-1)` |`lf t55xx trace `|Y |`[1] Show T55x7 traceability data (page 1/ blk 0-1)`
|`lf t55xx wakeup `|N |`Send AOR wakeup command` |`lf t55xx wakeup `|N |`Send AOR wakeup command`
|`lf t55xx wipe `|N |`[q] Wipe a T55xx tag and set defaults (will destroy any data on tag)`
|`lf t55xx write `|N |`b <block> d <data> p [password] [1] -- Write T55xx block data. Optional [p password], [page1]` |`lf t55xx write `|N |`b <block> d <data> p [password] [1] -- Write T55xx block data. Optional [p password], [page1]`
|`lf t55xx bruteforce `|N |`<start password> <end password> Simple bruteforce attack to find password`
|`lf t55xx chk `|N |`Check passwords from dictionary/flash`
|`lf t55xx protect `|N |`Password protect tag`
|`lf t55xx recoverpw `|N |`[password] Try to recover from bad password write from a cloner. Only use on PW protected chips!`
|`lf t55xx sniff `|Y |`Attempt to recover T55xx commands from sample buffer`
|`lf t55xx special `|N |`Show block changes with 64 different offsets`
|`lf t55xx wipe `|N |`[q] Wipe a T55xx tag and set defaults (will destroy any data on tag)`
### lf viking ### lf viking
@ -807,7 +901,7 @@ Check column "offline" for their availability.
|`lf viking help `|Y |`This help` |`lf viking help `|Y |`This help`
|`lf viking demod `|Y |`Demodulate a Viking tag from the GraphBuffer` |`lf viking demod `|Y |`Demodulate a Viking tag from the GraphBuffer`
|`lf viking read `|N |`Attempt to read and Extract tag data from the antenna` |`lf viking read `|N |`Attempt to read and Extract tag data from the antenna`
|`lf viking clone `|N |`clone Viking tag to T55x7 (or to q5/T5555)` |`lf viking clone `|N |`clone Viking tag to T55x7 or Q5/T5555`
|`lf viking sim `|N |`simulate Viking tag` |`lf viking sim `|N |`simulate Viking tag`
@ -820,7 +914,7 @@ Check column "offline" for their availability.
|`lf visa2000 help `|Y |`This help` |`lf visa2000 help `|Y |`This help`
|`lf visa2000 demod `|Y |`demodulate an VISA2000 tag from the GraphBuffer` |`lf visa2000 demod `|Y |`demodulate an VISA2000 tag from the GraphBuffer`
|`lf visa2000 read `|N |`attempt to read and extract tag data from the antenna` |`lf visa2000 read `|N |`attempt to read and extract tag data from the antenna`
|`lf visa2000 clone `|N |`clone Visa2000 tag to T55x7 (or to q5/T5555)` |`lf visa2000 clone `|N |`clone Visa2000 tag to T55x7 or Q5/T5555`
|`lf visa2000 sim `|N |`simulate Visa2000 tag` |`lf visa2000 sim `|N |`simulate Visa2000 tag`
@ -831,19 +925,21 @@ Check column "offline" for their availability.
|command |offline |description |command |offline |description
|------- |------- |----------- |------- |------- |-----------
|`mem help `|Y |`This help` |`mem help `|Y |`This help`
|`mem spiffs `|N |`High level SPI FileSystem Flash manipulation [rdv40]` |`mem baudrate `|N |`Set Flash memory Spi baudrate`
|`mem spibaud `|N |`Set Flash memory Spi baudrate [rdv40]` |`mem spiffs `|N |`High level SPI FileSystem Flash manipulation`
|`mem info `|N |`Flash memory information [rdv40]` |`mem info `|N |`Flash memory information`
|`mem load `|N |`Load data into flash memory [rdv40]` |`mem load `|N |`Load data into flash memory`
|`mem dump `|N |`Dump data from flash memory [rdv40]` |`mem dump `|N |`Dump data from flash memory`
|`mem wipe `|N |`Wipe data from flash memory [rdv40]` |`mem wipe `|N |`Wipe data from flash memory`
### reveng ### reveng
{ CRC calculations from RevEng software } { CRC calculations from RevEng software }
### sc [=] reveng: no mode switch specified. Use reveng -h for help.
### smart
{ Smart card ISO-7816 commands... } { Smart card ISO-7816 commands... }
@ -865,9 +961,9 @@ Check column "offline" for their availability.
|command |offline |description |command |offline |description
|------- |------- |----------- |------- |------- |-----------
|`script help `|Y |`This help` |`script help `|Y |`Usage info`
|`script list `|Y |`List available scripts` |`script list `|Y |`List available scripts`
|`script run `|Y |`<name> -- Execute a script` |`script run `|Y |`<name> -- execute a script`
### trace ### trace
@ -907,7 +1003,7 @@ Check column "offline" for their availability.
|------- |------- |----------- |------- |------- |-----------
|`wiegand help `|Y |`This help` |`wiegand help `|Y |`This help`
|`wiegand list `|Y |`List available wiegand formats` |`wiegand list `|Y |`List available wiegand formats`
|`wiegand encode `|Y |`Convert ` |`wiegand encode `|Y |`Encode to wiegand raw hex`
|`wiegand decode `|Y |`Convert raw hex to wiegand format` |`wiegand decode `|Y |`Convert raw hex to decoded wiegand format`

BIN
doc/datasheets/hc06.pdf Normal file

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show more