diff --git a/.lsan_suppressions b/.lsan_suppressions new file mode 100644 index 000000000..6ac2d14a1 --- /dev/null +++ b/.lsan_suppressions @@ -0,0 +1 @@ +leak:libfontconfig.so diff --git a/Makefile b/Makefile index 1f3b0b44b..4634a8b54 100644 --- a/Makefile +++ b/Makefile @@ -248,7 +248,7 @@ print-%: ; @echo $* = $($*) style: # Make sure astyle is installed @which astyle >/dev/null || ( echo "Please install 'astyle' package first" ; exit 1 ) - # Remove spaces & tabs at EOL, add LF at EOF if needed on *.c, *.h, *.cpp. *.lua, *.py, *.pl, Makefile + # Remove spaces & tabs at EOL, add LF at EOF if needed on *.c, *.h, *.cpp. *.lua, *.py, *.pl, Makefile, *.v find . \( -not -path "./cov-int/*" -and -not -path "./fpga/xst/*" -and \( -name "*.[ch]" -or \( -name "*.cpp" -and -not -name "*.moc.cpp" \) -or -name "*.lua" -or -name "*.py" -or -name "*.pl" -or -name "Makefile" -or -name "*.v" \) \) \ -exec perl -pi -e 's/[ \t]+$$//' {} \; \ -exec sh -c "tail -c1 {} | xxd -p | tail -1 | grep -q -v 0a$$" \; \ @@ -259,23 +259,32 @@ style: --keep-one-line-blocks --max-instatement-indent=60 \ --style=google --pad-oper --unpad-paren --pad-header \ --align-pointer=name {} \; + # Update commands.md + [ -x client/proxmark3 ] && client/proxmark3 -m > doc/commands.md # Detecting weird codepages and tabs. +ifeq ($(platform),Darwin) +miscchecks: TABSCMD=egrep -l '\t' {} +else +miscchecks: TABSCMD=grep -lP '\t' {} +endif +ifneq (,$(EDIT)) +miscchecks: TABSCMD+= && vi {} -c ':set tabstop=4' -c ':set et|retab' -c ':wq' +endif miscchecks: - # Make sure recode is installed +# Make sure recode is installed @which recode >/dev/null || ( echo "Please install 'recode' package first" ; exit 1 ) @echo "Files with suspicious chars:" - @find . \( -name "*.[ch]" -or -name "*.cpp" -or -name "*.lua" -or -name "*.py" -or -name "*.pl" -or -name "Makefile" -or -name "*.v" \) \ + @find . \( -not -path "./cov-int/*" -and -not -path "./client/deps/*" -and \( -name "*.[ch]" -or -name "*.cpp" -or -name "*.lua" -or -name "*.py" -or -name "*.pl" -or -name "Makefile" -or -name "*.v" \) \) \ -exec sh -c "cat {} |recode utf8.. >/dev/null || echo {}" \; - @echo "Files with tabs:" -# to remove tabs within lines, one can try with: vi $file -c ':set tabstop=4' -c ':set et|retab' -c ':wq' -ifeq ($(platform),Darwin) - @find . \( -name "*.[ch]" -or \( -name "*.cpp" -and -not -name "*.moc.cpp" \) -or -name "*.lua" -or -name "*.py" -or -name "*.pl" -or -name "*.md" -or -name "*.txt" -or -name "*.awk" -or -name "*.v" \) \ - -exec egrep -l '\t' {} \; +ifneq (,$(EDIT)) + @echo "Files with tabs: (EDIT enabled, files will be rewritten!)" else - @find . \( -name "*.[ch]" -or \( -name "*.cpp" -and -not -name "*.moc.cpp" \) -or -name "*.lua" -or -name "*.py" -or -name "*.pl" -or -name "*.md" -or -name "*.txt" -or -name "*.awk" -or -name "*.v" \) \ - -exec grep -lP '\t' {} \; + @echo "Files with tabs: (rerun with EDIT=1 if you want to convert them with vim)" endif +# to remove tabs within lines, one can try with: vi $file -c ':set tabstop=4' -c ':set et|retab' -c ':wq' + @find . \( -not -path "./cov-int/*" -and -not -path "./client/deps/*" -and \( -name "*.[ch]" -or \( -name "*.cpp" -and -not -name "*.moc.cpp" \) -or -name "*.lua" -or -name "*.py" -or -name "*.pl" -or -name "*.md" -or -name "*.txt" -or -name "*.awk" -or -name "*.v" \) \) \ + -exec sh -c "$(TABSCMD)" \; # @echo "Files with printf \\\\t:" # @find . \( -name "*.[ch]" -or \( -name "*.cpp" -and -not -name "*.moc.cpp" \) -or -name "*.lua" -or -name "*.py" -or -name "*.pl" -or -name "*.md" -or -name "*.txt" -or -name "*.awk" -or -name "*.v" \) \ # -exec grep -lP '\\t' {} \; diff --git a/Makefile.defs b/Makefile.defs index 1c702930a..06eb2e36f 100644 --- a/Makefile.defs +++ b/Makefile.defs @@ -50,6 +50,13 @@ endif DEFCXXFLAGS = -Wall -Werror -O3 -pipe DEFCFLAGS = -Wall -Werror -O3 -fstrict-aliasing -pipe +DEFLDFLAGS = +# Next ones are activated only if SANITIZE=1 +ifeq ($(SANITIZE),1) + DEFCFLAGS += -g -fsanitize=address -fno-omit-frame-pointer + DEFCXXFLAGS += -g -fsanitize=address -fno-omit-frame-pointer + DEFLDFLAGS += -g -fsanitize=address +endif # Some more warnings we want as errors: DEFCFLAGS += -Wbad-function-cast -Wredundant-decls -Wmissing-prototypes -Wchar-subscripts -Wshadow -Wundef -Wwrite-strings -Wunused -Wuninitialized -Wpointer-arith -Winline -Wformat -Wformat-security -Winit-self -Wmissing-include-dirs -Wnested-externs -Wmissing-declarations -Wempty-body -Wignored-qualifiers -Wmissing-field-initializers -Wtype-limits -Wold-style-definition # Some more warnings we need first to eliminate, so temporarely tolerated: diff --git a/Makefile.host b/Makefile.host index e374a9294..694ab5a1c 100644 --- a/Makefile.host +++ b/Makefile.host @@ -19,6 +19,7 @@ CFLAGS ?= $(DEFCFLAGS) CFLAGS += $(MYDEFS) $(MYCFLAGS) $(MYINCLUDES) CXXFLAGS ?= $(DEFCXXFLAGS) CXXFLAGS += $(MYDEFS) $(MYCXXFLAGS) $(MYINCLUDES) +LDFLAGS ?= $(DEFLDFLAGS) LDFLAGS += $(MYLDFLAGS) LDLIBS += $(MYLDLIBS) diff --git a/README.md b/README.md index 8fb77dc14..330faaef6 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ | ------------------- |:-------------------:| -------------------:| |[Notes on UART](/doc/uart_notes.md)|[Notes on Termux / Android](/doc/termux_notes.md)|[Notes on paths](/doc/path_notes.md)| |[Notes on frame format](/doc/new_frame_format.md)|[Notes on tracelog / wireshark](/doc/trace_notes.md)|[Notes on EMV](/doc/emv_notes.md)| -|[Notes on external flash](/doc/ext_flash_notes.md)|[Notes on loclass](/doc/loclass_notes.md)|[Notes on Coverity Scan Config & Run](/doc/md/Development/Coverity-Scan-Config-%26-Run.md)| +|[Notes on external flash](/doc/ext_flash_notes.md)|[Notes on loclass](/doc/loclass_notes.md)|[Notes on Coverity Scan Config & Run](/doc/md/Development/Coverity-Scan-Config-and-Run.md)| |[Notes on file formats used with Proxmark3](/doc/extensions_notes.md)|[Notes on MFU binary format](/doc/mfu_binary_format_notes.md)|[Notes on FPGA & ARM](/doc/fpga_arm_notes.md)| |[Developing standalone mode](/armsrc/Standalone/readme.md)|[Wiki about standalone mode](https://github.com/RfidResearchGroup/proxmark3/wiki/Standalone-mode)|[Notes on Magic cards](/doc/magic_cards_notes.md)| |[Notes on Color usage](/doc/colors_notes.md)|[Makefile vs CMake](/doc/md/Development/Makefile-vs-CMake.md)|[Notes on Cloner guns](/doc/cloner_notes.md)| @@ -57,7 +57,7 @@ On the software side: quite a lot, see the [Changelog file](CHANGELOG.md). This repo compiles nicely on - Proxspace v3.x - - [latest release v3.6](https://github.com/Gator96100/ProxSpace/releases) + - [latest release v3.7](https://github.com/Gator96100/ProxSpace/releases) - Windows/mingw environment with Qt5.6.1 & GCC 4.9 - Ubuntu 16.04 -> 20.04 - ParrotOS, Gentoo, Pentoo, Kali, Nethunter, Archlinux, Fedora, Debian diff --git a/appveyor.yml b/appveyor.yml index 8586bb48a..44e6b6040 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -2,14 +2,14 @@ version: 3.0.1.{build} image: Visual Studio 2019 clone_folder: C:\ProxSpace\pm3\proxmark cache: - - C:\cache -> appveyor.yml + - C:\ps-cache -> appveyor.yml environment: proxspace_url: https://github.com/Gator96100/ProxSpace/archive/master.zip proxspace_zip_file: \proxspace.zip proxspace_zip_folder_name: ProxSpace-* proxspace_path: C:\ProxSpace proxspace_home_path: \ProxSpace\pm3 - proxspace_cache_path: C:\cache + proxspace_cache_path: C:\ps-cache wsl_git_path: C:\proxmark APPVEYOR_SAVE_CACHE_ON_ERROR: true @@ -29,7 +29,6 @@ init: $releasename+=$env:APPVEYOR_BUILD_VERSION + " [" + $env:APPVEYOR_REPO_COMMIT_SHORT + "]" - Write-Host "repository: $env:appveyor_repo_name branch:$env:APPVEYOR_REPO_BRANCH release: $releasename" -ForegroundColor Yellow Add-AppveyorMessage -Message "[$env:APPVEYOR_REPO_COMMIT_SHORT]$env:appveyor_repo_name($env:APPVEYOR_REPO_BRANCH)" -Category Information -Details "repository: $env:appveyor_repo_name branch: $env:APPVEYOR_REPO_BRANCH release: $releasename" @@ -68,6 +67,7 @@ clone_script: WSLExec "WSL install..." "sudo apt-get -y install --reinstall --no-install-recommends git ca-certificates build-essential pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev libbz2-dev qtbase5-dev cmake 1>/dev/null" WSLExec "WSL QT fix..." "sudo strip --remove-section=.note.ABI-tag /usr/lib/x86_64-linux-gnu/libQt5Core.so.5" Add-AppveyorMessage -Message "WSL setup took $(([System.Environment]::TickCount-$WSLInstallTime) / 1000) sec" -Category Information + New-Item -ItemType "file" -Path "C:\WSL-Finished.txt" -Force | Out-Null } $env:PSInstallTime=[System.Environment]::TickCount @@ -154,8 +154,9 @@ install: } Start-Sleep -s 5 - Receive-Job -Name WSLInstall + Receive-Job -Name WSLInstall -ErrorAction SilentlyContinue } + #Receive-Job -Wait -Name PSInstall } Function GitClone($Text, $Folder) { @@ -175,7 +176,9 @@ install: Write-Host "ProxSpace: move cache..." -NoNewLine - Move-Item -Path "$env:proxspace_cache_path" -Destination "$env:proxspace_path\msys2\var\cache" -Force -ErrorAction SilentlyContinue + New-Item -ItemType Directory -Force -Path "$env:proxspace_path\msys2\var\cache\" | Out-Null + + Copy-Item -Path "$env:proxspace_cache_path\*" -Destination "$env:proxspace_path\msys2\var\cache\" -Force -Recurse -ErrorAction SilentlyContinue Write-Host "[ OK ]" -ForegroundColor Gree @@ -212,6 +215,7 @@ build_script: $WSLjob = Start-Job -Name WSLCompile -ScriptBlock { Function ExecWSLCmd($Cmd) { + cd $env:wsl_git_path wsl -- bash -c $Cmd } @@ -231,11 +235,17 @@ build_script: } #WSL: wait for installation to finish - Receive-Job -Wait -Name WSLInstall + if(!(Test-Path "C:\WSL-Finished.txt")){ + Write-Host "Waiting for WSL installation to finish..." -NoNewLine + while(!(Test-Path "C:\WSL-Finished.txt")) { + Start-Sleep -s 5 + } + Remove-Item -Force "C:\WSL-Finished.txt" -ErrorAction SilentlyContinue + Write-Host "$Name [ OK ]" -ForegroundColor Green + } #Windows Subsystem for Linux (WSL) Write-Host "---------- WSL make ----------" -ForegroundColor Yellow - cd $env:wsl_git_path $TestTime=[System.Environment]::TickCount ExecWSLCmd "make clean;make V=1" #some checks @@ -266,7 +276,9 @@ build_script: Write-Host "ProxSpace: create new cache..." -NoNewLine - ExecMinGWCmd 'yes | pacman -Sc > /dev/null 2>&1' + cd $env:proxspace_path + + ./runme64.bat -c "yes | pacman -Sc > /dev/null 2>&1" Remove-Item -Recurse -Force -Path "$env:proxspace_cache_path" -ErrorAction SilentlyContinue @@ -316,8 +328,9 @@ build_script: ExecCheck "PS cmake Tests" + Receive-Job -Wait -Name WSLInstall -ErrorAction SilentlyContinue + Receive-Job -Wait -Job $WSLjob - test_script: - ps: >- @@ -332,4 +345,4 @@ on_success: on_failure: - ps: Write-Host "Build error." -ForegroundColor Red on_finish: -- ps: # $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) +- ps: # $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) \ No newline at end of file diff --git a/armsrc/Standalone/hf_aveful.c b/armsrc/Standalone/hf_aveful.c index 9a56be82c..97ef78745 100644 --- a/armsrc/Standalone/hf_aveful.c +++ b/armsrc/Standalone/hf_aveful.c @@ -147,14 +147,18 @@ void RunMod(void) { int state = STATE_SEARCH; DbpString("Scanning..."); + int button_pressed = BUTTON_NO_CLICK; for (;;) { // Was our button held down or pressed? - int button_pressed = BUTTON_HELD(1000); + button_pressed = BUTTON_HELD(1000); if (button_pressed != BUTTON_NO_CLICK || data_available()) break; else if (state == STATE_SEARCH) { if (!iso14443a_select_card(NULL, &card, NULL, true, 0, true)) { + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_D_OFF(); + SpinDelay(500); continue; } else { if (card.sak == SAK && card.atqa[0] == ATQA0 && card.atqa[1] == ATQA1 && card.uidlen == 7) { @@ -245,6 +249,8 @@ void RunMod(void) { state = STATE_SEARCH; } } + if (button_pressed == BUTTON_HOLD) //Holding down the button + break; } DbpString("exiting"); diff --git a/armsrc/Standalone/hf_colin.c b/armsrc/Standalone/hf_colin.c index 8e20ae414..e3115ee7a 100644 --- a/armsrc/Standalone/hf_colin.c +++ b/armsrc/Standalone/hf_colin.c @@ -484,22 +484,18 @@ failtag: iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); SpinOff(50); LED_A_ON(); - uint8_t ticker = 0; while (!iso14443a_select_card(cjuid, &p_card, &cjcuid, true, 0, true)) { WDT_HIT(); - - ticker++; - if (ticker % 64 == 0) { - LED_A_INV(); - } - if (BUTTON_HELD(10) == BUTTON_HOLD) { WDT_HIT(); DbprintfEx(FLAG_NEWLINE, "\t\t\t[ READING FLASH ]"); ReadLastTagFromFlash(); goto readysim; } + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + SpinDelay(500); + LED_A_INV(); } SpinOff(50); diff --git a/armsrc/Standalone/hf_iceclass.c b/armsrc/Standalone/hf_iceclass.c index 2a0ef6236..00de115e6 100644 --- a/armsrc/Standalone/hf_iceclass.c +++ b/armsrc/Standalone/hf_iceclass.c @@ -125,7 +125,7 @@ static void download_instructions(uint8_t t) { case ICE_STATE_FULLSIM: { DbpString("The emulator memory was saved to SPIFFS"); DbpString("1. " _YELLOW_("mem spiffs dump o " HF_ICLASS_FULLSIM_MOD_BIN " f " HF_ICLASS_FULLSIM_MOD" e")); - DbpString("2. " _YELLOW_("hf iclass view f " HF_ICLASS_FULLSIM_MOD_BIN)); + DbpString("2. " _YELLOW_("hf iclass view -f " HF_ICLASS_FULLSIM_MOD_BIN)); break; } case ICE_STATE_ATTACK: { diff --git a/armsrc/Standalone/hf_mattyrun.c b/armsrc/Standalone/hf_mattyrun.c index c0d603fbd..e14e89789 100644 --- a/armsrc/Standalone/hf_mattyrun.c +++ b/armsrc/Standalone/hf_mattyrun.c @@ -575,4 +575,5 @@ void RunMod(void) { } } } + LEDsoff(); } diff --git a/armsrc/Standalone/hf_msdsal.c b/armsrc/Standalone/hf_msdsal.c index f97dc0d7c..b5585c188 100644 --- a/armsrc/Standalone/hf_msdsal.c +++ b/armsrc/Standalone/hf_msdsal.c @@ -305,6 +305,8 @@ void RunMod(void) { DbpString("\n"_YELLOW_("!!") "Waiting for a card reader..."); } } + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_D_OFF(); } else if (state == STATE_EMU) { LED_A_OFF(); LED_C_ON(); diff --git a/armsrc/Standalone/hf_young.c b/armsrc/Standalone/hf_young.c index a1b32dfab..1673b8975 100644 --- a/armsrc/Standalone/hf_young.c +++ b/armsrc/Standalone/hf_young.c @@ -54,7 +54,7 @@ void RunMod(void) { for (;;) { WDT_HIT(); // exit from Standalone Mode, send a usbcommand. - if (data_available()) return; + if (data_available()) break; SpinDelay(300); @@ -72,7 +72,7 @@ void RunMod(void) { for (;;) { // exit from Standalone Mode, send a usbcommand. - if (data_available()) return; + if (data_available()) break; if (BUTTON_PRESS()) { if (cardRead[selected]) { @@ -89,6 +89,9 @@ void RunMod(void) { } if (!iso14443a_select_card(NULL, &card[selected], NULL, true, 0, true)) { + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LED_D_OFF(); + SpinDelay(500); continue; } else { Dbprintf("Read UID:"); @@ -220,7 +223,7 @@ void RunMod(void) { DbpString("Playing"); for (; ;) { // exit from Standalone Mode, send a usbcommand. - if (data_available()) return; + if (data_available()) break; int button_pressed = BUTTON_HELD(1000); if (button_pressed == BUTTON_NO_CLICK) { // No button action, proceed with sim @@ -277,4 +280,6 @@ void RunMod(void) { LED(selected + 1, 0); } } + DbpString(_YELLOW_("[=]") "exiting"); + LEDsoff(); } diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 2c6ace8ee..d4b5faf27 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -68,6 +68,24 @@ extern uint32_t _stack_start, _stack_end; struct common_area common_area __attribute__((section(".commonarea"))); static int button_status = BUTTON_NO_CLICK; static bool allow_send_wtx = false; +static uint16_t tearoff_delay_us = 0; +static bool tearoff_enabled = false; + +int tearoff_hook(void) { + if (tearoff_enabled) { + if (tearoff_delay_us == 0) { + Dbprintf(_RED_("No tear-off delay configured!")); + return PM3_SUCCESS; // SUCCESS = the hook didn't do anything + } + SpinDelayUsPrecision(tearoff_delay_us); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + tearoff_enabled = false; + Dbprintf(_YELLOW_("Tear-off triggered!")); + return PM3_ETEAROFF; + } else { + return PM3_SUCCESS; // SUCCESS = the hook didn't do anything + } +} void send_wtx(uint16_t wtx) { if (allow_send_wtx) { @@ -731,6 +749,24 @@ static void PacketReceived(PacketCommandNG *packet) { reply_ng(CMD_SET_DBGMODE, PM3_SUCCESS, NULL, 0); break; } + case CMD_SET_TEAROFF: { + struct p { + uint16_t delay_us; + bool on; + bool off; + } PACKED; + struct p *payload = (struct p *)packet->data.asBytes; + if (payload->on && payload->off) + reply_ng(CMD_SET_TEAROFF, PM3_EINVARG, NULL, 0); + if (payload->on) + tearoff_enabled = true; + if (payload->off) + tearoff_enabled = false; + if (payload->delay_us > 0) + tearoff_delay_us = payload->delay_us; + reply_ng(CMD_SET_TEAROFF, PM3_SUCCESS, NULL, 0); + break; + } // always available case CMD_HF_DROPFIELD: { hf_field_off(); @@ -827,7 +863,8 @@ static void PacketReceived(PacketCommandNG *packet) { break; } case CMD_LF_HID_CLONE: { - CopyHIDtoT55x7(packet->oldarg[0], packet->oldarg[1], packet->oldarg[2], packet->data.asBytes[0]); + lf_hidsim_t *payload = (lf_hidsim_t *)packet->data.asBytes; + CopyHIDtoT55x7(payload->hi2, payload->hi, payload->lo, payload->longFMT); break; } case CMD_LF_IO_WATCH: { @@ -954,6 +991,16 @@ static void PacketReceived(PacketCommandNG *packet) { EM4xWriteWord(payload->address, payload->data, payload->password, payload->usepwd); break; } + case CMD_LF_EM4X_PROTECTWORD: { + struct p { + uint32_t password; + uint32_t data; + uint8_t usepwd; + } PACKED; + struct p *payload = (struct p *) packet->data.asBytes; + EM4xProtectWord(payload->data, payload->password, payload->usepwd); + break; + } case CMD_LF_AWID_WATCH: { uint32_t high, low; int res = lf_awid_watch(0, &high, &low); diff --git a/armsrc/appmain.h b/armsrc/appmain.h index 594723983..092e88d0e 100644 --- a/armsrc/appmain.h +++ b/armsrc/appmain.h @@ -16,6 +16,8 @@ extern int g_rsamples; // = 0; extern uint8_t g_trigger; +int tearoff_hook(void); + // ADC Vref = 3300mV, and an (10M+1M):1M voltage divider on the HF input can measure voltages up to 36300 mV #define MAX_ADC_HF_VOLTAGE 36300 // ADC Vref = 3300mV, (240k-10M):240k voltage divider, 140800 mV diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 6cd7c9525..ec5d11d00 100644 --- a/armsrc/iso14443a.c +++ b/armsrc/iso14443a.c @@ -134,11 +134,36 @@ static hf14a_config hf14aconfig = { 0, 0, 0, 0, 0 } ; void printHf14aConfig(void) { DbpString(_CYAN_("HF 14a config")); - Dbprintf("[a] Anticol override......%i: %s%s%s", hf14aconfig.forceanticol, (hf14aconfig.forceanticol == 0) ? _GREEN_("No") " (follow standard)" : "", (hf14aconfig.forceanticol == 1) ? _RED_("Yes: Always do anticol") : "", (hf14aconfig.forceanticol == 2) ? _RED_("Yes: Always skip anticol") : ""); - Dbprintf("[b] BCC override..........%i: %s%s%s", hf14aconfig.forcebcc, (hf14aconfig.forcebcc == 0) ? _GREEN_("No") " (follow standard)" : "", (hf14aconfig.forcebcc == 1) ? _RED_("Yes: Always do CL2") : "", (hf14aconfig.forcebcc == 2) ? _RED_("Yes: Always use card BCC") : ""); - Dbprintf("[2] CL2 override..........%i: %s%s%s", hf14aconfig.forcecl2, (hf14aconfig.forcecl2 == 0) ? _GREEN_("No") " (follow standard)" : "", (hf14aconfig.forcecl2 == 1) ? _RED_("Yes: Always do CL2") : "", (hf14aconfig.forcecl2 == 2) ? _RED_("Yes: Always skip CL2") : ""); - Dbprintf("[3] CL3 override..........%i: %s%s%s", hf14aconfig.forcecl3, (hf14aconfig.forcecl3 == 0) ? _GREEN_("No") " (follow standard)" : "", (hf14aconfig.forcecl3 == 1) ? _RED_("Yes: Always do CL3") : "", (hf14aconfig.forcecl3 == 2) ? _RED_("Yes: Always skip CL3") : ""); - Dbprintf("[r] RATS override.........%i: %s%s%s", hf14aconfig.forcerats, (hf14aconfig.forcerats == 0) ? _GREEN_("No") " (follow standard)" : "", (hf14aconfig.forcerats == 1) ? _RED_("Yes: Always do RATS") : "", (hf14aconfig.forcerats == 2) ? _RED_("Yes: Always skip RATS") : ""); + Dbprintf(" [a] Anticol override....%i %s%s%s", + hf14aconfig.forceanticol, + (hf14aconfig.forceanticol == 0) ? "( " _GREEN_("No") " ) follow standard " : "", + (hf14aconfig.forceanticol == 1) ? "( " _RED_("Yes") " ) always do anticol" : "", + (hf14aconfig.forceanticol == 2) ? "( " _RED_("Yes") " ) always skip anticol" : "" + ); + Dbprintf(" [b] BCC override........%i %s%s%s", + hf14aconfig.forcebcc, + (hf14aconfig.forcebcc == 0) ? "( " _GREEN_("No") " ) follow standard" : "", + (hf14aconfig.forcebcc == 1) ? "( " _RED_("Yes") " ) always do CL2" : "", + (hf14aconfig.forcebcc == 2) ? "( " _RED_("Yes") " ) always use card BCC" : "" + ); + Dbprintf(" [2] CL2 override........%i %s%s%s", + hf14aconfig.forcecl2, + (hf14aconfig.forcecl2 == 0) ? "( " _GREEN_("No") " ) follow standard" : "", + (hf14aconfig.forcecl2 == 1) ? "( " _RED_("Yes") " ) always do CL2" : "", + (hf14aconfig.forcecl2 == 2) ? "( " _RED_("Yes") " ) always skip CL2" : "" + ); + Dbprintf(" [3] CL3 override........%i %s%s%s", + hf14aconfig.forcecl3, + (hf14aconfig.forcecl3 == 0) ? "( " _GREEN_("No") " ) follow standard" : "", + (hf14aconfig.forcecl3 == 1) ? "( " _RED_("Yes") " ) always do CL3" : "", + (hf14aconfig.forcecl3 == 2) ? "( " _RED_("Yes") " ) always skip CL3" : "" + ); + Dbprintf(" [r] RATS override.......%i %s%s%s", + hf14aconfig.forcerats, + (hf14aconfig.forcerats == 0) ? "( " _GREEN_("No") " q follow standard " : "", + (hf14aconfig.forcerats == 1) ? "( " _RED_("Yes") " ) always do RATS" : "", + (hf14aconfig.forcerats == 2) ? "( " _RED_("Yes") " ) always skip RATS" : "" + ); } /** diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c index f333ac88e..976e13148 100644 --- a/armsrc/iso14443b.c +++ b/armsrc/iso14443b.c @@ -752,26 +752,26 @@ static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) { // The soft decision on the bit uses an estimate of just the // quadrant of the reference angle, not the exact angle. #define MAKE_SOFT_DECISION() { \ - if(Demod.sumI > 0) { \ - v = ci; \ - } else { \ - v = -ci; \ - } \ - if(Demod.sumQ > 0) { \ - v += cq; \ - } else { \ - v -= cq; \ - } \ - } + if(Demod.sumI > 0) { \ + v = ci; \ + } else { \ + v = -ci; \ + } \ + if(Demod.sumQ > 0) { \ + v += cq; \ + } else { \ + v -= cq; \ + } \ + } -#define SUBCARRIER_DETECT_THRESHOLD 8 +#define SUBCARRIER_DETECT_THRESHOLD 8 // Subcarrier amplitude v = sqrt(ci^2 + cq^2), approximated here by max(abs(ci),abs(cq)) + 1/2*min(abs(ci),abs(cq))) #define AMPLITUDE(ci,cq) (MAX(ABS(ci),ABS(cq)) + (MIN(ABS(ci),ABS(cq))/2)) switch (Demod.state) { case DEMOD_UNSYNCD: { - if (AMPLITUDE(ci, cq) > SUBCARRIER_DETECT_THRESHOLD) { // subcarrier detected + if (AMPLITUDE(ci, cq) > SUBCARRIER_DETECT_THRESHOLD) { // subcarrier detected Demod.state = DEMOD_PHASE_REF_TRAINING; Demod.sumI = ci; Demod.sumQ = cq; @@ -783,7 +783,7 @@ static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) { // While we get a constant signal if (AMPLITUDE(ci, cq) > SUBCARRIER_DETECT_THRESHOLD) { if (((ABS(Demod.sumI) > ABS(Demod.sumQ)) && (((ci > 0) && (Demod.sumI > 0)) || ((ci < 0) && (Demod.sumI < 0)))) || // signal closer to horizontal, polarity check based on on I - ((ABS(Demod.sumI) <= ABS(Demod.sumQ)) && (((cq > 0) && (Demod.sumQ > 0)) || ((cq < 0) && (Demod.sumQ < 0))))) { // signal closer to vertical, polarity check based on on Q + ((ABS(Demod.sumI) <= ABS(Demod.sumQ)) && (((cq > 0) && (Demod.sumQ > 0)) || ((cq < 0) && (Demod.sumQ < 0))))) { // signal closer to vertical, polarity check based on on Q if (Demod.posCount < 10) { // refine signal approximation during first 10 samples Demod.sumI += ci; @@ -799,7 +799,7 @@ static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) { } else { // at this point it can be start of 14b' data or start of 14b SOF MAKE_SOFT_DECISION(); - Demod.posCount = 1; // this was the first half + Demod.posCount = 1; // this was the first half Demod.thisBit = v; Demod.shiftReg = 0; Demod.state = DEMOD_RECEIVING_DATA; @@ -815,7 +815,7 @@ static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) { Demod.posCount++; MAKE_SOFT_DECISION(); if (v > 0) { - if (Demod.posCount > 3 * 2) { // max 19us between characters = 16 1/fs, max 3 etu after low phase of SOF = 24 1/fs + if (Demod.posCount > 3 * 2) { // max 19us between characters = 16 1/fs, max 3 etu after low phase of SOF = 24 1/fs LED_C_OFF(); if (Demod.bitCount == 0 && Demod.len == 0) { // received SOF only, this is valid for iClass/Picopass return true; @@ -823,8 +823,8 @@ static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) { Demod.state = DEMOD_UNSYNCD; } } - } else { // start bit detected - Demod.posCount = 1; // this was the first half + } else { // start bit detected + Demod.posCount = 1; // this was the first half Demod.thisBit = v; Demod.shiftReg = 0; Demod.state = DEMOD_RECEIVING_DATA; @@ -857,14 +857,14 @@ static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) { MAKE_SOFT_DECISION(); - if (Demod.posCount == 0) { // first half of bit + if (Demod.posCount == 0) { // first half of bit Demod.thisBit = v; Demod.posCount = 1; - } else { // second half of bit + } else { // second half of bit Demod.thisBit += v; Demod.shiftReg >>= 1; - if (Demod.thisBit > 0) { // logic '1' + if (Demod.thisBit > 0) { // logic '1' Demod.shiftReg |= 0x200; } @@ -927,12 +927,12 @@ static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) { * Demodulate the samples we received from the tag, also log to tracebuffer */ static int Get14443bAnswerFromTag(uint8_t *response, uint16_t max_len, int timeout, uint32_t *eof_time) { - + int samples = 0, ret = 0; // Set up the demodulator for tag -> reader responses. Demod14bInit(response, max_len); - + // Setup and start DMA. //FpgaSetupSsc(FPGA_MAJOR_MODE_HF_READER); @@ -996,7 +996,7 @@ static int Get14443bAnswerFromTag(uint8_t *response, uint16_t max_len, int timeo if (Handle14443bSamplesFromTag(ci, cq)) { - *eof_time = dma_start_time + (samples ) - DELAY_TAG_TO_ARM; // end of EOF + *eof_time = dma_start_time + (samples) - DELAY_TAG_TO_ARM; // end of EOF if (Demod.len > Demod.max_len) { ret = -2; // overflow @@ -1044,7 +1044,7 @@ static void TransmitFor14443b_AsReader(uint32_t *start_time) { if (GetCountSspClk() > *start_time) { // we may miss the intended time *start_time = (GetCountSspClk() + 32) & 0xfffffff0; // next possible time } - + // wait while (GetCountSspClk() < *start_time); @@ -1068,7 +1068,7 @@ static void TransmitFor14443b_AsReader(uint32_t *start_time) { LED_B_OFF(); *start_time += DELAY_ARM_TO_TAG; - + // wait for last transfer to complete while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXEMPTY)) {}; } @@ -1093,7 +1093,7 @@ static void CodeIso14443bAsReader(const uint8_t *cmd, int len) { * * QUESTION: how long is a 1 or 0 in pulses in the xcorr_848 mode? * 1 "stuffbit" = 1ETU (9us) - * + * * TR2 - After the PICC response, the PCD is required to wait the Frame Delay Time (TR2) before transmission of the next command. The minimum frame delay time required for all commands is 14 ETUs @@ -1101,7 +1101,7 @@ static void CodeIso14443bAsReader(const uint8_t *cmd, int len) { */ int i; tosend_reset(); - + // Send SOF // 10-11 ETUs of ZERO for (i = 0; i < 11; i++) { @@ -1185,7 +1185,7 @@ int iso14443b_apdu(uint8_t const *msg, size_t msg_len, bool send_chaining, void real_cmd[0] = 0xA2; // r-block + ACK real_cmd[0] |= iso14b_pcb_blocknum; } - + AddCrc14B(real_cmd, msg_len + 1); // send @@ -1269,7 +1269,7 @@ static int iso14443b_select_cts_card(iso14b_cts_card_select_t *card) { AddCrc14B(cmdLSBUID, 1); uint8_t r[8]; - + uint32_t start_time = 0; uint32_t eof_time = 0; CodeAndTransmit14443bAsReader(cmdINIT, sizeof(cmdINIT), &start_time, &eof_time); @@ -1842,10 +1842,10 @@ void SendRawCommand14443B_Ex(PacketCommandNG *c) { iso14443b_setup(); } - if ((param & ISO14B_SET_TIMEOUT) == ISO14B_SET_TIMEOUT) { + if ((param & ISO14B_SET_TIMEOUT) == ISO14B_SET_TIMEOUT) { iso14b_set_timeout(timeout); } - + if ((param & ISO14B_CLEARTRACE) == ISO14B_CLEARTRACE) { clear_trace(); } @@ -1854,7 +1854,7 @@ void SendRawCommand14443B_Ex(PacketCommandNG *c) { int status; uint32_t sendlen = sizeof(iso14b_card_select_t); iso14b_card_select_t card; - memset((void*)&card, 0x00, sizeof(card)); + memset((void *)&card, 0x00, sizeof(card)); if ((param & ISO14B_SELECT_STD) == ISO14B_SELECT_STD) { status = iso14443b_select_card(&card); @@ -1877,7 +1877,7 @@ void SendRawCommand14443B_Ex(PacketCommandNG *c) { reply_mix(CMD_HF_ISO14443B_COMMAND, status, sendlen, 0, (uint8_t *)&cts, sendlen); // 0: OK 2: demod fail, 3:crc fail, if (status > 0) goto out; - } + } if ((param & ISO14B_APDU) == ISO14B_APDU) { uint8_t res; diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index f3c3494a9..e84edd8a0 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -1883,112 +1883,112 @@ void LockPassSlixIso15693(uint32_t pass_id, uint32_t password) { LED_A_ON(); - uint8_t cmd_inventory[] = {ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_INVENTORY | ISO15693_REQINV_SLOT1, 0x01, 0x00, 0x00, 0x00 }; - uint8_t cmd_get_rnd[] = {ISO15693_REQ_DATARATE_HIGH, 0xB2, 0x04, 0x00, 0x00 }; - uint8_t cmd_set_pass[] = {ISO15693_REQ_DATARATE_HIGH, 0xB3, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - //uint8_t cmd_write_pass[] = {ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_ADDRESS, 0xB4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - uint8_t cmd_lock_pass[] = {ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_ADDRESS, 0xB5, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00 }; - uint16_t crc; - int recvlen = 0; - uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH]; - uint32_t start_time = 0; - bool done = false; + uint8_t cmd_inventory[] = {ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_INVENTORY | ISO15693_REQINV_SLOT1, 0x01, 0x00, 0x00, 0x00 }; + uint8_t cmd_get_rnd[] = {ISO15693_REQ_DATARATE_HIGH, 0xB2, 0x04, 0x00, 0x00 }; + uint8_t cmd_set_pass[] = {ISO15693_REQ_DATARATE_HIGH, 0xB3, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + //uint8_t cmd_write_pass[] = {ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_ADDRESS, 0xB4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + uint8_t cmd_lock_pass[] = {ISO15693_REQ_DATARATE_HIGH | ISO15693_REQ_ADDRESS, 0xB5, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00 }; + uint16_t crc; + int recvlen = 0; + uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH]; + uint32_t start_time = 0; + bool done = false; - // setup 'get random number' command - crc = Iso15693Crc(cmd_get_rnd, 3); - cmd_get_rnd[3] = crc & 0xff; - cmd_get_rnd[4] = crc >> 8; + // setup 'get random number' command + crc = Iso15693Crc(cmd_get_rnd, 3); + cmd_get_rnd[3] = crc & 0xff; + cmd_get_rnd[4] = crc >> 8; - Dbprintf("LockPass: Press button lock password, long-press to terminate."); + Dbprintf("LockPass: Press button lock password, long-press to terminate."); - while (!done) { + while (!done) { - LED_D_ON(); - switch(BUTTON_HELD(1000)) { - case BUTTON_SINGLE_CLICK: - Dbprintf("LockPass: Reset 'DONE'-LED (A)"); - LED_A_OFF(); - LED_B_OFF(); - LED_C_OFF(); - break; - case BUTTON_HOLD: - Dbprintf("LockPass: Terminating"); - done = true; - break; - default: - SpinDelay(50); - continue; - } + LED_D_ON(); + switch(BUTTON_HELD(1000)) { + case BUTTON_SINGLE_CLICK: + Dbprintf("LockPass: Reset 'DONE'-LED (A)"); + LED_A_OFF(); + LED_B_OFF(); + LED_C_OFF(); + break; + case BUTTON_HOLD: + Dbprintf("LockPass: Terminating"); + done = true; + break; + default: + SpinDelay(50); + continue; + } - if (done) [ - break; - } + if (done) [ + break; + } - recvlen = SendDataTag(cmd_get_rnd, sizeof(cmd_get_rnd), true, true, recvbuf, sizeof(recvbuf), start_time); - if (recvlen != 5) { - LED_C_ON(); - } else { - Dbprintf("LockPass: Received random 0x%02X%02X (%d)", recvbuf[1], recvbuf[2], recvlen); + recvlen = SendDataTag(cmd_get_rnd, sizeof(cmd_get_rnd), true, true, recvbuf, sizeof(recvbuf), start_time); + if (recvlen != 5) { + LED_C_ON(); + } else { + Dbprintf("LockPass: Received random 0x%02X%02X (%d)", recvbuf[1], recvbuf[2], recvlen); - // setup 'set password' command - cmd_set_pass[4] = ((password>>0) &0xFF) ^ recvbuf[1]; - cmd_set_pass[5] = ((password>>8) &0xFF) ^ recvbuf[2]; - cmd_set_pass[6] = ((password>>16) &0xFF) ^ recvbuf[1]; - cmd_set_pass[7] = ((password>>24) &0xFF) ^ recvbuf[2]; + // setup 'set password' command + cmd_set_pass[4] = ((password>>0) &0xFF) ^ recvbuf[1]; + cmd_set_pass[5] = ((password>>8) &0xFF) ^ recvbuf[2]; + cmd_set_pass[6] = ((password>>16) &0xFF) ^ recvbuf[1]; + cmd_set_pass[7] = ((password>>24) &0xFF) ^ recvbuf[2]; - crc = Iso15693Crc(cmd_set_pass, 8); - cmd_set_pass[8] = crc & 0xff; - cmd_set_pass[9] = crc >> 8; + crc = Iso15693Crc(cmd_set_pass, 8); + cmd_set_pass[8] = crc & 0xff; + cmd_set_pass[9] = crc >> 8; - Dbprintf("LockPass: Sending old password to end privacy mode", cmd_set_pass[4], cmd_set_pass[5], cmd_set_pass[6], cmd_set_pass[7]); - recvlen = SendDataTag(cmd_set_pass, sizeof(cmd_set_pass), false, true, recvbuf, sizeof(recvbuf), start_time); - if (recvlen != 3) { - Dbprintf("LockPass: Failed to set password (%d)", recvlen); - LED_B_ON(); - } else { - crc = Iso15693Crc(cmd_inventory, 3); - cmd_inventory[3] = crc & 0xff; - cmd_inventory[4] = crc >> 8; + Dbprintf("LockPass: Sending old password to end privacy mode", cmd_set_pass[4], cmd_set_pass[5], cmd_set_pass[6], cmd_set_pass[7]); + recvlen = SendDataTag(cmd_set_pass, sizeof(cmd_set_pass), false, true, recvbuf, sizeof(recvbuf), start_time); + if (recvlen != 3) { + Dbprintf("LockPass: Failed to set password (%d)", recvlen); + LED_B_ON(); + } else { + crc = Iso15693Crc(cmd_inventory, 3); + cmd_inventory[3] = crc & 0xff; + cmd_inventory[4] = crc >> 8; - Dbprintf("LockPass: Searching for tag..."); - recvlen = SendDataTag(cmd_inventory, sizeof(cmd_inventory), false, true, recvbuf, sizeof(recvbuf), start_time); - if (recvlen != 12) { - Dbprintf("LockPass: Failed to read inventory (%d)", recvlen); - LED_B_ON(); - LED_C_ON(); - } else { + Dbprintf("LockPass: Searching for tag..."); + recvlen = SendDataTag(cmd_inventory, sizeof(cmd_inventory), false, true, recvbuf, sizeof(recvbuf), start_time); + if (recvlen != 12) { + Dbprintf("LockPass: Failed to read inventory (%d)", recvlen); + LED_B_ON(); + LED_C_ON(); + } else { - Dbprintf("LockPass: Answer from %02X%02X%02X%02X%02X%02X%02X%02X", recvbuf[9], recvbuf[8], recvbuf[7], recvbuf[6], recvbuf[5], recvbuf[4], recvbuf[3], recvbuf[2]); + Dbprintf("LockPass: Answer from %02X%02X%02X%02X%02X%02X%02X%02X", recvbuf[9], recvbuf[8], recvbuf[7], recvbuf[6], recvbuf[5], recvbuf[4], recvbuf[3], recvbuf[2]); - memcpy(&cmd_lock_pass[3], &recvbuf[2], 8); + memcpy(&cmd_lock_pass[3], &recvbuf[2], 8); - cmd_lock_pass[8+3] = pass_id; + cmd_lock_pass[8+3] = pass_id; - crc = Iso15693Crc(cmd_lock_pass, 8+4); - cmd_lock_pass[8+4] = crc & 0xff; - cmd_lock_pass[8+5] = crc >> 8; + crc = Iso15693Crc(cmd_lock_pass, 8+4); + cmd_lock_pass[8+4] = crc & 0xff; + cmd_lock_pass[8+5] = crc >> 8; - Dbprintf("LockPass: locking to password 0x%02X%02X%02X%02X for ID %02X", cmd_set_pass[4], cmd_set_pass[5], cmd_set_pass[6], cmd_set_pass[7], pass_id); + Dbprintf("LockPass: locking to password 0x%02X%02X%02X%02X for ID %02X", cmd_set_pass[4], cmd_set_pass[5], cmd_set_pass[6], cmd_set_pass[7], pass_id); - recvlen = SendDataTag(cmd_lock_pass, sizeof(cmd_lock_pass), false, true, recvbuf, sizeof(recvbuf), start_time); - if (recvlen != 3) { - Dbprintf("LockPass: Failed to lock password (%d)", recvlen); - } else { - Dbprintf("LockPass: Successful (%d)", recvlen); - } - LED_A_ON(); - } - } } - } + recvlen = SendDataTag(cmd_lock_pass, sizeof(cmd_lock_pass), false, true, recvbuf, sizeof(recvbuf), start_time); + if (recvlen != 3) { + Dbprintf("LockPass: Failed to lock password (%d)", recvlen); + } else { + Dbprintf("LockPass: Successful (%d)", recvlen); + } + LED_A_ON(); + } + } } + } - Dbprintf("LockPass: Finishing"); - FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + Dbprintf("LockPass: Finishing"); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - cmd_send(CMD_ACK, recvlen, 0, 0, recvbuf, recvlen); - LED_A_OFF(); - LED_B_OFF(); - LED_C_OFF(); - LED_D_OFF(); + cmd_send(CMD_ACK, recvlen, 0, 0, recvbuf, recvlen); + LED_A_OFF(); + LED_B_OFF(); + LED_C_OFF(); + LED_D_OFF(); } */ diff --git a/armsrc/lfops.c b/armsrc/lfops.c index b68e54bbc..03e322681 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -2369,6 +2369,7 @@ int copy_em410x_to_t55xx(uint8_t card, uint8_t clock, uint32_t id_hi, uint32_t i #define FWD_CMD_LOGIN 0xC #define FWD_CMD_WRITE 0xA #define FWD_CMD_READ 0x9 +#define FWD_CMD_PROTECT 0x3 #define FWD_CMD_DISABLE 0x5 static uint8_t forwardLink_data[64]; //array of forwarded bits @@ -2572,14 +2573,61 @@ void EM4xWriteWord(uint8_t addr, uint32_t data, uint32_t pwd, uint8_t usepwd) { SendForward(len); - // Wait 20ms for write to complete? - WaitMS(7); + if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured + StopTicks(); + reply_ng(CMD_LF_EM4X_WRITEWORD, PM3_ETEAROFF, NULL, 0); + } else { + // Wait 20ms for write to complete? + // No, when write is denied, err preamble comes much sooner + //WaitUS(10820); // tPC+tWEE - DoPartialAcquisition(20, false, 6000, 1000); + DoPartialAcquisition(0, false, 6000, 1000); - StopTicks(); + StopTicks(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + reply_ng(CMD_LF_EM4X_WRITEWORD, PM3_SUCCESS, NULL, 0); + } + LEDsoff(); +} + +void EM4xProtectWord(uint32_t data, uint32_t pwd, uint8_t usepwd) { + + StartTicks(); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); - reply_ng(CMD_LF_EM4X_WRITEWORD, PM3_SUCCESS, NULL, 0); + WaitMS(50); + + LED_A_ON(); + + // clear buffer now so it does not interfere with timing later + BigBuf_Clear_ext(false); + + /* should we read answer from Logincommand? + * + * should receive + * 0000 1010 ok. + * 0000 0001 fail + **/ + if (usepwd) EM4xLogin(pwd); + + forward_ptr = forwardLink_data; + uint8_t len = Prepare_Cmd(FWD_CMD_PROTECT); + len += Prepare_Data(data & 0xFFFF, data >> 16); + + SendForward(len); + + if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured + StopTicks(); + reply_ng(CMD_LF_EM4X_PROTECTWORD, PM3_ETEAROFF, NULL, 0); + } else { + // Wait 20ms for write to complete? + // No, when write is denied, err preamble comes much sooner + //WaitUS(13640); // tPC+tPR + + DoPartialAcquisition(0, false, 6000, 1000); + StopTicks(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + reply_ng(CMD_LF_EM4X_PROTECTWORD, PM3_SUCCESS, NULL, 0); + } LEDsoff(); } diff --git a/armsrc/lfops.h b/armsrc/lfops.h index 0ac8066af..1c191d65d 100644 --- a/armsrc/lfops.h +++ b/armsrc/lfops.h @@ -58,6 +58,7 @@ void TurnReadLFOn(uint32_t delay); void EM4xReadWord(uint8_t addr, uint32_t pwd, uint8_t usepwd); void EM4xWriteWord(uint8_t addr, uint32_t data, uint32_t pwd, uint8_t usepwd); +void EM4xProtectWord(uint32_t data, uint32_t pwd, uint8_t usepwd); void Cotag(uint32_t arg0); void setT55xxConfig(uint8_t arg0, t55xx_configurations_t *c); diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index 76cbea5c1..8b1bba150 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -2702,25 +2702,24 @@ void MifareU_Otp_Tearoff(uint8_t arg0, uint32_t arg1, uint8_t *datain) { uint8_t data_testwrite[4] = {0x00}; memcpy(data_fullwrite, datain, 4); memcpy(data_testwrite, datain + 4, 4); -// optional authentication before? - if (DBGLEVEL >= DBG_ERROR) DbpString("Preparing OTP tear-off"); + if (DBGLEVEL >= DBG_DEBUG) DbpString("Preparing OTP tear-off"); + + if (tearOffTime > 43000) + tearOffTime = 43000; + + MifareUWriteBlock(blockNo, 0, data_fullwrite); LEDsoff(); iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); clear_trace(); set_tracing(true); - StartTicks(); - // write cmd to send, include CRC // 1b write, 1b block, 4b data, 2 crc uint8_t cmd[] = {MIFARE_ULC_WRITE, blockNo, data_testwrite[0], data_testwrite[1], data_testwrite[2], data_testwrite[3], 0, 0}; - - MifareUWriteBlock(blockNo, 0, data_fullwrite); - AddCrc14A(cmd, sizeof(cmd) - 2); - if (DBGLEVEL >= DBG_ERROR) DbpString("Transmitting"); + // anticollision / select card if (!iso14443a_select_card(NULL, NULL, NULL, true, 0, true)) { if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card"); @@ -2732,11 +2731,10 @@ void MifareU_Otp_Tearoff(uint8_t arg0, uint32_t arg1, uint8_t *datain) { // Wait before cutting power. aka tear-off LED_D_ON(); - WaitUS(tearOffTime); + + SpinDelayUsPrecision(tearOffTime); + if (DBGLEVEL >= DBG_DEBUG) Dbprintf(_YELLOW_("OTP tear-off triggered!")); switch_off(); reply_ng(CMD_HF_MFU_OTP_TEAROFF, PM3_SUCCESS, NULL, 0); - StopTicks(); - - if (DBGLEVEL >= DBG_ERROR) DbpString("Done"); } diff --git a/armsrc/ticks.c b/armsrc/ticks.c index e8ac13f89..9b563cc54 100644 --- a/armsrc/ticks.c +++ b/armsrc/ticks.c @@ -13,6 +13,31 @@ #include "proxmark3_arm.h" #include "dbprint.h" + +// timer counts in 666ns increments (32/48MHz), rounding applies +// WARNING: timer can't measure more than 43ms (666ns * 0xFFFF) +void SpinDelayUsPrecision(int us) { + int ticks = ((MCK / 1000000) * us + 16) >> 5; + + // Borrow a PWM unit for my real-time clock + AT91C_BASE_PWMC->PWMC_ENA = PWM_CHANNEL(0); + + // 48 MHz / 32 gives 1.5 Mhz + AT91C_BASE_PWMC_CH0->PWMC_CMR = PWM_CH_MODE_PRESCALER(5); // Channel Mode Register + AT91C_BASE_PWMC_CH0->PWMC_CDTYR = 0; // Channel Duty Cycle Register + AT91C_BASE_PWMC_CH0->PWMC_CPRDR = 0xFFFF; // Channel Period Register + + uint16_t start = AT91C_BASE_PWMC_CH0->PWMC_CCNTR; + + for (;;) { + uint16_t now = AT91C_BASE_PWMC_CH0->PWMC_CCNTR; + if (now == (uint16_t)(start + ticks)) + return; + + WDT_HIT(); + } +} + // timer counts in 21.3us increments (1024/48MHz), rounding applies // WARNING: timer can't measure more than 1.39s (21.3us * 0xffff) void SpinDelayUs(int us) { diff --git a/armsrc/ticks.h b/armsrc/ticks.h index 9d8d178d5..d26b05bbc 100644 --- a/armsrc/ticks.h +++ b/armsrc/ticks.h @@ -20,6 +20,7 @@ void SpinDelay(int ms); void SpinDelayUs(int us); +void SpinDelayUsPrecision(int us); // precision 0.6us , running for 43ms before void StartTickCount(void); uint32_t RAMFUNC GetTickCount(void); diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index dd4811435..c371ecb29 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -248,7 +248,7 @@ set (TARGET_SOURCES ${PM3_ROOT}/client/src/cmdlfcotag.c ${PM3_ROOT}/client/src/cmdlfem4x.c ${PM3_ROOT}/client/src/cmdlfem4x50.c - ${PM3_ROOT}/client/src/cmdlffdx.c + ${PM3_ROOT}/client/src/cmdlffdxb.c ${PM3_ROOT}/client/src/cmdlfgallagher.c ${PM3_ROOT}/client/src/cmdlfguard.c ${PM3_ROOT}/client/src/cmdlfhid.c diff --git a/client/Makefile b/client/Makefile index 29fb4462e..9fa8565e6 100644 --- a/client/Makefile +++ b/client/Makefile @@ -309,6 +309,7 @@ ifeq ($(QT_FOUND),1) endif endif +LDFLAGS ?= $(DEFLDFLAGS) PM3LDFLAGS = $(LDFLAGS) ifeq ($(platform),Darwin) PM3LDFLAGS += -framework Foundation -framework AppKit @@ -442,7 +443,7 @@ SRCS = aidsearch.c \ cmdlfcotag.c \ cmdlfem4x.c \ cmdlfem4x50.c \ - cmdlffdx.c \ + cmdlffdxb.c \ cmdlfguard.c \ cmdlfgallagher.c \ cmdlfhid.c \ diff --git a/client/android/CMakeLists.txt b/client/android/CMakeLists.txt index 7b7335071..3ab423c3c 100644 --- a/client/android/CMakeLists.txt +++ b/client/android/CMakeLists.txt @@ -127,7 +127,7 @@ add_library(pm3rrg_rdv4 SHARED ${PM3_ROOT}/client/src/cmdlfcotag.c ${PM3_ROOT}/client/src/cmdlfem4x.c ${PM3_ROOT}/client/src/cmdlfem4x50.c - ${PM3_ROOT}/client/src/cmdlffdx.c + ${PM3_ROOT}/client/src/cmdlffdxb.c ${PM3_ROOT}/client/src/cmdlfgallagher.c ${PM3_ROOT}/client/src/cmdlfguard.c ${PM3_ROOT}/client/src/cmdlfhid.c diff --git a/client/deps/cliparser/argtable3.c b/client/deps/cliparser/argtable3.c index c34ee982b..2fe32b082 100644 --- a/client/deps/cliparser/argtable3.c +++ b/client/deps/cliparser/argtable3.c @@ -2231,9 +2231,9 @@ struct arg_int *arg_intn( #include #include static uint64_t strtollu0X(const char *str, - const char * *endptr, - char X, - int base) { + const char * *endptr, + char X, + int base) { uint64_t val; /* stores result */ int s = 1; /* sign is +1 or -1 */ const char *ptr = str; /* ptr to current position in str */ @@ -4529,11 +4529,11 @@ static void arg_cat_optionv(char *dest, } if (datatype) { -/* if (longopts) - arg_cat(&dest, "=", &ndest); - else if (shortopts) - arg_cat(&dest, " ", &ndest); -*/ + /* if (longopts) + arg_cat(&dest, "=", &ndest); + else if (shortopts) + arg_cat(&dest, " ", &ndest); + */ if (longopts) arg_cat(&dest, " ", &ndest); else if (shortopts) diff --git a/client/deps/cliparser/argtable3.h b/client/deps/cliparser/argtable3.h index 2988d013f..55564aa2f 100644 --- a/client/deps/cliparser/argtable3.h +++ b/client/deps/cliparser/argtable3.h @@ -192,19 +192,19 @@ struct arg_int *arg_int1(const char *shortopts, const char *longopts, const char struct arg_int *arg_intn(const char *shortopts, const char *longopts, const char *datatype, int mincount, int maxcount, const char *glossary); struct arg_u64 *arg_u64_0(const char *shortopts, - const char *longopts, - const char *datatype, - const char *glossary); + const char *longopts, + const char *datatype, + const char *glossary); struct arg_u64 *arg_u64_1(const char *shortopts, - const char *longopts, - const char *datatype, - const char *glossary); + const char *longopts, + const char *datatype, + const char *glossary); struct arg_u64 *arg_u64_n(const char *shortopts, - const char *longopts, - const char *datatype, - int mincount, - int maxcount, - const char *glossary); + const char *longopts, + const char *datatype, + int mincount, + int maxcount, + const char *glossary); struct arg_dbl *arg_dbl0(const char *shortopts, diff --git a/client/deps/cliparser/cliparser.c b/client/deps/cliparser/cliparser.c index 8ce757792..cc82fc334 100644 --- a/client/deps/cliparser/cliparser.c +++ b/client/deps/cliparser/cliparser.c @@ -70,7 +70,7 @@ int CLIParserParseArg(CLIParserContext *ctx, int argc, char **argv, void *vargta PrintAndLogEx(NORMAL, "\n"_SectionTagColor_("usage:")); PrintAndLogEx(NORMAL, " "_CommandColor_("%s")NOLF, ctx->programName); arg_print_syntax(stdout, ctx->argtable, "\n\n"); - + PrintAndLogEx(NORMAL, _SectionTagColor_("options:")); arg_print_glossary(stdout, ctx->argtable, " "_ArgColor_("%-30s")" "_ArgHelpColor_("%s")"\n"); diff --git a/client/deps/hardnested/hardnested_bruteforce.c b/client/deps/hardnested/hardnested_bruteforce.c index 82f8c6c04..0c768f400 100644 --- a/client/deps/hardnested/hardnested_bruteforce.c +++ b/client/deps/hardnested/hardnested_bruteforce.c @@ -174,7 +174,7 @@ crack_states_thread(void *x) { char progress_text[80]; char keystr[19]; sprintf(keystr, "%012" PRIx64 " ", key); - sprintf(progress_text, "Brute force phase completed. Key found: " _YELLOW_("%s"), keystr); + sprintf(progress_text, "Brute force phase completed. Key found: " _YELLOW_("%s"), keystr); hardnested_print_progress(thread_arg->num_acquired_nonces, progress_text, 0.0, 0); break; } else if (keys_found) { diff --git a/client/deps/jansson/pack_unpack.c b/client/deps/jansson/pack_unpack.c index 279499ebd..fbe0d44ef 100644 --- a/client/deps/jansson/pack_unpack.c +++ b/client/deps/jansson/pack_unpack.c @@ -740,8 +740,12 @@ static int unpack(scanner_t *s, json_t *root, va_list *ap) { case 'b': if (root && !json_is_boolean(root)) { - set_error(s, "", json_error_wrong_type, "Expected true or false, got %s", - type_name(root)); + set_error(s, + "", + json_error_wrong_type, + "Expected true or false, got %s", + type_name(root) + ); return -1; } diff --git a/client/deps/reveng/cli.c b/client/deps/reveng/cli.c index 88e8d3722..5d5d91a18 100644 --- a/client/deps/reveng/cli.c +++ b/client/deps/reveng/cli.c @@ -167,8 +167,9 @@ int reveng_main(int argc, char *argv[]) { pkchop(&model.spoly); width = plen(model.spoly); rflags |= R_HAVEP; - if (c == 'P') + if (c == 'P') { prcp(&model.spoly); + } mnovel(&model); break; case 'l': /* l little-endian input and output */ @@ -332,6 +333,7 @@ ipqx: mbynum(&model, --args); ufound(&model); } while (args); + mfree(&model); break; case 'd': /* d dump CRC model */ /* maybe we don't want to do this: @@ -387,6 +389,10 @@ ipqx: apolys = calloc(args * sizeof(poly_t), sizeof(char)); if (!apolys) { uerror("cannot allocate memory for argument list"); + pfree(&model.spoly); + pfree(&model.init); + pfree(&model.xorout); + mfree(&model); return 0; } @@ -421,16 +427,20 @@ ipqx: continue; if (rflags & R_HAVEX && psncmp(&model.xorout, &pset.xorout)) continue; + apoly = pclone(pset.xorout); - if (pset.flags & P_REFOUT) + if (pset.flags & P_REFOUT) { prev(&apoly); + } + for (qptr = apolys; qptr < pptr; ++qptr) { crc = pcrc(*qptr, pset.spoly, pset.init, apoly, 0); if (ptst(crc)) { pfree(&crc); break; - } else + } else { pfree(&crc); + } } pfree(&apoly); if (qptr == pptr) { @@ -444,14 +454,19 @@ ipqx: /* toggle refIn/refOut and reflect arguments */ if (~rflags & R_HAVERI) { model.flags ^= P_REFIN | P_REFOUT; - for (qptr = apolys; qptr < pptr; ++qptr) + for (qptr = apolys; qptr < pptr; ++qptr) { prevch(qptr, ibperhx); + } } } while (~rflags & R_HAVERI && ++pass < 2); } + if (uflags & C_RESULT) { - for (qptr = apolys; qptr < pptr; ++qptr) + for (qptr = apolys; qptr < pptr; ++qptr) { pfree(qptr); + } + free(apolys); + mfree(&model); return 1; //exit(EXIT_SUCCESS); } @@ -467,8 +482,10 @@ ipqx: pass = 0; do { mptr = candmods = reveng(&model, qpoly, rflags, args, apolys); - if (mptr && plen(mptr->spoly)) + if (mptr && plen(mptr->spoly)) { uflags |= C_RESULT; + } + while (mptr && plen(mptr->spoly)) { /* results were printed by the callback * string = mtostr(mptr); @@ -478,26 +495,31 @@ ipqx: mfree(mptr++); } free(candmods); + if (~rflags & R_HAVERI) { model.flags ^= P_REFIN | P_REFOUT; - for (qptr = apolys; qptr < pptr; ++qptr) + for (qptr = apolys; qptr < pptr; ++qptr) { prevch(qptr, ibperhx); + } } } while (~rflags & R_HAVERI && ++pass < 2); - for (qptr = apolys; qptr < pptr; ++qptr) + + for (qptr = apolys; qptr < pptr; ++qptr) { pfree(qptr); + } + free(apolys); + if (~uflags & C_RESULT) uerror("no models found"); + break; default: /* no mode specified */ fprintf(stderr, "%s: no mode switch specified. Use %s -h for help.\n", myname, myname); return 0; - //exit(EXIT_FAILURE); } return 1; - //exit(EXIT_SUCCESS); } void diff --git a/client/luascripts/hf_mf_dump-luxeo.lua b/client/luascripts/hf_mf_dump-luxeo.lua index 3ee86ecbc..70f1b42e0 100644 --- a/client/luascripts/hf_mf_dump-luxeo.lua +++ b/client/luascripts/hf_mf_dump-luxeo.lua @@ -77,65 +77,65 @@ local function setdevicedebug( status ) end local function xteaCrypt(num_rounds, v, key) - local v0 = v[0] - local v1 = v[1] - local delta = 0x9E3779B9 - local sum = 0 + local v0 = v[0] + local v1 = v[1] + local delta = 0x9E3779B9 + local sum = 0 - for i = 0, num_rounds-1 do - -- v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]); - v0 = band(bxor(bxor(lsh(v1,4), rsh(v1,5)) + v1, sum + key[band(sum,3)]) + v0, 0xFFFFFFFF) - sum = band(sum + delta, 0xFFFFFFFF) - -- v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]); - v1 = band(bxor(bxor(lsh(v0,4), rsh(v0,5)) + v0, sum + key[band(rsh(sum,11),3)]) + v1, 0xFFFFFFFF) - end - v[0] = v0 - v[1] = v1 + for i = 0, num_rounds-1 do + -- v0 += (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]); + v0 = band(bxor(bxor(lsh(v1,4), rsh(v1,5)) + v1, sum + key[band(sum,3)]) + v0, 0xFFFFFFFF) + sum = band(sum + delta, 0xFFFFFFFF) + -- v1 += (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]); + v1 = band(bxor(bxor(lsh(v0,4), rsh(v0,5)) + v0, sum + key[band(rsh(sum,11),3)]) + v1, 0xFFFFFFFF) + end + v[0] = v0 + v[1] = v1 end local function xteaDecrypt(num_rounds, v, key) - local v0 = v[0] - local v1 = v[1] - local delta = 0x9E3779B9 - local sum = band(delta * num_rounds, 0xFFFFFFFF) + local v0 = v[0] + local v1 = v[1] + local delta = 0x9E3779B9 + local sum = band(delta * num_rounds, 0xFFFFFFFF) - for i = 0, num_rounds-1 do - -- v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]); - v1 = band(v1 - bxor(bxor(lsh(v0,4), rsh(v0,5)) + v0, sum + key[band(rsh(sum,11),3)]), 0xFFFFFFFF) - sum = band(sum - delta, 0xFFFFFFFF) - -- v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]); - v0 = band(v0 - bxor(bxor(lsh(v1,4), rsh(v1,5)) + v1, sum + key[band(sum,3)]), 0xFFFFFFFF) - end - v[0] = v0 - v[1] = v1 + for i = 0, num_rounds-1 do + -- v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum>>11) & 3]); + v1 = band(v1 - bxor(bxor(lsh(v0,4), rsh(v0,5)) + v0, sum + key[band(rsh(sum,11),3)]), 0xFFFFFFFF) + sum = band(sum - delta, 0xFFFFFFFF) + -- v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]); + v0 = band(v0 - bxor(bxor(lsh(v1,4), rsh(v1,5)) + v1, sum + key[band(sum,3)]), 0xFFFFFFFF) + end + v[0] = v0 + v[1] = v1 end local function createxteakey(mfuid) - local xteakey = {} - local buid = {} - local tmpkey = {} - local uid = {} + local xteakey = {} + local buid = {} + local tmpkey = {} + local uid = {} - -- Warning ! "it is customary in Lua to START ARRAYS WITH ONE" - buid = utils.ConvertHexToBytes(mfuid) - uid[0] = bor(buid[1], lsh(buid[2], 8)) - uid[1] = bor(buid[3], lsh(buid[4], 8)) + -- Warning ! "it is customary in Lua to START ARRAYS WITH ONE" + buid = utils.ConvertHexToBytes(mfuid) + uid[0] = bor(buid[1], lsh(buid[2], 8)) + uid[1] = bor(buid[3], lsh(buid[4], 8)) - tmpkey[0] = 0x198B - tmpkey[1] = uid[0] - tmpkey[2] = 0x46D8 - tmpkey[3] = uid[1] - tmpkey[4] = 0x5310 - tmpkey[5] = bxor(uid[0], 0xA312) - tmpkey[6] = 0xFFCB - tmpkey[7] = bxor(uid[1], 0x55AA) + tmpkey[0] = 0x198B + tmpkey[1] = uid[0] + tmpkey[2] = 0x46D8 + tmpkey[3] = uid[1] + tmpkey[4] = 0x5310 + tmpkey[5] = bxor(uid[0], 0xA312) + tmpkey[6] = 0xFFCB + tmpkey[7] = bxor(uid[1], 0x55AA) - xteakey[0] = bor(lsh(tmpkey[1], 16), tmpkey[0]) - xteakey[1] = bor(lsh(tmpkey[3], 16), tmpkey[2]) - xteakey[2] = bor(lsh(tmpkey[5], 16), tmpkey[4]) - xteakey[3] = bor(lsh(tmpkey[7], 16), tmpkey[6]) + xteakey[0] = bor(lsh(tmpkey[1], 16), tmpkey[0]) + xteakey[1] = bor(lsh(tmpkey[3], 16), tmpkey[2]) + xteakey[2] = bor(lsh(tmpkey[5], 16), tmpkey[4]) + xteakey[3] = bor(lsh(tmpkey[7], 16), tmpkey[6]) - return xteakey + return xteakey end local function getblockdata(response) @@ -160,38 +160,38 @@ local function readblock(blockno, key) end local function readtag(mfkey,xteakey) - local tagdata = {} - local cleardata = {} - local v = {} - local vv = {} + local tagdata = {} + local cleardata = {} + local v = {} + local vv = {} - -- Read 4 sectors and build table - for sect = 8, 11 do - for blockn = sect * 4, (sect * 4) + 2 do - local blockdata = readblock(blockn, mfkey) - if not blockdata then return oops('[!] failed reading block') end - table.insert(tagdata, blockdata) - end - end + -- Read 4 sectors and build table + for sect = 8, 11 do + for blockn = sect * 4, (sect * 4) + 2 do + local blockdata = readblock(blockn, mfkey) + if not blockdata then return oops('[!] failed reading block') end + table.insert(tagdata, blockdata) + end + end - -- Decrypt data and build clear table - for key,value in ipairs(tagdata) do - local clearblockdata - v[0] = utils.SwapEndianness(value:sub(1, 8), 32) - v[1] = utils.SwapEndianness(value:sub(9, 16), 32) - xteaDecrypt(16, v, xteakey) - vv[0] = utils.SwapEndianness(value:sub(17, 24), 32) - vv[1] = utils.SwapEndianness(value:sub(25, 32), 32) - xteaDecrypt(16, vv, xteakey) - clearblockdata=string.format("%08X%08X%08X%08X", - utils.SwapEndianness(string.format("%08X", v[0]), 32), - utils.SwapEndianness(string.format("%08X", v[1]), 32), - utils.SwapEndianness(string.format("%08X", vv[0]), 32), - utils.SwapEndianness(string.format("%08X", vv[1]), 32)) - table.insert(cleardata, clearblockdata) - end + -- Decrypt data and build clear table + for key,value in ipairs(tagdata) do + local clearblockdata + v[0] = utils.SwapEndianness(value:sub(1, 8), 32) + v[1] = utils.SwapEndianness(value:sub(9, 16), 32) + xteaDecrypt(16, v, xteakey) + vv[0] = utils.SwapEndianness(value:sub(17, 24), 32) + vv[1] = utils.SwapEndianness(value:sub(25, 32), 32) + xteaDecrypt(16, vv, xteakey) + clearblockdata=string.format("%08X%08X%08X%08X", + utils.SwapEndianness(string.format("%08X", v[0]), 32), + utils.SwapEndianness(string.format("%08X", v[1]), 32), + utils.SwapEndianness(string.format("%08X", vv[0]), 32), + utils.SwapEndianness(string.format("%08X", vv[1]), 32)) + table.insert(cleardata, clearblockdata) + end - return tagdata,cleardata + return tagdata,cleardata end @@ -203,98 +203,98 @@ local function main(args) if o == 'h' then return help() end end - local xteakey = {} - -- local v = {} - local edata = {} - local cdata = {} + local xteakey = {} + -- local v = {} + local edata = {} + local cdata = {} - -- Turn off Debug - setdevicedebug(false) + -- Turn off Debug + setdevicedebug(false) - -- GET TAG UID - tag, err = lib14a.read(false, true) - if err then - lib14a.disconnect() - return oops(err) - end - core.clearCommandBuffer() + -- GET TAG UID + tag, err = lib14a.read(false, true) + if err then + lib14a.disconnect() + return oops(err) + end + core.clearCommandBuffer() - -- simple tag check - if 0x08 ~= tag.sak then - if 0x0400 ~= tag.atqa then - return oops(('[fail] found tag %s :: looking for Mifare S50 1k'):format(tag.name)) - end - end + -- simple tag check + if 0x08 ~= tag.sak then + if 0x0400 ~= tag.atqa then + return oops(('[fail] found tag %s :: looking for Mifare S50 1k'):format(tag.name)) + end + end - xteakey = createxteakey(tag.uid) - print(acblue.."UID: "..tag.uid..acoff) - print(acblue..string.format("XTEA key: %08X %08X %08X %08X", xteakey[0], xteakey[1], xteakey[2], xteakey[3])..acoff) + xteakey = createxteakey(tag.uid) + print(acblue.."UID: "..tag.uid..acoff) + print(acblue..string.format("XTEA key: %08X %08X %08X %08X", xteakey[0], xteakey[1], xteakey[2], xteakey[3])..acoff) - edata, cdata = readtag("415A54454B4D", xteakey) + edata, cdata = readtag("415A54454B4D", xteakey) - if edata == nil or cdata == nil then - print("ERROR Reading tag!") - return nil - end + if edata == nil or cdata == nil then + print("ERROR Reading tag!") + return nil + end - print("Ciphered data:") - for key,value in ipairs(edata) do - print(value) - if key % 3 == 0 then print("") end - end + print("Ciphered data:") + for key,value in ipairs(edata) do + print(value) + if key % 3 == 0 then print("") end + end - -- compute CRC for each segment + -- compute CRC for each segment crcH = utils.SwapEndianness(core.reveng_runmodel("CRC-16/ARC", cdata[1]..cdata[2]..cdata[3]:sub(1,28), false, '0'),16) crcA = utils.SwapEndianness(core.reveng_runmodel("CRC-16/ARC", cdata[4]..cdata[5]..cdata[6]..cdata[7]:sub(1,28), false, '0'),16) crcB = utils.SwapEndianness(core.reveng_runmodel("CRC-16/ARC", cdata[8]..cdata[9]..cdata[10]..cdata[11]:sub(1,28), false, '0'),16) - print("\nHeader:") - for key,value in ipairs(cdata) do - if key == 3 then - print(value:sub(1,28)..acmagenta..value:sub(29,32)..acoff) - if utils.SwapEndianness(value:sub(29,32),16) == crcH then strcrc = " OK" else strcrc = acred.." CRCERROR !!" end - print(acmagenta.."CRC16/ARC = "..string.format("0x%04X", crcH)..strcrc..acoff) - print("\nDataA:") - elseif key == 4 then - print(acgreen..value:sub(1,4)..acoff..value:sub(5,16)..accyan..value:sub(17,24)..acoff..value:sub(25,26)..accyan..value:sub(27,28)..acoff..value:sub(29,32)) - versionA = utils.SwapEndianness(value:sub(1,4),16) - dateA = string.format("%d/%02d/%02d %02d:%02d", tonumber(value:sub(17,18),10)+2000, tonumber(value:sub(19,20),10), - tonumber(string.format("%02X", band(tonumber(value:sub(21,22),16),0x3f)),10), - tonumber(value:sub(23,24),10), tonumber(value:sub(27,28),10)) - elseif key == 8 then - print(acgreen..value:sub(1,4)..acoff..value:sub(5,16)..accyan..value:sub(17,24)..acoff..value:sub(25,26)..accyan..value:sub(27,28)..acoff..value:sub(29,32)) - versionB = utils.SwapEndianness(value:sub(1,4),16) - dateB = string.format("%d/%02d/%02d %02d:%02d", tonumber(value:sub(17,18),10)+2000, tonumber(value:sub(19,20),10), - tonumber(string.format("%02X", band(tonumber(value:sub(21,22),16),0x3f)),10), - tonumber(value:sub(23,24),10), tonumber(value:sub(27,28),10)) - elseif key == 5 then - print(acyellow..value:sub(1,4)..acoff..value:sub(5,32)) - creditA = utils.SwapEndianness(value:sub(1,4),16)/100 - elseif key == 9 then - print(acyellow..value:sub(1,4)..acoff..value:sub(5,32)) - creditB = utils.SwapEndianness(value:sub(1,4),16)/100 - elseif key == 7 then - print(value:sub(1,28)..acmagenta..value:sub(29,32)..acoff) - print(acgreen.."Version "..string.format("0x%04X", versionA)..acoff) - print(acyellow.."Credit : "..creditA..acoff) - if utils.SwapEndianness(value:sub(29,32),16) == crcA then strcrc = " OK" else strcrc = acred.." CRCERROR !!" end - print(acmagenta.."CRC16/ARC = "..string.format("0x%04X", crcA)..strcrc..acoff) - print(accyan.."Date: "..dateA..acoff) - print("\nDataB:") - elseif key == 11 then - print(value:sub(1,28)..acmagenta..value:sub(29,32)..acoff) - print(acgreen.."Version "..string.format("0x%04X", versionB)..acoff) - print(acyellow.."Credit : "..creditB..acoff) - if utils.SwapEndianness(value:sub(29,32),16) == crcB then strcrc = " OK" else strcrc = acred.." CRCERROR !!" end - print(acmagenta.."CRC16/ARC = "..string.format("0x%04X", crcB)..strcrc..acoff) - print(accyan.."Date: "..dateB..acoff) - print("\nFooter:") - else - print(value) - end - end + print("\nHeader:") + for key,value in ipairs(cdata) do + if key == 3 then + print(value:sub(1,28)..acmagenta..value:sub(29,32)..acoff) + if utils.SwapEndianness(value:sub(29,32),16) == crcH then strcrc = " OK" else strcrc = acred.." CRCERROR !!" end + print(acmagenta.."CRC16/ARC = "..string.format("0x%04X", crcH)..strcrc..acoff) + print("\nDataA:") + elseif key == 4 then + print(acgreen..value:sub(1,4)..acoff..value:sub(5,16)..accyan..value:sub(17,24)..acoff..value:sub(25,26)..accyan..value:sub(27,28)..acoff..value:sub(29,32)) + versionA = utils.SwapEndianness(value:sub(1,4),16) + dateA = string.format("%d/%02d/%02d %02d:%02d", tonumber(value:sub(17,18),10)+2000, tonumber(value:sub(19,20),10), + tonumber(string.format("%02X", band(tonumber(value:sub(21,22),16),0x3f)),10), + tonumber(value:sub(23,24),10), tonumber(value:sub(27,28),10)) + elseif key == 8 then + print(acgreen..value:sub(1,4)..acoff..value:sub(5,16)..accyan..value:sub(17,24)..acoff..value:sub(25,26)..accyan..value:sub(27,28)..acoff..value:sub(29,32)) + versionB = utils.SwapEndianness(value:sub(1,4),16) + dateB = string.format("%d/%02d/%02d %02d:%02d", tonumber(value:sub(17,18),10)+2000, tonumber(value:sub(19,20),10), + tonumber(string.format("%02X", band(tonumber(value:sub(21,22),16),0x3f)),10), + tonumber(value:sub(23,24),10), tonumber(value:sub(27,28),10)) + elseif key == 5 then + print(acyellow..value:sub(1,4)..acoff..value:sub(5,32)) + creditA = utils.SwapEndianness(value:sub(1,4),16)/100 + elseif key == 9 then + print(acyellow..value:sub(1,4)..acoff..value:sub(5,32)) + creditB = utils.SwapEndianness(value:sub(1,4),16)/100 + elseif key == 7 then + print(value:sub(1,28)..acmagenta..value:sub(29,32)..acoff) + print(acgreen.."Version "..string.format("0x%04X", versionA)..acoff) + print(acyellow.."Credit : "..creditA..acoff) + if utils.SwapEndianness(value:sub(29,32),16) == crcA then strcrc = " OK" else strcrc = acred.." CRCERROR !!" end + print(acmagenta.."CRC16/ARC = "..string.format("0x%04X", crcA)..strcrc..acoff) + print(accyan.."Date: "..dateA..acoff) + print("\nDataB:") + elseif key == 11 then + print(value:sub(1,28)..acmagenta..value:sub(29,32)..acoff) + print(acgreen.."Version "..string.format("0x%04X", versionB)..acoff) + print(acyellow.."Credit : "..creditB..acoff) + if utils.SwapEndianness(value:sub(29,32),16) == crcB then strcrc = " OK" else strcrc = acred.." CRCERROR !!" end + print(acmagenta.."CRC16/ARC = "..string.format("0x%04X", crcB)..strcrc..acoff) + print(accyan.."Date: "..dateB..acoff) + print("\nFooter:") + else + print(value) + end + end - return + return end main(args) diff --git a/client/luascripts/hf_mf_gen3_writer.lua b/client/luascripts/hf_mf_gen3_writer.lua index 7795ac26c..1257f3413 100644 --- a/client/luascripts/hf_mf_gen3_writer.lua +++ b/client/luascripts/hf_mf_gen3_writer.lua @@ -34,7 +34,7 @@ version = 'v1.0.0' desc = [[ This script gives you an easy way to write your *.eml dumps into normal MIFARE Classic and Magic Gen3 cards. - Works with both 4 and 7 bytes NXP MIFARE Classic 1K cards. + Works with both 4 and 7 bytes NXP MIFARE Classic 1K cards. The script also has the possibility to change UID and permanent lock uid on magic Gen3 cards. It supports the following functionality. @@ -47,18 +47,18 @@ desc = [[ Script works in a wizard styled way. - Author Youtube channel: https://yev.ooo/ + Author Youtube channel: https://yev.ooo/ - Many Thanks, - Best Regards + Many Thanks, + Best Regards ]] example = [[ 1. script run mfc_gen3_writer ]] usage = [[ - Give script to know if you uses an Windows OS + Give script to know if you uses an Windows OS Select your *.eml dump from list to write to the card. - Follow the wizard. + Follow the wizard. ]] -- --- @@ -163,9 +163,9 @@ end -- local function KeyAB() if default_key_type == '00' then - return 'KeyA' + return 'KeyA' else - return 'KeyB' + return 'KeyB' end end -- @@ -265,7 +265,7 @@ local function main(args) eml_file_uid_end = 22 eml_file_lengt = 31 else - eml_file_uid_start = 9 + eml_file_uid_start = 9 eml_file_uid_end = 16 eml_file_lengt = 25 end @@ -366,7 +366,7 @@ local function main(args) print(tab) -- if checkkey() == true then - print(tab) + print(tab) if (utils.confirm(' Card is Empty. Write selected dump to card ?') == true) then for i = 1, #eml do core.console(string.format(cmd_wrbl_b, (i-1), default_key, eml[i])) diff --git a/client/luascripts/hf_mf_uidbruteforce.lua b/client/luascripts/hf_mf_uidbruteforce.lua index 461e8aad3..fc85b63bb 100644 --- a/client/luascripts/hf_mf_uidbruteforce.lua +++ b/client/luascripts/hf_mf_uidbruteforce.lua @@ -114,7 +114,7 @@ local function main(args) local c = string.format( command, n ) print('Running: "'..c..'"') core.console(c) - core.console('msleep '..timeout); + core.console('msleep '..timeout); core.console('hw ping') end diff --git a/client/luascripts/hf_mfu_magicwrite.lua b/client/luascripts/hf_mfu_magicwrite.lua index e29296f45..2961bd54c 100644 --- a/client/luascripts/hf_mfu_magicwrite.lua +++ b/client/luascripts/hf_mfu_magicwrite.lua @@ -15,75 +15,75 @@ author = 'Christian Herrmann' version = 'v1.1.3' desc = 'This script enables easy programming of a MAGIC NTAG 21* card' example = [[ - -- wipe tag - script run hf_mfu_magicwrite -w + -- wipe tag + script run hf_mfu_magicwrite -w - -- wipe a locked down tag by giving the password - script run hf_mfu_magicwrite -k ffffffff -w + -- wipe a locked down tag by giving the password + script run hf_mfu_magicwrite -k ffffffff -w - --read magic tag configuration - script run hf_mfu_magicwrite -c + --read magic tag configuration + script run hf_mfu_magicwrite -c - -- set uid - script run hf_mfu_magicwrite -u 04112233445566 + -- set uid + script run hf_mfu_magicwrite -u 04112233445566 - -- set pwd / pack - script run hf_mfu_magicwrite -p 11223344 -a 8080 + -- set pwd / pack + script run hf_mfu_magicwrite -p 11223344 -a 8080 - -- set version to NTAG213 - script run hf_mfu_magicwrite -v 0004040201000f03 + -- set version to NTAG213 + script run hf_mfu_magicwrite -v 0004040201000f03 - -- set signature - script run hf_mfu_magicwrite -s 1122334455667788990011223344556677889900112233445566778899001122 + -- set signature + script run hf_mfu_magicwrite -s 1122334455667788990011223344556677889900112233445566778899001122 ]] usage = [[ script run hf_mfu_easywrite -h -k -c -w -u -t -p -a -s -o -v ]] arguments = [[ - -h this help - -c read magic configuration - -u UID (14 hexsymbols), set UID on tag - -t tag type to impersonate - 1 = UL_EV1 48k - 2 = UL_EV1 128k - 3 = NTAG 210 - 4 = NTAG 212 - 5 = NTAG 213 (true) - 6 = NTAG 215 (true) - 7 = NTAG 216 (true) - 8 = NTAG I2C 1K - 9 = NTAG I2C 2K - 10 = NTAG I2C 1K PLUS - 11 = NTAG I2C 2K PLUS - 12 = NTAG 213F (true) - 13 = NTAG 216F (true) - -p password (8 hexsymbols), set password on tag. - -a pack ( 4 hexsymbols), set pack on tag. - -s signature data (64 hexsymbols), set signature data on tag. - -o OTP data (8 hexsymbols), set one-time-pad data on tag. - -v version data (16 hexsymbols), set version data on tag. - -w wipe tag. You can specify password if the tag has been locked down. Fills tag with zeros and put default values for NTAG213 (like -t 5) - -k pwd to use with the wipe option + -h this help + -c read magic configuration + -u UID (14 hexsymbols), set UID on tag + -t tag type to impersonate + 1 = UL_EV1 48k + 2 = UL_EV1 128k + 3 = NTAG 210 + 4 = NTAG 212 + 5 = NTAG 213 (true) + 6 = NTAG 215 (true) + 7 = NTAG 216 (true) + 8 = NTAG I2C 1K + 9 = NTAG I2C 2K + 10 = NTAG I2C 1K PLUS + 11 = NTAG I2C 2K PLUS + 12 = NTAG 213F (true) + 13 = NTAG 216F (true) + -p password (8 hexsymbols), set password on tag. + -a pack ( 4 hexsymbols), set pack on tag. + -s signature data (64 hexsymbols), set signature data on tag. + -o OTP data (8 hexsymbols), set one-time-pad data on tag. + -v version data (16 hexsymbols), set version data on tag. + -w wipe tag. You can specify password if the tag has been locked down. Fills tag with zeros and put default values for NTAG213 (like -t 5) + -k pwd to use with the wipe option ]] --- -- A debug printout-function local function dbg(args) - if not DEBUG then return end - if type(args) == 'table' then - local i = 1 - while result[i] do - dbg(result[i]) - i = i+1 - end - else - print('###', args) - end + if not DEBUG then return end + if type(args) == 'table' then + local i = 1 + while result[i] do + dbg(result[i]) + i = i+1 + end + else + print('###', args) + end end -- This is only meant to be used when errors occur local function oops(err) - print("ERROR: ",err) + print("ERROR: ",err) core.clearCommandBuffer() - return nil, err + return nil, err end --- -- Usage help @@ -102,11 +102,11 @@ end --- -- set the global password variable local function set_password(pwd) - if pwd == nil then _password = nil; return true, 'Ok' end - if #pwd ~= 8 then return nil, 'password wrong length. Must be 4 hex bytes' end - if #pwd == 0 then _password = nil end - _password = pwd - return true, 'Ok' + if pwd == nil then _password = nil; return true, 'Ok' end + if #pwd ~= 8 then return nil, 'password wrong length. Must be 4 hex bytes' end + if #pwd == 0 then _password = nil end + _password = pwd + return true, 'Ok' end --- Picks out and displays the data read from a tag -- Specifically, takes a usb packet, converts to a Command @@ -114,37 +114,37 @@ end -- reads the number of bytes specified in arg1 (arg0 in c-struct) -- @param usbpacket the data received from the device local function getResponseData(usbpacket) - local resp = Command.parse(usbpacket) - local len = tonumber(resp.arg1) * 2 - return string.sub(tostring(resp.data), 0, len); + local resp = Command.parse(usbpacket) + local len = tonumber(resp.arg1) * 2 + return string.sub(tostring(resp.data), 0, len); end --- -- local function sendRaw(rawdata, options) - local flags = lib14a.ISO14A_COMMAND.ISO14A_NO_DISCONNECT - + lib14a.ISO14A_COMMAND.ISO14A_RAW - + lib14a.ISO14A_COMMAND.ISO14A_APPEND_CRC + local flags = lib14a.ISO14A_COMMAND.ISO14A_NO_DISCONNECT + + lib14a.ISO14A_COMMAND.ISO14A_RAW + + lib14a.ISO14A_COMMAND.ISO14A_APPEND_CRC - local c = Command:newMIX{cmd = cmds.CMD_HF_ISO14443A_READER, - arg1 = flags, - -- arg2 contains the length, which is half the length of the ASCII-string rawdata - arg2 = string.len(rawdata)/2, - data = rawdata} + local c = Command:newMIX{cmd = cmds.CMD_HF_ISO14443A_READER, + arg1 = flags, + -- arg2 contains the length, which is half the length of the ASCII-string rawdata + arg2 = string.len(rawdata)/2, + data = rawdata} return c:sendMIX(options.ignore_response) end --- -- local function send(payload) - local usb, err = sendRaw(payload,{ignore_response = false}) - if err then return oops(err) end - return getResponseData(usb) + local usb, err = sendRaw(payload,{ignore_response = false}) + if err then return oops(err) end + return getResponseData(usb) end --- -- select tag and if password is set, authenticate local function connect() - core.clearCommandBuffer() + core.clearCommandBuffer() -- First of all, connect info, err = lib14a.read(true, true) @@ -154,221 +154,221 @@ local function connect() end core.clearCommandBuffer() - --authenticate if needed using global variable - if _password then - send('1B'.._password) - end + --authenticate if needed using global variable + if _password then + send('1B'.._password) + end return true end -- -- Read magic configuration local function read_config() - local info = connect() + local info = connect() if not info then return false, "Can't select card" end - -- read PWD - local pwd = send("30F0"):sub(1,8) + -- read PWD + local pwd = send("30F0"):sub(1,8) - -- 04 response indicates that blocks has been locked down. - if pwd == '04' then lib14a.disconnect(); return nil, "can't read configuration, "..err_lock end + -- 04 response indicates that blocks has been locked down. + if pwd == '04' then lib14a.disconnect(); return nil, "can't read configuration, "..err_lock end - -- read PACK - local pack = send("30F1"):sub(1,4) + -- read PACK + local pack = send("30F1"):sub(1,4) - -- read SIGNATURE - local signature1 = send('30F2'):sub(1,32) - local signature2 = send('30F6'):sub(1,32) + -- read SIGNATURE + local signature1 = send('30F2'):sub(1,32) + local signature2 = send('30F6'):sub(1,32) - -- read VERSION - local version = send('30FA'):sub(1,16) - -- read config - local cardtype = send('30FC'):sub(1,2) + -- read VERSION + local version = send('30FA'):sub(1,16) + -- read config + local cardtype = send('30FC'):sub(1,2) - local typestr = '' - if cardtype == '00' then typestr = 'NTAG 213' - elseif cardtype == '01' then typestr = 'NTAG 215' - elseif cardtype == '02' then typestr = 'NTAG 216' - end + local typestr = '' + if cardtype == '00' then typestr = 'NTAG 213' + elseif cardtype == '01' then typestr = 'NTAG 215' + elseif cardtype == '02' then typestr = 'NTAG 216' + end - print('Magic NTAG 21* Configuration') - print(' - Type ', typestr, '(genuine cardtype)') - print(' - Password', pwd) - print(' - Pack ', pack) - print(' - Version ', version) - print(' - Signature', signature1..signature2) + print('Magic NTAG 21* Configuration') + print(' - Type ', typestr, '(genuine cardtype)') + print(' - Password', pwd) + print(' - Pack ', pack) + print(' - Version ', version) + print(' - Signature', signature1..signature2) - lib14a.disconnect() - return true, 'Ok' + lib14a.disconnect() + return true, 'Ok' end --- -- Write SIGNATURE data local function write_signature(data) - -- uid string checks - if data == nil then return nil, 'empty data string' end - if #data == 0 then return nil, 'empty data string' end - if #data ~= 64 then return nil, 'data wrong length. Should be 32 hex bytes' end + -- uid string checks + if data == nil then return nil, 'empty data string' end + if #data == 0 then return nil, 'empty data string' end + if #data ~= 64 then return nil, 'data wrong length. Should be 32 hex bytes' end - local info = connect() + local info = connect() if not info then return false, "Can't select card" end - print('Writing new signature') + print('Writing new signature') - local b,c - local cmd = 'A2F%d%s' - local j = 2 - for i = 1, #data, 8 do - b = data:sub(i,i+7) - c = cmd:format(j,b) - local resp = send(c) - if resp == '04' then lib14a.disconnect(); return nil, 'Failed to write signature' end - j = j + 1 - end - lib14a.disconnect() - return true, 'Ok' + local b,c + local cmd = 'A2F%d%s' + local j = 2 + for i = 1, #data, 8 do + b = data:sub(i,i+7) + c = cmd:format(j,b) + local resp = send(c) + if resp == '04' then lib14a.disconnect(); return nil, 'Failed to write signature' end + j = j + 1 + end + lib14a.disconnect() + return true, 'Ok' end --- -- Write PWD local function write_pwd(pwd) - -- PWD string checks - if pwd == nil then return nil, 'empty PWD string' end - if #pwd == 0 then return nil, 'empty PWD string' end - if #pwd ~= 8 then return nil, 'PWD wrong length. Should be 4 hex bytes' end + -- PWD string checks + if pwd == nil then return nil, 'empty PWD string' end + if #pwd == 0 then return nil, 'empty PWD string' end + if #pwd ~= 8 then return nil, 'PWD wrong length. Should be 4 hex bytes' end - local info = connect() + local info = connect() if not info then return false, "Can't select card" end - print('Writing new PWD ', pwd) + print('Writing new PWD ', pwd) - local resp = send('A2F0'..pwd) - lib14a.disconnect() - if resp == '04' then - return nil, 'Failed to write password' - else - return true, 'Ok' - end + local resp = send('A2F0'..pwd) + lib14a.disconnect() + if resp == '04' then + return nil, 'Failed to write password' + else + return true, 'Ok' + end end --- -- Write PACK local function write_pack(pack) - -- PACK string checks - if pack == nil then return nil, 'empty PACK string' end - if #pack == 0 then return nil, 'empty PACK string' end - if #pack ~= 4 then return nil, 'PACK wrong length. Should be 4 hex bytes' end + -- PACK string checks + if pack == nil then return nil, 'empty PACK string' end + if #pack == 0 then return nil, 'empty PACK string' end + if #pack ~= 4 then return nil, 'PACK wrong length. Should be 4 hex bytes' end - local info = connect() + local info = connect() if not info then return false, "Can't select card" end - print('Writing new PACK', pack) + print('Writing new PACK', pack) - local resp = send('A2F1'..pack..'0000') - lib14a.disconnect() - if resp == '04' then - return nil, 'Failed to write pack' - else - return true, 'Ok' - end + local resp = send('A2F1'..pack..'0000') + lib14a.disconnect() + if resp == '04' then + return nil, 'Failed to write pack' + else + return true, 'Ok' + end end -- -- Write OTP block local function write_otp(block3) - -- OTP string checks - if block3 == nil then return nil, 'empty OTP string' end - if #block3 == 0 then return nil, 'empty OTP string' end - if #block3 ~= 8 then return nil, 'OTP wrong length. Should be 4 hex bytes' end + -- OTP string checks + if block3 == nil then return nil, 'empty OTP string' end + if #block3 == 0 then return nil, 'empty OTP string' end + if #block3 ~= 8 then return nil, 'OTP wrong length. Should be 4 hex bytes' end - local info = connect() + local info = connect() if not info then return false, "Can't select card" end - print('Writing new OTP ', block3) + print('Writing new OTP ', block3) - local resp = send('A203'..block3) - lib14a.disconnect() - if resp == '04' then - return nil, 'Failed to write OTP' - else - return true, 'Ok' - end + local resp = send('A203'..block3) + lib14a.disconnect() + if resp == '04' then + return nil, 'Failed to write OTP' + else + return true, 'Ok' + end end -- -- Writes a UID with bcc1, bcc2. Needs a magic tag. local function write_uid(uid) - -- uid string checks - if uid == nil then return nil, 'empty uid string' end - if #uid == 0 then return nil, 'empty uid string' end - if #uid ~= 14 then return nil, 'uid wrong length. Should be 7 hex bytes' end + -- uid string checks + if uid == nil then return nil, 'empty uid string' end + if #uid == 0 then return nil, 'empty uid string' end + if #uid ~= 14 then return nil, 'uid wrong length. Should be 7 hex bytes' end - local info = connect() + local info = connect() if not info then return false, "Can't select card" end - print('Writing new UID ', uid) + print('Writing new UID ', uid) - local uidbytes = utils.ConvertHexToBytes(uid) - local bcc1 = bxor(bxor(bxor(uidbytes[1], uidbytes[2]), uidbytes[3]), 0x88) - local bcc2 = bxor(bxor(bxor(uidbytes[4], uidbytes[5]), uidbytes[6]), uidbytes[7]) - local block0 = string.format('%02X%02X%02X%02X', uidbytes[1], uidbytes[2], uidbytes[3], bcc1) - local block1 = string.format('%02X%02X%02X%02X', uidbytes[4], uidbytes[5], uidbytes[6], uidbytes[7]) - local block2 = string.format('%02X%02X%02X%02X', bcc2, 0x48, 0x00, 0x00) - local resp + local uidbytes = utils.ConvertHexToBytes(uid) + local bcc1 = bxor(bxor(bxor(uidbytes[1], uidbytes[2]), uidbytes[3]), 0x88) + local bcc2 = bxor(bxor(bxor(uidbytes[4], uidbytes[5]), uidbytes[6]), uidbytes[7]) + local block0 = string.format('%02X%02X%02X%02X', uidbytes[1], uidbytes[2], uidbytes[3], bcc1) + local block1 = string.format('%02X%02X%02X%02X', uidbytes[4], uidbytes[5], uidbytes[6], uidbytes[7]) + local block2 = string.format('%02X%02X%02X%02X', bcc2, 0x48, 0x00, 0x00) + local resp - resp = send('A200'..block0) - resp = send('A201'..block1) - resp = send('A202'..block2) - lib14a.disconnect() + resp = send('A200'..block0) + resp = send('A201'..block1) + resp = send('A202'..block2) + lib14a.disconnect() - if resp == '04' then - return nil, 'Failed to write new uid' - else - return true, 'Ok' - end + if resp == '04' then + return nil, 'Failed to write new uid' + else + return true, 'Ok' + end end --- -- Write VERSION data, -- make sure you have correct version data local function write_version(data) - -- version string checks - if data == nil then return nil, 'empty version string' end - if #data == 0 then return nil, 'empty version string' end - if #data ~= 16 then return nil, 'version wrong length. Should be 8 hex bytes' end + -- version string checks + if data == nil then return nil, 'empty version string' end + if #data == 0 then return nil, 'empty version string' end + if #data ~= 16 then return nil, 'version wrong length. Should be 8 hex bytes' end - local info = connect() + local info = connect() if not info then return false, "Can't select card" end - print('Writing new version', data) + print('Writing new version', data) - local b1 = data:sub(1,8) - local b2 = data:sub(9,16) - local resp - resp = send('A2FA'..b1) - resp = send('A2FB'..b2) - lib14a.disconnect() - if resp == '04' then - return nil, 'Failed to write version' - else - return true, 'Ok' - end + local b1 = data:sub(1,8) + local b2 = data:sub(9,16) + local resp + resp = send('A2FA'..b1) + resp = send('A2FB'..b2) + lib14a.disconnect() + if resp == '04' then + return nil, 'Failed to write version' + else + return true, 'Ok' + end end --- -- writen TYPE which card is based on. -- 00 = 213, 01 = 215, 02 = 216 local function write_type(data) - -- type string checks - if data == nil then return nil, 'empty type string' end - if #data == 0 then return nil, 'empty type string' end - if #data ~= 2 then return nil, 'type wrong length. Should be 1 hex byte' end + -- type string checks + if data == nil then return nil, 'empty type string' end + if #data == 0 then return nil, 'empty type string' end + if #data ~= 2 then return nil, 'type wrong length. Should be 1 hex byte' end local info = connect() if not info then return false, "Can't select card" end - print('Writing new type', data) + print('Writing new type', data) - local resp = send('A2FC'..data..'000000') - lib14a.disconnect() - if resp == '04' then - return nil, 'Failed to write type' - else - return true, 'Ok' - end + local resp = send('A2FC'..data..'000000') + lib14a.disconnect() + if resp == '04' then + return nil, 'Failed to write type' + else + return true, 'Ok' + end end --- -- Set tag type. Predefinde version data together with magic type set. @@ -376,283 +376,283 @@ end -- we only truely be three types NTAG 213,215 and 216 local function set_type(tagtype) - -- tagtype checks - if type(tagtype) == 'string' then tagtype = tonumber(tagtype, 10) end - if tagtype == nil then return nil, 'empty tagtype' end + -- tagtype checks + if type(tagtype) == 'string' then tagtype = tonumber(tagtype, 10) end + if tagtype == nil then return nil, 'empty tagtype' end - if tagtype == 1 then - print('Setting: UL-EV1 48') - write_otp('00000000') -- Setting OTP to default 00 00 00 00 - write_version('0004030101000b03') -- UL-EV1 (48) 00 04 03 01 01 00 0b 03 - write_type('00') -- based on NTAG213.. + if tagtype == 1 then + print('Setting: UL-EV1 48') + write_otp('00000000') -- Setting OTP to default 00 00 00 00 + write_version('0004030101000b03') -- UL-EV1 (48) 00 04 03 01 01 00 0b 03 + write_type('00') -- based on NTAG213.. - -- Setting UL-Ev1 default config bl 16,17 - connect() - send('a210000000FF') - send('a21100050000') + -- Setting UL-Ev1 default config bl 16,17 + connect() + send('a210000000FF') + send('a21100050000') - elseif tagtype == 2 then - print('Setting: UL-EV1 128') - write_otp('00000000') -- Setting OTP to default 00 00 00 00 - write_version('0004030101000e03') -- UL-EV1 (128) 00 04 03 01 01 00 0e 03 - write_type('01') + elseif tagtype == 2 then + print('Setting: UL-EV1 128') + write_otp('00000000') -- Setting OTP to default 00 00 00 00 + write_version('0004030101000e03') -- UL-EV1 (128) 00 04 03 01 01 00 0e 03 + write_type('01') - -- Setting UL-Ev1 default config bl 37,38 - connect() - send('a225000000FF') - send('a22600050000') - elseif tagtype == 3 then - print('Setting: NTAG 210') - write_version('0004040101000b03') -- NTAG210 00 04 04 01 01 00 0b 03 - write_type('00') + -- Setting UL-Ev1 default config bl 37,38 + connect() + send('a225000000FF') + send('a22600050000') + elseif tagtype == 3 then + print('Setting: NTAG 210') + write_version('0004040101000b03') -- NTAG210 00 04 04 01 01 00 0b 03 + write_type('00') - -- Setting NTAG210 default CC block456 - connect() - send('a203e1100600') - send('a2040300fe00') - send('a20500000000') - -- Setting cfg1/cfg2 - send('a210000000FF') - send('a21100050000') - elseif tagtype == 4 then - print('Setting: NTAG 212') - write_version('0004040101000E03') -- NTAG212 00 04 04 01 01 00 0E 03 - write_type('00') + -- Setting NTAG210 default CC block456 + connect() + send('a203e1100600') + send('a2040300fe00') + send('a20500000000') + -- Setting cfg1/cfg2 + send('a210000000FF') + send('a21100050000') + elseif tagtype == 4 then + print('Setting: NTAG 212') + write_version('0004040101000E03') -- NTAG212 00 04 04 01 01 00 0E 03 + write_type('00') - -- Setting NTAG212 default CC block456 - connect() - send('a203e1101000') - send('a2040103900a') - send('a205340300fe') - -- Setting cfg1/cfg2 - send('a225000000FF') - send('a22600050000') - elseif tagtype == 5 then - print('Setting: NTAG 213') - write_version('0004040201000F03') -- NTAG213 00 04 04 02 01 00 0f 03 - write_type('00') + -- Setting NTAG212 default CC block456 + connect() + send('a203e1101000') + send('a2040103900a') + send('a205340300fe') + -- Setting cfg1/cfg2 + send('a225000000FF') + send('a22600050000') + elseif tagtype == 5 then + print('Setting: NTAG 213') + write_version('0004040201000F03') -- NTAG213 00 04 04 02 01 00 0f 03 + write_type('00') - -- Setting NTAG213 default CC block456 - connect() - send('a203e1101200') - send('a2040103a00c') - send('a205340300fe') - -- setting cfg1/cfg2 - send('a229000000ff') - send('a22a00050000') - elseif tagtype == 6 then - print('Setting: NTAG 215') - write_version('0004040201001103') -- NTAG215 00 04 04 02 01 00 11 03 - write_type('01') + -- Setting NTAG213 default CC block456 + connect() + send('a203e1101200') + send('a2040103a00c') + send('a205340300fe') + -- setting cfg1/cfg2 + send('a229000000ff') + send('a22a00050000') + elseif tagtype == 6 then + print('Setting: NTAG 215') + write_version('0004040201001103') -- NTAG215 00 04 04 02 01 00 11 03 + write_type('01') - -- Setting NTAG215 default CC block456 - connect() - send('a203e1103e00') - send('a2040300fe00') - send('a20500000000') - -- setting cfg1/cfg2 - send('a283000000ff') - send('a28400050000') - elseif tagtype == 7 then - print('Setting: NTAG 216') - write_version('0004040201001303') -- NTAG216 00 04 04 02 01 00 13 03 - write_type('02') + -- Setting NTAG215 default CC block456 + connect() + send('a203e1103e00') + send('a2040300fe00') + send('a20500000000') + -- setting cfg1/cfg2 + send('a283000000ff') + send('a28400050000') + elseif tagtype == 7 then + print('Setting: NTAG 216') + write_version('0004040201001303') -- NTAG216 00 04 04 02 01 00 13 03 + write_type('02') - -- Setting NTAG216 default CC block456 - connect() - send('a203e1106d00') - send('a2040300fe00') - send('a20500000000') - -- setting cfg1/cfg2 - send('a2e3000000ff') - send('a2e400050000') - elseif tagtype == 8 then - print('Setting: NTAG I2C 1K') - write_version('0004040502011303') -- NTAG_I2C_1K 00 04 04 05 02 01 13 03 - write_type('02') + -- Setting NTAG216 default CC block456 + connect() + send('a203e1106d00') + send('a2040300fe00') + send('a20500000000') + -- setting cfg1/cfg2 + send('a2e3000000ff') + send('a2e400050000') + elseif tagtype == 8 then + print('Setting: NTAG I2C 1K') + write_version('0004040502011303') -- NTAG_I2C_1K 00 04 04 05 02 01 13 03 + write_type('02') - -- Setting NTAG I2C 1K default CC block456 - connect() - send('a203e1106D00') - send('a2040300fe00') - send('a20500000000') - elseif tagtype == 9 then - print('Setting: NTAG I2C 2K') - write_version('0004040502011503') -- NTAG_I2C_2K 00 04 04 05 02 01 15 03 - write_type('02') + -- Setting NTAG I2C 1K default CC block456 + connect() + send('a203e1106D00') + send('a2040300fe00') + send('a20500000000') + elseif tagtype == 9 then + print('Setting: NTAG I2C 2K') + write_version('0004040502011503') -- NTAG_I2C_2K 00 04 04 05 02 01 15 03 + write_type('02') - -- Setting NTAG I2C 2K default CC block456 - connect() - send('a203e110EA00') - send('a2040300fe00') - send('a20500000000') - elseif tagtype == 10 then - print('Setting: NTAG I2C plus 1K') - write_version('0004040502021303') -- NTAG_I2C_1K 00 04 04 05 02 02 13 03 - write_type('02') + -- Setting NTAG I2C 2K default CC block456 + connect() + send('a203e110EA00') + send('a2040300fe00') + send('a20500000000') + elseif tagtype == 10 then + print('Setting: NTAG I2C plus 1K') + write_version('0004040502021303') -- NTAG_I2C_1K 00 04 04 05 02 02 13 03 + write_type('02') - -- Setting NTAG I2C 1K default CC block456 - connect() - send('a203e1106D00') - send('a2040300fe00') - send('a20500000000') - elseif tagtype == 11 then - print('Setting: NTAG I2C plus 2K') - write_version('0004040502021503') -- NTAG_I2C_2K 00 04 04 05 02 02 15 03 - write_type('02') + -- Setting NTAG I2C 1K default CC block456 + connect() + send('a203e1106D00') + send('a2040300fe00') + send('a20500000000') + elseif tagtype == 11 then + print('Setting: NTAG I2C plus 2K') + write_version('0004040502021503') -- NTAG_I2C_2K 00 04 04 05 02 02 15 03 + write_type('02') - -- Setting NTAG I2C 2K default CC block456 - connect() - send('a203e1106D00') - send('a2040300fe00') - send('a20500000000') - elseif tagtype == 12 then - print('Setting: NTAG 213F') - write_version('0004040401000F03') -- NTAG213F 00 04 04 04 01 00 0f 03 - write_type('00') + -- Setting NTAG I2C 2K default CC block456 + connect() + send('a203e1106D00') + send('a2040300fe00') + send('a20500000000') + elseif tagtype == 12 then + print('Setting: NTAG 213F') + write_version('0004040401000F03') -- NTAG213F 00 04 04 04 01 00 0f 03 + write_type('00') - -- Setting NTAG213 default CC block456 - connect() - send('a203e1101200') - send('a2040103a00c') - send('a205340300fe') - -- setting cfg1/cfg2 - send('a229000000ff') - send('a22a00050000') - elseif tagtype == 13 then - print('Setting: NTAG 216F') - write_version('0004040401001303') -- NTAG216F 00 04 04 04 01 00 13 03 - write_type('02') + -- Setting NTAG213 default CC block456 + connect() + send('a203e1101200') + send('a2040103a00c') + send('a205340300fe') + -- setting cfg1/cfg2 + send('a229000000ff') + send('a22a00050000') + elseif tagtype == 13 then + print('Setting: NTAG 216F') + write_version('0004040401001303') -- NTAG216F 00 04 04 04 01 00 13 03 + write_type('02') - -- Setting NTAG216 default CC block456 - connect() - send('a203e1106d00') - send('a2040300fe00') - send('a20500000000') - -- setting cfg1/cfg2 - send('a2e3000000ff') - send('a2e400050000') - end + -- Setting NTAG216 default CC block456 + connect() + send('a203e1106d00') + send('a2040300fe00') + send('a20500000000') + -- setting cfg1/cfg2 + send('a2e3000000ff') + send('a2e400050000') + end - lib14a.disconnect() - if resp == '04' then - return nil, 'Failed to set type' - else - return true, 'Ok' - end + lib14a.disconnect() + if resp == '04' then + return nil, 'Failed to set type' + else + return true, 'Ok' + end end --- -- wipe tag local function wipe() - local info = connect() + local info = connect() if not info then return false, "Can't select card" end - local err, msg, resp - local cmd_empty = 'A2%02X00000000' - local cmd_cfg1 = 'A2%02X000000FF' - local cmd_cfg2 = 'A2%02X00050000' + local err, msg, resp + local cmd_empty = 'A2%02X00000000' + local cmd_cfg1 = 'A2%02X000000FF' + local cmd_cfg2 = 'A2%02X00050000' - print('Wiping tag') + print('Wiping tag') - for b = 3, 0xFB do - --configuration block 0 - if b == 0x29 or b == 0x83 or b == 0xe3 then - local cmd = (cmd_cfg1):format(b) - resp = send(cmd) - --configuration block 1 - elseif b == 0x2a or b == 0x84 or b == 0xe4 then - local cmd = (cmd_cfg2):format(b) - resp = send(cmd) - else - resp = send(cmd_empty:format(b)) - end - if resp == '04' or #resp == 0 then - io.write('\nwrote block '..b, ' failed\n') - err = true - else - io.write('.') - end - io.flush() - end - io.write('\r\n') + for b = 3, 0xFB do + --configuration block 0 + if b == 0x29 or b == 0x83 or b == 0xe3 then + local cmd = (cmd_cfg1):format(b) + resp = send(cmd) + --configuration block 1 + elseif b == 0x2a or b == 0x84 or b == 0xe4 then + local cmd = (cmd_cfg2):format(b) + resp = send(cmd) + else + resp = send(cmd_empty:format(b)) + end + if resp == '04' or #resp == 0 then + io.write('\nwrote block '..b, ' failed\n') + err = true + else + io.write('.') + end + io.flush() + end + io.write('\r\n') - lib14a.disconnect() + lib14a.disconnect() - if err then return nil, "Tag locked down, "..err_lock end + if err then return nil, "Tag locked down, "..err_lock end - print('setting default values...') + print('setting default values...') - set_password(nil) + set_password(nil) - -- set NTAG213 default values - err, msg = set_type(5) - if err == nil then return err, msg end + -- set NTAG213 default values + err, msg = set_type(5) + if err == nil then return err, msg end - --set UID - err, msg = write_uid('04112233445566') - if err == nil then return err, msg end + --set UID + err, msg = write_uid('04112233445566') + if err == nil then return err, msg end - --set pwd - err, msg = write_pwd('FFFFFFFF') - if err == nil then return err, msg end + --set pwd + err, msg = write_pwd('FFFFFFFF') + if err == nil then return err, msg end - --set pack - err, msg = write_pack('0000') - if err == nil then return err, msg end + --set pack + err, msg = write_pack('0000') + if err == nil then return err, msg end - return true, 'Ok' + return true, 'Ok' end --- -- The main entry point function main(args) - print( string.rep('--',20) ) - print( string.rep('--',20) ) - print() + print( string.rep('--',20) ) + print( string.rep('--',20) ) + print() - local err, msg + local err, msg - if #args == 0 then return help() end + if #args == 0 then return help() end - -- Read the parameters - for o, a in getopt.getopt(args, 'hck:u:t:p:a:s:o:v:w') do + -- Read the parameters + for o, a in getopt.getopt(args, 'hck:u:t:p:a:s:o:v:w') do - -- help - if o == "h" then return help() end + -- help + if o == "h" then return help() end - --key - if o == 'k' then err, msg = set_password(a) end + --key + if o == 'k' then err, msg = set_password(a) end - -- configuration - if o == "c" then err, msg = read_config() end + -- configuration + if o == "c" then err, msg = read_config() end - --wipe tag - if o == "w" then err, msg = wipe() end + --wipe tag + if o == "w" then err, msg = wipe() end - -- write uid - if o == "u" then err, msg = write_uid(a) end + -- write uid + if o == "u" then err, msg = write_uid(a) end - -- write type/version - if o == "t" then err, msg = set_type(a) end + -- write type/version + if o == "t" then err, msg = set_type(a) end - -- write pwd - if o == "p" then err, msg = write_pwd(a) end + -- write pwd + if o == "p" then err, msg = write_pwd(a) end - -- write pack - if o == "a" then err, msg = write_pack(a) end + -- write pack + if o == "a" then err, msg = write_pack(a) end - -- write signature - if o == "s" then err, msg = write_signature(a) end + -- write signature + if o == "s" then err, msg = write_signature(a) end - -- write otp - if o == "o" then err, msg = write_otp(a) end + -- write otp + if o == "o" then err, msg = write_otp(a) end - -- write version - if o == "v" then err, msg = write_version(a) end + -- write version + if o == "v" then err, msg = write_version(a) end - if err == nil then return oops(msg) end - end + if err == nil then return oops(msg) end + end end diff --git a/client/luascripts/lf_em_tearoff.lua b/client/luascripts/lf_em_tearoff.lua new file mode 100644 index 000000000..2aa0dd5ee --- /dev/null +++ b/client/luascripts/lf_em_tearoff.lua @@ -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 ] [-a ] [-p ] [-s ] [-e ] [-r ] [-w ] +]] +arguments = [[ + -h This help + -n steps in milliseconds for each tearoff + -a address to target on card + -p (optional) use a password + -s initial start delay + -e end delay, must be larger than start delay + -r 4 hex bytes value to be read + -w 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) diff --git a/client/luascripts/lf_em_tearoff_protect.lua b/client/luascripts/lf_em_tearoff_protect.lua new file mode 100644 index 000000000..49ee99cec --- /dev/null +++ b/client/luascripts/lf_em_tearoff_protect.lua @@ -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 ] [-p ] [-s ] [-e ] +]] +arguments = [[ + -h This help + -n steps in milliseconds for each tear-off + -p (optional) use a password + -s initial start delay + -e 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) diff --git a/client/luascripts/lf_hid_bulkclone.lua b/client/luascripts/lf_hid_bulkclone.lua index dae59a53c..0e74f82b5 100644 --- a/client/luascripts/lf_hid_bulkclone.lua +++ b/client/luascripts/lf_hid_bulkclone.lua @@ -192,7 +192,7 @@ local function main(args) print('Press enter to program card '..cardnum..':'..facility..' (hex: '..card..')') --This would be better with 'press Enter', but we'll take what we can get. io.read() - core.console( ('lf hid clone %s'):format(card) ) + core.console( ('lf hid clone -r %s'):format(card) ) end end diff --git a/client/luascripts/multi_bruteforce.lua b/client/luascripts/multi_bruteforce.lua index ef1edc697..e9b320058 100644 --- a/client/luascripts/multi_bruteforce.lua +++ b/client/luascripts/multi_bruteforce.lua @@ -18,7 +18,7 @@ desc = [[ \ / \ / `---' `---' -*SUPPORTED TAGS: pyramid, awid, fdx, jablotron, noralsy, presco, visa2000, 14a, hid +*SUPPORTED TAGS: pyramid, awid, fdxb, jablotron, noralsy, presco, visa2000, 14a, hid This script uses the Proxmark3 implementations of simulation to bruteforce given ranges of id. It uses both LF and HF simulations. @@ -42,7 +42,7 @@ arguments = [[ -r *see below RFID Tag: the RFID tag to emulate pyramid awid - fdx + fdxb jablotron noralsy presco @@ -180,8 +180,8 @@ local function main(args) consolecommand = 'lf awid sim' rfidtagname = 'AWID' facilityrequired = 1 - elseif rfidtag == 'fdx' then -- I'm not sure why you would need to bruteforce this ¯\_(ツ)_/¯ - consolecommand = 'lf fdx sim' + elseif rfidtag == 'fdxb' then -- I'm not sure why you would need to bruteforce this ¯\_(ツ)_/¯ + consolecommand = 'lf fdxb sim' rfidtagname = 'FDX-B' facilityrequired = 1 elseif rfidtag == 'jablotron' then @@ -214,7 +214,7 @@ local function main(args) end facilityrequired = 0 -- Disable the FC required check, as we used it for type instead of FC elseif rfidtag == 'hid' then - consolecommand = 'lf hid sim' + consolecommand = 'lf hid sim -r' rfidtagname = 'HID' facilityrequired = 1 else -- Display error and exit out if bad RFID tag was supplied diff --git a/client/luascripts/tests/data_tracetest.lua b/client/luascripts/tests/data_tracetest.lua index 2ce83116c..1e75b707b 100644 --- a/client/luascripts/tests/data_tracetest.lua +++ b/client/luascripts/tests/data_tracetest.lua @@ -77,7 +77,7 @@ local function main(args) print( string.rep('--',20) ) print( string.rep('--',20) ) - local cmdDataLoad = 'data load %s'; + local cmdDataLoad = 'data load -f %s'; local cwd = core.cwd(); local tracesEM = "find '"..cwd.."/traces/ ' -iname 'em*.pm3' -type f" diff --git a/client/src/cmdcrc.c b/client/src/cmdcrc.c index 8830f5530..4f241dcee 100644 --- a/client/src/cmdcrc.c +++ b/client/src/cmdcrc.c @@ -25,6 +25,7 @@ #include "reveng.h" #include "ui.h" #include "util.h" +#include "pm3_cmd.h" #define MAX_ARGS 20 @@ -253,7 +254,6 @@ int RunModel(char *inModel, char *inHexStr, bool reverse, char endian, char *res int ibperhx = 8, obperhx = 8; // int rflags = 0; // search flags - int c; poly_t apoly, crc; char *string; @@ -265,7 +265,7 @@ int RunModel(char *inModel, char *inHexStr, bool reverse, char endian, char *res SETBMP(); //set model - c = mbynam(&model, inModel); + int c = mbynam(&model, inModel); if (!c) { PrintAndLogEx(ERR, "error: preset model '%s' not found. Use reveng -D to list presets. [%d]", inModel, c); return 0; @@ -405,7 +405,7 @@ static int CmdrevengSearch(const char *Cmd) { #define NMODELS 106 - char inHexStr[100] = {0x00}; + char inHexStr[256] = {0x00}; int dataLen = param_getstr(Cmd, 0, inHexStr, sizeof(inHexStr)); if (dataLen < 4) return 0; @@ -418,7 +418,12 @@ static int CmdrevengSearch(const char *Cmd) { char revResult[30]; int ans = GetModels(Models, &count, width); bool found = false; - if (!ans) return 0; + if (!ans) { + for (int i = 0; i < count; i++) { + free(Models[i]); + } + return 0; + } // try each model and get result for (int i = 0; i < count; i++) { @@ -429,8 +434,10 @@ static int CmdrevengSearch(const char *Cmd) { // round up to # of characters in this model's crc uint8_t crcChars = ((width[i] + 7) / 8) * 2; // can't test a model that has more crc digits than our data - if (crcChars >= dataLen) + if (crcChars >= dataLen) { + free(Models[i]); continue; + } PrintAndLogEx(DEBUG , "DEBUG: dataLen %d, crcChars %u, width[i] %u" @@ -439,8 +446,10 @@ static int CmdrevengSearch(const char *Cmd) { , width[i] ); - if (crcChars == 0) + if (crcChars == 0) { + free(Models[i]); continue; + } memset(result, 0, 30); char *inCRC = calloc(crcChars + 1, sizeof(char)); @@ -492,26 +501,29 @@ static int CmdrevengSearch(const char *Cmd) { free(Models[i]); } - if (!found) PrintAndLogEx(FAILED, "\nno matches found\n"); - return 1; + if (found == false) + PrintAndLogEx(FAILED, "\nno matches found\n"); + + return PM3_SUCCESS; } int CmdCrc(const char *Cmd) { - char name[] = {"reveng "}; - char Cmd2[100 + 7]; - memcpy(Cmd2, name, 7); - memcpy(Cmd2 + 7, Cmd, 100); + char c[100 + 7]; + snprintf(c, sizeof(c), "reveng "); + snprintf(c + strlen(c), sizeof(c) - strlen(c), Cmd, strlen(Cmd)); + char *argv[MAX_ARGS]; - int argc = split(Cmd2, argv); + int argc = split(c, argv); if (argc == 3 && memcmp(argv[1], "-g", 2) == 0) { CmdrevengSearch(argv[2]); } else { reveng_main(argc, argv); } + for (int i = 0; i < argc; ++i) { free(argv[i]); } - return 0; + return PM3_SUCCESS; } diff --git a/client/src/cmddata.c b/client/src/cmddata.c index cdbf1f04b..bb831f311 100644 --- a/client/src/cmddata.c +++ b/client/src/cmddata.c @@ -27,31 +27,17 @@ #include "fileutils.h" // searchFile #include "mifare/ndef.h" #include "cliparser.h" +#include "cmdlft55xx.h" // print... uint8_t DemodBuffer[MAX_DEMOD_BUF_LEN]; size_t DemodBufferLen = 0; -size_t g_DemodStartIdx = 0; +int32_t g_DemodStartIdx = 0; int g_DemodClock = 0; static int CmdHelp(const char *Cmd); -static int usage_data_save(void) { - PrintAndLogEx(NORMAL, "Save trace from graph window , i.e. the GraphBuffer"); - PrintAndLogEx(NORMAL, "This is a text file with number -127 to 127. With the option `w` you can save it as wave file"); - PrintAndLogEx(NORMAL, "Filename should be without file extension"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: data save [h] [w] [f ]"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h this help"); - PrintAndLogEx(NORMAL, " w save as wave format (.wav)"); - PrintAndLogEx(NORMAL, " f save file name"); - PrintAndLogEx(NORMAL, "Samples:"); - PrintAndLogEx(NORMAL, " data save f mytrace - save graphbuffer to file"); - PrintAndLogEx(NORMAL, " data save f mytrace w - save graphbuffer to wave file"); - return PM3_SUCCESS; -} static int usage_data_printdemodbuf(void) { - PrintAndLogEx(NORMAL, "Usage: data printdemodbuffer x o l "); + PrintAndLogEx(NORMAL, "Usage: data print x o l "); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h this help"); PrintAndLogEx(NORMAL, " i invert Demodbuffer before printing"); @@ -236,15 +222,6 @@ static int usage_data_autocorr(void) { PrintAndLogEx(NORMAL, " g save back to GraphBuffer (overwrite)"); return PM3_SUCCESS; } -static int usage_data_undecimate(void) { - PrintAndLogEx(NORMAL, "Usage: data undec [factor]"); - PrintAndLogEx(NORMAL, "This function performs un-decimation, by repeating each sample N times"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h This help"); - PrintAndLogEx(NORMAL, " factor The number of times to repeat each sample.[default:2]"); - PrintAndLogEx(NORMAL, "Example: 'data undec 3'"); - return PM3_SUCCESS; -} static int usage_data_detectclock(void) { PrintAndLogEx(NORMAL, "Usage: data detectclock [modulation] "); PrintAndLogEx(NORMAL, " [modulation as char], specify the modulation type you want to detect the clock of"); @@ -269,7 +246,7 @@ static int usage_data_bin2hex(void) { } static int usage_data_buffclear(void) { PrintAndLogEx(NORMAL, "This function clears the bigbuff on deviceside"); - PrintAndLogEx(NORMAL, "Usage: data buffclear [h]"); + PrintAndLogEx(NORMAL, "Usage: data clear [h]"); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h This help"); return PM3_SUCCESS; @@ -544,6 +521,7 @@ static int CmdConvertBitStream(const char *Cmd) { //emSearch will auto search for EM410x format in bitstream //askType switches decode: ask/raw = 0, ask/manchester = 1 int ASKDemod_ext(int clk, int invert, int maxErr, size_t maxLen, bool amplify, bool verbose, bool emSearch, uint8_t askType, bool *stCheck) { + PrintAndLogEx(DEBUG, "DEBUG: (ASKDemod_ext) clk %i invert %i maxErr %i maxLen %zu amplify %i verbose %i emSearch %i askType %i ", clk, invert, maxErr, maxLen, amplify, verbose, emSearch, askType); uint8_t askamp = 0; if (!maxLen) maxLen = pm3_capabilities.bigbuf_size; @@ -638,28 +616,37 @@ int ASKDemod(int clk, int invert, int maxErr, size_t maxLen, bool amplify, bool //attempts to demodulate ask while decoding manchester //prints binary found and saves in graphbuffer for further commands static int Cmdaskmandemod(const char *Cmd) { + + size_t slen = strlen(Cmd); + char cmdp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) > 45 || cmdp == 'h') return usage_data_rawdemod_am(); - bool st = false; - if (Cmd[0] == 's') { - st = true; - Cmd++; - } else if (Cmd[1] == 's') { - st = true; - Cmd += 2; - } - int clk = 0; - int invert = 0; - int maxErr = 100; + if (slen > 45 || cmdp == 'h') return usage_data_rawdemod_am(); + + bool st = false, amplify = false; + int clk = 0, invert = 0, maxErr = 100; size_t maxLen = 0; - bool amplify = false; - char amp = tolower(param_getchar(Cmd, 0)); - sscanf(Cmd, "%i %i %i %zu %c", &clk, &invert, &maxErr, &maxLen, &); - amplify = amp == 'a'; + + if (slen) { + + if (Cmd[0] == 's') { + st = true; + Cmd++; + } else if (slen > 1 && Cmd[1] == 's') { + st = true; + Cmd += 2; + } + + char amp = tolower(param_getchar(Cmd, 0)); + sscanf(Cmd, "%i %i %i %zu %c", &clk, &invert, &maxErr, &maxLen, &); + + amplify = (amp == 'a'); + } + if (clk == 1) { invert = 1; clk = 0; } + if (invert != 0 && invert != 1) { PrintAndLogEx(WARNING, "Invalid value for invert: %i", invert); return PM3_EINVARG; @@ -998,12 +985,29 @@ static int CmdBuffClear(const char *Cmd) { return PM3_SUCCESS; } -static int CmdDec(const char *Cmd) { - (void)Cmd; // Cmd is not used so far - for (size_t i = 0; i < (GraphTraceLen / 2); ++i) - GraphBuffer[i] = GraphBuffer[i * 2]; - GraphTraceLen /= 2; - PrintAndLogEx(NORMAL, "decimated by 2"); +static int CmdDecimate(const char *Cmd) { + + CLIParserContext *ctx; + CLIParserInit(&ctx, "data decimate", + "Performs decimation, by reducing samples N times in the grapbuf. Good for PSK\n", + "data decimate\n" + "data decimate 4" + ); + + void *argtable[] = { + arg_param_begin, + arg_int0(NULL, NULL, "", "factor to reduce sample set (default 2)"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + int n = arg_get_int_def(ctx, 1, 2); + CLIParserFree(ctx); + + for (size_t i = 0; i < (GraphTraceLen / n); ++i) + GraphBuffer[i] = GraphBuffer[i * n]; + + GraphTraceLen /= n; + PrintAndLogEx(SUCCESS, "decimated by " _GREEN_("%u"), n); RepaintGraphWindow(); return PM3_SUCCESS; } @@ -1014,19 +1018,34 @@ static int CmdDec(const char *Cmd) { * @param Cmd * @return */ -static int CmdUndec(const char *Cmd) { - char cmdp = tolower(param_getchar(Cmd, 0)); - if (cmdp == 'h') return usage_data_undecimate(); +static int CmdUndecimate(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "data undecimate", + "Performs un-decimation, by repeating each sample N times in the graphbuf", + "data undecimate\n" + "data undecimate 4\n" + ); - uint8_t factor = param_get8ex(Cmd, 0, 2, 10); + void *argtable[] = { + arg_param_begin, + arg_int0(NULL, NULL, "", "factor to repeat each sample (default 2)"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + int factor = arg_get_int_def(ctx, 1, 2); + CLIParserFree(ctx); //We have memory, don't we? int swap[MAX_GRAPH_TRACE_LEN] = {0}; uint32_t g_index = 0, s_index = 0; while (g_index < GraphTraceLen && s_index + factor < MAX_GRAPH_TRACE_LEN) { int count = 0; - for (count = 0; count < factor && s_index + count < MAX_GRAPH_TRACE_LEN; count++) - swap[s_index + count] = GraphBuffer[g_index]; + for (count = 0; count < factor && s_index + count < MAX_GRAPH_TRACE_LEN; count++) { + swap[s_index + count] = ( + (double)(factor - count) / (factor - 1)) * GraphBuffer[g_index] + + ((double)count / factor) * GraphBuffer[g_index + 1] + ; + } s_index += count; g_index++; } @@ -1437,7 +1456,7 @@ void setClockGrid(uint32_t clk, int offset) { } int CmdGrid(const char *Cmd) { - sscanf(Cmd, "%i %i", &PlotGridX, &PlotGridY); + sscanf(Cmd, "%lf %lf", &PlotGridX, &PlotGridY); PlotGridXdefault = PlotGridX; PlotGridYdefault = PlotGridY; RepaintGraphWindow(); @@ -1675,6 +1694,48 @@ int CmdTuneSamples(const char *Cmd) { if (package->peak_v > NON_VOLTAGE && package->peak_f > 0) PrintAndLogEx(SUCCESS, "LF optimal: %5.2f V - %6.2f kHz", (package->peak_v * ANTENNA_ERROR) / 1000.0, LF_DIV2FREQ(package->peak_f)); + const double vdd_rdv4 = 9000; + const double vdd_other = 5400; // Empirical measures in mV + double vdd = IfPm3Rdv4Fw() ? vdd_rdv4 : vdd_other; + if (package->peak_v > NON_VOLTAGE && package->peak_f > 0) { + + // Q measure with Q=f/delta_f + double v_3db_scaled = (double)(package->peak_v * 0.707) / 512; // /512 == >>9 + uint32_t s2 = 0, s4 = 0; + for (int i = 1; i < 256; i++) { + if ((s2 == 0) && (package->results[i] > v_3db_scaled)) { + s2 = i; + } + if ((s2 != 0) && (package->results[i] < v_3db_scaled)) { + s4 = i; + break; + } + } + double lfq1 = 0; + if (s4 != 0) { // we got all our points of interest + double a = package->results[s2 - 1]; + double b = package->results[s2]; + double f1 = LF_DIV2FREQ(s2 - 1 + (v_3db_scaled - a) / (b - a)); + double c = package->results[s4 - 1]; + double d = package->results[s4]; + double f2 = LF_DIV2FREQ(s4 - 1 + (c - v_3db_scaled) / (c - d)); + lfq1 = LF_DIV2FREQ(package->peak_f) / (f1 - f2); + PrintAndLogEx(SUCCESS, "Approx. Q factor (*): %.1lf by frequency bandwidth measurement", lfq1); + } + + // Q measure with Vlr=Q*(2*Vdd/pi) + double lfq2 = (double)package->peak_v * 3.14 / 2 / vdd; + PrintAndLogEx(SUCCESS, "Approx. Q factor (*): %.1lf by peak voltage measurement", lfq2); + // cross-check results + if (lfq1 > 3) { + double approx_vdd = (double)package->peak_v * 3.14 / 2 / lfq1; + if ((approx_vdd > (vdd_rdv4 + vdd_other) / 2) && (! IfPm3Rdv4Fw())) + PrintAndLogEx(WARNING, "Contradicting measures seem to indicate you're running a " _YELLOW_("PM3_OTHER firmware on a RDV4") ", please check your setup"); + if ((approx_vdd < (vdd_rdv4 + vdd_other) / 2) && (IfPm3Rdv4Fw())) + PrintAndLogEx(WARNING, "Contradicting measures seem to indicate you're running a " _YELLOW_("PM3_RDV4 firmware on a non-RDV4") ", please check your setup"); + } + } + char judgement[20]; memset(judgement, 0, sizeof(judgement)); // LF evaluation @@ -1694,6 +1755,11 @@ int CmdTuneSamples(const char *Cmd) { memset(judgement, 0, sizeof(judgement)); + if (package->v_hf >= HF_UNUSABLE_V) { + // Q measure with Vlr=Q*(2*Vdd/pi) + double hfq = (double)package->v_hf * 3.14 / 2 / vdd; + PrintAndLogEx(SUCCESS, "Approx. Q factor (*): %.1lf by peak voltage measurement", hfq); + } if (package->v_hf < HF_UNUSABLE_V) sprintf(judgement, _RED_("UNUSABLE")); else if (package->v_hf < HF_MARGINAL_V) @@ -1702,6 +1768,7 @@ int CmdTuneSamples(const char *Cmd) { sprintf(judgement, _GREEN_("OK")); PrintAndLogEx((package->v_hf < HF_UNUSABLE_V) ? WARNING : SUCCESS, "HF antenna is %s", judgement); + PrintAndLogEx(NORMAL, "\n(*) Q factor must be measured without tag on the antenna"); // graph LF measurements // even here, these values has 3% error. @@ -1712,9 +1779,11 @@ int CmdTuneSamples(const char *Cmd) { } if (test1 > 0) { - PrintAndLogEx(SUCCESS, "\nDisplaying LF tuning graph. Divisor %d is %.2f kHz, %d is %.2f kHz.\n\n", + PrintAndLogEx(SUCCESS, "\nDisplaying LF tuning graph. Divisor %d (blue) is %.2f kHz, %d (red) is %.2f kHz.\n\n", LF_DIVISOR_134, LF_DIV2FREQ(LF_DIVISOR_134), LF_DIVISOR_125, LF_DIV2FREQ(LF_DIVISOR_125)); GraphTraceLen = 256; + CursorCPos = LF_DIVISOR_125; + CursorDPos = LF_DIVISOR_134; ShowGraphWindow(); RepaintGraphWindow(); } else { @@ -1726,16 +1795,26 @@ int CmdTuneSamples(const char *Cmd) { } static int CmdLoad(const char *Cmd) { - char filename[FILE_PATH_SIZE] = {0x00}; - int len = 0; - len = strlen(Cmd); - if (len == 0) return PM3_EFILE; + CLIParserContext *ctx; + CLIParserInit(&ctx, "data load", + "This command loads the contents of a pm3 file into graph window\n", + "data load -f myfilename" + ); - if (len > FILE_PATH_SIZE) len = FILE_PATH_SIZE; - memcpy(filename, Cmd, len); + void *argtable[] = { + arg_param_begin, + arg_strx0("f", "file", "", "file to load"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); - char *path; + int fnlen = 0; + char filename[FILE_PATH_SIZE] = {0}; + CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); + CLIParserFree(ctx); + + char *path = NULL; if (searchFile(&path, TRACES_SUBDIR, filename, ".pm3", true) != PM3_SUCCESS) { if (searchFile(&path, TRACES_SUBDIR, filename, "", false) != PM3_SUCCESS) { return PM3_EFILE; @@ -1759,7 +1838,6 @@ static int CmdLoad(const char *Cmd) { if (GraphTraceLen >= MAX_GRAPH_TRACE_LEN) break; } - fclose(f); PrintAndLogEx(SUCCESS, "loaded " _YELLOW_("%zu") " samples", GraphTraceLen); @@ -1789,6 +1867,7 @@ int CmdLtrim(const char *Cmd) { GraphBuffer[i - ds] = GraphBuffer[i]; GraphTraceLen -= ds; + g_DemodStartIdx -= ds; RepaintGraphWindow(); return PM3_SUCCESS; } @@ -1811,7 +1890,7 @@ static int CmdMtrim(const char *Cmd) { uint32_t start = 0, stop = 0; sscanf(Cmd, "%u %u", &start, &stop); - if (start > GraphTraceLen || stop > GraphTraceLen || start >= stop) + if (start > GraphTraceLen || stop > GraphTraceLen || start >= stop) return PM3_ESOFT; // leave start position sample @@ -1858,39 +1937,29 @@ int CmdPlot(const char *Cmd) { int CmdSave(const char *Cmd) { - int len = 0; - char filename[FILE_PATH_SIZE] = {0x00}; - uint8_t cmdp = 0; - bool errors = false, as_wave = false, has_name = false; + CLIParserContext *ctx; + CLIParserInit(&ctx, "data save", + "Save trace from graph window , i.e. the GraphBuffer\n" + "This is a text file with number -127 to 127. With the option `w` you can save it as wave file\n" + "Filename should be without file extension", + "data save -f myfilename -> save graph buffer to file\n" + "data save --wave -f myfilename -> save graph buffer to wave file" + ); - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - char ctmp = tolower(param_getchar(Cmd, cmdp)); - switch (ctmp) { - case 'h': - return usage_data_save(); - case 'f': - len = param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE); - if (len < 1) { - errors = true; - break; - } - has_name = true; - cmdp += 2; - break; - case 'w': - as_wave = true; - cmdp++; - break; - default: - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } + void *argtable[] = { + arg_param_begin, + arg_lit0("w", "wave", "save as wave format (.wav)"), + arg_strx0("f", "file", "", "save file name"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); - if (!has_name) errors = true; + bool as_wave = arg_get_lit(ctx, 1); - if (errors || cmdp == 0) return usage_data_save(); + int fnlen = 0; + char filename[FILE_PATH_SIZE] = {0}; + CLIGetStrWithReturn(ctx, 2, (uint8_t *)filename, &fnlen); + CLIParserFree(ctx); if (as_wave) return saveFileWAVE(filename, GraphBuffer, GraphTraceLen); @@ -1898,32 +1967,32 @@ int CmdSave(const char *Cmd) { return saveFilePM3(filename, GraphBuffer, GraphTraceLen); } -static int CmdScale(const char *Cmd) { +static int CmdTimeScale(const char *Cmd) { CLIParserContext *ctx; - CLIParserInit(&ctx, "data scale", - "Set cursor display scale.\n" - "Setting the scale makes the differential `dt` reading between the yellow and purple markers meaningful.\n" - "once the scale is set, the differential reading between brackets can become a time duration.", - "data scale --sr 125 -u ms -> for LF sampled at 125 kHz. Reading will be in milliseconds\n" - "data scale --sr 1.695 -u us -> for HF sampled at 1.695 MHz. Reading will be in microseconds\n" - "data scale --sr 16 -u ETU -> for HF with 16 samples per ETU. Reading will be in ETUs" - ); + CLIParserInit(&ctx, "data timescale", + "Set cursor display timescale.\n" + "Setting the timescale makes the differential `dt` reading between the yellow and purple markers meaningful.\n" + "once the timescale is set, the differential reading between brackets can become a time duration.", + "data timescale --sr 125 -u ms -> for LF sampled at 125 kHz. Reading will be in milliseconds\n" + "data timescale --sr 1.695 -u us -> for HF sampled at 16 * fc/128. Reading will be in microseconds\n" + "data timescale --sr 16 -u ETU -> for HF with 16 samples per ETU (fc/128). Reading will be in ETUs" + ); void *argtable[] = { arg_param_begin, - arg_dbl1(NULL, "sr", "", "sets scale according to sampling rate"), + arg_dbl1(NULL, "sr", "", "sets timescale factor according to sampling rate"), arg_str0("u", "unit", "", "time unit to display (max 10 chars)"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); CursorScaleFactor = arg_get_dbl_def(ctx, 1, 1); if (CursorScaleFactor <= 0) { - PrintAndLogEx(FAILED, "bad, can't have negative or zero scale"); + PrintAndLogEx(FAILED, "bad, can't have negative or zero timescale factor"); CursorScaleFactor = 1; } int len = 0; CursorScaleFactorUnit[0] = '\x00'; - CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t*)CursorScaleFactorUnit, sizeof(CursorScaleFactorUnit), &len); + CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)CursorScaleFactorUnit, sizeof(CursorScaleFactorUnit), &len); CLIParserFree(ctx); RepaintGraphWindow(); return PM3_SUCCESS; @@ -2298,45 +2367,206 @@ static int CmdDataNDEF(const char *Cmd) { return res; } +typedef struct { + t55xx_modulation modulation; + int bitrate; + int carrier; + uint8_t fc1; + uint8_t fc2; +} lf_modulation_t; + +static int print_modulation(lf_modulation_t b) { + PrintAndLogEx(INFO, " Modulation.... " _GREEN_("%s"), GetSelectedModulationStr(b.modulation)); + PrintAndLogEx(INFO, " Bit clock..... " _GREEN_("RF/%d"), b.bitrate); + switch (b.modulation) { + case DEMOD_PSK1: + case DEMOD_PSK2: + case DEMOD_PSK3: + PrintAndLogEx(SUCCESS, " Carrier rate.. %d", b.carrier); + break; + case DEMOD_FSK: + case DEMOD_FSK1: + case DEMOD_FSK1a: + case DEMOD_FSK2: + case DEMOD_FSK2a: + PrintAndLogEx(SUCCESS, " Field Clocks.. FC/%u, FC/%u", b.fc1, b.fc2); + break; + case DEMOD_NRZ: + case DEMOD_ASK: + case DEMOD_BI: + case DEMOD_BIa: + default: + break; + } + PrintAndLogEx(NORMAL, ""); + return PM3_SUCCESS; +} + +static int try_detect_modulation(void) { + + lf_modulation_t tests[6]; + int clk = 0, firstClockEdge = 0; + uint8_t hits = 0, ans = 0; + uint8_t fc1 = 0, fc2 = 0; + bool st = false; + + ans = fskClocks(&fc1, &fc2, (uint8_t *)&clk, &firstClockEdge); + + if (ans && ((fc1 == 10 && fc2 == 8) || (fc1 == 8 && fc2 == 5))) { + + if ((FSKrawDemod(0, 0, 0, 0, false) == PM3_SUCCESS)) { + tests[hits].modulation = DEMOD_FSK; + if (fc1 == 8 && fc2 == 5) { + tests[hits].modulation = DEMOD_FSK1a; + } else if (fc1 == 10 && fc2 == 8) { + tests[hits].modulation = DEMOD_FSK2; + } + + tests[hits].bitrate = clk; + tests[hits].fc1 = fc1; + tests[hits].fc2 = fc2; + ++hits; + } + + } else { + clk = GetAskClock("", false); + if (clk > 0) { + // 0 = auto clock + // 0 = no invert + // 1 = maxError 1 + // 0 = max len + // false = no amplify + // false = no verbose + // false = no emSearch + // 1 = Ask/Man + // st = true + if ((ASKDemod_ext(0, 0, 1, 0, false, false, false, 1, &st) == PM3_SUCCESS)) { + tests[hits].modulation = DEMOD_ASK; + tests[hits].bitrate = clk; + ++hits; + } + // "0 0 1 " == clock auto, invert true, maxError 1. + // false = no verbose + // false = no emSearch + // 1 = Ask/Man + // st = true + + // ASK / biphase + if ((ASKbiphaseDemod(0, 0, 0, 2, false) == PM3_SUCCESS)) { + tests[hits].modulation = DEMOD_BI; + tests[hits].bitrate = clk; + ++hits; + } + // ASK / Diphase + if ((ASKbiphaseDemod(0, 0, 1, 2, false) == PM3_SUCCESS)) { + tests[hits].modulation = DEMOD_BIa; + tests[hits].bitrate = clk; + ++hits; + } + } + clk = GetNrzClock("", false); + if ((NRZrawDemod(0, 0, 1, false) == PM3_SUCCESS)) { + tests[hits].modulation = DEMOD_NRZ; + tests[hits].bitrate = clk; + ++hits; + } + + clk = GetPskClock("", false); + if (clk > 0) { + // allow undo + save_restoreGB(GRAPH_SAVE); + // skip first 160 samples to allow antenna to settle in (psk gets inverted occasionally otherwise) + CmdLtrim("160"); + if ((PSKDemod(0, 0, 6, false) == PM3_SUCCESS)) { + tests[hits].modulation = DEMOD_PSK1; + tests[hits].bitrate = clk; + ++hits; + + // get psk carrier + tests[hits].carrier = GetPskCarrier(false); + } + //undo trim samples + save_restoreGB(GRAPH_RESTORE); + } + } + + if (hits) { + PrintAndLogEx(SUCCESS, "Found [%d] possible matches for modulation.", hits); + for (int i = 0; i < hits; ++i) { + PrintAndLogEx(INFO, "--[%d]---------------", i + 1); + print_modulation(tests[i]); + } + return PM3_SUCCESS; + } else { + PrintAndLogEx(INFO, "Signal doesn't match"); + return PM3_ESOFT; + } +} + +static int CmdDataModulationSearch(const char *Cmd) { + CLIParserContext *ctx; + CLIParserInit(&ctx, "data modulation", + "search LF signal after clock and modulation\n", + "data modulation" + ); + + void *argtable[] = { + arg_param_begin, + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIParserFree(ctx); + return try_detect_modulation(); +} + static command_t CommandTable[] = { - {"help", CmdHelp, AlwaysAvailable, "This help"}, - {"askedgedetect", CmdAskEdgeDetect, AlwaysAvailable, "[threshold] Adjust Graph for manual ASK demod using the length of sample differences to detect the edge of a wave (use 20-45, def:25)"}, - {"autocorr", CmdAutoCorr, AlwaysAvailable, "[window length] [g] -- Autocorrelation over window - g to save back to GraphBuffer (overwrite)"}, - {"biphaserawdecode", CmdBiphaseDecodeRaw, AlwaysAvailable, "[offset] [invert<0|1>] [maxErr] -- Biphase decode bin stream in DemodBuffer (offset = 0|1 bits to shift the decode start)"}, - {"bin2hex", Cmdbin2hex, AlwaysAvailable, " -- Converts binary to hexadecimal"}, - {"bitsamples", CmdBitsamples, IfPm3Present, "Get raw samples as bitstring"}, - {"buffclear", CmdBuffClear, AlwaysAvailable, "Clears bigbuff on deviceside and graph window"}, - {"convertbitstream", CmdConvertBitStream, AlwaysAvailable, "Convert GraphBuffer's 0/1 values to 127 / -127"}, - {"dec", CmdDec, AlwaysAvailable, "Decimate samples"}, - {"detectclock", CmdDetectClockRate, AlwaysAvailable, "[] Detect ASK, FSK, NRZ, PSK clock rate of wave in GraphBuffer"}, - {"fsktonrz", CmdFSKToNRZ, AlwaysAvailable, "Convert fsk2 to nrz wave for alternate fsk demodulating (for weak fsk)"}, - {"getbitstream", CmdGetBitStream, AlwaysAvailable, "Convert GraphBuffer's >=1 values to 1 and <1 to 0"}, - {"grid", CmdGrid, AlwaysAvailable, " -- overlay grid on graph window, use zero value to turn off either"}, - {"hexsamples", CmdHexsamples, IfPm3Present, " [] -- Dump big buffer as hex bytes"}, - {"hex2bin", Cmdhex2bin, AlwaysAvailable, " -- Converts hexadecimal to binary"}, - {"hide", CmdHide, AlwaysAvailable, "Hide graph window"}, - {"hpf", CmdHpf, AlwaysAvailable, "Remove DC offset from trace"}, - {"load", CmdLoad, AlwaysAvailable, " -- Load trace (to graph window"}, - {"ltrim", CmdLtrim, AlwaysAvailable, " -- Trim samples from left of trace"}, - {"rtrim", CmdRtrim, AlwaysAvailable, " -- Trim samples from right of trace"}, - {"mtrim", CmdMtrim, AlwaysAvailable, " -- Trim out samples from the specified start to the specified stop"}, - {"manrawdecode", Cmdmandecoderaw, AlwaysAvailable, "[invert] [maxErr] -- Manchester decode binary stream in DemodBuffer"}, - {"norm", CmdNorm, AlwaysAvailable, "Normalize max/min to +/-128"}, - {"plot", CmdPlot, AlwaysAvailable, "Show graph window (hit 'h' in window for keystroke help)"}, - {"printdemodbuffer", CmdPrintDemodBuff, AlwaysAvailable, "[x] [o] [l] -- print the data in the DemodBuffer - 'x' for hex output"}, - {"rawdemod", CmdRawDemod, AlwaysAvailable, "[modulation] ... -see help (h option) -- Demodulate the data in the GraphBuffer and output binary"}, - {"samples", CmdSamples, IfPm3Present, "[512 - 40000] -- Get raw samples for graph window (GraphBuffer)"}, - {"save", CmdSave, AlwaysAvailable, "Save trace (from graph window)"}, - {"setgraphmarkers", CmdSetGraphMarkers, AlwaysAvailable, "[orange_marker] [blue_marker] (in graph window)"}, - {"scale", CmdScale, AlwaysAvailable, " -- 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 0 for Graphed wave + or - shift value"}, - {"dirthreshold", CmdDirectionalThreshold, AlwaysAvailable, " -- Max rising higher up-thres/ Min falling lower down-thres, keep rest as prev."}, - {"tune", CmdTuneSamples, IfPm3Present, "Get hw tune samples for graph window"}, - {"undec", CmdUndec, AlwaysAvailable, "Un-decimate samples by 2"}, - {"zerocrossings", CmdZerocrossings, AlwaysAvailable, "Count time between zero-crossings"}, - {"iir", CmdDataIIR, AlwaysAvailable, "apply IIR buttersworth filter on plotdata"}, + {"help", CmdHelp, AlwaysAvailable, "This help"}, + + {"-----------", CmdHelp, AlwaysAvailable, "------------------------- " _CYAN_("Modulation") "-------------------------"}, + {"biphaserawdecode", CmdBiphaseDecodeRaw, AlwaysAvailable, "Biphase decode bin stream in DemodBuffer"}, + {"detectclock", CmdDetectClockRate, AlwaysAvailable, "Detect ASK, FSK, NRZ, PSK clock rate of wave in GraphBuffer"}, + {"fsktonrz", CmdFSKToNRZ, AlwaysAvailable, "Convert fsk2 to nrz wave for alternate fsk demodulating (for weak fsk)"}, + {"manrawdecode", Cmdmandecoderaw, AlwaysAvailable, "Manchester decode binary stream in DemodBuffer"}, + {"modulation", CmdDataModulationSearch, AlwaysAvailable, "Identify LF signal for clock and modulation"}, + {"rawdemod", CmdRawDemod, AlwaysAvailable, "Demodulate the data in the GraphBuffer and output binary"}, + + {"-----------", CmdHelp, AlwaysAvailable, "------------------------- " _CYAN_("Graph") "-------------------------"}, + {"askedgedetect", CmdAskEdgeDetect, AlwaysAvailable, "[threshold] Adjust Graph for manual ASK demod using the length of sample differences to detect the edge of a wave (use 20-45, def:25)"}, + {"autocorr", CmdAutoCorr, AlwaysAvailable, "Autocorrelation over window"}, + {"dirthreshold", CmdDirectionalThreshold, AlwaysAvailable, " -- Max rising higher up-thres/ Min falling lower down-thres, keep rest as prev."}, + {"decimate", CmdDecimate, AlwaysAvailable, "Decimate samples"}, + {"undecimate", CmdUndecimate, AlwaysAvailable, "Un-decimate samples"}, + {"hide", CmdHide, AlwaysAvailable, "Hide graph window"}, + {"hpf", CmdHpf, AlwaysAvailable, "Remove DC offset from trace"}, + {"iir", CmdDataIIR, AlwaysAvailable, "apply IIR buttersworth filter on plotdata"}, + {"grid", CmdGrid, AlwaysAvailable, " -- overlay grid on graph window, use zero value to turn off either"}, + {"ltrim", CmdLtrim, AlwaysAvailable, " -- Trim samples from left of trace"}, + {"mtrim", CmdMtrim, AlwaysAvailable, " -- Trim out samples from the specified start to the specified stop"}, + {"norm", CmdNorm, AlwaysAvailable, "Normalize max/min to +/-128"}, + {"plot", CmdPlot, AlwaysAvailable, "Show graph window (hit 'h' in window for keystroke help)"}, + {"rtrim", CmdRtrim, AlwaysAvailable, " -- Trim samples from right of trace"}, + {"setgraphmarkers", CmdSetGraphMarkers, AlwaysAvailable, "[orange_marker] [blue_marker] (in graph window)"}, + {"shiftgraphzero", CmdGraphShiftZero, AlwaysAvailable, " -- Shift 0 for Graphed wave + or - shift value"}, + {"timescale", CmdTimeScale, AlwaysAvailable, "Set a timescale to get a differential reading between the yellow and purple markers as time duration\n"}, + {"zerocrossings", CmdZerocrossings, AlwaysAvailable, "Count time between zero-crossings"}, + + {"convertbitstream", CmdConvertBitStream, AlwaysAvailable, "Convert GraphBuffer's 0/1 values to 127 / -127"}, + {"getbitstream", CmdGetBitStream, AlwaysAvailable, "Convert GraphBuffer's >=1 values to 1 and <1 to 0"}, + + + {"-----------", CmdHelp, AlwaysAvailable, "------------------------- " _CYAN_("General") "-------------------------"}, + {"bin2hex", Cmdbin2hex, AlwaysAvailable, "Converts binary to hexadecimal"}, + {"bitsamples", CmdBitsamples, IfPm3Present, "Get raw samples as bitstring"}, + {"clear", CmdBuffClear, AlwaysAvailable, "Clears bigbuf on deviceside and graph window"}, + {"hexsamples", CmdHexsamples, IfPm3Present, " [] -- Dump big buffer as hex bytes"}, + {"hex2bin", Cmdhex2bin, AlwaysAvailable, "Converts hexadecimal to binary"}, + {"load", CmdLoad, AlwaysAvailable, "Load contents of file into graph window"}, {"ndef", CmdDataNDEF, AlwaysAvailable, "Decode NDEF records"}, + {"print", CmdPrintDemodBuff, AlwaysAvailable, "print the data in the DemodBuffer"}, + {"samples", CmdSamples, IfPm3Present, "[512 - 40000] -- Get raw samples for graph window (GraphBuffer)"}, + {"save", CmdSave, AlwaysAvailable, "Save signal trace data (from graph window)"}, + {"setdebugmode", CmdSetDebugMode, AlwaysAvailable, "<0|1|2> -- Set Debugging Level on client side"}, + {"tune", CmdTuneSamples, IfPm3Present, "Measure tuning of device antenna. Results shown in graph window"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmddata.h b/client/src/cmddata.h index 86a60a9bb..785e88b49 100644 --- a/client/src/cmddata.h +++ b/client/src/cmddata.h @@ -60,7 +60,7 @@ int CmdPlot(const char *Cmd); int CmdSave(const char *Cmd); // used by cmd auto int CmdTuneSamples(const char *Cmd); // used by cmd lf hw -int ASKbiphaseDemod(int offset, int clk, int invert, int maxErr, bool verbose); // used by cmd lf em4x, lf fdx, lf guard, lf jablotron, lf nedap, lf t55xx +int ASKbiphaseDemod(int offset, int clk, int invert, int maxErr, bool verbose); // used by cmd lf em4x, lf fdxb, lf guard, lf jablotron, lf nedap, lf t55xx int ASKDemod(int clk, int invert, int maxErr, size_t maxLen, bool amplify, bool verbose, bool emSearch, uint8_t askType); // used by cmd lf em4x, lf t55xx, lf viking int ASKDemod_ext(int clk, int invert, int maxErr, size_t maxLen, bool amplify, bool verbose, bool emSearch, uint8_t askType, bool *stCheck); // used by cmd lf, lf em4x, lf noralsy, le presco, lf securekey, lf t55xx, lf visa2k int FSKrawDemod(uint8_t rfLen, uint8_t invert, uint8_t fchigh, uint8_t fclow, bool verbose); // used by cmd lf, lf em4x, lf t55xx @@ -86,7 +86,7 @@ extern uint8_t DemodBuffer[MAX_DEMOD_BUF_LEN]; extern size_t DemodBufferLen; extern int g_DemodClock; -extern size_t g_DemodStartIdx; +extern int32_t g_DemodStartIdx; #ifdef __cplusplus } diff --git a/client/src/cmdflashmem.c b/client/src/cmdflashmem.c index 1262b5645..7f663c45b 100644 --- a/client/src/cmdflashmem.c +++ b/client/src/cmdflashmem.c @@ -27,7 +27,7 @@ static int CmdHelp(const char *Cmd); static int CmdFlashmemSpiBaudrate(const char *Cmd) { - + CLIParserContext *ctx; CLIParserInit(&ctx, "mem baudrate", "Set the baudrate for the SPI flash memory communications.\n" @@ -35,8 +35,8 @@ static int CmdFlashmemSpiBaudrate(const char *Cmd) { "Unless you know what you are doing, please stay at 24MHz.\n" "If >= 24MHz, FASTREADS instead of READS instruction will be used.", "mem baudrate --mhz 48" - ); - + ); + void *argtable[] = { arg_param_begin, arg_int1(NULL, "mhz", "<24|48>", "SPI baudrate in MHz"), @@ -72,7 +72,7 @@ static int CmdFlashMemLoad(const char *Cmd) { "mem load -f mfc_default_keys -m -> upload MFC keys\n" "mem load -f t55xx_default_pwds -t -> upload T55XX passwords\n" "mem load -f iclass_default_keys -i -> upload iCLASS keys\n" - ); + ); void *argtable[] = { arg_param_begin, @@ -88,10 +88,10 @@ static int CmdFlashMemLoad(const char *Cmd) { int offset = arg_get_int_def(ctx, 1, 0); bool is_mfc = arg_get_lit(ctx, 2); bool is_iclass = arg_get_lit(ctx, 3); - bool is_t55xx = arg_get_lit(ctx, 4); + bool is_t55xx = arg_get_lit(ctx, 4); int fnlen = 0; char filename[FILE_PATH_SIZE] = {0}; - CLIParamStrToBuf(arg_get_str(ctx, 5), (uint8_t*)filename, FILE_PATH_SIZE, &fnlen); + CLIParamStrToBuf(arg_get_str(ctx, 5), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); CLIParserFree(ctx); Dictionary_t d = DICTIONARY_NONE; @@ -227,7 +227,7 @@ static int CmdFlashMemDump(const char *Cmd) { "mem dump -f myfile -> download all flashmem to file\n" "mem dump --view -o 262015 --len 128 -> display 128 bytes from offset 262015 (RSA sig)\n" "mem dump --view -f myfile -o 241664 --len 58 -> display 58 bytes from offset 241664 and save to file" - ); + ); void *argtable[] = { arg_param_begin, @@ -244,7 +244,7 @@ static int CmdFlashMemDump(const char *Cmd) { bool view = arg_get_lit(ctx, 3); int fnlen = 0; char filename[FILE_PATH_SIZE] = {0}; - CLIParamStrToBuf(arg_get_str(ctx, 4), (uint8_t*)filename, FILE_PATH_SIZE, &fnlen); + CLIParamStrToBuf(arg_get_str(ctx, 4), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); CLIParserFree(ctx); uint8_t *dump = calloc(len, sizeof(uint8_t)); @@ -282,7 +282,7 @@ static int CmdFlashMemWipe(const char *Cmd) { _WHITE_("[ ") _RED_("!!! OBS") " ] use with caution", "mem wipe -p 0 -> wipes first page" // "mem wipe -i -> inital total wipe" - ); + ); void *argtable[] = { arg_param_begin, @@ -297,7 +297,7 @@ static int CmdFlashMemWipe(const char *Cmd) { // initalwipe = arg_get_lit(ctx, 2); CLIParserFree(ctx); - if (page < 0 || page > 2 ) { + if (page < 0 || page > 2) { PrintAndLogEx(WARNING, "page must be 0, 1 or 2"); return PM3_EINVARG; } @@ -309,8 +309,8 @@ static int CmdFlashMemWipe(const char *Cmd) { PrintAndLogEx(WARNING, "timeout while waiting for reply."); return PM3_ETIMEOUT; } - - const char* msg = "Flash WIPE "; + + const char *msg = "Flash WIPE "; uint8_t isok = resp.oldarg[0] & 0xFF; if (isok) PrintAndLogEx(SUCCESS, "%s ( " _GREEN_("ok")" )", msg); @@ -329,7 +329,7 @@ static int CmdFlashMemInfo(const char *Cmd) { "Collect signature and verify it from flash memory", "mem info" // "mem info -s" - ); + ); void *argtable[] = { arg_param_begin, @@ -375,7 +375,7 @@ static int CmdFlashMemInfo(const char *Cmd) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "--- " _CYAN_("RDV4 RSA signature") " ---------------"); for (int i = 0; i < (sizeof(mem.signature) / 32); i++) { - PrintAndLogEx(INFO, " %s", sprint_hex_inrow(mem.signature + (i * 32), 32)); + PrintAndLogEx(INFO, " %s", sprint_hex_inrow(mem.signature + (i * 32), 32)); } //------------------------------------------------------------------------------- @@ -453,13 +453,13 @@ static int CmdFlashMemInfo(const char *Cmd) { PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "--- " _CYAN_("RDV4 RSA Public key") " --------------"); - char str_exp[10]; + char str_exp[10]; char str_pk[261]; size_t exlen = 0, pklen = 0; mbedtls_mpi_write_string(&rsa.E, 16, str_exp, sizeof(str_exp), &exlen); mbedtls_mpi_write_string(&rsa.N, 16, str_pk, sizeof(str_pk), &pklen); - PrintAndLogEx(INFO, "Len.................. %u", rsa.len); + PrintAndLogEx(INFO, "Len.................. %"PRIu64, rsa.len); PrintAndLogEx(INFO, "Exponent............. %s", str_exp); PrintAndLogEx(INFO, "Public key modulus N"); PrintAndLogEx(INFO, " %.64s", str_pk); @@ -468,7 +468,7 @@ static int CmdFlashMemInfo(const char *Cmd) { PrintAndLogEx(INFO, " %.64s", str_pk + 192); PrintAndLogEx(NORMAL, ""); - const char *msgkey = "RSA key validation... "; + const char *msgkey = "RSA key validation... "; if (is_keyok) PrintAndLogEx(SUCCESS, "%s( " _GREEN_("ok") " )", msgkey); else @@ -511,7 +511,7 @@ static int CmdFlashMemInfo(const char *Cmd) { } PrintAndLogEx(INFO, "Signed"); for (int i = 0; i < (sizeof(sign) / 32); i++) { - PrintAndLogEx(INFO, " %s", sprint_hex_inrow(sign + (i * 32), 32)); + PrintAndLogEx(INFO, " %s", sprint_hex_inrow(sign + (i * 32), 32)); } } diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index 49cdf2e90..eebecc747 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -269,9 +269,13 @@ static int usage_hf_14a_reader(void) { } static int CmdHF14AList(const char *Cmd) { - (void)Cmd; // Cmd is not used so far - CmdTraceList("14a"); - return 0; + char args[128] = {0}; + if (strlen(Cmd) == 0) { + snprintf(args, sizeof(args), "-t 14a"); + } else { + strncpy(args, Cmd, sizeof(args) - 1); + } + return CmdTraceList(args); } int hf14a_getconfig(hf14a_config *config) { @@ -1267,14 +1271,14 @@ static int CmdHF14ACmdRaw(const char *Cmd) { *buf = 0; if (++datalen >= sizeof(data)) { if (crc) - PrintAndLogEx(NORMAL, "Buffer is full, we can't add CRC to your data"); + PrintAndLogEx(FAILED, "Buffer is full, we can't add CRC to your data"); break; } } continue; } - PrintAndLogEx(NORMAL, "Invalid char on input"); - return 0; + PrintAndLogEx(FAILED, "Invalid char on input"); + return PM3_ESOFT; } if (crc && datalen > 0 && datalen < sizeof(data) - 2) { @@ -1301,7 +1305,7 @@ static int CmdHF14ACmdRaw(const char *Cmd) { flags |= ISO14A_SET_TIMEOUT; if (timeout > MAX_TIMEOUT) { timeout = MAX_TIMEOUT; - PrintAndLogEx(NORMAL, "Set timeout to 40542 seconds (11.26 hours). The max we can wait for response"); + PrintAndLogEx(INFO, "Set timeout to 40542 seconds (11.26 hours). The max we can wait for response"); } argtimeout = 13560000 / 1000 / (8 * 16) * timeout; // timeout in ETUs (time to transfer 1 bit, approx. 9.4 us) } @@ -1345,18 +1349,32 @@ static int waitCmd(uint8_t iSelect, uint32_t timeout) { if (iSelect) { len = (resp.oldarg[1] & 0xFFFF); if (len) { - PrintAndLogEx(NORMAL, "Card selected. UID[%i]:", len); + PrintAndLogEx(SUCCESS, "Card selected. UID[%u]:", len); } else { PrintAndLogEx(WARNING, "Can't select card."); } } else { - PrintAndLogEx(NORMAL, "received %i bytes", len); + PrintAndLogEx(SUCCESS, "received " _YELLOW_("%u") " bytes", len); } if (!len) return 1; - PrintAndLogEx(NORMAL, "%s", sprint_hex(resp.data.asBytes, len)); + uint8_t *data = resp.data.asBytes; + + if (len >= 3) { + bool crc = check_crc(CRC_14443_A, data, len); + + PrintAndLogEx(SUCCESS, "%s[%02X %02X] %s", + sprint_hex(data, len - 2), + data[len - 2], + data[len - 1], + (crc) ? _GREEN_("ok") : _RED_("fail") + ); + } else { + PrintAndLogEx(SUCCESS, "%s", sprint_hex(data, len)); + } + } else { PrintAndLogEx(WARNING, "timeout while waiting for reply."); return 3; @@ -1954,6 +1972,9 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { } } else { PrintAndLogEx(INFO, "proprietary non iso14443-4 card found, RATS not supported"); + if ((card.sak & 0x20) == 0x20) { + PrintAndLogEx(INFO, "SAK incorrectly claims that card supports RATS"); + } } int isMagic = 0; diff --git a/client/src/cmdhf14b.c b/client/src/cmdhf14b.c index 542dc3aec..9056b26a9 100644 --- a/client/src/cmdhf14b.c +++ b/client/src/cmdhf14b.c @@ -77,9 +77,10 @@ static bool wait_cmd_14b(bool verbose, bool is_select) { // 0: OK; -1: attrib fail; -2:crc fail int status = (int)resp.oldarg[0]; if (status == 0) { - + if (verbose) { - PrintAndLogEx(SUCCESS, "len %u | %s", len, sprint_hex(data, len)); + PrintAndLogEx(SUCCESS, "received " _YELLOW_("%u") " bytes", len); + PrintAndLogEx(SUCCESS, "%s", sprint_hex(data, len)); } return true; } else { @@ -93,8 +94,8 @@ static bool wait_cmd_14b(bool verbose, bool is_select) { if (len >= 3) { bool crc = check_crc(CRC_14443_B, data, len); - PrintAndLogEx(SUCCESS, "len %u | %s[%02X %02X] %s", - len, + PrintAndLogEx(SUCCESS, "received " _YELLOW_("%u") " bytes", len); + PrintAndLogEx(SUCCESS, "%s[%02X %02X] %s", sprint_hex(data, len - 2), data[len - 2], data[len - 1], @@ -104,48 +105,53 @@ static bool wait_cmd_14b(bool verbose, bool is_select) { if (verbose) PrintAndLogEx(INFO, "no response from tag"); } else { - PrintAndLogEx(SUCCESS, "len %u | %s", len, sprint_hex(data, len)); + PrintAndLogEx(SUCCESS, "%s", sprint_hex(data, len)); } } return true; } else { - PrintAndLogEx(WARNING, "command execution timeout"); + PrintAndLogEx(WARNING, "timeout while waiting for reply"); return false; } } static int CmdHF14BList(const char *Cmd) { - (void)Cmd; // Cmd is not used so far - CmdTraceList("14b"); - return PM3_SUCCESS; + char args[128] = {0}; + if (strlen(Cmd) == 0) { + snprintf(args, sizeof(args), "-t 14b"); + } else { + strncpy(args, Cmd, sizeof(args) - 1); + } + return CmdTraceList(args); } static int CmdHF14BSim(const char *Cmd) { - + CLIParserContext *ctx; CLIParserInit(&ctx, "hf 14b sim", "Simulate a ISO/IEC 14443 type B tag with 4 byte UID / PUPI", "hf 14b sim\n" "hf 14b sim -u 11AA33BB" - ); - + ); + void *argtable[] = { arg_param_begin, arg_strx0("u", "uid", "hex", "4byte UID/PUPI"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); - + uint8_t pupi[4]; int n = 0; int res = CLIParamHexToBuf(arg_get_str(ctx, 1), pupi, sizeof(pupi), &n); + CLIParserFree(ctx); + if (res) { PrintAndLogEx(FAILED, "failed to read pupi"); return PM3_EINVARG; } - CLIParserFree(ctx); clearCommandBuffer(); - SendCommandNG(CMD_HF_ISO14443B_SIMULATE, pupi, sizeof(pupi)); + SendCommandNG(CMD_HF_ISO14443B_SIMULATE, pupi, sizeof(pupi)); return PM3_SUCCESS; } @@ -155,44 +161,44 @@ static int CmdHF14BSniff(const char *Cmd) { CLIParserInit(&ctx, "hf 14b sniff", "Sniff the communication reader and tag", "hf 14b sniff" - ); - + ); + void *argtable[] = { arg_param_begin, arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, true); CLIParserFree(ctx); - + PacketResponseNG resp; clearCommandBuffer(); SendCommandNG(CMD_HF_ISO14443B_SNIFF, NULL, 0); WaitForResponse(CMD_HF_ISO14443B_SNIFF, &resp); - + PrintAndLogEx(HINT, "Try `" _YELLOW_("hf 14b list") "` to view captured tracelog"); PrintAndLogEx(HINT, "Try `" _YELLOW_("trace save h") "` to save tracelog for later analysing"); return PM3_SUCCESS; } static int CmdHF14BCmdRaw(const char *Cmd) { - + CLIParserContext *ctx; CLIParserInit(&ctx, "hf 14b raw", "Sends raw bytes to card ", "hf 14b raw -cks --data 0200a40400 -> standard select\n" "hf 14b raw -ck --sr --data 0200a40400 -> SRx select\n" "hf 14b raw -ck --cts --data 0200a40400 -> C-ticket select\n" - ); - + ); + void *argtable[] = { arg_param_begin, arg_lit0("k", "keep", "leave the signal field ON after receive response"), - arg_lit0("s", "std", "activate field and select standard card"), - arg_lit0(NULL, "sr", "activate field and select SRx ST"), - arg_lit0(NULL, "cts", "activate field and select ASK C-ticket"), + arg_lit0("s", "std", "activate field, use ISO14B select"), + arg_lit0(NULL, "sr", "activate field, use SRx ST select"), + arg_lit0(NULL, "cts", "activate field, use ASK C-ticket select"), arg_lit0("c", "crc", "calculate and append CRC"), - arg_lit0("r", "noresponse", "do not read response"), + arg_lit0("r", "noresponse", "do not read response from card"), arg_int0("t", "timeout", "", "timeout in ms"), arg_lit0("v", "verbose", "verbose"), arg_strx0("d", "data", "", "data, bytes to send"), @@ -217,7 +223,7 @@ static int CmdHF14BCmdRaw(const char *Cmd) { if (select_std) { flags |= (ISO14B_SELECT_STD | ISO14B_CLEARTRACE); if (verbose) - PrintAndLogEx(INFO, "using standard select"); + PrintAndLogEx(INFO, "using ISO14443-B select"); } else if (select_sr) { flags |= (ISO14B_SELECT_SR | ISO14B_CLEARTRACE); if (verbose) @@ -266,7 +272,8 @@ static int CmdHF14BCmdRaw(const char *Cmd) { return PM3_SUCCESS; } - bool success = true; + bool success = true; + // Select, device will send back iso14b_card_select_t, don't print it. if (select_std) { success = wait_cmd_14b(verbose, true); @@ -617,8 +624,8 @@ static void print_st_general_info(uint8_t *data, uint8_t len) { static void print_ct_general_info(void *vcard) { iso14b_cts_card_select_t card; memcpy(&card, (iso14b_cts_card_select_t *)vcard, sizeof(iso14b_cts_card_select_t)); - - uint32_t uid32 = (card.uid[0] |card.uid[1] << 8 |card.uid[2] << 16 | card.uid[3] << 24); + + uint32_t uid32 = (card.uid[0] | card.uid[1] << 8 | card.uid[2] << 16 | card.uid[3] << 24); PrintAndLogEx(SUCCESS, "ASK C-Ticket"); PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s") " ( " _YELLOW_("%010u") " )", sprint_hex(card.uid, sizeof(card.uid)), uid32); PrintAndLogEx(SUCCESS, " Product Code: %02X", card.pc); @@ -650,7 +657,7 @@ static bool HF14B_Std_Info(bool verbose) { SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_STD | ISO14B_DISCONNECT, 0, 0, NULL, 0); if (!WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) { - if (verbose) PrintAndLogEx(WARNING, "command execution timeout"); + if (verbose) PrintAndLogEx(WARNING, "timeout while waiting for reply"); switch_off_field_14b(); return is_success; } @@ -690,7 +697,7 @@ static bool HF14B_ST_Info(bool verbose) { SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_SR | ISO14B_DISCONNECT, 0, 0, NULL, 0); if (!WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) { - if (verbose) PrintAndLogEx(WARNING, "command execution timeout"); + if (verbose) PrintAndLogEx(WARNING, "timeout while waiting for reply"); return false; } @@ -711,7 +718,7 @@ static int CmdHF14Binfo(const char *Cmd) { CLIParserInit(&ctx, "hf 14b info", "Tag information for ISO/IEC 14443 type B based tags", "hf 14b info\n" - ); + ); void *argtable[] = { arg_param_begin, @@ -734,7 +741,7 @@ static bool HF14B_st_reader(bool verbose) { SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_SR | ISO14B_DISCONNECT, 0, 0, NULL, 0); if (!WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) { - if (verbose) PrintAndLogEx(WARNING, "command execution timeout"); + if (verbose) PrintAndLogEx(WARNING, "timeout while waiting for reply"); return is_success; } @@ -774,7 +781,7 @@ static bool HF14B_std_reader(bool verbose) { SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_STD | ISO14B_DISCONNECT, 0, 0, NULL, 0); if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT) == false) { - if (verbose) PrintAndLogEx(WARNING, "command execution timeout"); + if (verbose) PrintAndLogEx(WARNING, "timeout while waiting for reply"); return false; } @@ -817,7 +824,7 @@ static bool HF14B_ask_ct_reader(bool verbose) { PacketResponseNG resp; SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_CTS | ISO14B_DISCONNECT, 0, 0, NULL, 0); if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT) == false) { - if (verbose) PrintAndLogEx(WARNING, "command execution timeout"); + if (verbose) PrintAndLogEx(WARNING, "timeout while waiting for reply"); return false; } @@ -859,7 +866,7 @@ static bool HF14B_other_reader(bool verbose) { SendCommandMIX(CMD_HF_ISO14443B_COMMAND, flags, datalen, 0, data, datalen); if (!WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) { - if (verbose) PrintAndLogEx(WARNING, "command execution timeout"); + if (verbose) PrintAndLogEx(WARNING, "timeout while waiting for reply"); switch_off_field_14b(); return false; } @@ -883,7 +890,7 @@ static bool HF14B_other_reader(bool verbose) { clearCommandBuffer(); SendCommandMIX(CMD_HF_ISO14443B_COMMAND, flags, 1, 0, data, 1); if (!WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) { - if (verbose) PrintAndLogEx(WARNING, "command execution timeout"); + if (verbose) PrintAndLogEx(WARNING, "timeout while waiting for reply"); switch_off_field_14b(); return false; } @@ -907,7 +914,7 @@ static bool HF14B_other_reader(bool verbose) { clearCommandBuffer(); SendCommandMIX(CMD_HF_ISO14443B_COMMAND, flags, 1, 0, data, 1); if (!WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) { - if (verbose) PrintAndLogEx(WARNING, "command execution timeout"); + if (verbose) PrintAndLogEx(WARNING, "timeout while waiting for reply"); switch_off_field_14b(); return false; } @@ -937,7 +944,7 @@ static int CmdHF14BReader(const char *Cmd) { CLIParserInit(&ctx, "hf 14b reader", "Act as a 14443B reader to identify a tag", "hf 14b reader\n" - ); + ); void *argtable[] = { arg_param_begin, @@ -955,20 +962,20 @@ static int CmdHF14BReader(const char *Cmd) { * this command just dumps the contents of the memory/ */ static int CmdHF14BReadSri(const char *Cmd) { - + CLIParserContext *ctx; CLIParserInit(&ctx, "hf 14b sriread", "Read contents of a SRI512 | SRIX4K tag", "hf 14b sriread\n" - ); - + ); + void *argtable[] = { arg_param_begin, arg_param_end }; - CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIExecWithReturn(ctx, Cmd, argtable, true); CLIParserFree(ctx); - + iso14b_card_select_t card; if (get_14b_UID(&card) == false) { PrintAndLogEx(WARNING, "no tag found"); @@ -976,7 +983,7 @@ static int CmdHF14BReadSri(const char *Cmd) { } if (card.uidlen != 8) { - PrintAndLogEx(FAILED, "current dump command only work with SRI4K / SRI512 tags"); + PrintAndLogEx(FAILED, "current dump command only work with SRI4K / SRI512 tags"); return PM3_SUCCESS; } @@ -1068,8 +1075,8 @@ static int CmdHF14BDump(const char *Cmd) { "Tries to autodetect cardtype, memory size defaults to SRI4K", "hf 14b dump\n" "hf 14b dump -f myfilename\n" - ); - + ); + void *argtable[] = { arg_param_begin, arg_strx0("f", "file", "", "(optional) filename, if no UID will be used as filename"), @@ -1080,7 +1087,7 @@ static int CmdHF14BDump(const char *Cmd) { int fnlen = 0; char filename[FILE_PATH_SIZE] = {0}; char *fptr = filename; - CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t*)filename, FILE_PATH_SIZE, &fnlen); + CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); CLIParserFree(ctx); iso14b_card_select_t card; @@ -1088,9 +1095,9 @@ static int CmdHF14BDump(const char *Cmd) { PrintAndLogEx(WARNING, "no tag found"); return PM3_SUCCESS; } - + if (card.uidlen != 8) { - PrintAndLogEx(FAILED, "current dump command only work with SRI4K / SRI512 tags"); + PrintAndLogEx(FAILED, "current dump command only work with SRI4K / SRI512 tags"); return PM3_SUCCESS; } @@ -1355,12 +1362,12 @@ static int select_card_14443b_4(bool disconnect, iso14b_card_select_t *card) { // Anticollision + SELECT SR card SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_SR, 0, 0, NULL, 0); - if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT) == false) { + if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT) == false) { PrintAndLogEx(INFO, "Trying 14B Select CTS"); // Anticollision + SELECT ASK C-Ticket card SendCommandMIX(CMD_HF_ISO14443B_COMMAND, ISO14B_CONNECT | ISO14B_SELECT_CTS, 0, 0, NULL, 0); - if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT) == false) { + if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT) == false) { PrintAndLogEx(ERR, "connection timeout"); switch_off_field_14b(); return PM3_ESOFT; @@ -1427,7 +1434,7 @@ static int handle_14b_apdu(bool chainingin, uint8_t *datain, int datainlen, bool if (dlen < 0) { dlen = 0; } - + *dataoutlen += dlen; if (maxdataoutlen && *dataoutlen > maxdataoutlen) { @@ -1496,7 +1503,7 @@ static int exchange_14b_apdu(uint8_t *datain, int datainlen, bool activate_field // TODO check this one... // check R-block ACK // *dataoutlen!=0. 'A && (!A || B)' is equivalent to 'A && B' - if ((*dataoutlen == 0) && (*dataoutlen != 0 || chaining != chainBlockNotLast)) { + if ((*dataoutlen == 0) && (*dataoutlen != 0 || chaining != chainBlockNotLast)) { if (leave_signal_on == false) { switch_off_field_14b(); } @@ -1635,11 +1642,11 @@ static int CmdHF14BAPDU(const char *Cmd) { CLIParserFree(ctx); PrintAndLogEx(NORMAL, ">>>>[%s%s%s] %s", - activate_field ? "sel" : "", - leave_signal_on ? " keep" : "", - decode_TLV ? " TLV" : "", - sprint_hex(data, datalen) - ); + activate_field ? "sel" : "", + leave_signal_on ? " keep" : "", + decode_TLV ? " TLV" : "", + sprint_hex(data, datalen) + ); if (decode_APDU) { APDUStruct apdu; @@ -1671,7 +1678,7 @@ static int CmdHF14BNdef(const char *Cmd) { CLIParserInit(&ctx, "hf 14b ndef", "Print NFC Data Exchange Format (NDEF)", "hf 14b ndef" - ); + ); void *argtable[] = { arg_param_begin, arg_param_end @@ -1761,7 +1768,7 @@ static int CmdHF14BNdef(const char *Cmd) { } res = NDEFRecordsDecodeAndPrint(response + 2, resplen - 4); - + out: switch_off_field_14b(); return res; @@ -1769,7 +1776,7 @@ out: static command_t CommandTable[] = { {"help", CmdHelp, AlwaysAvailable, "This help"}, - {"apdu", CmdHF14BAPDU, IfPm3Iso14443b, "Send ISO 14443-4 APDU to tag"}, + {"apdu", CmdHF14BAPDU, IfPm3Iso14443b, "Send ISO 14443-4 APDU to tag"}, {"dump", CmdHF14BDump, IfPm3Iso14443b, "Read all memory pages of an ISO14443-B tag, save to file"}, {"info", CmdHF14Binfo, IfPm3Iso14443b, "Tag information"}, {"list", CmdHF14BList, AlwaysAvailable, "List ISO 14443B history"}, diff --git a/client/src/cmdhf15.c b/client/src/cmdhf15.c index cbef47554..238aad435 100644 --- a/client/src/cmdhf15.c +++ b/client/src/cmdhf15.c @@ -60,9 +60,9 @@ typedef struct { uint64_t uid; int mask; // how many MSB bits used const char *desc; -} productName; +} productName_t; -const productName uidmapping[] = { +const productName_t uidmapping[] = { // UID, #significant Bits, "Vendor(+Product)" { 0xE001000000000000LL, 16, "Motorola UK" }, @@ -1342,9 +1342,13 @@ static int CmdHF15Dump(const char *Cmd) { } static int CmdHF15List(const char *Cmd) { - (void)Cmd; // Cmd is not used so far - CmdTraceList("15"); - return PM3_SUCCESS; + char args[128] = {0}; + if (strlen(Cmd) == 0) { + snprintf(args, sizeof(args), "-t 15"); + } else { + strncpy(args, Cmd, sizeof(args) - 1); + } + return CmdTraceList(args); } static int CmdHF15Raw(const char *Cmd) { diff --git a/client/src/cmdhfcryptorf.c b/client/src/cmdhfcryptorf.c index b473b2fa2..bf2df530c 100644 --- a/client/src/cmdhfcryptorf.c +++ b/client/src/cmdhfcryptorf.c @@ -115,9 +115,13 @@ static int switch_off_field_cryptorf(void) { } static int CmdHFCryptoRFList(const char *Cmd) { - (void)Cmd; // Cmd is not used so far - CmdTraceList("cryptorf"); - return PM3_SUCCESS; + char args[128] = {0}; + if (strlen(Cmd) == 0) { + snprintf(args, sizeof(args), "-t cryptorf"); + } else { + strncpy(args, Cmd, sizeof(args) - 1); + } + return CmdTraceList(args); } static int CmdHFCryptoRFSim(const char *Cmd) { diff --git a/client/src/cmdhffelica.c b/client/src/cmdhffelica.c index 092677b42..083e69b21 100644 --- a/client/src/cmdhffelica.c +++ b/client/src/cmdhffelica.c @@ -407,9 +407,13 @@ static bool add_last_IDm(uint8_t position, uint8_t *data) { } static int CmdHFFelicaList(const char *Cmd) { - (void)Cmd; - CmdTraceList("felica"); - return PM3_SUCCESS; + char args[128] = {0}; + if (strlen(Cmd) == 0) { + snprintf(args, sizeof(args), "-t felica"); + } else { + strncpy(args, Cmd, sizeof(args) - 1); + } + return CmdTraceList(args); } static int CmdHFFelicaReader(const char *Cmd) { diff --git a/client/src/cmdhffido.c b/client/src/cmdhffido.c index ee2da7bfa..009a14e9f 100644 --- a/client/src/cmdhffido.c +++ b/client/src/cmdhffido.c @@ -36,10 +36,21 @@ #include "emv/dump.h" #include "ui.h" #include "cmdhf14a.h" +#include "cmdtrace.h" static int CmdHelp(const char *Cmd); -static int CmdHFFidoInfo(const char *cmd) { +static int cmd_hf_fido_list(const char *Cmd) { + char args[128] = {0}; + if (strlen(Cmd) == 0) { + snprintf(args, sizeof(args), "-t 14a"); + } else { + strncpy(args, Cmd, sizeof(args) - 1); + } + return CmdTraceList(args); +} + +static int cmd_hf_fido_info(const char *cmd) { if (cmd && strlen(cmd) > 0) PrintAndLogEx(WARNING, "WARNING: command doesn't have any parameters.\n"); @@ -150,7 +161,7 @@ static json_t *OpenJson(CLIParserContext *ctx, int paramnum, char *fname, void * return root; } -static int CmdHFFidoRegister(const char *cmd) { +static int cmd_hf_fido_register(const char *cmd) { uint8_t data[64] = {0}; int chlen = 0; uint8_t cdata[250] = {0}; @@ -386,7 +397,7 @@ static int CmdHFFidoRegister(const char *cmd) { return PM3_SUCCESS; } -static int CmdHFFidoAuthenticate(const char *cmd) { +static int cmd_hf_fido_authenticate(const char *cmd) { uint8_t data[512] = {0}; uint8_t hdata[250] = {0}; bool public_key_loaded = false; @@ -652,7 +663,7 @@ static int GetExistsFileNameJson(const char *prefixDir, const char *reqestedFile return PM3_SUCCESS; } -static int CmdHFFido2MakeCredential(const char *cmd) { +static int cmd_hf_fido_2make_credential(const char *cmd) { json_error_t error; char fname[FILE_PATH_SIZE] = {0}; @@ -777,7 +788,7 @@ static int CmdHFFido2MakeCredential(const char *cmd) { return PM3_SUCCESS; } -static int CmdHFFido2GetAssertion(const char *cmd) { +static int cmd_hf_fido_2get_assertion(const char *cmd) { json_error_t error; char fname[FILE_PATH_SIZE] = {0}; @@ -903,13 +914,14 @@ static int CmdHFFido2GetAssertion(const char *cmd) { } static command_t CommandTable[] = { - {"help", CmdHelp, AlwaysAvailable, "This help."}, - {"info", CmdHFFidoInfo, IfPm3Iso14443a, "Info about FIDO tag."}, - {"reg", CmdHFFidoRegister, IfPm3Iso14443a, "FIDO U2F Registration Message."}, - {"auth", CmdHFFidoAuthenticate, IfPm3Iso14443a, "FIDO U2F Authentication Message."}, - {"make", CmdHFFido2MakeCredential, IfPm3Iso14443a, "FIDO2 MakeCredential command."}, - {"assert", CmdHFFido2GetAssertion, IfPm3Iso14443a, "FIDO2 GetAssertion command."}, - {NULL, NULL, 0, NULL} + {"help", CmdHelp, AlwaysAvailable, "This help."}, + {"info", cmd_hf_fido_list, IfPm3Iso14443a, "List ISO 14443A history"}, + {"info", cmd_hf_fido_info, IfPm3Iso14443a, "Info about FIDO tag."}, + {"reg", cmd_hf_fido_register, IfPm3Iso14443a, "FIDO U2F Registration Message."}, + {"auth", cmd_hf_fido_authenticate, IfPm3Iso14443a, "FIDO U2F Authentication Message."}, + {"make", cmd_hf_fido_2make_credential, IfPm3Iso14443a, "FIDO2 MakeCredential command."}, + {"assert", cmd_hf_fido_2get_assertion, IfPm3Iso14443a, "FIDO2 GetAssertion command."}, + {NULL, NULL, 0, NULL} }; int CmdHFFido(const char *Cmd) { diff --git a/client/src/cmdhficlass.c b/client/src/cmdhficlass.c index 8dfe7720a..28b710fe8 100644 --- a/client/src/cmdhficlass.c +++ b/client/src/cmdhficlass.c @@ -18,6 +18,7 @@ #include "cmdparser.h" // command_t #include "commonutil.h" // ARRAYLEN #include "cmdtrace.h" +#include "cliparser.h" #include "util_posix.h" #include "comms.h" #include "des.h" @@ -224,21 +225,6 @@ static int usage_hf_iclass_readblock(void) { PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } -static int usage_hf_iclass_view(void) { - PrintAndLogEx(NORMAL, "Print a iCLASS tag dump file\n"); - PrintAndLogEx(NORMAL, "Usage: hf iClass view [f ] [s ] [e ] [v]\n"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h Show this help"); - PrintAndLogEx(NORMAL, " f filename of dump"); - PrintAndLogEx(NORMAL, " s print from this block (default block6)"); - PrintAndLogEx(NORMAL, " e end printing at this block (default 0, ALL)"); - PrintAndLogEx(NORMAL, " v verbose output"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass view f hf-iclass-AA162D30F8FF12F1-dump.bin")); - PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass view s 1 f hf-iclass-AA162D30F8FF12F1-dump.bin")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} static int usage_hf_iclass_calc_newkey(void) { PrintAndLogEx(NORMAL, "Calculate new key for updating\n"); PrintAndLogEx(NORMAL, "Usage: hf iclass calc_newkey o n s [csn] e\n"); @@ -359,20 +345,7 @@ static int usage_hf_iclass_lookup(void) { PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } -static int usage_hf_iclass_permutekey(void) { - PrintAndLogEx(NORMAL, "Permute function from 'heart of darkness' paper.\n"); - PrintAndLogEx(NORMAL, "Usage: hf iclass permute [h] \n"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h Show this help"); - PrintAndLogEx(NORMAL, " r reverse permuted key"); - PrintAndLogEx(NORMAL, " f permute key"); - PrintAndLogEx(NORMAL, " input bytes"); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass permute r 0123456789abcdef")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} + static int cmp_uint32(const void *a, const void *b) { @@ -631,9 +604,13 @@ static void print_picopass_header(const picopass_hdr *hdr) { } static int CmdHFiClassList(const char *Cmd) { - (void)Cmd; // Cmd is not used so far - CmdTraceList("iclass"); - return PM3_SUCCESS; + char args[128] = {0}; + if (strlen(Cmd) == 0) { + snprintf(args, sizeof(args), "-t iclass"); + } else { + strncpy(args, Cmd, sizeof(args) - 1); + } + return CmdTraceList(args); } static int CmdHFiClassSniff(const char *Cmd) { @@ -2680,43 +2657,31 @@ void printIclassDumpContents(uint8_t *iclass_dump, uint8_t startblock, uint8_t e } static int CmdHFiClassView(const char *Cmd) { - int startblock = 0; - int endblock = 0; - char filename[FILE_PATH_SIZE]; - bool errors = false, verbose = false; - uint8_t cmdp = 0; - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_hf_iclass_view(); - case 'f': - if (param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE) >= FILE_PATH_SIZE) { - PrintAndLogEx(FAILED, "Filename too long"); - errors = true; - break; - } - cmdp += 2; - break; - case 's': - startblock = param_get8ex(Cmd, cmdp + 1, 0, 10); - cmdp += 2; - break; - case 'e': - endblock = param_get8ex(Cmd, cmdp + 1, 0, 10); - cmdp += 2; - break; - case 'v': - verbose = true; - cmdp++; - break; - default: - PrintAndLogEx(WARNING, "unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf iclass view", + "Print a iCLASS tag dump file", + "hf iclass view -f hf-iclass-AA162D30F8FF12F1-dump.bin\n" + "hf iclass view --startblock 1 --file hf-iclass-AA162D30F8FF12F1-dump.bin\n"); - if (errors || (strlen(Cmd) == 0)) return usage_hf_iclass_view(); + void *argtable[] = { + arg_param_begin, + arg_str1("f", "file", "", "filename of dump"), + arg_int0("s", "startblock", "", "print from this block (default block6)"), + arg_int0("e", "endblock", "", "end printing at this block (default 0, ALL)"), + arg_lit0("v", "verbose", "verbose output"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + + int fnlen = 0; + char filename[FILE_PATH_SIZE]; + CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); + + int startblock = arg_get_int_def(ctx, 2, 0); + int endblock = arg_get_int_def(ctx, 3, 0); + bool verbose = arg_get_lit(ctx, 4); + + CLIParserFree(ctx); uint8_t *dump = NULL; size_t bytes_read = 0; @@ -3522,17 +3487,26 @@ static int CmdHFiClassPermuteKey(const char *Cmd) { uint8_t data[16] = {0}; bool isReverse = false; int len = 0; - char cmdp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) == 0 || cmdp == 'h') - return usage_hf_iclass_permutekey(); - isReverse = (cmdp == 'r'); + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf iclass permute", + "Permute function from 'heart of darkness' paper.", + "hf iclass permute --reverse --key 0123456789abcdef\n" + "hf iclass permute --key ff55330f0055330f\n"); - param_gethex_ex(Cmd, 1, data, &len); - if (len % 2) - return usage_hf_iclass_permutekey(); + void *argtable[] = { + arg_param_begin, + arg_lit0("r", "reverse", "reverse permuted key"), + arg_str1(NULL, "key", "", "input key"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); - len >>= 1; + isReverse = arg_get_lit(ctx, 1); + + CLIGetHexWithReturn(ctx, 2, data, &len); + + CLIParserFree(ctx); memcpy(key, data, 8); @@ -3580,7 +3554,7 @@ static command_t CommandTable[] = { {"encrypt", CmdHFiClassEncryptBlk, AlwaysAvailable, "[options..] Encrypt given block data"}, {"decrypt", CmdHFiClassDecrypt, AlwaysAvailable, "[options..] Decrypt given block data or tag dump file" }, {"managekeys", CmdHFiClassManageKeys, AlwaysAvailable, "[options..] Manage keys to use with iclass commands"}, - {"permutekey", CmdHFiClassPermuteKey, IfPm3Iclass, " Permute function from 'heart of darkness' paper"}, + {"permute", CmdHFiClassPermuteKey, IfPm3Iclass, " Permute function from 'heart of darkness' paper"}, {"view", CmdHFiClassView, AlwaysAvailable, "[options..] Display content from tag dump file"}, {NULL, NULL, NULL, NULL} diff --git a/client/src/cmdhflegic.c b/client/src/cmdhflegic.c index 5d9147896..481d1f1bc 100644 --- a/client/src/cmdhflegic.c +++ b/client/src/cmdhflegic.c @@ -1401,9 +1401,13 @@ static int CmdLegicWipe(const char *Cmd) { } static int CmdLegicList(const char *Cmd) { - (void)Cmd; // Cmd is not used so far - CmdTraceList("legic"); - return PM3_SUCCESS; + char args[128] = {0}; + if (strlen(Cmd) == 0) { + snprintf(args, sizeof(args), "-t legic"); + } else { + strncpy(args, Cmd, sizeof(args) - 1); + } + return CmdTraceList(args); } static command_t CommandTable[] = { diff --git a/client/src/cmdhflto.c b/client/src/cmdhflto.c index 6623f9cd2..7313d23fb 100644 --- a/client/src/cmdhflto.c +++ b/client/src/cmdhflto.c @@ -207,9 +207,13 @@ int infoLTO(bool verbose) { } static int CmdHfLTOList(const char *Cmd) { - (void)Cmd; // Cmd is not used so far - CmdTraceList("lto"); - return PM3_SUCCESS; + char args[128] = {0}; + if (strlen(Cmd) == 0) { + snprintf(args, sizeof(args), "-t lto"); + } else { + strncpy(args, Cmd, sizeof(args) - 1); + } + return CmdTraceList(args); } static int lto_rdbl(uint8_t blk, uint8_t *block_responce, uint8_t *block_cnt_responce, bool verbose) { diff --git a/client/src/cmdhfmf.c b/client/src/cmdhfmf.c index a06c7a3ae..f197194d4 100644 --- a/client/src/cmdhfmf.c +++ b/client/src/cmdhfmf.c @@ -1002,6 +1002,7 @@ static int CmdHF14AMfDump(const char *Cmd) { return PM3_ESOFT; strcpy(keyFilename, fptr); + free(fptr); } if ((f = fopen(keyFilename, "rb")) == NULL) { @@ -1163,6 +1164,7 @@ static int CmdHF14AMfDump(const char *Cmd) { return PM3_ESOFT; strcpy(dataFilename, fptr); + free(fptr); } uint16_t bytes = 16 * (FirstBlockOfSector(numSectors - 1) + NumBlocksPerSector(numSectors - 1)); @@ -1226,6 +1228,7 @@ static int CmdHF14AMfRestore(const char *Cmd) { return 1; strcpy(keyFilename, fptr); + free(fptr); } if ((fkeys = fopen(keyFilename, "rb")) == NULL) { @@ -1260,6 +1263,7 @@ static int CmdHF14AMfRestore(const char *Cmd) { return 1; strcpy(dataFilename, fptr); + free(fptr); } if ((fdump = fopen(dataFilename, "rb")) == NULL) { @@ -1570,8 +1574,10 @@ jumptoend: if (createMfcKeyDump(fptr, SectorsCnt, e_sector) != PM3_SUCCESS) { PrintAndLogEx(ERR, "Failed to save keys to file"); free(e_sector); + free(fptr); return PM3_ESOFT; } + free(fptr); } free(e_sector); } @@ -1775,8 +1781,10 @@ jumptoend: if (createMfcKeyDump(fptr, SectorsCnt, e_sector) != PM3_SUCCESS) { PrintAndLogEx(ERR, "Failed to save keys to file"); free(e_sector); + free(fptr); return PM3_ESOFT; } + free(fptr); } free(e_sector); @@ -2013,7 +2021,6 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { uint8_t block[16] = {0x00}; uint8_t *dump; int bytes; - char *fnameptr = filename; // Settings bool slow = false; bool legacy_mfchk = false; @@ -2136,7 +2143,6 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { // read uid to generate a filename for the key file char *fptr = GenerateFilename("hf-mf-", "-key.bin"); - // check if tag doesn't have static nonce has_staticnonce = detect_classic_static_nonce(); @@ -2146,6 +2152,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { if (prng_type < 0) { PrintAndLogEx(FAILED, "\nNo tag detected or other tag communication error"); free(e_sector); + free(fptr); return prng_type; } } @@ -2259,6 +2266,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) { keyBlock = calloc(ARRAYLEN(g_mifare_default_keys), 6); if (keyBlock == NULL) { free(e_sector); + free(fptr); return PM3_EMALLOC; } @@ -2403,6 +2411,7 @@ noValidKeyFound: PrintAndLogEx(FAILED, "No usable key was found!"); free(keyBlock); free(e_sector); + free(fptr); return PM3_ESOFT; } } @@ -2516,11 +2525,13 @@ tryNested: case PM3_ETIMEOUT: { PrintAndLogEx(ERR, "\nError: No response from Proxmark3."); free(e_sector); + free(fptr); return PM3_ESOFT; } case PM3_EOPABORTED: { PrintAndLogEx(WARNING, "\nButton pressed. Aborted."); free(e_sector); + free(fptr); return PM3_EOPABORTED; } case PM3_EFAILED: { @@ -2551,6 +2562,7 @@ tryNested: default: { PrintAndLogEx(ERR, "unknown Error.\n"); free(e_sector); + free(fptr); return PM3_ESOFT; } } @@ -2582,6 +2594,7 @@ tryHardnested: // If the nested attack fails then we try the hardnested attack } } free(e_sector); + free(fptr); return PM3_ESOFT; } @@ -2606,11 +2619,13 @@ tryStaticnested: case PM3_ETIMEOUT: { PrintAndLogEx(ERR, "\nError: No response from Proxmark3."); free(e_sector); + free(fptr); return PM3_ESOFT; } case PM3_EOPABORTED: { PrintAndLogEx(WARNING, "\nButton pressed. Aborted."); free(e_sector); + free(fptr); return PM3_EOPABORTED; } case PM3_SUCCESS: { @@ -2676,6 +2691,7 @@ all_found: if (!dump) { PrintAndLogEx(ERR, "Fail, cannot allocate memory"); free(e_sector); + free(fptr); return PM3_EMALLOC; } memset(dump, 0, bytes); @@ -2685,16 +2701,19 @@ all_found: PrintAndLogEx(ERR, "Fail, transfer from device time-out"); free(e_sector); free(dump); + free(fptr); return PM3_ETIMEOUT; } - fnameptr = GenerateFilename("hf-mf-", "-dump"); + char *fnameptr = GenerateFilename("hf-mf-", "-dump"); if (fnameptr == NULL) { free(dump); free(e_sector); + free(fptr); return PM3_ESOFT; } strcpy(filename, fnameptr); + free(fnameptr); saveFile(filename, ".bin", dump, bytes); saveFileEML(filename, dump, bytes, MFBLOCK_SIZE); @@ -2706,6 +2725,7 @@ all_found: free(dump); free(e_sector); + free(fptr); return PM3_SUCCESS; } @@ -2982,6 +3002,7 @@ out: if (createMfcKeyDump(fptr, sectorsCnt, e_sector) != PM3_SUCCESS) { PrintAndLogEx(ERR, "Failed to save keys to file"); } + free(fptr); } } @@ -3285,6 +3306,7 @@ out: if (createMfcKeyDump(fptr, SectorsCnt, e_sector) != PM3_SUCCESS) { PrintAndLogEx(ERR, "Failed to save keys to file"); } + free(fptr); } free(keyBlock); @@ -4040,7 +4062,6 @@ static int CmdHF14AMfEKeyPrn(const char *Cmd) { char *fptr = filename; fptr += snprintf(fptr, sizeof(filename), "hf-mf-"); FillFileNameByUID(fptr + strlen(fptr), uid, "-key", sizeof(uid)); - createMfcKeyDump(filename, sectors_cnt, e_sector); } @@ -4732,6 +4753,7 @@ static int CmdHF14AMfice(const char *Cmd) { if (fptr == NULL) return PM3_EFILE; strcpy(filename, fptr); + free(fptr); } PrintAndLogEx(NORMAL, "Collecting "_YELLOW_("%u")" nonces \n", limit); @@ -5174,8 +5196,13 @@ static int CmdHFMFPersonalize(const char *cmd) { } static int CmdHF14AMfList(const char *Cmd) { - (void)Cmd; // Cmd is not used so far - return CmdTraceList("mf"); + char args[128] = {0}; + if (strlen(Cmd) == 0) { + snprintf(args, sizeof(args), "-t mf"); + } else { + strncpy(args, Cmd, sizeof(args) - 1); + } + return CmdTraceList(args); } static int CmdHf14AGen3UID(const char *Cmd) { diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index d43df03a4..4ffebe47c 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -4470,8 +4470,13 @@ static int CmdHF14aDesChk(const char *Cmd) { } static int CmdHF14ADesList(const char *Cmd) { - (void)Cmd; // Cmd is not used so far - return CmdTraceList("des"); + char args[128] = {0}; + if (strlen(Cmd) == 0) { + snprintf(args, sizeof(args), "-t des"); + } else { + strncpy(args, Cmd, sizeof(args) - 1); + } + return CmdTraceList(args); } /* diff --git a/client/src/cmdhfmfhard.c b/client/src/cmdhfmfhard.c index 3d378322e..d75e6b0a3 100644 --- a/client/src/cmdhfmfhard.c +++ b/client/src/cmdhfmfhard.c @@ -143,12 +143,10 @@ static inline void clear_bitarray24(uint32_t *bitarray) { memset(bitarray, 0x00, sizeof(uint32_t) * (1 << 19)); } - static inline void set_bitarray24(uint32_t *bitarray) { memset(bitarray, 0xff, sizeof(uint32_t) * (1 << 19)); } - static inline void set_bit24(uint32_t *bitarray, uint32_t index) { bitarray[index >> 5] |= 0x80000000 >> (index & 0x0000001f); } @@ -157,36 +155,46 @@ static inline uint32_t test_bit24(uint32_t *bitarray, uint32_t index) { return bitarray[index >> 5] & (0x80000000 >> (index & 0x0000001f)); } - static inline uint32_t next_state(uint32_t *bitarray, uint32_t state) { - if (++state == 1 << 24) return 1 << 24; + if (++state == (1 << 24)) { + return (1 << 24); + } + uint32_t index = state >> 5; - uint_fast8_t bit = state & 0x1f; + uint_fast8_t bit = state & 0x1F; uint32_t line = bitarray[index] << bit; - while (bit <= 0x1f) { - if (line & 0x80000000) return state; + + while (bit <= 0x1F) { + if (line & 0x80000000) { + return state; + } state++; bit++; line <<= 1; } index++; - while (bitarray[index] == 0x00000000 && state < 1 << 24) { + while (state < (1 << 24) && bitarray[index] == 0x00000000) { index++; state += 0x20; } - if (state >= 1 << 24) return 1 << 24; + + if (state >= (1 << 24)) { + return (1 << 24); + } #if defined __GNUC__ return state + __builtin_clz(bitarray[index]); #else bit = 0x00; line = bitarray[index]; - while (bit <= 0x1f) { - if (line & 0x80000000) return state; + while (bit <= 0x1F) { + if (line & 0x80000000) { + return state; + } state++; bit++; line <<= 1; } - return 1 << 24; + return (1 << 24); #endif } diff --git a/client/src/cmdhfmfu.c b/client/src/cmdhfmfu.c index 0e242a029..219c7c27d 100644 --- a/client/src/cmdhfmfu.c +++ b/client/src/cmdhfmfu.c @@ -24,7 +24,7 @@ #define MAX_UL_BLOCKS 0x0F -#define MAX_ULC_BLOCKS 0x2B +#define MAX_ULC_BLOCKS 0x2F #define MAX_ULEV1a_BLOCKS 0x13 #define MAX_ULEV1b_BLOCKS 0x28 #define MAX_NTAG_203 0x29 @@ -168,17 +168,13 @@ static int usage_hf_mfu_sim(void) { } static int usage_hf_mfu_ucauth(void) { - PrintAndLogEx(NORMAL, "Usage: hf mfu cauth k "); - PrintAndLogEx(NORMAL, " 0 (default): 3DES standard key"); - PrintAndLogEx(NORMAL, " 1 : all 0x00 key"); - PrintAndLogEx(NORMAL, " 2 : 0x00-0x0F key"); - PrintAndLogEx(NORMAL, " 3 : nfc key"); - PrintAndLogEx(NORMAL, " 4 : all 0x01 key"); - PrintAndLogEx(NORMAL, " 5 : all 0xff key"); - PrintAndLogEx(NORMAL, " 6 : 0x00-0xFF key"); + PrintAndLogEx(NORMAL, "Tests 3DES password on Mifare Ultralight-C tag."); + PrintAndLogEx(NORMAL, "If password is not specified, a set of known defaults will be tested."); + PrintAndLogEx(NORMAL, "Usage: hf mfu cauth "); + PrintAndLogEx(NORMAL, " [password] - (32 hex symbols)"); PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu cauth k")); - PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu cauth k 3")); + PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu cauth")); + PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu cauth 000102030405060708090a0b0c0d0e0f")); PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } @@ -244,12 +240,14 @@ static int usage_hf_mfu_otp_tearoff(void) { PrintAndLogEx(NORMAL, " s