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/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 000000000..d3d86ee80 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,55 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "name": "(gdb) Attach", + "type": "cppdbg", + "request": "attach", + "program": "${cwd}/client/proxmark3", + //"processId": "${command:pickProcess}", + "processId": "${input:ProcessID}", + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ] + },{ + "name": "(gdb) Build & Launch", + "type": "cppdbg", + "request": "launch", + "program": "${cwd}/client/proxmark3", + "args": ["/dev/ttyACM0"], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [ + { + "description": "Enable pretty-printing for gdb", + "text": "-enable-pretty-printing", + "ignoreFailures": true + } + ], + "preLaunchTask": "client: Debug: clean & make", + "miDebuggerPath": "/usr/bin/gdb" + } + ], + "inputs": [ + { + // Using Extension "Tasks Shell Input" https://marketplace.visualstudio.com/items?itemName=augustocdias.tasks-shell-input + "id": "ProcessID", + "type": "command", + "command": "shellCommand.execute", + "args": { + "command": "pgrep -n proxmark3", + } + } + ] +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 20b68be0e..155aa80cd 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -4,24 +4,82 @@ "version": "2.0.0", "tasks": [ { - "label": "build", + "label": "all: Make & run", "type": "shell", - "command": "make clean && make all -j$(nproc --all)", + "command": "make -j && ./pm3", "problemMatcher": [ "$gcc" - ] + ], + "group": { + "kind": "build", + "isDefault": true + } }, { - "label": "flash fullimage", + "label": "choose: Make", "type": "shell", - "command": "sudo ./pm3-flash-fullimage", + "command": "make ${input:componentType} -j", + "problemMatcher": [ + "$gcc" + ], + "group": "build", + }, + { + "label": "client: Debug: make", + "type": "shell", + "command": "make client -j DEBUG=1", + "problemMatcher": [ + "$gcc" + ], + "group": "build", + }, + { + "label": "client: Debug: clean & make", + "type": "shell", + "command": "make client/clean && make client -j DEBUG=1", + "problemMatcher": [ + "$gcc" + ], + "group": "build", + }, + { + "label": "fullimage: Make & Flash", + "type": "shell", + "command": "make fullimage && ./pm3-flash-fullimage", "problemMatcher": [] }, { - "label": "FLASH BOOTROM", + "label": "BOOTROM: Make & Flash", "type": "shell", - "command": "sudo ./pm3-flash-bootrom", + "command": "make bootrom && ./pm3-flash-bootrom", "problemMatcher": [] + }, + { + "label": "Run client", + "type": "shell", + "command": "./pm3", + "problemMatcher": [] + } + ], + "inputs": [ + { + "type": "pickString", + "id": "componentType", + "description": "What Makefile target do you want to execute?", + "options": [ + "all", + "client", + "bootrom", + "fullimage", + "recovery", + "clean", + "install", + "uninstall", + "style", + "miscchecks", + "check", + ], + "default": "all" } ] } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e5f00a78..d7bdfe891 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ All notable changes to this project will be documented in this file. This project uses the changelog in accordance with [keepchangelog](http://keepachangelog.com/). Please use this to write notable changes, which is not the same as git commit log... ## [unreleased][unreleased] + - Removed 'hf iclass replay' - use the 'hf iclass dump' or 'hf iclass rdbl' with option "n" instead (@iceman1001). Concept taken from official repo (@pwpiwi) - Add low level support for 14b' aka Innovatron (@doegox) - Add doc/cliparser.md (@mwalker33) - Add `hf 14b apdu` - send APDU over ISO14443B (@iceman1001) diff --git a/Makefile b/Makefile index 1f3b0b44b..89e5b4c98 100644 --- a/Makefile +++ b/Makefile @@ -173,6 +173,9 @@ help: @echo "+ .../check - Run offline tests against specific target. See above." @echo "+ miscchecks - Detect various encoding issues in source code" @echo + @echo "+ udev - Sets udev rules on *nix" + @echo "+ accessrights - Ensure user belongs to correct group on *nix" + @echo @echo "Possible platforms: try \"make PLATFORM=\" for more info, default is PM3RDV4" @echo "To activate verbose mode, use make V=1" @@ -248,7 +251,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 +262,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..16d5ec9e5 100644 --- a/Makefile.defs +++ b/Makefile.defs @@ -27,6 +27,9 @@ LD = g++ SH = sh BASH = bash PERL = perl +CCC =foo +CC_VERSION = $(shell $(CC) -dumpversion 2>/dev/null|sed 's/\..*//') +CC_VERSION := $(or $(strip $(CC_VERSION)),0) PATHSEP=/ PREFIX ?= /usr/local @@ -40,27 +43,52 @@ INSTALLDOCSRELPATH ?= share/doc/proxmark3 platform = $(shell uname) DETECTED_OS=$(platform) -ifeq ($(platform),Darwin) - AR= /usr/bin/ar rcs - RANLIB= /usr/bin/ranlib +ifeq ($(shell $(CC) -v 2>&1 | grep -c "clang version"), 1) + DETECTED_COMPILER = clang else - AR= ar rcs - RANLIB= ranlib + DETECTED_COMPILER = gcc endif -DEFCXXFLAGS = -Wall -Werror -O3 -pipe -DEFCFLAGS = -Wall -Werror -O3 -fstrict-aliasing -pipe +ifeq ($(platform),Darwin) + AR= /usr/bin/ar rcs + RANLIB= /usr/bin/ranlib +else + AR= ar rcs + RANLIB= ranlib +endif + +ifeq ($(DEBUG),1) + DEFCXXFLAGS = -g -O0 -pipe + DEFCFLAGS = -g -O0 -fstrict-aliasing -pipe + DEFLDFLAGS = +else + DEFCXXFLAGS = -Wall -Werror -O3 -pipe + DEFCFLAGS = -Wall -Werror -O3 -fstrict-aliasing -pipe + DEFLDFLAGS = +endif +# 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: DEFCFLAGS += -Wcast-align -Wno-error=cast-align DEFCFLAGS += -Wswitch-enum -Wno-error=switch-enum - +# GCC 10 has issues with false positives on stringop-overflow, let's disable them for now (cf https://gcc.gnu.org/bugzilla/show_bug.cgi?id=92955, https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94335) +# beware these flags didn't exist for GCC < 7 +ifeq ($(shell expr $(CC_VERSION) \>= 10), 1) + ifneq ($(DETECTED_COMPILER), clang) + DEFCFLAGS += -Wno-stringop-overflow -Wno-error=stringop-overflow + endif +endif ifeq ($(platform),Darwin) -# their readline has strict-prototype issues -DEFCFLAGS += -Wno-strict-prototypes + # their readline has strict-prototype issues + DEFCFLAGS += -Wno-strict-prototypes else -DEFCFLAGS += -Wstrict-prototypes + DEFCFLAGS += -Wstrict-prototypes endif # Next ones are activated only if GCCEXTRA=1 or CLANGEXTRA=1 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 d5ef4ac7f..44e6b6040 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,13 +1,17 @@ version: 3.0.1.{build} image: Visual Studio 2019 clone_folder: C:\ProxSpace\pm3\proxmark +cache: + - C:\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: \ProxSpace + proxspace_path: C:\ProxSpace proxspace_home_path: \ProxSpace\pm3 + proxspace_cache_path: C:\ps-cache wsl_git_path: C:\proxmark + APPVEYOR_SAVE_CACHE_ON_ERROR: true init: - ps: >- @@ -25,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" @@ -34,39 +37,19 @@ init: clone_script: - ps: >- - Function ExecUpdate($Text, $firstStart) { - Write-Host "$Text" - Start-Process "cmd.exe" "/c ""cd /D $env:proxspace_path && runme64.bat -c ""exit""""" - $StartTime=[System.Environment]::TickCount - Start-Sleep -s 10 - while($true) { - $cmdprocess = Get-Process "cmd" -ErrorAction SilentlyContinue - - if (!$cmdprocess -Or $cmdprocess.HasExited) { - Write-Host "$Text" -NoNewLine - Write-Host "[ OK ]" -ForegroundColor Green - break - } - - if ($firstStart -And (Test-Path "$env:proxspace_path\msys2\etc\pacman.conf.pacnew")) { - Start-Sleep -s 5 - $tmp = $cmdprocess.CloseMainWindow() - Start-Sleep -s 5 - Stop-Process -Name "cmd" -Force -ErrorAction SilentlyContinue - Write-Host "$Text" -NoNewLine - Write-Host "Exit by pacman.conf" -ForegroundColor Green - break - } - - if ([System.Environment]::TickCount-$StartTime -gt 1000000) { - Write-Host "$Text" -NoNewLine - Write-host "Exit by timeout" -ForegroundColor Yellow - break - } - - Start-Sleep -s 5 - Receive-Job -Job $WSLjob + Function GitClone($Text, $Folder) { + Write-Host "$Text" -NoNewLine + if(-not $env:appveyor_pull_request_number) { + git clone -q --branch=$env:appveyor_repo_branch https://github.com/$env:appveyor_repo_name.git $Folder + cd $Folder + git checkout -qf $env:appveyor_repo_commit + } else { + git clone -q https://github.com/$env:appveyor_repo_name.git $Folder + cd $Folder + git fetch -q origin +refs/pull/$env:appveyor_pull_request_number/merge: + git checkout -qf FETCH_HEAD } + Write-Host "[ OK ]" -ForegroundColor Green } $WSLjob = Start-Job -Name WSLInstall -ScriptBlock { @@ -84,6 +67,96 @@ 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 + + Write-Host "ProxSpace: Removing folder..." -NoNewLine + + cd \ + + Remove-Item -Recurse -Force -Path $env:proxspace_path -ErrorAction SilentlyContinue + + Write-Host "[ OK ]" -ForegroundColor Green + + Write-Host "ProxSpace: downloading..." -NoNewLine + + [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 + + Invoke-WebRequest "$env:proxspace_url" -outfile "$env:proxspace_zip_file" + + Write-Host "[ OK ]" -ForegroundColor Green + + Write-Host "ProxSpace: extracting..." -NoNewLine + + Expand-Archive -LiteralPath "$env:proxspace_zip_file" -DestinationPath "\" + + Remove-Item "$env:proxspace_zip_file" + + Write-Host "[ OK ]" -ForegroundColor Green + + Write-Host "ProxSpace: renaming folder..." -NoNewLine + + Get-ChildItem -Path "\$env:proxspace_zip_folder_name" | Rename-Item -NewName (Split-Path $env:proxspace_path -Leaf) + + Write-Host "[ OK ]" -ForegroundColor Gree + + $psversion = (Select-String -Pattern 'PSVERSION=' -SimpleMatch -Path "$env:proxspace_path\msys2\ps\09-proxspace_setup.post").Line.Split("""")[1] + + Write-Host "ProxSpace version: $psversion" -ForegroundColor Yellow + + GitClone "ProxSpace: Cloning repository <$env:appveyor_repo_name> to $env:appveyor_build_folder ..." $env:appveyor_build_folder + + GitClone "WSL: Cloning repository <$env:appveyor_repo_name> to $env:wsl_git_path ..." $env:wsl_git_path + + +install: +- ps: >- + + Function ExecUpdate($Text, $firstStart) { + Write-Host "$Text" + + $PSjob = Start-Job -Name PSInstall -ScriptBlock { + cd $env:proxspace_path + ./runme64.bat -c "exit" + } + + $StartTime=[System.Environment]::TickCount + Start-Sleep -s 10 + while($true) { + if ($PSjob.State -eq 'Completed') { + Write-Host "$Text" -NoNewLine + Write-Host "[ OK ]" -ForegroundColor Green + break + } + + if ($PSjob.State -eq 'Failed') { + Write-Host "$Text" -NoNewLine + Write-Host "[ Failed ]" -ForegroundColor Red + break + } + + if ($firstStart -And (Test-Path "$env:proxspace_path\msys2\etc\pacman.conf.pacnew")) { + Start-Sleep -s 5 + Stop-Job -Job $PSjob + Start-Sleep -s 5 + Write-Host "$Text" -NoNewLine + Write-Host "Exit by pacman.conf" -ForegroundColor Green + break + } + + if ([System.Environment]::TickCount-$StartTime -gt 1000000) { + Stop-Job -Job $PSjob + Write-Host "$Text" -NoNewLine + Write-host "Exit by timeout" -ForegroundColor Yellow + break + } + + Start-Sleep -s 5 + Receive-Job -Name WSLInstall -ErrorAction SilentlyContinue + } + #Receive-Job -Wait -Name PSInstall } Function GitClone($Text, $Folder) { @@ -101,63 +174,20 @@ clone_script: Write-Host "[ OK ]" -ForegroundColor Green } - Write-Host "ProxSpace: Removing folder..." -NoNewLine + Write-Host "ProxSpace: move cache..." -NoNewLine - $PSInstallTime=[System.Environment]::TickCount + New-Item -ItemType Directory -Force -Path "$env:proxspace_path\msys2\var\cache\" | Out-Null - cd \ - - Remove-Item -Recurse -Force -Path $env:proxspace_path - - Write-Host "[ OK ]" -ForegroundColor Green - - Receive-Job -Job $WSLjob - - Write-Host "ProxSpace: downloading..." -NoNewLine - - [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 - - Invoke-WebRequest "$env:proxspace_url" -outfile "$env:proxspace_zip_file" - - Write-Host "[ OK ]" -ForegroundColor Green - - Receive-Job -Job $WSLjob - - Write-Host "ProxSpace: extracting..." -NoNewLine - - Expand-Archive -LiteralPath "$env:proxspace_zip_file" -DestinationPath "\" - - Remove-Item "$env:proxspace_zip_file" - - Write-Host "[ OK ]" -ForegroundColor Green - - Receive-Job -Job $WSLjob - - Write-Host "ProxSpace: renaming folder..." -NoNewLine - - Get-ChildItem -Path "\$env:proxspace_zip_folder_name" | Rename-Item -NewName (Split-Path $env:proxspace_path -Leaf) + Copy-Item -Path "$env:proxspace_cache_path\*" -Destination "$env:proxspace_path\msys2\var\cache\" -Force -Recurse -ErrorAction SilentlyContinue Write-Host "[ OK ]" -ForegroundColor Gree ExecUpdate "ProxSpace: initial msys2 startup..." $true - ExecUpdate "ProxSpace: installing required packages..." $false - - - $psversion = (Select-String -Pattern 'PSVERSION=' -SimpleMatch -Path "$env:proxspace_path\msys2\ps\09-proxspace_setup.post").Line.Split("""")[1] - - Write-Host "ProxSpace version: $psversion" -ForegroundColor Yellow - - Add-AppveyorMessage -Message "ProxSpace download and update took $(([System.Environment]::TickCount-$PSInstallTime) / 1000) sec" -Category Information - - GitClone "ProxSpace: Cloning repository <$env:appveyor_repo_name> to $env:appveyor_build_folder ..." $env:appveyor_build_folder - - Receive-Job -Wait -Job $WSLjob - - GitClone "WSL: Cloning repository <$env:appveyor_repo_name> to $env:wsl_git_path ..." $env:wsl_git_path + ExecUpdate "ProxSpace: installing required packages..." $false + Add-AppveyorMessage -Message "ProxSpace download and update took $(([System.Environment]::TickCount-$env:PSInstallTime) / 1000) sec" -Category Information -install: build_script: - ps: >- @@ -185,6 +215,7 @@ build_script: $WSLjob = Start-Job -Name WSLCompile -ScriptBlock { Function ExecWSLCmd($Cmd) { + cd $env:wsl_git_path wsl -- bash -c $Cmd } @@ -202,10 +233,19 @@ build_script: throw "Tests error." } } + + #WSL: wait for installation to finish + 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 @@ -234,6 +274,18 @@ build_script: #ProxSpace + Write-Host "ProxSpace: create new cache..." -NoNewLine + + 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 + + Move-Item -Path "$env:proxspace_path\msys2\var\cache" -Destination "$env:proxspace_cache_path" -Force + + Write-Host "[ OK ]" -ForegroundColor Gree + Write-Host "---------- PS make ----------" -ForegroundColor Yellow $TestTime=[System.Environment]::TickCount @@ -276,8 +328,9 @@ build_script: ExecCheck "PS cmake Tests" + Receive-Job -Wait -Name WSLInstall -ErrorAction SilentlyContinue + Receive-Job -Wait -Job $WSLjob - test_script: - ps: >- @@ -292,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..0c06bc90b 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: { @@ -302,15 +302,17 @@ static int reader_dump_mode(void) { Iso15693InitReader(); set_tracing(false); + + picopass_hdr *hdr = (picopass_hdr *)card_data; + // select tag. uint32_t eof_time = 0; - bool res = select_iclass_tag(card_data, auth.use_credit_key, &eof_time); + bool res = select_iclass_tag(hdr, auth.use_credit_key, &eof_time); if (res == false) { switch_off(); continue; } - picopass_hdr *hdr = (picopass_hdr *)card_data; // sanity check of CSN. if (hdr->csn[7] != 0xE0 && hdr->csn[6] != 0x12) { switch_off(); @@ -366,7 +368,7 @@ static int reader_dump_mode(void) { auth.use_credit_key = true; memcpy(auth.key, aa2_key, sizeof(auth.key)); - res = select_iclass_tag(card_data, auth.use_credit_key, &eof_time); + res = select_iclass_tag(hdr, auth.use_credit_key, &eof_time); if (res) { // sanity check of CSN. 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 9dc2472c8..52c9a132b 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: { @@ -933,6 +970,23 @@ static void PacketReceived(PacketCommandNG *packet) { ); break; } + case CMD_LF_EM4X_LOGIN: { + struct p { + uint32_t password; + } PACKED; + struct p *payload = (struct p *) packet->data.asBytes; + EM4xLogin(payload->password); + break; + } + case CMD_LF_EM4X_BF: { + struct p { + uint32_t start_pwd; + uint32_t n; + } PACKED; + struct p *payload = (struct p *) packet->data.asBytes; + EM4xBruteforce(payload->start_pwd, payload->n); + break; + } case CMD_LF_EM4X_READWORD: { struct p { uint32_t password; @@ -954,6 +1008,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); @@ -1211,7 +1275,11 @@ static void PacketReceived(PacketCommandNG *packet) { break; } case CMD_HF_ISO14443A_ANTIFUZZ: { - iso14443a_antifuzz(packet->oldarg[0]); + struct p { + uint8_t flag; + } PACKED; + struct p *payload = (struct p *) packet->data.asBytes; + iso14443a_antifuzz(payload->flag); break; } case CMD_HF_EPA_COLLECT_NONCE: { @@ -1442,6 +1510,15 @@ static void PacketReceived(PacketCommandNG *packet) { MifareU_Otp_Tearoff(packet->oldarg[0], packet->oldarg[1], packet->data.asBytes); break; } + case CMD_HF_MFU_COUNTER_TEAROFF: { + struct p { + uint8_t counter; + uint32_t tearoff_time; + } PACKED; + struct p *payload = (struct p *) packet->data.asBytes; + MifareU_Counter_Tearoff(payload->counter, payload->tearoff_time); + break; + } case CMD_HF_MIFARE_STATIC_NONCE: { MifareHasStaticNonce(); break; @@ -1472,6 +1549,14 @@ static void PacketReceived(PacketCommandNG *packet) { break; } case CMD_HF_ICLASS_SIMULATE: { + /* + struct p { + uint8_t reader[4]; + uint8_t mac[4]; + } PACKED; + struct p *payload = (struct p *) packet->data.asBytes; + */ + SimulateIClass(packet->oldarg[0], packet->oldarg[1], packet->oldarg[2], packet->data.asBytes); break; } @@ -1479,15 +1564,6 @@ static void PacketReceived(PacketCommandNG *packet) { ReaderIClass(packet->oldarg[0]); break; } - case CMD_HF_ICLASS_REPLAY: { - struct p { - uint8_t reader[4]; - uint8_t mac[4]; - } PACKED; - struct p *payload = (struct p *) packet->data.asBytes; - ReaderIClass_Replay(payload->reader, payload->mac); - break; - } case CMD_HF_ICLASS_EML_MEMSET: { //iceman, should call FPGADOWNLOAD before, since it corrupts BigBuf FpgaDownloadAndGo(FPGA_BITSTREAM_HF); @@ -1514,18 +1590,8 @@ static void PacketReceived(PacketCommandNG *packet) { iClass_Dump(packet->data.asBytes); break; } - case CMD_HF_ICLASS_CLONE: { - struct p { - uint8_t startblock; - uint8_t endblock; - uint8_t data[]; - } PACKED; - struct p *payload = (struct p *)packet->data.asBytes; - iClass_Clone(payload->startblock, payload->endblock, payload->data); - break; - } case CMD_HF_ICLASS_RESTORE: { - iClass_Restore(packet->data.asBytes); + iClass_Restore((iclass_restore_req_t *)packet->data.asBytes); break; } #endif @@ -1567,7 +1633,11 @@ static void PacketReceived(PacketCommandNG *packet) { break; } case CMD_SMART_SETCLOCK: { - SmartCardSetClock(packet->oldarg[0]); + struct p { + uint32_t new_clk; + } PACKED; + struct p *payload = (struct p *)packet->data.asBytes; + SmartCardSetClock(payload->new_clk); break; } case CMD_SMART_RAW: { 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/em4x50.c b/armsrc/em4x50.c index e19a91e4b..fe5c493b2 100644 --- a/armsrc/em4x50.c +++ b/armsrc/em4x50.c @@ -14,6 +14,7 @@ #include "lfadc.h" #include "commonutil.h" #include "em4x50.h" +#include "appmain.h" // tear // Sam7s has several timers, we will use the source TIMER_CLOCK1 (aka AT91C_TC_CLKS_TIMER_DIV1_CLOCK) // TIMER_CLOCK1 = MCK/2, MCK is running at 48 MHz, Timer is running at 48/2 = 24 MHz @@ -350,6 +351,8 @@ static int find_double_listen_window(bool bcommand) { if (bcommand) { +// SpinDelay(10); + // data transmission from card has to be stopped, because // a commamd shall be issued @@ -953,14 +956,18 @@ static bool write(uint32_t word, uint32_t addresses) { // wait for T0 * EM4X50_T_TAG_TWA (write access time) wait_timer0(T0 * EM4X50_T_TAG_TWA); - // look for ACK sequence - if (check_ack(false)) { + // wait for T0 * EM4X50_T_TAG_TWA (write access time) + wait_timer(FPGA_TIMER_0, T0 * EM4X50_T_TAG_TWA); - // now EM4x50 needs T0 * EM4X50_T_TAG_TWEE (EEPROM write time) - // for saving data and should return with ACK - if (check_ack(false)) - return true; + // look for ACK sequence + if (check_ack(false)) { + // now EM4x50 needs T0 * EM4X50_T_TAG_TWEE (EEPROM write time) + // for saving data and should return with ACK + if (check_ack(false)) + return PM3_SUCCESS; + + } } } else { @@ -968,7 +975,7 @@ static bool write(uint32_t word, uint32_t addresses) { Dbprintf("error in command request"); } - return false; + return PM3_ESOFT; } static bool write_password(uint32_t password, uint32_t new_password) { @@ -986,9 +993,8 @@ static bool write_password(uint32_t password, uint32_t new_password) { // wait for T0 * EM4x50_T_TAG_TPP (processing pause time) wait_timer0(T0 * EM4X50_T_TAG_TPP); - // look for ACK sequence and send rm request - // during following listen window - if (check_ack(true)) { + // wait for T0 * EM4x50_T_TAG_TPP (processing pause time) + wait_timer(FPGA_TIMER_0, T0 * EM4X50_T_TAG_TPP); // send new password em4x50_reader_send_word(new_password); @@ -996,10 +1002,11 @@ static bool write_password(uint32_t password, uint32_t new_password) { // wait for T0 * EM4X50_T_TAG_TWA (write access time) wait_timer0(T0 * EM4X50_T_TAG_TWA); - if (check_ack(false)) if (check_ack(false)) - return true; + if (check_ack(false)) + return PM3_SUCCESS; + } } } else { @@ -1007,7 +1014,7 @@ static bool write_password(uint32_t password, uint32_t new_password) { Dbprintf("error in command request"); } - return false; + return PM3_ESOFT; } void em4x50_write(em4x50_data_t *etd) { @@ -1031,6 +1038,7 @@ void em4x50_write(em4x50_data_t *etd) { // write word to given address if (write(etd->word, etd->addresses)) { + if (res == PM3_SUCCESS) { // to verify result reset EM4x50 if (reset()) { @@ -1049,7 +1057,6 @@ void em4x50_write(em4x50_data_t *etd) { } status = (bsuccess << 1) + blogin; - lf_finalize(); reply_ng(CMD_ACK, status, (uint8_t *)words, 136); } @@ -1071,7 +1078,7 @@ void em4x50_write_password(em4x50_data_t *etd) { } lf_finalize(); - reply_ng(CMD_ACK, bsuccess, 0, 0); + reply_ng(CMD_LF_EM4X50_WRITE_PASSWORD, bsuccess, 0, 0); } void em4x50_wipe(uint32_t *password) { diff --git a/armsrc/hfsnoop.c b/armsrc/hfsnoop.c index ec13dbc85..4e4539f3e 100644 --- a/armsrc/hfsnoop.c +++ b/armsrc/hfsnoop.c @@ -99,7 +99,7 @@ int HfSniff(uint32_t samplesToSkip, uint32_t triggersToSkip, uint16_t *len) { optimizedSniff((uint16_t *)mem, *len); - if (DBGLEVEL >= DBG_INFO) { + if (DBGLEVEL >= DBG_INFO) { Dbprintf("Trigger kicked in (%d >= 180)", r); Dbprintf("Collected %u samples", *len); } diff --git a/armsrc/i2c.c b/armsrc/i2c.c index 1ca742893..7b858dd36 100644 --- a/armsrc/i2c.c +++ b/armsrc/i2c.c @@ -47,12 +47,6 @@ static void __attribute__((optimize("O0"))) I2CSpinDelayClk(uint16_t delay) { #define I2C_DELAY_2CLK I2CSpinDelayClk(2) #define I2C_DELAY_XCLK(x) I2CSpinDelayClk((x)) -#define I2C_DELAY_100us I2CSpinDelayClk( 100 / 3) -#define I2C_DELAY_600us I2CSpinDelayClk( 600 / 3) -#define I2C_DELAY_10ms I2CSpinDelayClk( 10 * 1000 / 3 ) -#define I2C_DELAY_30ms I2CSpinDelayClk( 30 * 1000 / 3 ) -#define I2C_DELAY_100ms I2CSpinDelayClk( 100 * 1000 / 3) - #define ISO7618_MAX_FRAME 255 // try i2c bus recovery at 100kHz = 5us high, 5us low @@ -134,11 +128,11 @@ void I2C_Reset_EnterMainProgram(void) { StartTicks(); I2C_init(); I2C_SetResetStatus(0, 0, 0); - I2C_DELAY_30ms; + WaitMS(30); I2C_SetResetStatus(1, 0, 0); - I2C_DELAY_30ms; + WaitMS(30); I2C_SetResetStatus(1, 1, 1); - I2C_DELAY_10ms; + WaitMS(10); } // Reset the SIM_Adapter, then enter the bootloader program @@ -147,9 +141,9 @@ void I2C_Reset_EnterBootloader(void) { StartTicks(); I2C_init(); I2C_SetResetStatus(0, 1, 1); - I2C_DELAY_100ms; + WaitMS(100); I2C_SetResetStatus(1, 1, 1); - I2C_DELAY_10ms; + WaitMS(10); } // Wait for the clock to go High. @@ -193,7 +187,7 @@ static bool WaitSCL_L_timeout(void) { if (!SCL_read) return true; - I2C_DELAY_100us; + WaitMS(1); } return (delay == 0); } @@ -440,8 +434,7 @@ int16_t I2C_BufferRead(uint8_t *data, uint8_t len, uint8_t device_cmd, uint8_t d // extra wait 500us (514us measured) // 200us (xx measured) -// WaitUS(600); - I2C_DELAY_600us; + WaitUS(600); bool bBreak = true; uint16_t readcount = 0; @@ -811,8 +804,7 @@ void SmartCardUpgrade(uint64_t arg0) { } // writing takes time. -// WaitMS(50); - I2C_DELAY_100ms; + WaitMS(100); // read res = I2C_ReadFW(verfiydata, size, msb, lsb, I2C_DEVICE_ADDRESS_BOOT); @@ -844,12 +836,10 @@ void SmartCardSetClock(uint64_t arg0) { LED_D_ON(); set_tracing(true); I2C_Reset_EnterMainProgram(); - // Send SIM CLC // start [C0 05 xx] stop I2C_WriteByte(arg0, I2C_DEVICE_CMD_SIM_CLC, I2C_DEVICE_ADDRESS_MAIN); - - reply_mix(CMD_ACK, 1, 0, 0, 0, 0); + reply_ng(CMD_SMART_SETCLOCK, PM3_SUCCESS, NULL, 0); set_tracing(false); LEDsoff(); } diff --git a/armsrc/iclass.c b/armsrc/iclass.c index 7f22b59cc..03f7dcbba 100644 --- a/armsrc/iclass.c +++ b/armsrc/iclass.c @@ -1276,7 +1276,7 @@ static bool iclass_send_cmd_with_retries(uint8_t *cmd, size_t cmdsize, uint8_t * * @return false = fail * true = Got all. */ -static bool select_iclass_tag_ex(uint8_t *card_data, bool use_credit_key, uint32_t *eof_time, uint8_t *status) { +static bool select_iclass_tag_ex(picopass_hdr *hdr, bool use_credit_key, uint32_t *eof_time, uint8_t *status) { static uint8_t act_all[] = { ICLASS_CMD_ACTALL }; static uint8_t identify[] = { ICLASS_CMD_READ_OR_IDENTIFY, 0x00, 0x73, 0x33 }; @@ -1286,8 +1286,6 @@ static bool select_iclass_tag_ex(uint8_t *card_data, bool use_credit_key, uint32 uint8_t read_check_cc[] = { 0x80 | ICLASS_CMD_READCHECK, 0x02 }; uint8_t resp[ICLASS_BUFFER_SIZE] = {0}; - picopass_hdr *hdr = (picopass_hdr *)card_data; - // Bit 4: K.If this bit equals to one, the READCHECK will use the Credit Key (Kc); if equals to zero, Debit Key (Kd) will be used // bit 7: parity. if (use_credit_key) @@ -1370,6 +1368,8 @@ static bool select_iclass_tag_ex(uint8_t *card_data, bool use_credit_key, uint32 } else { + // on NON_SECURE_PAGEMODE cards, AIA is on block2.. + // read App Issuer Area block 2 read_aia[1] = 0x02; read_aia[2] = 0x61; @@ -1385,23 +1385,23 @@ static bool select_iclass_tag_ex(uint8_t *card_data, bool use_credit_key, uint32 if (status) { *status |= FLAG_ICLASS_AIA; - memcpy(card_data + (8 * 2), resp, 8); + memcpy(hdr->epurse, resp, sizeof(hdr->epurse)); } } return true; } -bool select_iclass_tag(uint8_t *card_data, bool use_credit_key, uint32_t *eof_time) { +bool select_iclass_tag(picopass_hdr *hdr, bool use_credit_key, uint32_t *eof_time) { uint8_t result = 0; - return select_iclass_tag_ex(card_data, use_credit_key, eof_time, &result); + return select_iclass_tag_ex(hdr, use_credit_key, eof_time, &result); } // Reader iClass Anticollission // turn off afterwards void ReaderIClass(uint8_t flags) { - uint8_t card_data[6 * 8] = {0xFF}; + picopass_hdr hdr = {0}; // uint8_t last_csn[8] = {0, 0, 0, 0, 0, 0, 0, 0}; uint8_t resp[ICLASS_BUFFER_SIZE] = {0}; memset(resp, 0xFF, sizeof(resp)); @@ -1419,14 +1419,13 @@ void ReaderIClass(uint8_t flags) { uint8_t result_status = 0; uint32_t eof_time = 0; - bool status = select_iclass_tag_ex(card_data, use_credit_key, &eof_time, &result_status); + bool status = select_iclass_tag_ex(&hdr, use_credit_key, &eof_time, &result_status); if (status == false) { - reply_mix(CMD_ACK, 0xFF, 0, 0, card_data, 0); + reply_mix(CMD_ACK, 0xFF, 0, 0, NULL, 0); switch_off(); return; } - // Page mapping for secure mode // 0 : CSN // 1 : Configuration @@ -1444,7 +1443,7 @@ void ReaderIClass(uint8_t flags) { // with 0xFF:s in block 3 and 4. LED_B_ON(); - reply_mix(CMD_ACK, result_status, 0, 0, card_data, sizeof(card_data)); + reply_mix(CMD_ACK, result_status, 0, 0, (uint8_t *)&hdr, sizeof(hdr)); //Send back to client, but don't bother if we already sent this - // only useful if looping in arm (not try_once && not abort_after_read) @@ -1470,101 +1469,6 @@ void ReaderIClass(uint8_t flags) { switch_off(); } -// turn off afterwards -void ReaderIClass_Replay(uint8_t *rnr, uint8_t *mac) { - - BigBuf_free(); - - uint8_t check[] = { ICLASS_CMD_CHECK, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - - memcpy(check + 1, rnr, 4); - memcpy(check + 5, mac, 4); - - uint8_t *card_data = BigBuf_malloc(ICLASS_16KS_SIZE); - if (card_data == NULL) { - DbpString("fail to allocate memory"); - reply_ng(CMD_HF_ICLASS_REPLAY, PM3_EMALLOC, NULL, 0); - return; - } - memset(card_data, 0xFF, ICLASS_16KS_SIZE); - - uint32_t start_time = 0; - uint32_t eof_time = 0; - - Iso15693InitReader(); - - picopass_hdr hdr = {0}; - bool res = select_iclass_tag((uint8_t *)&hdr, false, &eof_time); - if (res == false) { - reply_ng(CMD_HF_ICLASS_REPLAY, PM3_ETIMEOUT, NULL, 0); - switch_off(); - return; - } - - uint8_t resp[10] = {0}; - - //for now replay captured auth (as cc not updated) - start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; - res = iclass_send_cmd_with_retries(check, sizeof(check), resp, sizeof(resp), 4, 3, &start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time); - if (res == false) { - reply_ng(CMD_HF_ICLASS_REPLAY, PM3_ETIMEOUT, NULL, 0); - switch_off(); - return; - } - - uint8_t mem = hdr.conf.mem_config; - uint8_t cardsize = ((mem & 0x80) == 0x80) ? 255 : 32; - - /* - static struct memory_t { - int k16; - int book; - int k2; - int lockauth; - int keyaccess; - } memory; - - // memory.k16 = ((mem & 0x80) == 0x80); - // memory.book = ((mem & 0x20) == 0x20); - // memory.k2 = ((mem & 0x08) == 0x08); - // memory.lockauth = ((mem & 0x02) == 0x02); - // memory.keyaccess = ((mem & 0x01) == 0x01); - // uint8_t cardsize = memory.k16 ? 255 : 32; - */ - - bool dumpsuccess = true; - - // main read loop - uint16_t i; - for (i = 0; i <= cardsize; i++) { - - uint8_t c[] = {ICLASS_CMD_READ_OR_IDENTIFY, i, 0x00, 0x00}; - AddCrc(c + 1, 1); - - res = iclass_send_cmd_with_retries(c, sizeof(c), resp, sizeof(resp), 10, 3, &start_time, ICLASS_READER_TIMEOUT_OTHERS, &eof_time); - if (res) { - memcpy(card_data + (8 * i), resp, 8); - } else { - Dbprintf("failed to read block %u ( 0x%02x)", i, i); - dumpsuccess = false; - } - } - - struct p { - bool isOK; - uint16_t block_cnt; - uint32_t bb_offset; - } PACKED response; - - response.isOK = dumpsuccess; - response.block_cnt = i; - response.bb_offset = card_data - BigBuf_get_addr(); - reply_ng(CMD_HF_ICLASS_REPLAY, PM3_SUCCESS, (uint8_t *)&response, sizeof(response)); - - BigBuf_free(); - switch_off(); -} - // used with function select_and_auth (cmdhficlass.c) // which needs to authenticate before doing more things like read/write // selects and authenticate to a card, sends back div_key and mac to client. @@ -1585,24 +1489,30 @@ bool authenticate_iclass_tag(iclass_auth_req_t *payload, picopass_hdr *hdr, uint memcpy(ccnr, hdr->epurse, sizeof(hdr->epurse)); - if (payload->use_raw) - memcpy(div_key, payload->key, 8); - else - iclass_calc_div_key(hdr->csn, payload->key, div_key, payload->use_elite); + if (payload->use_replay) { - if (payload->use_credit_key) - memcpy(hdr->key_c, div_key, sizeof(hdr->key_c)); - else - memcpy(hdr->key_d, div_key, sizeof(hdr->key_d)); + memcpy(pmac, payload->key + 4, 4); + memcpy(cmd_check + 1, payload->key, 8); - opt_doReaderMAC(ccnr, div_key, pmac); + } else { + if (payload->use_raw) + memcpy(div_key, payload->key, 8); + else + iclass_calc_div_key(hdr->csn, payload->key, div_key, payload->use_elite); - // copy MAC to check command (readersignature) - cmd_check[5] = pmac[0]; - cmd_check[6] = pmac[1]; - cmd_check[7] = pmac[2]; - cmd_check[8] = pmac[3]; + if (payload->use_credit_key) + memcpy(hdr->key_c, div_key, sizeof(hdr->key_c)); + else + memcpy(hdr->key_d, div_key, sizeof(hdr->key_d)); + opt_doReaderMAC(ccnr, div_key, pmac); + + // copy MAC to check command (readersignature) + cmd_check[5] = pmac[0]; + cmd_check[6] = pmac[1]; + cmd_check[7] = pmac[2]; + cmd_check[8] = pmac[3]; + } return iclass_send_cmd_with_retries(cmd_check, sizeof(cmd_check), resp_auth, sizeof(resp_auth), 4, 2, start_time, ICLASS_READER_TIMEOUT_OTHERS, eof_time); } @@ -1632,7 +1542,7 @@ void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain) { readcheck_cc[0] = 0x10 | ICLASS_CMD_READCHECK; // select card / e-purse - uint8_t card_data[6 * 8] = {0}; + picopass_hdr hdr = {0}; iclass_premac_t *keys = (iclass_premac_t *)datain; @@ -1646,7 +1556,7 @@ void iClass_Authentication_fast(uint64_t arg0, uint64_t arg1, uint8_t *datain) { uint32_t start_time = 0, eof_time = 0; - if (select_iclass_tag(card_data, use_credit_key, &eof_time) == false) + if (select_iclass_tag(&hdr, use_credit_key, &eof_time) == false) goto out; start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; @@ -1723,7 +1633,7 @@ void iClass_ReadBlock(uint8_t *msg) { // select tag. uint32_t eof_time = 0; picopass_hdr hdr = {0}; - bool res = select_iclass_tag((uint8_t *)&hdr, payload->use_credit_key, &eof_time); + bool res = select_iclass_tag(&hdr, payload->use_credit_key, &eof_time); if (res == false) { if (payload->send_reply) { response.isOK = res; @@ -1796,7 +1706,7 @@ void iClass_Dump(uint8_t *msg) { // select tag. uint32_t eof_time = 0; picopass_hdr hdr = {0}; - bool res = select_iclass_tag((uint8_t *)&hdr, req->use_credit_key, &eof_time); + bool res = select_iclass_tag(&hdr, req->use_credit_key, &eof_time); if (res == false) { if (req->send_reply) { reply_ng(CMD_HF_ICLASS_DUMP, PM3_ETIMEOUT, NULL, 0); @@ -1866,10 +1776,12 @@ void iClass_Dump(uint8_t *msg) { BigBuf_free(); } -static bool iclass_writeblock_ext(uint8_t blockno, uint8_t *data) { +static bool iclass_writeblock_ext(uint8_t blockno, uint8_t *data, uint8_t *mac) { + // write command: cmd, 1 blockno, 8 data, 4 mac uint8_t write[16] = { 0x80 | ICLASS_CMD_UPDATE, blockno }; - memcpy(write + 2, data, 12); // data + mac + memcpy(write + 2, data, 8); + memcpy(write + 10, mac, 4); AddCrc(write + 1, 13); uint8_t resp[10] = {0}; @@ -1914,7 +1826,7 @@ void iClass_WriteBlock(uint8_t *msg) { // select tag. uint32_t eof_time = 0; picopass_hdr hdr = {0}; - bool res = select_iclass_tag((uint8_t *)&hdr, payload->req.use_credit_key, &eof_time); + bool res = select_iclass_tag(&hdr, payload->req.use_credit_key, &eof_time); if (res == false) { goto out; } @@ -1937,10 +1849,14 @@ void iClass_WriteBlock(uint8_t *msg) { wb[0] = payload->req.blockno; memcpy(wb + 1, payload->data, 8); - if (payload->req.use_credit_key) - doMAC_N(wb, sizeof(wb), hdr.key_c, mac); - else - doMAC_N(wb, sizeof(wb), hdr.key_d, mac); + if (payload->req.use_replay) { + doMAC_N(wb, sizeof(wb), payload->req.key + 4, mac); + } else { + if (payload->req.use_credit_key) + doMAC_N(wb, sizeof(wb), hdr.key_c, mac); + else + doMAC_N(wb, sizeof(wb), hdr.key_d, mac); + } memcpy(write + 2, payload->data, 8); // data memcpy(write + 10, mac, sizeof(mac)); // mac @@ -1949,8 +1865,29 @@ void iClass_WriteBlock(uint8_t *msg) { start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; uint8_t resp[10] = {0}; - res = iclass_send_cmd_with_retries(write, sizeof(write), resp, sizeof(resp), 10, 3, &start_time, ICLASS_READER_TIMEOUT_UPDATE, &eof_time); - if (res == false) { + + uint8_t tries = 3; + while (tries-- > 0) { + + iclass_send_as_reader(write, sizeof(write), &start_time, &eof_time); + + if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured + res = false; + switch_off(); + if (payload->req.send_reply) + reply_ng(CMD_HF_ICLASS_WRITEBL, PM3_ETEAROFF, (uint8_t *)&res, sizeof(uint8_t)); + return; + } else { + + if (GetIso15693AnswerFromTag(resp, sizeof(resp), ICLASS_READER_TIMEOUT_UPDATE, &eof_time) == 10) { + res = true; + break; + } + } + } + + if (tries == 0) { + res = false; goto out; } @@ -1983,29 +1920,75 @@ out: reply_ng(CMD_HF_ICLASS_WRITEBL, PM3_SUCCESS, (uint8_t *)&res, sizeof(uint8_t)); } -// turn off afterwards -void iClass_Clone(uint8_t startblock, uint8_t endblock, uint8_t *data) { -} +void iClass_Restore(iclass_restore_req_t *msg) { -void iClass_Restore(uint8_t *msg) { + // sanitation + if (msg == NULL) { + reply_ng(CMD_HF_ICLASS_RESTORE, PM3_ESOFT, NULL, 0); + return; + } - iclass_restore_req_t *cmd = (iclass_restore_req_t *)msg; -// iclass_auth_req_t *req = &cmd->req; + if (msg->item_cnt == 0) { + if (msg->req.send_reply) { + reply_ng(CMD_HF_ICLASS_RESTORE, PM3_ESOFT, NULL, 0); + } + return; + } LED_A_ON(); - uint16_t written = 0; - uint16_t total_blocks = (cmd->end_block - cmd->start_block) + 1; - for (uint8_t b = cmd->start_block; b < total_blocks; b++) { + Iso15693InitReader(); - if (iclass_writeblock_ext(b, cmd->data + ((b - cmd->start_block) * 12))) { - Dbprintf("Write block [%02x] successful", b); - written++; - } else { - Dbprintf("Write block [%02x] failed", b); + uint16_t written = 0; + uint32_t eof_time = 0; + picopass_hdr hdr = {0}; + + // select + bool res = select_iclass_tag(&hdr, msg->req.use_credit_key, &eof_time); + if (res == false) { + goto out; + } + + // authenticate + uint8_t mac[4] = {0}; + uint32_t start_time = eof_time + DELAY_ICLASS_VICC_TO_VCD_READER; + + // authenticate + if (msg->req.do_auth) { + res = authenticate_iclass_tag(&msg->req, &hdr, &start_time, &eof_time, mac); + if (res == false) { + goto out; } } + // main loop + for (uint8_t i = 0; i < msg->item_cnt; i++) { + + iclass_restore_item_t item = msg->blocks[i]; + + // calc new mac for data, using 1b blockno, 8b data, + uint8_t wb[9] = {0}; + wb[0] = item.blockno; + memcpy(wb + 1, item.data, 8); + + if (msg->req.use_credit_key) + doMAC_N(wb, sizeof(wb), hdr.key_c, mac); + else + doMAC_N(wb, sizeof(wb), hdr.key_d, mac); + + // data + mac + if (iclass_writeblock_ext(item.blockno, item.data, mac)) { + Dbprintf("Write block [%02x] " _GREEN_("successful"), item.blockno); + written++; + } else { + Dbprintf("Write block [%02x] " _RED_("failed"), item.blockno); + } + } + +out: + switch_off(); - uint8_t isOK = (written == total_blocks) ? 1 : 0; - reply_ng(CMD_HF_ICLASS_CLONE, PM3_SUCCESS, (uint8_t *)&isOK, sizeof(uint8_t)); + if (msg->req.send_reply) { + int isOK = (written == msg->item_cnt) ? PM3_SUCCESS : PM3_ESOFT; + reply_ng(CMD_HF_ICLASS_RESTORE, isOK, NULL, 0); + } } diff --git a/armsrc/iclass.h b/armsrc/iclass.h index 3776aa385..1895ebbf6 100644 --- a/armsrc/iclass.h +++ b/armsrc/iclass.h @@ -17,13 +17,11 @@ void SniffIClass(uint8_t jam_search_len, uint8_t *jam_search_string); void ReaderIClass(uint8_t arg0); -void ReaderIClass_Replay(uint8_t *rnr, uint8_t *mac); void iClass_WriteBlock(uint8_t *msg); void iClass_Dump(uint8_t *msg); -void iClass_Restore(uint8_t *msg); -void iClass_Clone(uint8_t startblock, uint8_t endblock, uint8_t *data); +void iClass_Restore(iclass_restore_req_t *msg); int do_iclass_simulation_nonsec(void); int do_iclass_simulation(int simulationMode, uint8_t *reader_mac_buf); @@ -37,6 +35,6 @@ bool iclass_auth(iclass_auth_req_t *payload, uint8_t *out); void iClass_ReadBlock(uint8_t *msg); bool iclass_read_block(uint16_t blockno, uint8_t *data, uint32_t *start_time, uint32_t *eof_time); -bool select_iclass_tag(uint8_t *card_data, bool use_credit_key, uint32_t *eof_time); +bool select_iclass_tag(picopass_hdr *hdr, bool use_credit_key, uint32_t *eof_time); bool authenticate_iclass_tag(iclass_auth_req_t *payload, picopass_hdr *hdr, uint32_t *start_time, uint32_t *eof_time, uint8_t *mac_out); #endif diff --git a/armsrc/iso14443a.c b/armsrc/iso14443a.c index 6ada61171..cf0bce153 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" : "" + ); } /** @@ -2365,7 +2390,7 @@ void iso14443a_antifuzz(uint32_t flags) { } } - reply_old(CMD_ACK, 1, 0, 0, 0, 0); + reply_ng(CMD_HF_ISO14443A_ANTIFUZZ, PM3_SUCCESS, NULL, 0); switch_off(); BigBuf_free_keep_EM(); } @@ -2599,13 +2624,13 @@ int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint32 } // else force RATS // RATS, Request for answer to select - if (!no_rats) { - uint8_t rats[] = { ISO14443A_CMD_RATS, 0x80, 0x00, 0x00 }; // FSD=256, FSDI=8, CID=0 + if (no_rats == false) { + uint8_t rats[] = { ISO14443A_CMD_RATS, 0x80, 0x00, 0x00 }; // FSD=256, FSDI=8, CID=0 AddCrc14A(rats, 2); ReaderTransmit(rats, sizeof(rats), NULL); int len = ReaderReceive(resp, resp_par); - - if (!len) return 0; + if (len == 0) + return 0; if (p_card) { memcpy(p_card->ats, resp, sizeof(p_card->ats)); @@ -2687,7 +2712,7 @@ void iso14443a_setup(uint8_t fpga_minor_mode) { LED_D_ON(); FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | fpga_minor_mode); - SpinDelay(100); + SpinDelay(50); // Start the timer StartCountSspClk(); @@ -2904,10 +2929,15 @@ void ReaderIso14443a(PacketCommandNG *c) { ReaderTransmit(cmd, len, NULL); // 8 bits, odd parity } } - arg0 = ReaderReceive(buf, par); - FpgaDisableTracing(); - reply_old(CMD_ACK, arg0, 0, 0, buf, sizeof(buf)); + if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured + FpgaDisableTracing(); + reply_mix(CMD_ACK, 0, 0, 0, NULL, 0); + } else { + arg0 = ReaderReceive(buf, par); + FpgaDisableTracing(); + reply_old(CMD_ACK, arg0, 0, 0, buf, sizeof(buf)); + } } if ((param & ISO14A_REQUEST_TRIGGER)) diff --git a/armsrc/iso14443b.c b/armsrc/iso14443b.c index 01d890d28..64c0ba67f 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,8 @@ 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; Demod.sumQ += cq; @@ -798,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; @@ -814,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; @@ -822,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; @@ -856,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; } @@ -926,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); @@ -995,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 @@ -1043,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); @@ -1067,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)) {}; } @@ -1092,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 @@ -1100,10 +1101,10 @@ static void CodeIso14443bAsReader(const uint8_t *cmd, int len) { */ int i; tosend_reset(); - + // Send SOF // 10-11 ETUs of ZERO - for (i = 0; i < 10; i++) { + for (i = 0; i < 11; i++) { tosend_stuffbit(0); } // 2-3 ETUs of ONE @@ -1132,23 +1133,21 @@ static void CodeIso14443bAsReader(const uint8_t *cmd, int len) { // EGT extra guard time 1 ETU = 9us // For PCD it ranges 0-57us === 0 - 6 ETU // FOR PICC it ranges 0-19us == 0 - 2 ETU - } // Send EOF // 10-11 ETUs of ZERO - for (i = 0; i < 10; i++) { + for (i = 0; i < 11; i++) { tosend_stuffbit(0); } - tosend_stuffbit(1); /* Transition time. TR0 - guard time * TR0 - 8 ETU's minimum. * TR0 - 32 ETU's maximum for ATQB only * TR0 - FWT for all other commands * 32,64,128,256,512, ... , 262144, 524288 ETU */ - int pad = (12 + (len * 10) + 11) & 0x7; + int pad = (11 + 2 + (len * 10) + 11) & 0x7; for (i = 0; i < 16 - pad; ++i) tosend_stuffbit(1); @@ -1186,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 @@ -1270,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); @@ -1524,7 +1523,7 @@ void iso14443b_setup(void) { // Signal field is on with the appropriate LED FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_READER | FPGA_HF_READER_MODE_SEND_SHALLOW_MOD); - SpinDelay(100); + SpinDelay(50); // Start the timer StartCountSspClk(); @@ -1841,17 +1840,21 @@ void SendRawCommand14443B_Ex(PacketCommandNG *c) { if ((param & ISO14B_CONNECT) == ISO14B_CONNECT) { iso14443b_setup(); - clear_trace(); } - if ((param & ISO14B_SET_TIMEOUT)) + if ((param & ISO14B_SET_TIMEOUT) == ISO14B_SET_TIMEOUT) { iso14b_set_timeout(timeout); + } + if ((param & ISO14B_CLEARTRACE) == ISO14B_CLEARTRACE) { + clear_trace(); + } set_tracing(true); int status; uint32_t sendlen = sizeof(iso14b_card_select_t); iso14b_card_select_t card; + memset((void *)&card, 0x00, sizeof(card)); if ((param & ISO14B_SELECT_STD) == ISO14B_SELECT_STD) { status = iso14443b_select_card(&card); @@ -1874,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; @@ -1892,12 +1895,17 @@ void SendRawCommand14443B_Ex(PacketCommandNG *c) { uint32_t eof_time = 0; CodeAndTransmit14443bAsReader(cmd, len, &start_time, &eof_time); - eof_time += DELAY_ISO14443B_VCD_TO_VICC_READER; - status = Get14443bAnswerFromTag(buf, sizeof(buf), 5 * ISO14443B_READER_TIMEOUT, &eof_time); // raw - FpgaDisableTracing(); + if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured + FpgaDisableTracing(); + reply_mix(CMD_HF_ISO14443B_COMMAND, -2, 0, 0, NULL, 0); + } else { + eof_time += DELAY_ISO14443B_VCD_TO_VICC_READER; + status = Get14443bAnswerFromTag(buf, sizeof(buf), 5 * ISO14443B_READER_TIMEOUT, &eof_time); // raw + FpgaDisableTracing(); - sendlen = MIN(Demod.len, PM3_CMD_DATA_SIZE); - reply_mix(CMD_HF_ISO14443B_COMMAND, status, sendlen, 0, Demod.output, sendlen); + sendlen = MIN(Demod.len, PM3_CMD_DATA_SIZE); + reply_mix(CMD_HF_ISO14443B_COMMAND, status, sendlen, 0, Demod.output, sendlen); + } } out: diff --git a/armsrc/iso15693.c b/armsrc/iso15693.c index 3125f90bf..bacceb165 100644 --- a/armsrc/iso15693.c +++ b/armsrc/iso15693.c @@ -290,6 +290,7 @@ void TransmitTo15693Tag(const uint8_t *cmd, int len, uint32_t *start_time) { LED_B_OFF(); *start_time = *start_time + DELAY_ARM_TO_TAG; + FpgaDisableTracing(); } //----------------------------------------------------------------------------- @@ -732,6 +733,7 @@ int GetIso15693AnswerFromTag(uint8_t *response, uint16_t max_len, uint16_t timeo } FpgaDisableSscDma(); + FpgaDisableTracing(); uint32_t sof_time = *eof_time - (dt->len * 8 * 8 * 16) // time for byte transfers @@ -1469,15 +1471,21 @@ int SendDataTag(uint8_t *send, int sendlen, bool init, bool speed_fast, uint8_t // low speed (1 out of 256) CodeIso15693AsReader256(send, sendlen); } - + int res = 0; tosend_t *ts = get_tosend(); TransmitTo15693Tag(ts->buf, ts->max, &start_time); - *eof_time = start_time + 32 * ((8 * ts->max) - 4); // substract the 4 padding bits after EOF - LogTrace_ISO15693(send, sendlen, (start_time * 4), (*eof_time * 4), NULL, true); - int res = 0; - if (recv != NULL) { - res = GetIso15693AnswerFromTag(recv, max_recv_len, timeout, eof_time); + if (tearoff_hook() == PM3_ETEAROFF) { // tearoff occured + + res = PM3_ETEAROFF; + + } else { + + *eof_time = start_time + 32 * ((8 * ts->max) - 4); // substract the 4 padding bits after EOF + LogTrace_ISO15693(send, sendlen, (start_time * 4), (*eof_time * 4), NULL, true); + if (recv != NULL) { + res = GetIso15693AnswerFromTag(recv, max_recv_len, timeout, eof_time); + } } return res; } @@ -1586,41 +1594,49 @@ void ReaderIso15693(uint32_t parameter) { BuildIdentifyRequest(cmd); uint32_t start_time = 0; uint32_t eof_time; - int answerLen = SendDataTag(cmd, sizeof(cmd), true, true, answer, ISO15693_MAX_RESPONSE_LENGTH, start_time, ISO15693_READER_TIMEOUT, &eof_time); - start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; + int recvlen = SendDataTag(cmd, sizeof(cmd), true, true, answer, ISO15693_MAX_RESPONSE_LENGTH, start_time, ISO15693_READER_TIMEOUT, &eof_time); - // we should do a better check than this - if (answerLen >= 12) { - uint8_t uid[8]; - uid[0] = answer[9]; // always E0 - uid[1] = answer[8]; // IC Manufacturer code - uid[2] = answer[7]; - uid[3] = answer[6]; - uid[4] = answer[5]; - uid[5] = answer[4]; - uid[6] = answer[3]; - uid[7] = answer[2]; + if (recvlen == PM3_ETEAROFF) { // tearoff occured + reply_mix(CMD_ACK, recvlen, 0, 0, NULL, 0); + } else { - if (DBGLEVEL >= DBG_EXTENDED) { - Dbprintf("[+] UID = %02X%02X%02X%02X%02X%02X%02X%02X", - uid[0], uid[1], uid[2], uid[3], - uid[4], uid[5], uid[5], uid[6] - ); + start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; + + // we should do a better check than this + if (recvlen >= 12) { + uint8_t uid[8]; + uid[0] = answer[9]; // always E0 + uid[1] = answer[8]; // IC Manufacturer code + uid[2] = answer[7]; + uid[3] = answer[6]; + uid[4] = answer[5]; + uid[5] = answer[4]; + uid[6] = answer[3]; + uid[7] = answer[2]; + + if (DBGLEVEL >= DBG_EXTENDED) { + Dbprintf("[+] UID = %02X%02X%02X%02X%02X%02X%02X%02X", + uid[0], uid[1], uid[2], uid[3], + uid[4], uid[5], uid[5], uid[6] + ); + } + // send UID back to client. + // arg0 = 1 = OK + // arg1 = len of response (12 bytes) + // arg2 = rtf + // asbytes = uid. + reply_mix(CMD_ACK, 1, sizeof(uid), 0, uid, sizeof(uid)); + + if (DBGLEVEL >= DBG_EXTENDED) { + Dbprintf("[+] %d octets read from IDENTIFY request:", recvlen); + DbdecodeIso15693Answer(recvlen, answer); + Dbhexdump(recvlen, answer, true); + } + } else { + DbpString("Failed to select card"); + reply_mix(CMD_ACK, 0, 0, 0, NULL, 0); } - // send UID back to client. - // arg0 = 1 = OK - // arg1 = len of response (12 bytes) - // arg2 = rtf - // asbytes = uid. - reply_mix(CMD_ACK, 1, sizeof(uid), 0, uid, sizeof(uid)); } - - if (DBGLEVEL >= DBG_EXTENDED) { - Dbprintf("[+] %d octets read from IDENTIFY request:", answerLen); - DbdecodeIso15693Answer(answerLen, answer); - Dbhexdump(answerLen, answer, true); - } - switch_off(); BigBuf_free(); } @@ -1765,6 +1781,11 @@ void BruteforceIso15693Afi(uint32_t speed) { if (recvlen >= 12) { Dbprintf("NoAFI UID = %s", iso15693_sprintUID(NULL, recv + 2)); + } else { + DbpString("Failed to select card"); + reply_ng(CMD_ACK, PM3_ESOFT, NULL, 0); + switch_off(); + return; } // now with AFI @@ -1814,10 +1835,9 @@ void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint LED_A_ON(); - int recvlen = 0; uint8_t recvbuf[ISO15693_MAX_RESPONSE_LENGTH]; - uint32_t eof_time = 0; uint16_t timeout; + uint32_t eof_time = 0; bool request_answer = false; switch (data[1]) { @@ -1835,43 +1855,29 @@ void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint timeout = ISO15693_READER_TIMEOUT; } - if (DBGLEVEL >= DBG_EXTENDED) { - Dbprintf("SEND:"); - Dbhexdump(datalen, data, false); - } - uint32_t start_time = 0; - recvlen = SendDataTag(data, datalen, true, speed, (recv ? recvbuf : NULL), sizeof(recvbuf), start_time, timeout, &eof_time); + int recvlen = SendDataTag(data, datalen, true, speed, (recv ? recvbuf : NULL), sizeof(recvbuf), start_time, timeout, &eof_time); - // send a single EOF to get the tag response - if (request_answer) { - start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; - recvlen = SendDataTagEOF((recv ? recvbuf : NULL), sizeof(recvbuf), start_time, ISO15693_READER_TIMEOUT, &eof_time); + if (recvlen == PM3_ETEAROFF) { // tearoff occured + reply_mix(CMD_ACK, recvlen, 0, 0, NULL, 0); + } else { + + // send a single EOF to get the tag response + if (request_answer) { + start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER; + recvlen = SendDataTagEOF((recv ? recvbuf : NULL), sizeof(recvbuf), start_time, ISO15693_READER_TIMEOUT, &eof_time); + } + + if (recv) { + recvlen = MIN(recvlen, ISO15693_MAX_RESPONSE_LENGTH); + reply_mix(CMD_ACK, recvlen, 0, 0, recvbuf, recvlen); + } else { + reply_mix(CMD_ACK, 1, 0, 0, NULL, 0); + } } - - // for the time being, switch field off to protect rdv4.0 // note: this prevents using hf 15 cmd with s option - which isn't implemented yet anyway FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); LED_D_OFF(); - - if (recv) { - - if (recvlen > ISO15693_MAX_RESPONSE_LENGTH) { - recvlen = ISO15693_MAX_RESPONSE_LENGTH; - } - reply_mix(CMD_ACK, recvlen, 0, 0, recvbuf, recvlen); - - if (DBGLEVEL >= DBG_EXTENDED) { - - Dbprintf("RECV:"); - if (recvlen > 0) { - Dbhexdump(recvlen, recvbuf, false); - DbdecodeIso15693Answer(recvlen, recvbuf); - } - } - } else { - reply_mix(CMD_ACK, 1, 0, 0, 0, 0); - } } /* @@ -1881,112 +1887,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..a6fbb7bba 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 @@ -2466,7 +2467,7 @@ static uint8_t Prepare_Data(uint16_t data_low, uint16_t data_hi) { // Requires: forwarLink_data filled with valid bits (1 bit per byte) // fwd_bit_count set with number of bits to be sent //==================================================================== -static void SendForward(uint8_t fwd_bit_count) { +static void SendForward(uint8_t fwd_bit_count, bool fast) { // iceman, 21.3us increments for the USclock verification. // 55FC * 8us == 440us / 21.3 === 20.65 steps. could be too short. Go for 56FC instead @@ -2479,9 +2480,10 @@ static void SendForward(uint8_t fwd_bit_count) { fwd_write_ptr = forwardLink_data; fwd_bit_sz = fwd_bit_count; - // Set up FPGA, 125kHz or 95 divisor - LFSetupFPGAForADC(LF_DIVISOR_125, true); - + if (! fast) { + // Set up FPGA, 125kHz or 95 divisor + LFSetupFPGAForADC(LF_DIVISOR_125, true); + } // force 1st mod pulse (start gap must be longer for 4305) fwd_bit_sz--; //prepare next bit modulation fwd_write_ptr++; @@ -2489,28 +2491,98 @@ static void SendForward(uint8_t fwd_bit_count) { TurnReadLF_off(EM_START_GAP); TurnReadLFOn(18 * 8); - // now start writting with bitbanging the antenna. (each bit should be 32*8 total length) + // now start writing with bitbanging the antenna. (each bit should be 32*8 total length) while (fwd_bit_sz-- > 0) { //prepare next bit modulation if (((*fwd_write_ptr++) & 1) == 1) { WaitUS(32 * 8); } else { TurnReadLF_off(23 * 8); - TurnReadLFOn((32 - 23) * 8); + TurnReadLFOn(18 * 8); } } } -static void EM4xLogin(uint32_t pwd) { +static void EM4xLoginEx(uint32_t pwd) { forward_ptr = forwardLink_data; uint8_t len = Prepare_Cmd(FWD_CMD_LOGIN); len += Prepare_Data(pwd & 0xFFFF, pwd >> 16); - SendForward(len); + SendForward(len, false); //WaitUS(20); // no wait for login command. // should receive // 0000 1010 ok // 0000 0001 fail } +void EM4xBruteforce(uint32_t start_pwd, uint32_t n) { + // With current timing, 18.6 ms per test = 53.8 pwds/s + reply_ng(CMD_LF_EM4X_BF, PM3_SUCCESS, NULL, 0); + StartTicks(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + WaitMS(20); + LED_A_ON(); + LFSetupFPGAForADC(LF_DIVISOR_125, true); + uint32_t candidates_found = 0; + for (uint32_t pwd = start_pwd; pwd < 0xFFFFFFFF; pwd++) { + if (((pwd - start_pwd) & 0x3F) == 0x00) { + WDT_HIT(); + if (BUTTON_PRESS() || data_available()) { + Dbprintf("EM4x05 Bruteforce Interrupted"); + break; + } + } + // Report progress every 256 attempts + if (((pwd - start_pwd) & 0xFF) == 0x00) { + Dbprintf("Trying: %06Xxx", pwd >> 8); + } + clear_trace(); + + forward_ptr = forwardLink_data; + uint8_t len = Prepare_Cmd(FWD_CMD_LOGIN); + len += Prepare_Data(pwd & 0xFFFF, pwd >> 16); + SendForward(len, true); + + WaitUS(400); + DoPartialAcquisition(0, false, 350, 1000); + uint8_t *mem = BigBuf_get_addr(); + if (mem[334] < 128) { + candidates_found++; + Dbprintf("Password candidate: " _GREEN_("%08X"), pwd); + if ((n != 0) && (candidates_found == n)) { + Dbprintf("EM4x05 Bruteforce Stopped. %i candidate%s found", candidates_found, candidates_found > 1 ? "s" : ""); + break; + } + } + // Beware: if smaller, tag might not have time to be back in listening state yet + WaitMS(1); + } + StopTicks(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + LEDsoff(); +} + +void EM4xLogin(uint32_t pwd) { + + StartTicks(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + WaitMS(20); + + LED_A_ON(); + + // clear buffer now so it does not interfere with timing later + BigBuf_Clear_ext(false); + + EM4xLoginEx(pwd); + + WaitUS(400); + // We need to acquire more than needed, to help demodulators finding the proper modulation + DoPartialAcquisition(0, false, 6000, 1000); + + StopTicks(); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); + reply_ng(CMD_LF_EM4X_LOGIN, PM3_SUCCESS, NULL, 0); + LEDsoff(); +} + void EM4xReadWord(uint8_t addr, uint32_t pwd, uint8_t usepwd) { StartTicks(); @@ -2528,17 +2600,17 @@ void EM4xReadWord(uint8_t addr, uint32_t pwd, uint8_t usepwd) { * 0000 1010 ok * 0000 0001 fail **/ - if (usepwd) EM4xLogin(pwd); + if (usepwd) EM4xLoginEx(pwd); forward_ptr = forwardLink_data; uint8_t len = Prepare_Cmd(FWD_CMD_READ); len += Prepare_Addr(addr); - SendForward(len); + SendForward(len, false); WaitUS(400); - DoPartialAcquisition(20, false, 6000, 1000); + DoPartialAcquisition(0, false, 6000, 1000); StopTicks(); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); @@ -2563,23 +2635,70 @@ void EM4xWriteWord(uint8_t addr, uint32_t data, uint32_t pwd, uint8_t usepwd) { * 0000 1010 ok. * 0000 0001 fail **/ - if (usepwd) EM4xLogin(pwd); + if (usepwd) EM4xLoginEx(pwd); forward_ptr = forwardLink_data; uint8_t len = Prepare_Cmd(FWD_CMD_WRITE); len += Prepare_Addr(addr); len += Prepare_Data(data & 0xFFFF, data >> 16); - SendForward(len); + SendForward(len, false); - // 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) EM4xLoginEx(pwd); + + forward_ptr = forwardLink_data; + uint8_t len = Prepare_Cmd(FWD_CMD_PROTECT); + len += Prepare_Data(data & 0xFFFF, data >> 16); + + SendForward(len, false); + + 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..0ec050158 100644 --- a/armsrc/lfops.h +++ b/armsrc/lfops.h @@ -56,8 +56,11 @@ void T55xxDangerousRawTest(uint8_t *data); void TurnReadLFOn(uint32_t delay); +void EM4xLogin(uint32_t pwd); +void EM4xBruteforce(uint32_t start_pwd, uint32_t n); 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..11c89a98b 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -2695,32 +2695,30 @@ void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain) { // // Tear-off attack against MFU. // - Moebius et al -void MifareU_Otp_Tearoff(uint8_t arg0, uint32_t arg1, uint8_t *datain) { +void MifareU_Otp_Tearoff(uint8_t arg0, uint32_t tearoff_time, uint8_t *datain) { uint8_t blockNo = arg0; - uint32_t tearOffTime = arg1; uint8_t data_fullwrite[4] = {0x00}; 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 (tearoff_time > 43000) + tearoff_time = 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 +2730,51 @@ 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(tearoff_time); + 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"); +} + +// +// Tear-off attack against MFU counter +void MifareU_Counter_Tearoff(uint8_t counter, uint32_t tearoff_time) { + + if (tearoff_time > 43000) + tearoff_time = 43000; + + LEDsoff(); + iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); + clear_trace(); + set_tracing(true); + + // Send MFU counter increase cmd + uint8_t cmd[] = { + MIFARE_ULEV1_INCR_CNT, + counter, + 0, // lsb + 0, + 0, // msb + 0, // rfu + 0, + 0, + }; + AddCrc14A(cmd, sizeof(cmd) - 2); + + // anticollision / select card + if (!iso14443a_select_card(NULL, NULL, NULL, true, 0, true)) { + if (DBGLEVEL >= DBG_ERROR) Dbprintf("Can't select card"); + OnError(1); + return; + }; + + // send + ReaderTransmit(cmd, sizeof(cmd), NULL); + LED_D_ON(); + SpinDelayUsPrecision(tearoff_time); + switch_off(); + + reply_ng(CMD_HF_MFU_COUNTER_TEAROFF, PM3_SUCCESS, NULL, 0); } diff --git a/armsrc/mifarecmd.h b/armsrc/mifarecmd.h index 58cec9b49..f83f119e2 100644 --- a/armsrc/mifarecmd.h +++ b/armsrc/mifarecmd.h @@ -64,5 +64,5 @@ void Mifare_DES_Auth2(uint32_t arg0, uint8_t *datain); // Tear-off test for MFU void MifareU_Otp_Tearoff(uint8_t arg0, uint32_t arg1, uint8_t *datain); - +void MifareU_Counter_Tearoff(uint8_t counter, uint32_t tearoff_time); #endif 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..6d4abf82d 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -18,6 +18,7 @@ # -DANDROID_NATIVE_API_LEVEL=android-19 \ # -DSKIPBT=1 -DSKIPPYTHON=1 -DSKIPPTHREAD=1 .. +message(STATUS "CMake ${CMAKE_VERSION}") cmake_minimum_required(VERSION 3.10) project(proxmark3) SET (PM3_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/..) @@ -246,9 +247,11 @@ set (TARGET_SOURCES ${PM3_ROOT}/client/src/cmdlf.c ${PM3_ROOT}/client/src/cmdlfawid.c ${PM3_ROOT}/client/src/cmdlfcotag.c + ${PM3_ROOT}/client/src/cmdlfdestron.c ${PM3_ROOT}/client/src/cmdlfem4x.c + ${PM3_ROOT}/client/src/cmdlfem4x05.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 @@ -494,20 +497,10 @@ if (NOT APPLE) set(ADDITIONAL_LNK ${ADDITIONAL_LNK} -Wl,--as-needed -latomic -Wl,--no-as-needed) endif (NOT APPLE) - -find_library(pm3rrg_rdv4_cliparser REQUIRED) -find_library(pm3rrg_rdv4_tinycbor REQUIRED) -find_library(pm3rrg_rdv4_lua REQUIRED) -find_library(pm3rrg_rdv4_mbedtls REQUIRED) -find_library(pm3rrg_rdv4_reveng REQUIRED) -find_library(pm3rrg_rdv4_hardnested REQUIRED) - if (NOT JANSSON_FOUND) - find_library(pm3rrg_rdv4_jansson REQUIRED) set(ADDITIONAL_LNK pm3rrg_rdv4_jansson ${ADDITIONAL_LNK}) endif (NOT JANSSON_FOUND) if (NOT WHEREAMI_FOUND) - find_library(pm3rrg_rdv4_whereami REQUIRED) set(ADDITIONAL_LNK pm3rrg_rdv4_whereami ${ADDITIONAL_LNK}) endif (NOT WHEREAMI_FOUND) diff --git a/client/Makefile b/client/Makefile index 29fb4462e..b4393ad36 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 @@ -440,9 +441,11 @@ SRCS = aidsearch.c \ cmdlf.c \ cmdlfawid.c \ cmdlfcotag.c \ + cmdlfdestron.c \ cmdlfem4x.c \ + cmdlfem4x05.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..69e71d5d5 100644 --- a/client/android/CMakeLists.txt +++ b/client/android/CMakeLists.txt @@ -1,4 +1,5 @@ # version +message(STATUS "CMake ${CMAKE_VERSION}") cmake_minimum_required(VERSION 3.4.1) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -fvisibility=hidden -w") @@ -12,7 +13,6 @@ add_subdirectory(../deps deps) if (CMAKE_MAKE_PROGRAM MATCHES ".*ninja.*") set(BZIP2_INCLUDE_DIRS ${BZIP2_ROOT}) set(BZIP2_LIBRARIES pm3rrg_rdv4_bzip2) - find_library(pm3rrg_rdv4_bzip2 REQUIRED) elseif (UNIX) # Cross compile at Unix Makefile System. # bzip2 dep. include(ExternalProject) @@ -125,9 +125,10 @@ add_library(pm3rrg_rdv4 SHARED ${PM3_ROOT}/client/src/cmdlf.c ${PM3_ROOT}/client/src/cmdlfawid.c ${PM3_ROOT}/client/src/cmdlfcotag.c + ${PM3_ROOT}/client/src/cmdlfdestron.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 @@ -189,15 +190,6 @@ target_include_directories(pm3rrg_rdv4 PRIVATE ${PM3_ROOT}/common_fpga ${PM3_ROOT}/client/src) -find_library(pm3rrg_rdv4_cliparser REQUIRED) -find_library(pm3rrg_rdv4_jansson REQUIRED) -find_library(pm3rrg_rdv4_tinycbor REQUIRED) -find_library(pm3rrg_rdv4_lua REQUIRED) -find_library(pm3rrg_rdv4_mbedtls REQUIRED) -find_library(pm3rrg_rdv4_reveng REQUIRED) -find_library(pm3rrg_rdv4_hardnested REQUIRED) -find_library(pm3rrg_rdv4_whereami REQUIRED) - target_link_libraries(pm3rrg_rdv4 ${BZIP2_LIBRARIES} pm3rrg_rdv4_hardnested diff --git a/client/cmdscripts/test_psk_clone.cmd b/client/cmdscripts/test_psk_clone.cmd index f37ddcfea..784fecd1e 100644 --- a/client/cmdscripts/test_psk_clone.cmd +++ b/client/cmdscripts/test_psk_clone.cmd @@ -14,7 +14,7 @@ lf search rem Test of keri clone & read lf t55xx wipe -lf keri clone 1337 +lf keri clone --id 1337 lf keri read lf search diff --git a/client/deps/amiibo.cmake b/client/deps/amiibo.cmake index 234547cd1..491d90d60 100644 --- a/client/deps/amiibo.cmake +++ b/client/deps/amiibo.cmake @@ -14,7 +14,6 @@ add_library(pm3rrg_rdv4_amiibo STATIC if (NOT TARGET pm3rrg_rdv4_mbedtls) include(mbedtls.cmake) endif() -find_library(pm3rrg_rdv4_mbedtls REQUIRED) target_link_libraries(pm3rrg_rdv4_amiibo PRIVATE m pm3rrg_rdv4_mbedtls) diff --git a/client/deps/cliparser.cmake b/client/deps/cliparser.cmake index b16451c07..fccae33b7 100644 --- a/client/deps/cliparser.cmake +++ b/client/deps/cliparser.cmake @@ -3,6 +3,7 @@ add_library(pm3rrg_rdv4_cliparser STATIC cliparser/cliparser.c ) +target_compile_definitions(pm3rrg_rdv4_cliparser PRIVATE _ISOC99_SOURCE) target_include_directories(pm3rrg_rdv4_cliparser PRIVATE ../../common ../../include diff --git a/client/deps/cliparser/Makefile b/client/deps/cliparser/Makefile index 4873372c4..1994992f9 100644 --- a/client/deps/cliparser/Makefile +++ b/client/deps/cliparser/Makefile @@ -9,3 +9,12 @@ MYSRCS = \ LIB_A = libcliparser.a include ../../../Makefile.host + +$(info PLATFORM $(platform)) +ifneq (,$(findstring MINGW,$(platform))) + # Mingw uses by default Microsoft printf, we want the GNU printf (e.g. for %z) + # and setting _ISOC99_SOURCE sets internally __USE_MINGW_ANSI_STDIO=1 + # FTR __USE_MINGW_ANSI_STDIO seems deprecated in Mingw32 + # but not Mingw64 https://fr.osdn.net/projects/mingw/lists/archive/users/2019-January/000199.html + CFLAGS += -D_ISOC99_SOURCE +endif diff --git a/client/deps/cliparser/argtable3.c b/client/deps/cliparser/argtable3.c index 5019001e4..2fe32b082 100644 --- a/client/deps/cliparser/argtable3.c +++ b/client/deps/cliparser/argtable3.c @@ -1927,10 +1927,8 @@ struct arg_file *arg_filen( #include #include #include - #include "argtable3.h" - static void arg_int_resetfn(struct arg_int *parent) { ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent)); parent->count = 0; @@ -2226,6 +2224,263 @@ struct arg_int *arg_intn( ARG_TRACE(("arg_intn() returns %p\n", result)); return result; } + + +// uint64_t support +#include +#include +#include +static uint64_t strtollu0X(const char *str, + const char * *endptr, + char X, + int base) { + uint64_t val; /* stores result */ + int s = 1; /* sign is +1 or -1 */ + const char *ptr = str; /* ptr to current position in str */ + + /* skip leading whitespace */ + while (ISSPACE(*ptr)) + ptr++; + // printf("1) %s\n",ptr); + + /* scan optional sign character */ + switch (*ptr) { + case '+': + ptr++; + s = 1; + break; + case '-': + ptr++; + s = -1; + break; + default: + s = 1; + break; + } + // printf("2) %s\n",ptr); + + /* '0X' prefix */ + if ((*ptr++) != '0') { + /* printf("failed to detect '0'\n"); */ + *endptr = str; + return 0; + } + // printf("3) %s\n",ptr); + if (toupper(*ptr++) != toupper(X)) { + /* printf("failed to detect '%c'\n",X); */ + *endptr = str; + return 0; + } + // printf("4) %s\n",ptr); + + /* attempt conversion on remainder of string using strtol() */ + val = strtoull(ptr, (char * *)endptr, base); + + if (*endptr == ptr) { + /* conversion failed */ + *endptr = str; + return 0; + } + + /* success */ + return s * val; +} + + +static void arg_u64_resetfn(struct arg_u64 *parent) { + ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent)); + parent->count = 0; +} + +static int arg_u64_scanfn(struct arg_u64 *parent, const char *argval) { + int errorcode = 0; + if (parent->count == parent->hdr.maxcount) { + /* maximum number of arguments exceeded */ + errorcode = EMAXCOUNT; + } else if (!argval) { + /* a valid argument with no argument value was given. */ + /* This happens when an optional argument value was invoked. */ + /* leave parent arguiment value unaltered but still count the argument. */ + parent->count++; + } else { + uint64_t val; + const char *end; + + /* attempt to extract hex integer (eg: +0x123) from argval into val conversion */ + val = strtollu0X(argval, &end, 'X', 16); + if (end == argval) { + /* hex failed, attempt octal conversion (eg +0o123) */ + val = strtollu0X(argval, &end, 'O', 8); + if (end == argval) { + /* octal failed, attempt binary conversion (eg +0B101) */ + val = strtollu0X(argval, &end, 'B', 2); + if (end == argval) { + /* binary failed, attempt decimal conversion with no prefix (eg 1234) */ + val = strtoull(argval, (char * *)&end, 10); + if (end == argval) { + /* all supported number formats failed */ + return EBADINT; + } + } + } + } + + /* Safety check for integer overflow. WARNING: this check */ + /* achieves nothing on machines where size(int)==size(long). */ + if (val > ULLONG_MAX) +#ifdef __STDC_WANT_SECURE_LIB__ + errorcode = EOVERFLOW_; +#else + errorcode = EOVERFLOW; +#endif + + /* Detect any suffixes (KB,MB,GB) and multiply argument value appropriately. */ + /* We need to be mindful of integer overflows when using such big numbers. */ + if (detectsuffix(end, "KB")) { /* kilobytes */ + if (val > (ULLONG_MAX / 1024)) +#ifdef __STDC_WANT_SECURE_LIB__ + errorcode = EOVERFLOW_; /* Overflow would occur if we proceed */ +#else + errorcode = EOVERFLOW; /* Overflow would occur if we proceed */ +#endif + else + val *= 1024; /* 1KB = 1024 */ + } else if (detectsuffix(end, "MB")) { /* megabytes */ + if (val > (ULLONG_MAX / 1048576)) +#ifdef __STDC_WANT_SECURE_LIB__ + errorcode = EOVERFLOW_; /* Overflow would occur if we proceed */ +#else + errorcode = EOVERFLOW; /* Overflow would occur if we proceed */ +#endif + else + val *= 1048576; /* 1MB = 1024*1024 */ + } else if (detectsuffix(end, "GB")) { /* gigabytes */ + if (val > (ULLONG_MAX / 1073741824)) +#ifdef __STDC_WANT_SECURE_LIB__ + errorcode = EOVERFLOW_; /* Overflow would occur if we proceed */ +#else + errorcode = EOVERFLOW; /* Overflow would occur if we proceed */ +#endif + else + val *= 1073741824; /* 1GB = 1024*1024*1024 */ + } else if (!detectsuffix(end, "")) + errorcode = EBADINT; /* invalid suffix detected */ + + /* if success then store result in parent->uval[] array */ + if (errorcode == 0) + parent->uval[parent->count++] = val; + } + + /* printf("%s:scanfn(%p,%p) returns %d\n",__FILE__,parent,argval,errorcode); */ + return errorcode; +} + +static int arg_u64_checkfn(struct arg_u64 *parent) { + int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0; + /*printf("%s:checkfn(%p) returns %d\n",__FILE__,parent,errorcode);*/ + return errorcode; +} + +static void arg_u64_errorfn( + struct arg_u64 *parent, + FILE *fp, + int errorcode, + const char *argval, + const char *progname) { + const char *shortopts = parent->hdr.shortopts; + const char *longopts = parent->hdr.longopts; + const char *datatype = parent->hdr.datatype; + + /* make argval NULL safe */ + argval = argval ? argval : ""; + + fprintf(fp, "%s: ", progname); + switch (errorcode) { + case EMINCOUNT: + fputs("missing option ", fp); + arg_print_option(fp, shortopts, longopts, datatype, "\n"); + break; + + case EMAXCOUNT: + fputs("excess option ", fp); + arg_print_option(fp, shortopts, longopts, argval, "\n"); + break; + + case EBADINT: + fprintf(fp, "invalid argument \"%s\" to option ", argval); + arg_print_option(fp, shortopts, longopts, datatype, "\n"); + break; + +#ifdef __STDC_WANT_SECURE_LIB__ + case EOVERFLOW_: +#else + case EOVERFLOW: +#endif + fputs("integer overflow at option ", fp); + arg_print_option(fp, shortopts, longopts, datatype, " "); + fprintf(fp, "(%s is too large)\n", argval); + break; + } +} + +struct arg_u64 *arg_u64_0( + const char *shortopts, + const char *longopts, + const char *datatype, + const char *glossary) { + return arg_u64_n(shortopts, longopts, datatype, 0, 1, glossary); +} + +struct arg_u64 *arg_u64_1( + const char *shortopts, + const char *longopts, + const char *datatype, + const char *glossary) { + return arg_u64_n(shortopts, longopts, datatype, 1, 1, glossary); +} + +struct arg_u64 *arg_u64_n( + const char *shortopts, + const char *longopts, + const char *datatype, + int mincount, + int maxcount, + const char *glossary) { + size_t nbytes; + struct arg_u64 *result; + + /* foolproof things by ensuring maxcount is not less than mincount */ + maxcount = (maxcount < mincount) ? mincount : maxcount; + + nbytes = sizeof(struct arg_u64) /* storage for struct arg_u64 */ + + maxcount * sizeof(uint64_t); /* storage for uval[maxcount] array */ + + result = (struct arg_u64 *)malloc(nbytes); + if (result) { + /* init the arg_hdr struct */ + result->hdr.flag = ARG_HASVALUE; + result->hdr.shortopts = shortopts; + result->hdr.longopts = longopts; + result->hdr.datatype = datatype ? datatype : ""; + result->hdr.glossary = glossary; + result->hdr.mincount = mincount; + result->hdr.maxcount = maxcount; + result->hdr.parent = result; + result->hdr.resetfn = (arg_resetfn *)arg_u64_resetfn; + result->hdr.scanfn = (arg_scanfn *)arg_u64_scanfn; + result->hdr.checkfn = (arg_checkfn *)arg_u64_checkfn; + result->hdr.errorfn = (arg_errorfn *)arg_u64_errorfn; + + /* store the uval[maxcount] array immediately after the arg_int struct */ + result->uval = (uint64_t *)(result + 1); + result->count = 0; + } + + ARG_TRACE(("arg_u64_n() returns %p\n", result)); + return result; +} + + /******************************************************************************* * This file is part of the argtable3 library. * @@ -4020,7 +4275,10 @@ static void arg_parse_untagged(int argc, /* register an error for each unused argv[] entry */ while (optind < argc) { /*printf("arg_parse_untagged(): argv[%d]=\"%s\" not consumed\n",optind,argv[optind]);*/ - arg_register_error(endtable, endtable, ARG_ENOMATCH, argv[optind++]); + if (argv[optind][0] != '\x00') { + arg_register_error(endtable, endtable, ARG_ENOMATCH, argv[optind]); + } + optind++; } return; @@ -4271,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 d8e3c53cc..55564aa2f 100644 --- a/client/deps/cliparser/argtable3.h +++ b/client/deps/cliparser/argtable3.h @@ -35,6 +35,7 @@ #include /* FILE */ #include /* struct tm */ +#include #ifdef __cplusplus extern "C" { @@ -110,6 +111,12 @@ struct arg_int { int *ival; /* Array of parsed argument values */ }; +struct arg_u64 { + struct arg_hdr hdr; /* The mandatory argtable header struct */ + int count; /* Number of matching command line args */ + uint64_t *uval; /* Array of parsed argument values */ +}; + struct arg_dbl { struct arg_hdr hdr; /* The mandatory argtable header struct */ int count; /* Number of matching command line args */ @@ -176,32 +183,29 @@ struct arg_lit *arg_litn(const char *shortopts, int maxcount, const char *glossary); -struct arg_key *arg_key0(const char *keyword, - int flags, - const char *glossary); -struct arg_key *arg_key1(const char *keyword, - int flags, - const char *glossary); -struct arg_key *arg_keyn(const char *keyword, - int flags, - int mincount, - int maxcount, - const char *glossary); +struct arg_key *arg_key0(const char *keyword, int flags, const char *glossary); +struct arg_key *arg_key1(const char *keyword, int flags, const char *glossary); +struct arg_key *arg_keyn(const char *keyword, int flags, int mincount, int maxcount, const char *glossary); + +struct arg_int *arg_int0(const char *shortopts, const char *longopts, const char *datatype, const char *glossary); +struct arg_int *arg_int1(const char *shortopts, const char *longopts, const char *datatype, const char *glossary); +struct arg_int *arg_intn(const char *shortopts, const char *longopts, const char *datatype, int mincount, int maxcount, const char *glossary); + +struct arg_u64 *arg_u64_0(const char *shortopts, + const char *longopts, + const char *datatype, + const char *glossary); +struct arg_u64 *arg_u64_1(const char *shortopts, + 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); -struct arg_int *arg_int0(const char *shortopts, - const char *longopts, - const char *datatype, - const char *glossary); -struct arg_int *arg_int1(const char *shortopts, - const char *longopts, - const char *datatype, - const char *glossary); -struct arg_int *arg_intn(const char *shortopts, - const char *longopts, - const char *datatype, - int mincount, - int maxcount, - const char *glossary); struct arg_dbl *arg_dbl0(const char *shortopts, const char *longopts, diff --git a/client/deps/cliparser/cliparser.c b/client/deps/cliparser/cliparser.c index 4ec4eb303..e96f100bb 100644 --- a/client/deps/cliparser/cliparser.c +++ b/client/deps/cliparser/cliparser.c @@ -11,8 +11,10 @@ #include "cliparser.h" #include #include -#include // Get color constants -#include // get PrintAndLogEx +#include // Get color constants +#include // get PrintAndLogEx +#include // tolower +#include // PRIu64 #ifndef ARRAYLEN # define ARRAYLEN(x) (sizeof(x)/sizeof((x)[0])) @@ -70,7 +72,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"); @@ -125,7 +127,6 @@ int CLIParserParseArg(CLIParserContext *ctx, int argc, char **argv, void *vargta return 0; } - enum ParserState { PS_FIRST, PS_ARGUMENT, @@ -203,34 +204,33 @@ int CLIParserParseStringEx(CLIParserContext *ctx, const char *str, void *vargtab int CLIParamHexToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int *datalen) { *datalen = 0; - int ibuf = 0; - uint8_t tmp_buf[512] = {0}; - int res = CLIParamStrToBuf(argstr, tmp_buf, maxdatalen * 2, &ibuf); // *2 because here HEX + int tmplen = 0; + uint8_t tmpstr[(256 * 2) + 1] = {0}; + + // concat all strings in argstr into tmpstr[] + // + int res = CLIParamStrToBuf(argstr, tmpstr, sizeof(tmpstr), &tmplen); if (res) { - printf("Parameter error: buffer overflow.\n"); - fflush(stdout); return res; } - if (ibuf == 0) { + if (tmplen == 0) { return res; } - switch (param_gethex_to_eol((char *)tmp_buf, 0, data, maxdatalen, datalen)) { + res = param_gethex_to_eol((char *)tmpstr, 0, data, maxdatalen, datalen); + switch (res) { case 1: - printf("Parameter error: Invalid HEX value.\n"); - fflush(stdout); - return 1; + printf("Parameter error: Invalid HEX value\n"); + break; case 2: - printf("Parameter error: parameter too large.\n"); - fflush(stdout); - return 2; + printf("Parameter error: parameter too large\n"); + break; case 3: - printf("Parameter error: Hex string must have even number of digits.\n"); - fflush(stdout); - return 3; + printf("Parameter error: Hex string must have EVEN number of digits\n"); + break; } - - return 0; + fflush(stdout); + return res; } int CLIParamStrToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int *datalen) { @@ -238,27 +238,55 @@ int CLIParamStrToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int if (!argstr->count) return 0; - uint8_t tmp_buf[512] = {0}; + uint8_t tmpstr[(256 * 2) + 1] = {0}; int ibuf = 0; for (int i = 0; i < argstr->count; i++) { + int len = strlen(argstr->sval[i]); - memcpy(&tmp_buf[ibuf], argstr->sval[i], len); + + if (len > ((sizeof(tmpstr) / 2) - ibuf)) { + printf("Parameter error: string too long (%i chars), expect MAX %zu chars\n", len + ibuf, (sizeof(tmpstr) / 2)); + fflush(stdout); + return 2; + } + + memcpy(&tmpstr[ibuf], argstr->sval[i], len); + ibuf += len; } - tmp_buf[ibuf] = 0; - if (!ibuf) + ibuf = MIN(ibuf, (sizeof(tmpstr) / 2)); + tmpstr[ibuf] = 0; + + if (ibuf == 0) return 0; if (ibuf > maxdatalen) { + printf("Parameter error: string too long (%i chars), expected MAX %i chars\n", ibuf, maxdatalen); fflush(stdout); return 2; } - memcpy(data, tmp_buf, ibuf); + memcpy(data, tmpstr, ibuf + 1); *datalen = ibuf; return 0; } +uint64_t arg_get_u64_hexstr_def(CLIParserContext *ctx, uint8_t paramnum, uint64_t def) { + uint64_t rv = 0; + uint8_t data[8]; + int datalen = 0; + int res = CLIParamHexToBuf(arg_get_str(ctx, paramnum), data, sizeof(data), &datalen); + if (res == 0 && datalen > 0) { + for (uint8_t i = 0; i < datalen; i++) { + rv <<= 8; + rv |= data[i]; + } + } else { + rv = def; + } + return rv; +} + diff --git a/client/deps/cliparser/cliparser.h b/client/deps/cliparser/cliparser.h index 51c2ed8d5..996ad81ef 100644 --- a/client/deps/cliparser/cliparser.h +++ b/client/deps/cliparser/cliparser.h @@ -17,22 +17,39 @@ #define arg_param_begin arg_lit0("h", "help", "This help") #define arg_param_end arg_end(20) -#define arg_getsize(a) (sizeof(a) / sizeof(a[0])) -#define arg_get_lit(ctx, n) (((struct arg_lit*)((ctx)->argtable)[n])->count) -#define arg_get_int_count(ctx, n)(((struct arg_int*)((ctx)->argtable)[n])->count) -#define arg_get_int(ctx, n) (((struct arg_int*)((ctx)->argtable)[n])->ival[0]) -#define arg_get_int_def(ctx, n, def)(arg_get_int_count((ctx), n) ? (arg_get_int((ctx), n)) : (def)) -#define arg_get_str(ctx, n) ((struct arg_str*)((ctx)->argtable)[n]) -#define arg_get_str_len(ctx, n) (strlen(((struct arg_str*)((ctx)->argtable)[n])->sval[0])) +#define arg_getsize(a) (sizeof(a) / sizeof(a[0])) +#define arg_get_lit(ctx, n) (((struct arg_lit*)((ctx)->argtable)[(n)])->count) + +#define arg_get_int_count(ctx, n) (((struct arg_int*)((ctx)->argtable)[(n)])->count) +#define arg_get_int(ctx, n) (((struct arg_int*)((ctx)->argtable)[(n)])->ival[0]) +#define arg_get_int_def(ctx, n, def)(arg_get_int_count((ctx), (n)) ? (arg_get_int((ctx), (n))) : (def)) + +#define arg_get_dbl_count(ctx, n) (((struct arg_dbl*)((ctx)->argtable)[(n)])->count) +#define arg_get_dbl(ctx, n) (((struct arg_dbl*)((ctx)->argtable)[(n)])->dval[0]) +#define arg_get_dbl_def(ctx, n, def)(arg_get_dbl_count((ctx), (n)) ? (arg_get_dbl((ctx), (n))) : (def)) + +#define arg_get_u32(ctx, n) (uint32_t)(((struct arg_u64*)((ctx)->argtable)[(n)])->uval[0]) +#define arg_get_u32_def(ctx, n, def) (arg_get_u64_count((ctx), (n)) ? (arg_get_u32((ctx), (n))) : (uint32_t)(def)) + +#define arg_get_u64_count(ctx, n) (((struct arg_u64*)((ctx)->argtable)[(n)])->count) +#define arg_get_u64(ctx, n) (((struct arg_u64*)((ctx)->argtable)[(n)])->uval[0]) +#define arg_get_u64_def(ctx, n, def) (arg_get_u64_count((ctx), (n)) ? (arg_get_u64((ctx), (n))) : (uint64_t)(def)) + +#define arg_get_str(ctx, n) ((struct arg_str*)((ctx)->argtable)[(n)]) +#define arg_get_str_len(ctx, n) (strlen(((struct arg_str*)((ctx)->argtable)[(n)])->sval[0])) #define arg_strx1(shortopts, longopts, datatype, glossary) (arg_strn((shortopts), (longopts), (datatype), 1, 250, (glossary))) #define arg_strx0(shortopts, longopts, datatype, glossary) (arg_strn((shortopts), (longopts), (datatype), 0, 250, (glossary))) -#define CLIParserFree(ctx) if ((ctx)) {arg_freetable(ctx->argtable, ctx->argtableLen); free((ctx)); (ctx)=NULL;} -#define CLIExecWithReturn(ctx, cmd, atbl, ifempty) if (CLIParserParseString(ctx, cmd, atbl, arg_getsize(atbl), ifempty)) {CLIParserFree((ctx)); return PM3_ESOFT;} -#define CLIGetHexBLessWithReturn(ctx, paramnum, data, datalen, delta) if (CLIParamHexToBuf(arg_get_str(ctx, paramnum), data, sizeof(data) - (delta), datalen)) {CLIParserFree((ctx)); return PM3_ESOFT;} -#define CLIGetHexWithReturn(ctx, paramnum, data, datalen) if (CLIParamHexToBuf(arg_get_str(ctx, paramnum), data, sizeof(data), datalen)) {CLIParserFree((ctx)); return PM3_ESOFT;} -#define CLIGetStrWithReturn(ctx, paramnum, data, datalen) if (CLIParamStrToBuf(arg_get_str(ctx, paramnum), data, sizeof(data), datalen)) {CLIParserFree((ctx)); return PM3_ESOFT;} +#define CLIParserFree(ctx) if ((ctx)) {arg_freetable((ctx)->argtable, (ctx)->argtableLen); free((ctx)); (ctx)=NULL;} + +#define CLIExecWithReturn(ctx, cmd, atbl, ifempty) if (CLIParserParseString((ctx), (cmd), (atbl), arg_getsize((atbl)), (ifempty))) {CLIParserFree((ctx)); return PM3_ESOFT;} + +#define CLIGetHexBLessWithReturn(ctx, paramnum, data, datalen, delta) if (CLIParamHexToBuf(arg_get_str((ctx), (paramnum)), (data), sizeof((data)) - (delta), (datalen))) {CLIParserFree((ctx)); return PM3_ESOFT;} + +#define CLIGetHexWithReturn(ctx, paramnum, data, datalen) if (CLIParamHexToBuf(arg_get_str((ctx), (paramnum)), (data), sizeof((data)), (datalen))) {CLIParserFree((ctx)); return PM3_ESOFT;} + +#define CLIGetStrWithReturn(ctx, paramnum, data, datalen) if (CLIParamStrToBuf(arg_get_str((ctx), (paramnum)), (data), (*datalen), (datalen))) {CLIParserFree((ctx)); return PM3_ESOFT;} typedef struct { void **argtable; @@ -49,4 +66,6 @@ int CLIParserParseArg(CLIParserContext *ctx, int argc, char **argv, void *vargta int CLIParamHexToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int *datalen); int CLIParamStrToBuf(struct arg_str *argstr, uint8_t *data, int maxdatalen, int *datalen); + +uint64_t arg_get_u64_hexstr_def(CLIParserContext *ctx, uint8_t paramnum, uint64_t def); #endif 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/dictionaries/mfc_default_keys.dic b/client/dictionaries/mfc_default_keys.dic index 58c2c40bc..cf40e63fd 100644 --- a/client/dictionaries/mfc_default_keys.dic +++ b/client/dictionaries/mfc_default_keys.dic @@ -1203,3 +1203,9 @@ FEE2A3FBC5B6 # taurus avm # 005078565703 +# +# Ving? +# +0602721E8F06 +FC0B50AF8700 +F7BA51A9434E \ No newline at end of file diff --git a/client/dictionaries/t55xx_default_pwds.dic b/client/dictionaries/t55xx_default_pwds.dic index c35014d79..6e7a69583 100644 --- a/client/dictionaries/t55xx_default_pwds.dic +++ b/client/dictionaries/t55xx_default_pwds.dic @@ -26,6 +26,8 @@ A5B4C3D2 50520901 # default PROX 50524F58 +# blue gun EM4305 +F9DCEBA0 # Default pwd, simple: 00000000 11111111 @@ -45,9 +47,6 @@ EEEEEEEE FFFFFFFF a0a1a2a3 b0b1b2b3 -aabbccdd -bbccddee -ccddeeff 50415353 00000001 00000002 @@ -123,3 +122,7 @@ b5f44686 # seeds ul-ev1 C6EF3720 # TEA 7854794A # xbox tea constant :) F1EA5EED # burtle +69314718 # ln2 +57721566 # euler constant (dec) +93C467E3 # euler constant (hex) +27182818 # natural log diff --git a/client/luascripts/hf_14b_calypso.lua b/client/luascripts/hf_14b_calypso.lua index 6fa40711e..72ac0f102 100644 --- a/client/luascripts/hf_14b_calypso.lua +++ b/client/luascripts/hf_14b_calypso.lua @@ -32,7 +32,7 @@ device-side. local function calypso_parse(result) local r = Command.parse(result) if r.arg1 >= 0 then - local len = r.arg2 * 2 + local len = r.arg1 * 2 if len > 0 then r.data = string.sub(r.data, 0, len); return r, nil @@ -113,8 +113,9 @@ end local function calypso_send_cmd_raw(data, ignoreresponse ) local command, flags, result, err - flags = lib14b.ISO14B_COMMAND.ISO14B_RAW + - lib14b.ISO14B_COMMAND.ISO14B_APPEND_CRC + flags = lib14b.ISO14B_COMMAND.ISO14B_APDU +-- flags = lib14b.ISO14B_COMMAND.ISO14B_RAW + +-- lib14b.ISO14B_COMMAND.ISO14B_APPEND_CRC data = data or "00" @@ -162,6 +163,7 @@ local function calypso_apdu_status(apdu) return status, desc, err end +local CLA = '94' local _calypso_cmds = { -- Break down of command bytes: @@ -184,27 +186,25 @@ local _calypso_cmds = { -- Electronic Purse file -- Electronic Transaction log file - - --['01.Select ICC file'] = '0294 a4 00 0002 3f00', - ['01.Select ICC file'] = '0294 a4 080004 3f00 0002', - ['02.ICC'] = '0394 b2 01 041d', - ['03.Select EnvHol file'] = '0294 a4 080004 2000 2001', - ['04.EnvHol1'] = '0394 b2 01 041d', - ['05.Select EvLog file'] = '0294 a4 080004 2000 2010', - ['06.EvLog1'] = '0394 b2 01 041d', - ['07.EvLog2'] = '0294 b2 02 041d', - ['08.EvLog3'] = '0394 b2 03 041d', - ['09.Select ConList file']= '0294 a4 080004 2000 2050', - ['10.ConList'] = '0394 b2 01 041d', - ['11.Select Contra file'] = '0294 a4 080004 2000 2020', - ['12.Contra1'] = '0394 b2 01 041d', - ['13.Contra2'] = '0294 b2 02 041d', - ['14.Contra3'] = '0394 b2 03 041d', - ['15.Contra4'] = '0294 b2 04 041d', - ['16.Select Counter file']= '0394 a4 080004 2000 2069', - ['17.Counter'] = '0294 b2 01 041d', - ['18.Select SpecEv file'] = '0394 a4 080004 2000 2040', - ['19.SpecEv1'] = '0294 b2 01 041d', + ['01.Select ICC file'] = CLA..'a4 080004 3f00 0002', + ['02.ICC'] = CLA..'b2 01 041d', + ['03.Select EnvHol file'] = CLA..'a4 080004 2000 2001', + ['04.EnvHol1'] = CLA..'b2 01 041d', + ['05.Select EvLog file'] = CLA..'a4 080004 2000 2010', + ['06.EvLog1'] = CLA..'b2 01 041d', + ['07.EvLog2'] = CLA..'b2 02 041d', + ['08.EvLog3'] = CLA..'b2 03 041d', + ['09.Select ConList file']= CLA..'a4 080004 2000 2050', + ['10.ConList'] = CLA..'b2 01 041d', + ['11.Select Contra file'] = CLA..'a4 080004 2000 2020', + ['12.Contra1'] = CLA..'b2 01 041d', + ['13.Contra2'] = CLA..'b2 02 041d', + ['14.Contra3'] = CLA..'b2 03 041d', + ['15.Contra4'] = CLA..'b2 04 041d', + ['16.Select Counter file']= CLA..'a4 080004 2000 2069', + ['17.Counter'] = CLA..'b2 01 041d', + ['18.Select SpecEv file'] = CLA..'a4 080004 2000 2040', + ['19.SpecEv1'] = CLA..'b2 01 041d', } --- diff --git a/client/luascripts/hf_14b_mobib.lua b/client/luascripts/hf_14b_mobib.lua new file mode 100644 index 000000000..01dd0f3a0 --- /dev/null +++ b/client/luascripts/hf_14b_mobib.lua @@ -0,0 +1,277 @@ +local cmds = require('commands') +local getopt = require('getopt') +local lib14b = require('read14b') +local utils = require('utils') +local iso7816 = require('7816_error') +local ansicolors = require('ansicolors') + +copyright = '' +author = 'Iceman' +version = 'v1.0.0' +desc = [[ +This is a script to communicate with a MOBIB tag using the '14b raw' commands +]] +example = [[ + script run hf_14b_mobib + script run hf_14b_mobib -b 11223344 + +]] +usage = [[ +script run hf_14b_mobib -h -b +]] +arguments = [[ + h this helptext + b raw bytes to send +]] + +--[[ +This script communicates with /armsrc/iso14443b.c, +Check there for details about data format and how commands are interpreted on the +device-side. +]] + +local function calypso_parse(result) + local r = Command.parse(result) + if r.arg1 >= 0 then + local len = r.arg1 * 2 + if len > 0 then + r.data = string.sub(r.data, 0, len); + return r, nil + end + end + return nil,nil +end +--- +-- A debug printout-function +local function dbg(args) + if not DEBUG then return end + if type(args) == 'table' then + local i = 1 + while args[i] do + dbg(args[i]) + i = i+1 + end + else + print('###', args) + end +end +--- +-- This is only meant to be used when errors occur +local function oops(err) + print('ERROR: ', err) + lib14b.disconnect() + return nil, err +end +--- +-- Usage help +local function help() + print(copyright) + print(author) + print(version) + print(desc) + print(ansicolors.cyan..'Usage'..ansicolors.reset) + print(usage) + print(ansicolors.cyan..'Arguments'..ansicolors.reset) + print(arguments) + print(ansicolors.cyan..'Example usage'..ansicolors.reset) + print(example) +end +-- +-- helper function, give current count of items in lua-table. +local function tablelen(T) + local count = 0 + for _ in pairs(T) do count = count + 1 end + return count +end +--- +-- helper function, gives a sorted table from table t, +-- order can be a seperate sorting-order function. +local function spairs(t, order) + -- collect the keys + local keys = {} + for k in pairs(t) do keys[#keys+1] = k end + + -- if order function given, sort by it by passing the table and keys a, b, + -- otherwise just sort the keys + if order then + table.sort(keys, function(a,b) return order(t, a, b) end) + else + table.sort(keys) + end + + -- return the iterator function + local i = 0 + return function() + i = i + 1 + if keys[i] then + return keys[i], t[keys[i]] + end + end +end +--- +-- Sends a usbpackage , "hf 14b raw" +-- if it reads the response, it converts it to a lua object "Command" first and the Data is cut to correct length. +local function calypso_send_cmd_raw(data, ignoreresponse ) + + local command, flags, result, err + flags = lib14b.ISO14B_COMMAND.ISO14B_APDU + + data = data or "00" + + command = Command:newMIX{ + cmd = cmds.CMD_HF_ISO14443B_COMMAND, + arg1 = flags, + arg2 = #data/2, -- LEN of data, half the length of the ASCII-string hex string + data = data} -- data bytes (commands etc) + + local use_cmd_ack = true + result, err = command:sendMIX(ignoreresponse, 2000, use_cmd_ack) + if result then + local count,cmd,arg0,arg1,arg2 = bin.unpack('LLLL', result) + if arg0 >= 0 then + return calypso_parse(result) + else + err = 'card response failed' + end + else + err = 'No response from card' + end + return result, err +end +--- +-- calypso_card_num : Reads card number from ATR and +-- writes it in the tree in decimal format. +local function calypso_card_num(card) + if not card then return end + local card_num = tonumber( card.uid:sub(1,8),16 ) + print('') + print('Card UID ' ..ansicolors.green..card.uid:format('%x')..ansicolors.reset) + print('Card Number ' ..ansicolors.green..string.format('%u', card_num)..ansicolors.reset) + print('-----------------------') +end +--- +-- analyse CALYPSO apdu status bytes. +local function calypso_apdu_status(apdu) + -- last two is CRC + -- next two is APDU status bytes. + local mess = 'FAIL' + local sw = apdu:sub( #apdu-7, #apdu-4) + desc, err = iso7816.tostring(sw) + --print ('SW', sw, desc, err ) + local status = ( sw == '9000' ) + return status, desc, err +end + +local CLA = '00' +local _calypso_cmds = { + ['01.SELECT AID 1TIC.ICA'] = CLA..'a4 0400 08 315449432e494341', + ['02.Select ICC file a'] = CLA..'a4 0000 02 3f00', + ['03.Select ICC file b'] = CLA..'a4 0000 02 0002', + ['04.ICC'] = CLA..'b2 0104 1d', + ['05.Select Holder file'] = CLA..'a4 0000 02 3f1c', + ['06.Holder1'] = CLA..'b2 0104 1d', + ['07.Holder2'] = CLA..'b2 0204 1d', + ['08.Select EnvHol file a'] = CLA..'a4 0000 00', + ['09.Select EnvHol file b'] = CLA..'a4 0000 02 2000', + ['10.Select EnvHol file c'] = CLA..'a4 0000 02 2001', + ['11.EnvHol1'] = CLA..'b2 0104 1d', + ['11.EnvHol2'] = CLA..'b2 0204 1d', + ['12.Select EvLog file'] = CLA..'a4 0000 02 2010', + ['13.EvLog1'] = CLA..'b2 0104 1d', + ['14.EvLog2'] = CLA..'b2 0204 1d', + ['15.EvLog3'] = CLA..'b2 0304 1d', + ['16.Select ConList file'] = CLA..'a4 0000 02 2050', + ['17.ConList'] = CLA..'b2 0104 1d', + ['18.Select Contra file'] = CLA..'a4 0000 02 2020', + ['19.Contra1'] = CLA..'b2 0104 1d', + ['20.Contra2'] = CLA..'b2 0204 1d', + ['21.Contra3'] = CLA..'b2 0304 1d', + ['22.Contra4'] = CLA..'b2 0404 1d', + ['23.Contra5'] = CLA..'b2 0504 1d', + ['24.Contra6'] = CLA..'b2 0604 1d', + ['25.Contra7'] = CLA..'b2 0704 1d', + ['26.Contra8'] = CLA..'b2 0804 1d', + ['27.Contra9'] = CLA..'b2 0904 1d', + ['28.ContraA'] = CLA..'b2 0a04 1d', + ['29.ContraB'] = CLA..'b2 0b04 1d', + ['30.ContraC'] = CLA..'b2 0c04 1d', + ['31.Select Counter file'] = CLA..'a4 0000 02 2069', + ['32.Counter'] = CLA..'b2 0104 1d', + ['33.Select LoadLog file a'] = CLA..'a4 0000 00', + ['34.Select LoadLog file b'] = CLA..'a4 0000 02 1000', + ['35.Select LoadLog file c'] = CLA..'a4 0000 02 1014', + ['36.LoadLog'] = CLA..'b2 0104 1d', + ['37.Select Purcha file'] = CLA..'a4 0000 02 1015', + ['38.Purcha1'] = CLA..'b2 0104 1d', + ['39.Purcha2'] = CLA..'b2 0204 1d', + ['40.Purcha3'] = CLA..'b2 0304 1d', + ['41.Select SpecEv file a'] = CLA..'a4 0000 00', + ['42.Select SpecEv file b'] = CLA..'a4 0000 02 2000', + ['43.Select SpecEv file c'] = CLA..'a4 0000 02 2040', + ['44.SpecEv1'] = CLA..'b2 0104 1d', + ['45.SpecEv2'] = CLA..'b2 0204 1d', + ['46.SpecEv3'] = CLA..'b2 0304 1d', + ['47.SpecEv4'] = CLA..'b2 0404 1d', +} + +--- +-- The main entry point +function main(args) + + print( string.rep('--',20) ) + print( string.rep('--',20) ) + print() + + local data, apdu, flags, uid, cid, result, err, card + -- Read the parameters + for o, a in getopt.getopt(args, 'h') do + if o == 'h' then return help() end + if o == 'b' then bytes = a end + end + +-- lib14b.connect() + + -- Select 14b tag. + card, err = lib14b.waitFor14443b() + if not card then return oops(err) end + + calypso_card_num(card) + cid = card.cid + + for i, apdu in spairs(_calypso_cmds) do + print('>> '..ansicolors.yellow..i..ansicolors.reset) + apdu = apdu:gsub('%s+', '') + result, err = calypso_send_cmd_raw(apdu , false) + if err then + print('<< '..err) + else + if result then + local status, desc, err = calypso_apdu_status(result.data) + local d = result.data:sub(3, (#result.data - 8)) + if status then + print('<< '..d..' ('..ansicolors.green..'ok'..ansicolors.reset..')') + else + print('<< '..d..' '..ansicolors.red..err..ansicolors.reset ) + end + else + print('<< no answer') + end + end + end + lib14b.disconnect() +end +--- +-- a simple selftest function, tries to convert +function selftest() + DEBUG = true + dbg('Performing test') + dbg('Tests done') +end +-- Flip the switch here to perform a sanity check. +-- It read a nonce in two different ways, as specified in the usage-section +if '--test'==args then + selftest() +else + -- Call the main + main(args) +end diff --git a/client/luascripts/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..8d18ec5da --- /dev/null +++ b/client/luascripts/lf_em_tearoff_protect.lua @@ -0,0 +1,330 @@ +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 --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) + word14b, err14b = core.em4x05_read(14, password) + if err14b then + return oops(err14b) + end + 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 + if auto then + n = 0 + ed = sd + else + tries = 0 + soon = 0 + late = 0 + 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 + 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 ffa6785b4..4f5c55363 100644 --- a/client/src/cmddata.c +++ b/client/src/cmddata.c @@ -27,45 +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_scale(void) { - PrintAndLogEx(NORMAL, "Set cursor display scale."); - PrintAndLogEx(NORMAL, "Setting the scale makes the differential `dt` reading between the yellow and purple markers meaningful. "); - PrintAndLogEx(NORMAL, "once the scale is set, the differential reading between brackets is the time duration in seconds."); - PrintAndLogEx(NORMAL, "For example, if acquiring in 125kHz, use scale 125."); - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(NORMAL, "Usage: data scale [h] "); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h this help"); - PrintAndLogEx(NORMAL, " sets scale of carrier frequency expressed in kHz"); - PrintAndLogEx(NORMAL, "Samples:"); - PrintAndLogEx(NORMAL, " data scale 125 - if sampled in 125kHz"); - return PM3_SUCCESS; -} static int usage_data_printdemodbuf(void) { - PrintAndLogEx(NORMAL, "Usage: data printdemodbuffer x o l "); + PrintAndLogEx(NORMAL, "Usage: data print x o l "); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h this help"); PrintAndLogEx(NORMAL, " i invert Demodbuffer before printing"); @@ -250,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"); @@ -283,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; @@ -558,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; @@ -652,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; @@ -1012,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; } @@ -1028,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++; } @@ -1451,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(); @@ -1689,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 @@ -1708,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) @@ -1716,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. @@ -1726,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 { @@ -1740,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; @@ -1773,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); @@ -1803,6 +1867,7 @@ int CmdLtrim(const char *Cmd) { GraphBuffer[i - ds] = GraphBuffer[i]; GraphTraceLen -= ds; + g_DemodStartIdx -= ds; RepaintGraphWindow(); return PM3_SUCCESS; } @@ -1825,7 +1890,8 @@ static int CmdMtrim(const char *Cmd) { uint32_t start = 0, stop = 0; sscanf(Cmd, "%u %u", &start, &stop); - if (start > GraphTraceLen || stop > GraphTraceLen || start > stop) return PM3_ESOFT; + if (start > GraphTraceLen || stop > GraphTraceLen || start >= stop) + return PM3_ESOFT; // leave start position sample start++; @@ -1871,39 +1937,31 @@ 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_str1("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); + CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen); + + CLIParserFree(ctx); if (as_wave) return saveFileWAVE(filename, GraphBuffer, GraphTraceLen); @@ -1911,15 +1969,33 @@ int CmdSave(const char *Cmd) { return saveFilePM3(filename, GraphBuffer, GraphTraceLen); } -static int CmdScale(const char *Cmd) { - char cmdp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) == 0 || cmdp == 'h') return usage_data_scale(); +static int CmdTimeScale(const char *Cmd) { - CursorScaleFactor = atoi(Cmd); - if (CursorScaleFactor == 0) { - PrintAndLogEx(FAILED, "bad, can't have zero scale"); + CLIParserContext *ctx; + 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 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 timescale factor"); CursorScaleFactor = 1; } + int len = 0; + CursorScaleFactorUnit[0] = '\x00'; + CLIParamStrToBuf(arg_get_str(ctx, 2), (uint8_t *)CursorScaleFactorUnit, sizeof(CursorScaleFactorUnit), &len); + CLIParserFree(ctx); RepaintGraphWindow(); return PM3_SUCCESS; } @@ -2293,45 +2369,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..00b7d9484 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) } @@ -1334,7 +1338,7 @@ static int CmdHF14ACmdRaw(const char *Cmd) { if (!res && datalen > 0) waitCmd(0, timeout); } - return 0; + return PM3_SUCCESS; } static int waitCmd(uint8_t iSelect, uint32_t timeout) { @@ -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 (iSelect == 0 && 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; @@ -1380,16 +1398,20 @@ static int CmdHF14AAntiFuzz(const char *Cmd) { }; CLIExecWithReturn(ctx, Cmd, argtable, false); - uint8_t arg0 = FLAG_4B_UID_IN_DATA; + struct { + uint8_t flag; + } PACKED param; + param.flag = FLAG_4B_UID_IN_DATA; + if (arg_get_lit(ctx, 2)) - arg0 = FLAG_7B_UID_IN_DATA; + param.flag = FLAG_7B_UID_IN_DATA; if (arg_get_lit(ctx, 3)) - arg0 = FLAG_10B_UID_IN_DATA; + param.flag = FLAG_10B_UID_IN_DATA; CLIParserFree(ctx); clearCommandBuffer(); - SendCommandMIX(CMD_HF_ISO14443A_ANTIFUZZ, arg0, 0, 0, NULL, 0); - return 0; + SendCommandNG(CMD_HF_ISO14443A_ANTIFUZZ, (uint8_t*)¶m, sizeof(param)); + return PM3_SUCCESS; } static int CmdHF14AChaining(const char *Cmd) { @@ -1420,7 +1442,7 @@ static int CmdHF14AChaining(const char *Cmd) { PrintAndLogEx(INFO, "\nISO 14443-4 input chaining %s.\n", APDUInFramingEnable ? "enabled" : "disabled"); - return 0; + return PM3_SUCCESS; } static void printTag(const char *tag) { @@ -1663,10 +1685,16 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { } getTagLabel(card.uid[0], card.uid[1]); break; - case 0x57: // Qualcomm + case 0x46: + if (memcmp(card.uid, "FSTN10m", 7) == 0) { + isMifareClassic = false; + printTag("Waveshare NFC-Powered e-Paper 1.54\" (please disregard MANUFACTURER mapping above)"); + } + break; + case 0x57: if (memcmp(card.uid, "WSDZ10m", 7) == 0) { isMifareClassic = false; - printTag("Waveshare NFC-Powered e-Paper"); + printTag("Waveshare NFC-Powered e-Paper (please disregard MANUFACTURER mapping above)"); } break; default: @@ -1813,11 +1841,47 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { if (card.ats[0] > pos && card.ats[0] < card.ats_len - 2) { const char *tip = ""; if (card.ats[0] - pos >= 7) { - if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x01\xBC\xD6", 7) == 0) { - tip = "-> MIFARE Plus X 2K or 4K"; - } else if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x00\x35\xC7", 7) == 0) { - tip = "-> MIFARE Plus S 2K or 4K"; + + if ((card.sak & 0x70) == 0x40) { // and no GetVersion().. + + if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x01\xBC\xD6", 7) == 0) { + tip = "-> MIFARE Plus X 2K/4K (SL3)"; + } else if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x00\x35\xC7", 7) == 0) { + + if ((card.atqa[0] & 0x02) == 0x02) + tip = "-> MIFARE Plus S 2K (SL3)"; + else if ((card.atqa[0] & 0x04) == 0x04) + tip = "-> MIFARE Plus S 4K (SL3)"; + + } else if (memcmp(card.ats + pos, "\xC1\x05\x21\x30\x00\xF6\xD1", 7) == 0) { + tip = "-> MIFARE Plus SE 1K (17pF)"; + } else if (memcmp(card.ats + pos, "\xC1\x05\x21\x30\x10\xF6\xD1", 7) == 0) { + tip = "-> MIFARE Plus SE 1K (70pF)"; + } + + } else { //SAK B4,5,6 + + if ((card.sak & 0x20) == 0x20) { // and no GetVersion().. + + + if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x01\xBC\xD6", 7) == 0) { + tip = "-> MIFARE Plus X 2K (SL1)"; + } else if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x00\x35\xC7", 7) == 0) { + tip = "-> MIFARE Plus S 2K (SL1)"; + } else if (memcmp(card.ats + pos, "\xC1\x05\x21\x30\x00\xF6\xD1", 7) == 0) { + tip = "-> MIFARE Plus SE 1K (17pF)"; + } else if (memcmp(card.ats + pos, "\xC1\x05\x21\x30\x10\xF6\xD1", 7) == 0) { + tip = "-> MIFARE Plus SE 1K (70pF)"; + } + } else { + if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x01\xBC\xD6", 7) == 0) { + tip = "-> MIFARE Plus X 4K (SL1)"; + } else if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x00\x35\xC7", 7) == 0) { + tip = "-> MIFARE Plus S 4K (SL1)"; + } + } } + } PrintAndLogEx(SUCCESS, " - HB : %s%s", sprint_hex(card.ats + pos, card.ats[0] - pos), tip); if (card.ats[pos] == 0xC1) { @@ -1954,6 +2018,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 15cf0a2c0..73f8c2a8f 100644 --- a/client/src/cmdhf14b.c +++ b/client/src/cmdhf14b.c @@ -63,7 +63,7 @@ static uint16_t get_sw(uint8_t *d, uint8_t n) { return d[n] * 0x0100 + d[n + 1]; } -static bool wait_cmd_14b(bool verbose) { +static bool wait_cmd_14b(bool verbose, bool is_select) { PacketResponseNG resp; if (WaitForResponseTimeout(CMD_HF_ISO14443B_COMMAND, &resp, TIMEOUT)) { @@ -71,13 +71,31 @@ static bool wait_cmd_14b(bool verbose) { uint16_t len = (resp.oldarg[1] & 0xFFFF); uint8_t *data = resp.data.asBytes; + // handle select responses + if (is_select) { + + // 0: OK; -1: attrib fail; -2:crc fail + int status = (int)resp.oldarg[0]; + if (status == 0) { + + if (verbose) { + PrintAndLogEx(SUCCESS, "received " _YELLOW_("%u") " bytes", len); + PrintAndLogEx(SUCCESS, "%s", sprint_hex(data, len)); + } + return true; + } else { + return false; + } + } + + // handle raw bytes responses if (verbose) { 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], @@ -87,46 +105,55 @@ static bool wait_cmd_14b(bool verbose) { 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); - + CLIExecWithReturn(ctx, Cmd, argtable, false); + uint8_t pupi[4]; int n = 0; - CLIParamHexToBuf(arg_get_str(ctx, 1), pupi, sizeof(pupi), &n); + int res = CLIParamHexToBuf(arg_get_str(ctx, 1), pupi, sizeof(pupi), &n); CLIParserFree(ctx); + if (res) { + PrintAndLogEx(FAILED, "failed to read pupi"); + return PM3_EINVARG; + } + + PrintAndLogEx(INFO, "Simulate with PUPI : " _GREEN_("%s"), sprint_hex_inrow(pupi, sizeof(pupi))); + PrintAndLogEx(INFO, "Press pm3-button to abort simulation"); clearCommandBuffer(); SendCommandNG(CMD_HF_ISO14443B_SIMULATE, pupi, sizeof(pupi)); - return PM3_SUCCESS; } @@ -136,52 +163,51 @@ 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 -s -c -k 0200a40400\n" - "hf 14b raw --sr -c -k 0200a40400\n" - "hf 14b raw --cts -c -k 0200a40400\n" - ); - + "hf 14b raw -cks --data 0200a40400 -> standard select\n" + "hf 14b raw -ck --sr --data 0200a40400 -> SRx select\n" + "hf 14b raw -ck --cts --data 0200a40400 -> C-ticket select\n" + ); + void *argtable[] = { arg_param_begin, arg_lit0("k", "keep", "leave the signal field ON after receive response"), - arg_lit0("s", "std", "activate field and select standard card"), - arg_lit0(NULL, "sr", "activate field and select SRx ST"), - arg_lit0(NULL, "cts", "activate field and select ASK C-ticket"), + arg_lit0("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_int0("t", "timeout", "dec", "timeout in ms"), - arg_lit0("v", "verbose", "verbose"), - arg_strx0(NULL, NULL, "", "bytes to send"), + 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"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); - bool select = false; bool keep_field_on = arg_get_lit(ctx, 1); bool select_std = arg_get_lit(ctx, 2); bool select_sr = arg_get_lit(ctx, 3); @@ -197,25 +223,25 @@ static int CmdHF14BCmdRaw(const char *Cmd) { } if (select_std) { - select = true; - flags |= ISO14B_SELECT_STD; + flags |= (ISO14B_SELECT_STD | ISO14B_CLEARTRACE); if (verbose) - PrintAndLogEx(INFO, "using standard select"); + PrintAndLogEx(INFO, "using ISO14443-B select"); } else if (select_sr) { - select = true; - flags |= ISO14B_SELECT_SR; + flags |= (ISO14B_SELECT_SR | ISO14B_CLEARTRACE); if (verbose) - PrintAndLogEx(INFO, "using SRx ST select"); + PrintAndLogEx(INFO, "using ST/SRx select"); } else if (select_cts) { - select = true; - flags |= ISO14B_SELECT_CTS; + flags |= (ISO14B_SELECT_CTS | ISO14B_CLEARTRACE); if (verbose) - PrintAndLogEx(INFO, "using ASK C-ticket select"); + PrintAndLogEx(INFO, "using ASK/C-ticket select"); } uint8_t data[PM3_CMD_DATA_SIZE] = {0x00}; int datalen = 0; - CLIParamHexToBuf(arg_get_str(ctx, 9), data, sizeof(data), &datalen); + int res = CLIParamHexToBuf(arg_get_str(ctx, 9), data, sizeof(data), &datalen); + if (res && verbose) { + PrintAndLogEx(INFO, "called with no raw bytes"); + } CLIParserFree(ctx); uint32_t time_wait = 0; @@ -244,18 +270,34 @@ static int CmdHF14BCmdRaw(const char *Cmd) { clearCommandBuffer(); SendCommandMIX(CMD_HF_ISO14443B_COMMAND, flags, datalen, time_wait, data, datalen); if (read_reply == false) { + clearCommandBuffer(); return PM3_SUCCESS; } bool success = true; - // get back iso14b_card_select_t, don't print it. - if (select) { - success = wait_cmd_14b(verbose); + + // Select, device will send back iso14b_card_select_t, don't print it. + if (select_std) { + success = wait_cmd_14b(verbose, true); + if (verbose && success) + PrintAndLogEx(SUCCESS, "Got response for standard select"); + } + + if (select_sr) { + success = wait_cmd_14b(verbose, true); + if (verbose && success) + PrintAndLogEx(SUCCESS, "Got response for ST/SRx select"); + } + + if (select_cts) { + success = wait_cmd_14b(verbose, true); + if (verbose && success) + PrintAndLogEx(SUCCESS, "Got response for ASK/C-ticket select"); } // get back response from the raw bytes you sent. if (success && datalen > 0) { - wait_cmd_14b(true); + wait_cmd_14b(true, false); } return PM3_SUCCESS; @@ -584,8 +626,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); @@ -617,7 +659,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; } @@ -657,7 +699,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; } @@ -678,7 +720,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, @@ -701,7 +743,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; } @@ -741,7 +783,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; } @@ -784,7 +826,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; } @@ -826,7 +868,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; } @@ -850,7 +892,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; } @@ -874,7 +916,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; } @@ -904,7 +946,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, @@ -922,20 +964,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"); @@ -943,7 +985,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; } @@ -1035,8 +1077,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"), @@ -1047,7 +1089,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; @@ -1055,9 +1097,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; } @@ -1322,12 +1364,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; @@ -1394,7 +1436,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) { @@ -1463,7 +1505,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(); } @@ -1525,10 +1567,10 @@ static int CmdHF14BAPDU(const char *Cmd) { CLIParserContext *ctx; CLIParserInit(&ctx, "hf 14b apdu", "Sends an ISO 7816-4 APDU via ISO 14443-4 block transmission protocol (T=CL). works with all apdu types from ISO 7816-4:2013", - "hf 14b apdu -s 94a40800043f000002\n" - "hf 14b apdu -sd 00A404000E325041592E5359532E444446303100 -> decode apdu\n" - "hf 14b apdu -sm 00A40400 325041592E5359532E4444463031 -l 256 -> encode standard apdu\n" - "hf 14b apdu -sm 00A40400 325041592E5359532E4444463031 -el 65536 -> encode extended apdu\n"); + "hf 14b apdu -s --hex 94a40800043f000002\n" + "hf 14b apdu -sd --hex 00A404000E325041592E5359532E444446303100 -> decode apdu\n" + "hf 14b apdu -sm 00A40400 -l 256 --hex 325041592E5359532E4444463031 -> encode standard apdu\n" + "hf 14b apdu -sm 00A40400 -el 65536 --hex 325041592E5359532E4444463031 -> encode extended apdu\n"); void *argtable[] = { arg_param_begin, @@ -1536,10 +1578,10 @@ static int CmdHF14BAPDU(const char *Cmd) { arg_lit0("k", "keep", "leave the signal field ON after receive response"), arg_lit0("t", "tlv", "executes TLV decoder if it possible"), arg_lit0("d", "decode", "decode apdu request if it possible"), - arg_str0("m", "make", "", "make apdu with head from this field and data from data field. Must be 4 bytes length: "), + arg_str0("m", "make", "", "make apdu with head from this field and data from data field. Must be 4 bytes length: "), arg_lit0("e", "extended", "make extended length apdu if `m` parameter included"), - arg_int0("l", "le", "", "Le apdu parameter if `m` parameter included"), - arg_strx1(NULL, NULL, "", "data if `m` parameter included"), + arg_int0("l", "le", "", "Le apdu parameter if `m` parameter included"), + arg_strx1(NULL, "hex", "", " if `m` parameter included"), arg_param_end }; CLIExecWithReturn(ctx, Cmd, argtable, false); @@ -1602,11 +1644,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; @@ -1638,7 +1680,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 @@ -1728,7 +1770,7 @@ static int CmdHF14BNdef(const char *Cmd) { } res = NDEFRecordsDecodeAndPrint(response + 2, resplen - 4); - + out: switch_off_field_14b(); return res; @@ -1736,7 +1778,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..6d276617c 100644 --- a/client/src/cmdhf15.c +++ b/client/src/cmdhf15.c @@ -34,6 +34,7 @@ #include "crc16.h" // iso15 crc #include "cmddata.h" // getsamples #include "fileutils.h" // savefileEML +#include "cliparser.h" #define FrameSOF Iso15693FrameSOF #define Logic0 Iso15693Logic0 @@ -60,9 +61,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" }, @@ -209,16 +210,6 @@ const productName uidmapping[] = { static int CmdHF15Help(const char *Cmd); -static int usage_15_demod(void) { - PrintAndLogEx(NORMAL, "Tries to demodulate / decode ISO15693, from downloaded samples.\n" - "Gather samples with 'hf 15 read' / 'hf 15 record'"); - return PM3_SUCCESS; -} -static int usage_15_samples(void) { - PrintAndLogEx(NORMAL, "Acquire samples as Reader (enables carrier, send inquiry\n" - "and download it to graphbuffer. Try 'hf 15 demod' to try to demodulate/decode signal"); - return PM3_SUCCESS; -} static int usage_15_info(void) { PrintAndLogEx(NORMAL, "Uses the optional command 'get_systeminfo' 0x2B to try and extract information\n" "command may fail, depending on tag.\n" @@ -235,36 +226,7 @@ static int usage_15_info(void) { _YELLOW_("\thf 15 info u")); return PM3_SUCCESS; } -static int usage_15_record(void) { - PrintAndLogEx(NORMAL, "Record activity without enabling carrier"); - return PM3_SUCCESS; -} -static int usage_15_reader(void) { - PrintAndLogEx(NORMAL, "This command identifies a ISO 15693 tag\n" - "\n" - "Usage: hf 15 reader [h]\n" - "Options:\n" - "\th this help\n" - "\t1 read once\n" - "\n" - "Example:\n" - _YELLOW_("\thf 15 reader\n") - _YELLOW_("\thf 15 reader 1\n")); - return PM3_SUCCESS; -} -static int usage_15_sim(void) { - PrintAndLogEx(NORMAL, "Usage: hf 15 sim \n" - "\n" - "Example:\n" - _YELLOW_("\thf 15 sim E016240000000000")); - return PM3_SUCCESS; -} -static int usage_15_findafi(void) { - PrintAndLogEx(NORMAL, "This command attempts to brute force AFI of an ISO15693 tag\n" - "\n" - "Usage: hf 15 findafi"); - return PM3_SUCCESS; -} + static int usage_15_writeafi(void) { PrintAndLogEx(NORMAL, "Usage: hf 15 writeafi \n" "\tuid (either): \n" @@ -323,7 +285,7 @@ static int usage_15_raw(void) { return PM3_SUCCESS; } static int usage_15_read(void) { - PrintAndLogEx(NORMAL, "Usage: hf 15 read [options] \n" + PrintAndLogEx(NORMAL, "Usage: hf 15 rdbl [options] \n" "Options:\n" "\t-2 use slower '1 out of 256' mode\n" "\tuid (either): \n" @@ -334,7 +296,7 @@ static int usage_15_read(void) { return PM3_SUCCESS; } static int usage_15_write(void) { - PrintAndLogEx(NORMAL, "Usage: hf 15 write [options] \n" + PrintAndLogEx(NORMAL, "Usage: hf 15 wrbl [options] \n" "Options:\n" "\t-2 use slower '1 out of 256' mode\n" "\t-o set OPTION Flag (needed for TI)\n" @@ -358,17 +320,6 @@ static int usage_15_readmulti(void) { "\t 1-6, number of pages"); return PM3_SUCCESS; } -static int usage_15_csetuid(void) { - PrintAndLogEx(NORMAL, "Set UID for magic Chinese card (only works with such cards)\n" - "\n" - "Usage: hf 15 csetuid \n" - "Options:\n" - "\tuid : <8B hex> full UID eg E011223344556677\n" - "\n" - "Example:\n" - _YELLOW_("\thf 15 csetuid E011223344556677")); - return PM3_SUCCESS; -} static int nxp_15693_print_signature(uint8_t *uid, uint8_t *signature) { @@ -691,17 +642,31 @@ static bool prepareHF15Cmd(char **cmd, uint16_t *reqlen, uint8_t *arg1, uint8_t } // Mode 3 -//helptext static int CmdHF15Demod(const char *Cmd) { - char cmdp = tolower(param_getchar(Cmd, 0)); - if (cmdp == 'h') return usage_15_demod(); + + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf 15 demod", + "Tries to demodulate / decode ISO15693, from downloaded samples.\n" + "Gather samples with 'hf 15 samples' / 'hf 15 sniff'", + "hf 15 demod\n"); + + void *argtable[] = { + arg_param_begin, + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIParserFree(ctx); // The sampling rate is 106.353 ksps/s, for T = 18.8 us int i, j; int max = 0, maxPos = 0; int skip = 4; - if (GraphTraceLen < 1000) return PM3_ESOFT; + if (GraphTraceLen < 1000) { + PrintAndLogEx(FAILED, "Too few samples in GraphBuffer. Need more than 1000"); + PrintAndLogEx(HINT, "Run " _YELLOW_("`hf 15 samples`") " to collect and download data"); + return PM3_ESOFT; + } // First, correlate for SOF for (i = 0; i < 1000; i++) { @@ -719,7 +684,7 @@ static int CmdHF15Demod(const char *Cmd) { i = maxPos + ARRAYLEN(FrameSOF) / skip; int k = 0; - uint8_t outBuf[20]; + uint8_t outBuf[2048] = {0}; memset(outBuf, 0, sizeof(outBuf)); uint8_t mask = 0x01; for (;;) { @@ -746,40 +711,80 @@ static int CmdHF15Demod(const char *Cmd) { } else { i += ARRAYLEN(Logic0) / skip; } + mask <<= 1; if (mask == 0) { k++; mask = 0x01; } + if ((i + (int)ARRAYLEN(FrameEOF)) >= GraphTraceLen) { PrintAndLogEx(INFO, "ran off end!"); break; } + + if (k > 2048) { + PrintAndLogEx(INFO, "ran out of buffer"); + break; + } } if (mask != 0x01) { PrintAndLogEx(WARNING, "Warning, uneven octet! (discard extra bits!)"); PrintAndLogEx(INFO, " mask = %02x", mask); } - PrintAndLogEx(INFO, "%d octets", k); - for (i = 0; i < k; i++) - PrintAndLogEx(SUCCESS, "# %2d: %02x ", i, outBuf[i]); + if (k == 0) { + return PM3_SUCCESS; + } - PrintAndLogEx(SUCCESS, "CRC %04x", Crc15(outBuf, k - 2)); + i = 0; + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "Got %d octets, decoded as following", k); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, " idx | data"); + PrintAndLogEx(SUCCESS, "-----+-------------------------------------------------"); + if (k / 16 > 0) { + for (; i < k; i += 16) { + PrintAndLogEx(SUCCESS, " %3i | %s", i, sprint_hex(outBuf + i, 16)); + } + } + + uint8_t mod = (k % 16); + if (mod > 0) { + PrintAndLogEx(SUCCESS, " %3i | %s", i, sprint_hex(outBuf + i, mod)); + } + PrintAndLogEx(SUCCESS, "-----+-------------------------------------------------"); + if (k > 2) { + PrintAndLogEx(SUCCESS, "--> CRC %04x", Crc15(outBuf, k - 2)); + } + PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } // * Acquire Samples as Reader (enables carrier, sends inquiry) //helptext static int CmdHF15Samples(const char *Cmd) { - char cmdp = tolower(param_getchar(Cmd, 0)); - if (cmdp == 'h') return usage_15_samples(); + + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf 15 samples", + "Acquire samples as Reader (enables carrier, send inquiry\n" + "and download it to graphbuffer. Try 'hf 15 demod' to try to demodulate/decode signal", + "hf 15 samples"); + + void *argtable[] = { + arg_param_begin, + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + CLIParserFree(ctx); clearCommandBuffer(); SendCommandNG(CMD_HF_ISO15693_ACQ_RAW_ADC, NULL, 0); getSamples(0, true); + + PrintAndLogEx(HINT, "Try `" _YELLOW_("hf 15 demod") "` to decode signal"); return PM3_SUCCESS; } @@ -816,6 +821,10 @@ static int NxpSysInfo(uint8_t *uid) { DropField(); int status = resp.oldarg[0]; + if (status == PM3_ETEAROFF) { + return status; + } + if (status < 2) { PrintAndLogEx(WARNING, "iso15693 card doesn't answer to NXP systeminfo command"); return PM3_EWRONGANSWER; @@ -975,6 +984,9 @@ static int CmdHF15Info(const char *Cmd) { DropField(); int status = resp.oldarg[0]; + if (status == PM3_ETEAROFF) { + return status; + } if (status < 2) { PrintAndLogEx(WARNING, "iso15693 card doesn't answer to systeminfo command (%d)", status); return PM3_EWRONGANSWER; @@ -1033,11 +1045,19 @@ static int CmdHF15Info(const char *Cmd) { return PM3_SUCCESS; } -// Record Activity without enabling carrier -//helptext +// Sniff Activity without enabling carrier static int CmdHF15Sniff(const char *Cmd) { - char cmdp = tolower(param_getchar(Cmd, 0)); - if (cmdp == 'h') return usage_15_record(); + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf 15 sniff", + "Sniff activity without enabling carrier", + "hf 15 sniff\n"); + + void *argtable[] = { + arg_param_begin, + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIParserFree(ctx); PacketResponseNG resp; clearCommandBuffer(); @@ -1051,30 +1071,58 @@ static int CmdHF15Sniff(const char *Cmd) { } static int CmdHF15Reader(const char *Cmd) { - char cmdp = tolower(param_getchar(Cmd, 0)); - if (cmdp == 'h') return usage_15_reader(); - bool loop_read = (cmdp == '1') ? false : true; + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf 15 reader", + "Act as a ISO15693 reader. Look for ISO15693 tags until Enter or the pm3 button is pressed\n", + "hf 15 reader\n" + "hf 15 reader -1"); - readHF15Uid(loop_read, true); + void *argtable[] = { + arg_param_begin, + arg_lit0("1", "one", "read once"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + bool read_once = arg_get_lit(ctx, 1); + CLIParserFree(ctx); + + PrintAndLogEx(INFO, "Starting ISO15 reader mode"); + PrintAndLogEx(INFO, "press " _YELLOW_("`enter`") " to cancel"); + readHF15Uid(!read_once, true); return PM3_SUCCESS; } // Simulation is still not working very good // helptext static int CmdHF15Sim(const char *Cmd) { - char cmdp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) < 1 || cmdp == 'h') return usage_15_sim(); + + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf 15 sim", + "Simulate a ISO15693 tag\n", + "hf 15 sim -u E011223344556677"); + + void *argtable[] = { + arg_param_begin, + arg_str1("u", "uid", "<8b hex>", "UID eg E011223344556677"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); struct { uint8_t uid[8]; } PACKED payload; - if (param_gethex(Cmd, 0, payload.uid, 16)) { + int uidlen = 0; + CLIGetHexWithReturn(ctx, 1, payload.uid, &uidlen); + CLIParserFree(ctx); + + if (uidlen != 9) { PrintAndLogEx(WARNING, "UID must include 16 HEX symbols"); return PM3_EINVARG; } PrintAndLogEx(SUCCESS, "Starting simulating UID " _YELLOW_("%s"), iso15693_sprintUID(NULL, payload.uid)); + PrintAndLogEx(INFO, "press " _YELLOW_("`enter`") " to cancel"); PacketResponseNG resp; clearCommandBuffer(); @@ -1087,17 +1135,25 @@ static int CmdHF15Sim(const char *Cmd) { // (There is no standard way of reading the AFI, although some tags support this) // helptext static int CmdHF15FindAfi(const char *Cmd) { - PacketResponseNG resp; - uint32_t timeout = 0; + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf 15 findafi", + "This command attempts to brute force AFI of an ISO15693 tag\n", + "hf 15 findafi"); - char cmdp = tolower(param_getchar(Cmd, 0)); - if (cmdp == 'h') return usage_15_findafi(); + void *argtable[] = { + arg_param_begin, + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); + CLIParserFree(ctx); PrintAndLogEx(SUCCESS, "press pm3-button to cancel"); clearCommandBuffer(); + PacketResponseNG resp; SendCommandMIX(CMD_HF_ISO15693_FINDAFI, strtol(Cmd, NULL, 0), 0, 0, NULL, 0); + uint32_t timeout = 0; while (!WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { timeout++; @@ -1153,9 +1209,13 @@ static int CmdHF15WriteAfi(const char *Cmd) { DropField(); return PM3_ETIMEOUT; } - DropField(); + int status = resp.oldarg[0]; + if (status == PM3_ETEAROFF) { + return status; + } + uint8_t *data = resp.data.asBytes; if ((data[0] & ISO15_RES_ERROR) == ISO15_RES_ERROR) { @@ -1212,6 +1272,10 @@ static int CmdHF15WriteDsfid(const char *Cmd) { } DropField(); + int status = resp.oldarg[0]; + if (status == PM3_ETEAROFF) { + return status; + } uint8_t *data = resp.data.asBytes; @@ -1296,6 +1360,9 @@ static int CmdHF15Dump(const char *Cmd) { if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { int len = resp.oldarg[0]; + if (len == PM3_ETEAROFF) { + continue; + } if (len < 2) { PrintAndLogEx(FAILED, "iso15693 command failed"); continue; @@ -1321,6 +1388,7 @@ static int CmdHF15Dump(const char *Cmd) { blocknum++; PrintAndLogEx(NORMAL, "." NOLF); + fflush(stdout); } } @@ -1342,9 +1410,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) { @@ -1415,6 +1487,10 @@ static int CmdHF15Raw(const char *Cmd) { if (reply) { if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) { int len = resp.oldarg[0]; + if (len == PM3_ETEAROFF) { + DropField(); + return len; + } if (len < 2) { PrintAndLogEx(WARNING, "command failed"); } else { @@ -1487,6 +1563,10 @@ static int CmdHF15Readmulti(const char *Cmd) { DropField(); int status = resp.oldarg[0]; + if (status == PM3_ETEAROFF) { + return status; + } + if (status < 2) { PrintAndLogEx(FAILED, "iso15693 card readmulti failed"); return PM3_EWRONGANSWER; @@ -1570,6 +1650,9 @@ static int CmdHF15Read(const char *Cmd) { DropField(); int status = resp.oldarg[0]; + if (status == PM3_ETEAROFF) { + return status; + } if (status < 2) { PrintAndLogEx(ERR, "iso15693 command failed"); return PM3_EWRONGANSWER; @@ -1657,6 +1740,10 @@ static int CmdHF15Write(const char *Cmd) { DropField(); int status = resp.oldarg[0]; + if (status == PM3_ETEAROFF) { + return status; + } + if (status < 2) { PrintAndLogEx(FAILED, "iso15693 command failed"); return PM3_EWRONGANSWER; @@ -1802,16 +1889,28 @@ static int CmdHF15Restore(const char *Cmd) { */ static int CmdHF15CSetUID(const char *Cmd) { - char cmdp = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) < 1 || cmdp == 'h') return usage_15_csetuid(); + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf 15 csetuid", + "Set UID for magic Chinese card (only works with such cards)\n", + "hf 15 csetuid -u E011223344556677"); + void *argtable[] = { + arg_param_begin, + arg_str1("u", "uid", "<8b hex>", "UID eg E011223344556677"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, false); struct { uint8_t uid[8]; } PACKED payload; - if (param_gethex(Cmd, 0, payload.uid, 16)) { - PrintAndLogEx(WARNING, "UID must include 16 HEX symbols"); + int uidlen = 0; + CLIGetHexWithReturn(ctx, 1, payload.uid, &uidlen); + CLIParserFree(ctx); + + if (uidlen != 8) { + PrintAndLogEx(WARNING, "UID must include 16 HEX symbols got "); return PM3_EINVARG; } @@ -1834,9 +1933,10 @@ static int CmdHF15CSetUID(const char *Cmd) { PacketResponseNG resp; clearCommandBuffer(); SendCommandNG(CMD_HF_ISO15693_CSETUID, (uint8_t *)&payload, sizeof(payload)); - if (WaitForResponseTimeout(CMD_HF_ISO15693_CSETUID, &resp, 2000) == false) { PrintAndLogEx(WARNING, "timeout while waiting for reply"); + DropField(); + return PM3_ESOFT; } PrintAndLogEx(INFO, "getting updated card details..."); @@ -1872,13 +1972,13 @@ static command_t CommandTable[] = { {"info", CmdHF15Info, IfPm3Iso15693, "Tag information"}, {"sniff", CmdHF15Sniff, IfPm3Iso15693, "Sniff ISO15693 traffic"}, {"raw", CmdHF15Raw, IfPm3Iso15693, "Send raw hex data to tag"}, - {"read", CmdHF15Read, IfPm3Iso15693, "Read a block"}, + {"rdbl", CmdHF15Read, IfPm3Iso15693, "Read a block"}, {"reader", CmdHF15Reader, IfPm3Iso15693, "Act like an ISO15693 reader"}, {"readmulti", CmdHF15Readmulti, IfPm3Iso15693, "Reads multiple Blocks"}, {"restore", CmdHF15Restore, IfPm3Iso15693, "Restore from file to all memory pages of an ISO15693 tag"}, {"samples", CmdHF15Samples, IfPm3Iso15693, "Acquire Samples as Reader (enables carrier, sends inquiry)"}, {"sim", CmdHF15Sim, IfPm3Iso15693, "Fake an ISO15693 tag"}, - {"write", CmdHF15Write, IfPm3Iso15693, "Write a block"}, + {"wrbl", CmdHF15Write, IfPm3Iso15693, "Write a block"}, {"-----------", CmdHF15Help, IfPm3Iso15693, "----------------------- " _CYAN_("afi") " -----------------------"}, {"findafi", CmdHF15FindAfi, IfPm3Iso15693, "Brute force AFI of an ISO15693 tag"}, {"writeafi", CmdHF15WriteAfi, IfPm3Iso15693, "Writes the AFI on an ISO15693 tag"}, 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..53cb10c98 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}; @@ -198,6 +209,7 @@ static int CmdHFFidoRegister(const char *cmd) { if (paramsPlain) { memset(cdata, 0x00, 32); + chlen = sizeof(cdata); CLIGetStrWithReturn(ctx, 6, cdata, &chlen); if (chlen > 16) { PrintAndLogEx(ERR, "ERROR: challenge parameter length in ASCII mode must be less than 16 chars instead of: %d", chlen); @@ -205,6 +217,7 @@ static int CmdHFFidoRegister(const char *cmd) { return PM3_EINVARG; } } else { + chlen = sizeof(cdata); CLIGetHexWithReturn(ctx, 6, cdata, &chlen); if (chlen && chlen != 32) { PrintAndLogEx(ERR, "ERROR: challenge parameter length must be 32 bytes only."); @@ -218,6 +231,7 @@ static int CmdHFFidoRegister(const char *cmd) { if (paramsPlain) { memset(adata, 0x00, 32); + applen = sizeof(adata); CLIGetStrWithReturn(ctx, 7, adata, &applen); if (applen > 16) { PrintAndLogEx(ERR, "ERROR: application parameter length in ASCII mode must be less than 16 chars instead of: %d", applen); @@ -225,6 +239,7 @@ static int CmdHFFidoRegister(const char *cmd) { return PM3_EINVARG; } } else { + applen = sizeof(adata); CLIGetHexWithReturn(ctx, 7, adata, &applen); if (applen && applen != 32) { PrintAndLogEx(ERR, "ERROR: application parameter length must be 32 bytes only."); @@ -386,7 +401,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; @@ -474,6 +489,7 @@ static int CmdHFFidoAuthenticate(const char *cmd) { if (paramsPlain) { memset(hdata, 0x00, 32); + hdatalen = sizeof(hdata); CLIGetStrWithReturn(ctx, 9, hdata, &hdatalen); if (hdatalen > 16) { PrintAndLogEx(ERR, "ERROR: challenge parameter length in ASCII mode must be less than 16 chars instead of: %d", hdatalen); @@ -481,6 +497,7 @@ static int CmdHFFidoAuthenticate(const char *cmd) { return PM3_EINVARG; } } else { + hdatalen = sizeof(hdata); CLIGetHexWithReturn(ctx, 10, hdata, &hdatalen); if (hdatalen && hdatalen != 32) { PrintAndLogEx(ERR, "ERROR: challenge parameter length must be 32 bytes only."); @@ -494,6 +511,7 @@ static int CmdHFFidoAuthenticate(const char *cmd) { if (paramsPlain) { memset(hdata, 0x00, 32); + hdatalen = sizeof(hdata); CLIGetStrWithReturn(ctx, 11, hdata, &hdatalen); if (hdatalen > 16) { PrintAndLogEx(ERR, "ERROR: application parameter length in ASCII mode must be less than 16 chars instead of: %d", hdatalen); @@ -501,6 +519,7 @@ static int CmdHFFidoAuthenticate(const char *cmd) { return PM3_EINVARG; } } else { + hdatalen = sizeof(hdata); CLIGetHexWithReturn(ctx, 10, hdata, &hdatalen); if (hdatalen && hdatalen != 32) { PrintAndLogEx(ERR, "ERROR: application parameter length must be 32 bytes only."); @@ -652,7 +671,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}; @@ -682,6 +701,7 @@ static int CmdHFFido2MakeCredential(const char *cmd) { uint8_t jsonname[FILE_PATH_SIZE] = {0}; char *cjsonname = (char *)jsonname; int jsonnamelen = 0; + jsonnamelen = sizeof(jsonname); CLIGetStrWithReturn(ctx, 5, jsonname, &jsonnamelen); if (!jsonnamelen) { @@ -777,7 +797,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}; @@ -806,7 +826,7 @@ static int CmdHFFido2GetAssertion(const char *cmd) { uint8_t jsonname[FILE_PATH_SIZE] = {0}; char *cjsonname = (char *)jsonname; - int jsonnamelen = 0; + int jsonnamelen = sizeof(jsonname); CLIGetStrWithReturn(ctx, 5, jsonname, &jsonnamelen); if (!jsonnamelen) { @@ -903,13 +923,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."}, + {"list", 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..75c77559c 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" @@ -154,10 +155,11 @@ static int usage_hf_iclass_dump(void) { PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h : Show this help"); PrintAndLogEx(NORMAL, " f : specify a filename to save dump to"); - PrintAndLogEx(NORMAL, " k : access Key as 16 hex symbols or 1 hex to select key from memory"); + PrintAndLogEx(NORMAL, " k : access Key as 16 hex symbols or 1 hex to select key from memory OR NR/MAC for replay"); PrintAndLogEx(NORMAL, " c : credit key as 16 hex symbols or 1 hex to select key from memory"); PrintAndLogEx(NORMAL, " e : elite computations applied to key"); PrintAndLogEx(NORMAL, " r : raw, the key is interpreted as raw block 3/4"); + PrintAndLogEx(NORMAL, " n : replay of NR/MAC"); PrintAndLogEx(NORMAL, " v : verbose output"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); @@ -194,10 +196,11 @@ static int usage_hf_iclass_writeblock(void) { PrintAndLogEx(NORMAL, " h : Show this help"); PrintAndLogEx(NORMAL, " b : The block number as 2 hex symbols"); PrintAndLogEx(NORMAL, " d : set the Data to write as 16 hex symbols"); - PrintAndLogEx(NORMAL, " k : access Key as 16 hex symbols or 1 hex to select key from memory"); + PrintAndLogEx(NORMAL, " k : access Key as 16 hex symbols or 1 hex to select key from memory OR NR/MAC for replay"); PrintAndLogEx(NORMAL, " c : credit key assumed\n"); PrintAndLogEx(NORMAL, " e : elite computations applied to key"); PrintAndLogEx(NORMAL, " r : raw, no computations applied to key (raw)"); +// PrintAndLogEx(NORMAL, " n : replay of NR/MAC"); PrintAndLogEx(NORMAL, " v : verbose output"); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass wrbl b 0A d AAAAAAAAAAAAAAAA k 001122334455667B")); @@ -212,10 +215,11 @@ static int usage_hf_iclass_readblock(void) { PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h : Show this help"); PrintAndLogEx(NORMAL, " b : The block number as 2 hex symbols"); - PrintAndLogEx(NORMAL, " k : Access Key as 16 hex symbols or 1 hex to select key from memory"); + PrintAndLogEx(NORMAL, " k : access Key as 16 hex symbols or 1 hex to select key from memory OR NR/MAC for replay"); PrintAndLogEx(NORMAL, " c : credit key assumed\n"); PrintAndLogEx(NORMAL, " e : elite computations applied to key"); PrintAndLogEx(NORMAL, " r : raw, no computations applied to key"); + PrintAndLogEx(NORMAL, " n : replay of NR/MAC"); PrintAndLogEx(NORMAL, " v : verbose output"); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass rdbl b 06 k 0011223344556677")); @@ -224,21 +228,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"); @@ -283,29 +272,6 @@ static int usage_hf_iclass_managekeys(void) { PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } -static int usage_hf_iclass_reader(void) { - PrintAndLogEx(NORMAL, "Act as a iCLASS reader. Look for iCLASS tags until Enter or the pm3 button is pressed\n"); - PrintAndLogEx(NORMAL, "Usage: hf iclass reader [h] [1]\n"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h Show this help"); - PrintAndLogEx(NORMAL, " 1 read only 1 tag"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass reader 1")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} -static int usage_hf_iclass_replay(void) { - PrintAndLogEx(NORMAL, "Replay a collected mac message\n"); - PrintAndLogEx(NORMAL, "Usage: hf iclass replay [h] [m ]\n"); - PrintAndLogEx(NORMAL, "Options:"); - PrintAndLogEx(NORMAL, " h Show this help"); - PrintAndLogEx(NORMAL, " r Reader nonce bytes to replay (8 hexsymbols)"); - PrintAndLogEx(NORMAL, " m Mac bytes to replay (8 hexsymbols)"); - PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_("\thf iclass replay r 00000000 m 89cb984b")); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; -} static int usage_hf_iclass_loclass(void) { PrintAndLogEx(NORMAL, "Execute the offline part of loclass attack"); PrintAndLogEx(NORMAL, " An iclass dumpfile is assumed to consist of an arbitrary number of"); @@ -359,20 +325,6 @@ 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) { @@ -472,57 +424,55 @@ uint8_t get_pagemap(const picopass_hdr *hdr) { } static void fuse_config(const picopass_hdr *hdr) { + + uint16_t otp = (hdr->conf.otp[1] << 8 | hdr->conf.otp[0]); + + PrintAndLogEx(INFO, " Raw: " _YELLOW_("%s"), sprint_hex((uint8_t *)&hdr->conf, 8)); + PrintAndLogEx(INFO, " " _YELLOW_("%02X") "..................... app limit", hdr->conf.app_limit); + PrintAndLogEx(INFO, " " _YELLOW_("%04X") " ( %5u )...... OTP", otp, otp); + PrintAndLogEx(INFO, " " _YELLOW_("%02X") "............ block write lock", hdr->conf.block_writelock); + PrintAndLogEx(INFO, " " _YELLOW_("%02X") "......... chip", hdr->conf.chip_config); + PrintAndLogEx(INFO, " " _YELLOW_("%02X") "...... mem", hdr->conf.mem_config); + PrintAndLogEx(INFO, " " _YELLOW_("%02X") "... EAS", hdr->conf.eas); + PrintAndLogEx(INFO, " " _YELLOW_("%02X") " fuses", hdr->conf.fuses); + uint8_t fuses = hdr->conf.fuses; + PrintAndLogEx(INFO, " Fuses:"); if (isset(fuses, FUSE_FPERS)) - PrintAndLogEx(SUCCESS, " Mode: " _GREEN_("Personalization (programmable)")); + PrintAndLogEx(SUCCESS, " mode......... " _GREEN_("Personalization (programmable)")); else - PrintAndLogEx(SUCCESS, " Mode: " _YELLOW_("Application (locked)")); + PrintAndLogEx(SUCCESS, " mode......... " _YELLOW_("Application (locked)")); if (isset(fuses, FUSE_CODING1)) { - PrintAndLogEx(SUCCESS, "Coding: RFU"); + PrintAndLogEx(SUCCESS, " coding...... RFU"); } else { if (isset(fuses, FUSE_CODING0)) - PrintAndLogEx(SUCCESS, "Coding: " _YELLOW_("ISO 14443-2 B / 15693")); + PrintAndLogEx(SUCCESS, " coding....... " _YELLOW_("ISO 14443-2 B / 15693")); else - PrintAndLogEx(SUCCESS, "Coding: " _YELLOW_("ISO 14443-B only")); + PrintAndLogEx(SUCCESS, " coding....... " _YELLOW_("ISO 14443-B only")); } uint8_t pagemap = get_pagemap(hdr); switch (pagemap) { case 0x0: - PrintAndLogEx(INFO, " Crypt: No auth possible. Read only if RA is enabled"); + PrintAndLogEx(INFO, " crypt........ No auth possible. Read only if RA is enabled"); break; case 0x1: - PrintAndLogEx(SUCCESS, " Crypt: Non secured page"); + PrintAndLogEx(SUCCESS, " crypt........ Non secured page"); break; case 0x2: - PrintAndLogEx(INFO, " Crypt: Secured page, keys locked"); + PrintAndLogEx(INFO, " crypt........ Secured page, keys locked"); break; case 0x03: - PrintAndLogEx(SUCCESS, " Crypt: Secured page, " _GREEN_("keys not locked")); + PrintAndLogEx(SUCCESS, " crypt........ Secured page, " _GREEN_("keys not locked")); break; } if (isset(fuses, FUSE_RA)) - PrintAndLogEx(SUCCESS, " RA: Read access enabled"); + PrintAndLogEx(SUCCESS, " RA........... Read access enabled (non-secure mode)"); else - PrintAndLogEx(INFO, " RA: Read access not enabled"); - - PrintAndLogEx(INFO, - "App limit " _YELLOW_("0x%02X") ", OTP " _YELLOW_("0x%02X%02X") ", Block write lock " _YELLOW_("0x%02X") - , hdr->conf.app_limit - , hdr->conf.otp[1] - , hdr->conf.otp[0] - , hdr->conf.block_writelock - ); - PrintAndLogEx(INFO, - " Chip " _YELLOW_("0x%02X") ", Mem " _YELLOW_("0x%02X") ", EAS " _YELLOW_("0x%02X") ", Fuses " _YELLOW_("0x%02X") - , hdr->conf.chip_config - , hdr->conf.mem_config - , hdr->conf.eas - , hdr->conf.fuses - ); + PrintAndLogEx(INFO, " RA........... Read access not enabled"); } static void getMemConfig(uint8_t mem_cfg, uint8_t chip_cfg, uint8_t *app_areas, uint8_t *kb) { @@ -583,57 +533,61 @@ static void mem_app_config(const picopass_hdr *hdr) { uint8_t app2_limit = card_app2_limit[type]; uint8_t pagemap = get_pagemap(hdr); - PrintAndLogEx(INFO, "------ " _CYAN_("Memory") " ------"); + PrintAndLogEx(INFO, "-------------------------- " _CYAN_("Memory") " --------------------------"); if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) { - PrintAndLogEx(INFO, " %u KBits (%u bytes)", kb, app2_limit * 8); + PrintAndLogEx(INFO, " %u KBits ( " _YELLOW_("%u") " bytes )", kb, app2_limit * 8); PrintAndLogEx(INFO, " Tag has not App Areas"); return; } - PrintAndLogEx(INFO, " %u KBits/%u App Areas (%u bytes)", kb, app_areas, (app2_limit + 1) * 8); + PrintAndLogEx(INFO, " %u KBits/%u App Areas ( " _YELLOW_("%u") " bytes )", kb, app_areas, (app2_limit + 1) * 8); PrintAndLogEx(INFO, " AA1 blocks %u { 0x06 - 0x%02X (06 - %02d) }", app1_limit, app1_limit + 5, app1_limit + 5); PrintAndLogEx(INFO, " AA2 blocks %u { 0x%02X - 0x%02X (%02d - %02d) }", app2_limit - app1_limit, app1_limit + 5 + 1, app2_limit, app1_limit + 5 + 1, app2_limit); - PrintAndLogEx(INFO, "------ " _CYAN_("KeyAccess") " ------"); - PrintAndLogEx(INFO, " Kd = Debit key (AA1), Kc = Credit key (AA2)"); + PrintAndLogEx(INFO, "------------------------- " _CYAN_("KeyAccess") " ------------------------"); + PrintAndLogEx(INFO, " * Kd, Debit key, AA1 Kc, Credit key, AA2 *"); uint8_t book = isset(mem, 0x20); if (book) { - PrintAndLogEx(INFO, " Read A - Kd"); - PrintAndLogEx(INFO, " Read B - Kc"); - PrintAndLogEx(INFO, " Write A - Kd"); - PrintAndLogEx(INFO, " Write B - Kc"); - PrintAndLogEx(INFO, " Debit - Kd or Kc"); - PrintAndLogEx(INFO, " Credit - Kc"); + PrintAndLogEx(INFO, " Read A....... debit"); + PrintAndLogEx(INFO, " Read B....... credit"); + PrintAndLogEx(INFO, " Write A...... debit"); + PrintAndLogEx(INFO, " Write B...... credit"); + PrintAndLogEx(INFO, " Debit........ debit or credit"); + PrintAndLogEx(INFO, " Credit....... credit"); } else { - PrintAndLogEx(INFO, " Read A - Kd or Kc"); - PrintAndLogEx(INFO, " Read B - Kd or Kc"); - PrintAndLogEx(INFO, " Write A - Kc"); - PrintAndLogEx(INFO, " Write B - Kc"); - PrintAndLogEx(INFO, " Debit - Kd or Kc"); - PrintAndLogEx(INFO, " Credit - Kc"); + PrintAndLogEx(INFO, " Read A....... debit or credit"); + PrintAndLogEx(INFO, " Read B....... debit or credit"); + PrintAndLogEx(INFO, " Write A...... credit"); + PrintAndLogEx(INFO, " Write B...... credit"); + PrintAndLogEx(INFO, " Debit........ debit or credit"); + PrintAndLogEx(INFO, " redit........ credit"); } } static void print_picopass_info(const picopass_hdr *hdr) { - PrintAndLogEx(INFO, "------ " _CYAN_("card configuration") " ------"); + PrintAndLogEx(INFO, "-------------------- " _CYAN_("card configuration") " --------------------"); fuse_config(hdr); mem_app_config(hdr); } static void print_picopass_header(const picopass_hdr *hdr) { - PrintAndLogEx(INFO, "------------ " _CYAN_("card") " -------------"); - PrintAndLogEx(SUCCESS, " CSN: " _GREEN_("%s") " (uid)", sprint_hex(hdr->csn, sizeof(hdr->csn))); - PrintAndLogEx(SUCCESS, " Config: %s (Card configuration)", sprint_hex((uint8_t *)&hdr->conf, sizeof(hdr->conf))); - PrintAndLogEx(SUCCESS, "E-purse: %s (Card challenge, CC)", sprint_hex(hdr->epurse, sizeof(hdr->epurse))); - PrintAndLogEx(SUCCESS, " Kd: %s (Debit key, hidden)", sprint_hex(hdr->key_d, sizeof(hdr->key_d))); - PrintAndLogEx(SUCCESS, " Kc: %s (Credit key, hidden)", sprint_hex(hdr->key_c, sizeof(hdr->key_c))); - PrintAndLogEx(SUCCESS, " AIA: %s (Application Issuer area)", sprint_hex(hdr->app_issuer_area, sizeof(hdr->app_issuer_area))); + PrintAndLogEx(INFO, "--------------------------- " _CYAN_("card") " ---------------------------"); + PrintAndLogEx(SUCCESS, " CSN: " _GREEN_("%s") " uid", sprint_hex(hdr->csn, sizeof(hdr->csn))); + PrintAndLogEx(SUCCESS, " Config: %s Card configuration", sprint_hex((uint8_t *)&hdr->conf, sizeof(hdr->conf))); + PrintAndLogEx(SUCCESS, "E-purse: %s Card challenge, CC", sprint_hex(hdr->epurse, sizeof(hdr->epurse))); + PrintAndLogEx(SUCCESS, " Kd: %s Debit key, hidden", sprint_hex(hdr->key_d, sizeof(hdr->key_d))); + PrintAndLogEx(SUCCESS, " Kc: %s Credit key, hidden", sprint_hex(hdr->key_c, sizeof(hdr->key_c))); + PrintAndLogEx(SUCCESS, " AIA: %s Application Issuer area", sprint_hex(hdr->app_issuer_area, sizeof(hdr->app_issuer_area))); } 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) { @@ -849,6 +803,8 @@ static int CmdHFiClassSim(const char *Cmd) { case ICLASS_SIM_MODE_CSN_DEFAULT: case ICLASS_SIM_MODE_FULL: default: { + PrintAndLogEx(INFO, "Starting iCLASS simulation"); + PrintAndLogEx(INFO, "press " _YELLOW_("`enter`") " to cancel"); uint8_t numberOfCSNs = 0; clearCommandBuffer(); SendCommandMIX(CMD_HF_ICLASS_SIMULATE, sim_type, numberOfCSNs, 1, CSN, 8); @@ -906,136 +862,25 @@ int read_iclass_csn(bool loop, bool verbose) { } static int CmdHFiClassReader(const char *Cmd) { - char cmdp = tolower(param_getchar(Cmd, 0)); - if (cmdp == 'h') return usage_hf_iclass_reader(); - bool loop_read = (cmdp == '1') ? false : true; - return read_iclass_csn(loop_read, true); -} + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf iclass reader", + "Act as a iCLASS reader. Look for iCLASS tags until Enter or the pm3 button is pressed\n", + "hf iclass reader\n" + "hf iclass reader -1"); -static int CmdHFiClassReader_Replay(const char *Cmd) { + void *argtable[] = { + arg_param_begin, + arg_lit0("1", "one", "read once"), + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + bool read_once = arg_get_lit(ctx, 1); + CLIParserFree(ctx); - struct { - uint8_t reader[4]; - uint8_t mac[4]; - } PACKED payload; - - - bool got_rnr, got_mac; - got_rnr = got_mac = false; - bool errors = false; - uint8_t cmdp = 0; - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': { - return usage_hf_iclass_replay(); - } - case 'r': { - if (param_gethex(Cmd, cmdp + 1, payload.reader, 8)) { - PrintAndLogEx(FAILED, "Reader Nr must include 8 HEX symbols"); - errors = true; - } else { - got_rnr = true; - } - cmdp += 2; - break; - } - case 'm': { - if (param_gethex(Cmd, cmdp + 1, payload.mac, 8)) { - PrintAndLogEx(FAILED, "Reader MAC must include 8 HEX symbols"); - errors = true; - } else { - got_mac = true; - } - cmdp += 2; - break; - } - default: { - PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } - } - - //Validations - if (errors || cmdp == 0) { - return usage_hf_iclass_replay(); - } - - if (got_rnr == false || got_mac == false) { - PrintAndLogEx(FAILED, "Reader Nr and MAC is needed"); - return PM3_EINVARG; - } - - PacketResponseNG resp; - clearCommandBuffer(); - SendCommandNG(CMD_HF_ICLASS_REPLAY, (uint8_t *)&payload, sizeof(payload)); - - while (true) { - PrintAndLogEx(NORMAL, "." NOLF); - - if (kbd_enter_pressed()) { - PrintAndLogEx(WARNING, "\naborted via keyboard!\n"); - DropField(); - return PM3_EOPABORTED; - } - - if (WaitForResponseTimeout(CMD_HF_ICLASS_REPLAY, &resp, 2000)) - break; - } - - PrintAndLogEx(NORMAL, ""); - if (resp.status != PM3_SUCCESS) { - PrintAndLogEx(ERR, "failed to communicate with card"); - return resp.status; - } - - struct p_resp { - bool isOK; - uint16_t block_cnt; - uint32_t bb_offset; - } PACKED; - struct p_resp *packet = (struct p_resp *)resp.data.asBytes; - - if (packet->isOK == false) { - PrintAndLogEx(WARNING, "replay reading blocks failed"); - return PM3_ESOFT; - } - - uint32_t startindex = packet->bb_offset; - uint32_t bytes_got = (packet->block_cnt * 8); - - uint8_t tag_data[0x100 * 8]; - memset(tag_data, 0xFF, sizeof(tag_data)); - - // response ok - now get bigbuf content of the dump - if (!GetFromDevice(BIG_BUF, tag_data, sizeof(tag_data), startindex, NULL, 0, NULL, 2500, false)) { - PrintAndLogEx(WARNING, "command execution time out"); - return PM3_ETIMEOUT; - } - - // print the dump - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "------+----+-------------------------+----------"); - PrintAndLogEx(INFO, " CSN |0x00| " _GREEN_("%s") "|", sprint_hex(tag_data, 8)); - printIclassDumpContents(tag_data, 1, (bytes_got / 8), bytes_got); - - // use CSN as filename - char filename[FILE_PATH_SIZE] = {0}; - strcat(filename, "hf-iclass-"); - FillFileNameByUID(filename, tag_data, "-dump", 8); - - // save the dump to .bin file - PrintAndLogEx(SUCCESS, "saving dump file - %u blocks read", bytes_got / 8); - saveFile(filename, ".bin", tag_data, bytes_got); - saveFileEML(filename, tag_data, bytes_got, 8); - saveFileJSON(filename, jsfIclass, tag_data, bytes_got, NULL); - - PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass decrypt") "` to decrypt dump file"); - PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass view") "` to view dump file"); - PrintAndLogEx(NORMAL, ""); - return PM3_SUCCESS; + PrintAndLogEx(INFO, "Starting iCLASS reader mode"); + PrintAndLogEx(INFO, "press " _YELLOW_("`enter`") " to cancel"); + return read_iclass_csn(!read_once, true); } static int CmdHFiClassELoad(const char *Cmd) { @@ -1274,27 +1119,11 @@ static int CmdHFiClassEView(const char *Cmd) { } PrintAndLogEx(NORMAL, ""); - uint8_t *csn = dump; - PrintAndLogEx(INFO, "------+----+-------------------------+----------"); - PrintAndLogEx(INFO, " CSN |0x00| " _GREEN_("%s") "|", sprint_hex(csn, 8)); printIclassDumpContents(dump, 1, blocks, bytes); - - /* - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "----+-------------------------+---------"); - PrintAndLogEx(INFO, "blk | data | ascii"); - PrintAndLogEx(INFO, "----+-------------------------+---------"); - for (uint16_t i = 0; i < blocks; i++){ - PrintAndLogEx(INFO, "%03d | %s ", i, sprint_hex_ascii(dump + (i * 8) , 8) ); - } - PrintAndLogEx(INFO, "----+-------------------------+---------"); - PrintAndLogEx(NORMAL, ""); - */ free(dump); return PM3_SUCCESS; } - static int CmdHFiClassDecrypt(const char *Cmd) { bool errors = false; @@ -1444,7 +1273,6 @@ static int CmdHFiClassDecrypt(const char *Cmd) { saveFileEML(fptr, decrypted, decryptedlen, 8); saveFileJSON(fptr, jsfIclass, decrypted, decryptedlen, NULL); - PrintAndLogEx(INFO, "Following output skips CSN / block0"); printIclassDumpContents(decrypted, 1, (decryptedlen / 8), decryptedlen); PrintAndLogEx(NORMAL, ""); @@ -1590,13 +1418,6 @@ static int CmdHFiClassEncryptBlk(const char *Cmd) { return PM3_SUCCESS; } -static void calc_wb_mac(uint8_t blockno, uint8_t *data, uint8_t *div_key, uint8_t *MAC) { - uint8_t wb[9]; - wb[0] = blockno; - memcpy(wb + 1, data, 8); - doMAC_N(wb, sizeof(wb), div_key, MAC); -} - static bool select_only(uint8_t *CSN, uint8_t *CCNR, bool verbose) { uint8_t flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE); @@ -1634,47 +1455,6 @@ static bool select_only(uint8_t *CSN, uint8_t *CCNR, bool verbose) { return true; } -static bool select_and_auth(uint8_t *KEY, uint8_t *MAC, uint8_t *div_key, bool use_credit_key, bool elite, bool rawkey, bool verbose) { - - iclass_auth_req_t payload = { - .use_raw = rawkey, - .use_elite = elite, - .use_credit_key = use_credit_key - }; - memcpy(payload.key, KEY, 8); - - SendCommandNG(CMD_HF_ICLASS_AUTH, (uint8_t *)&payload, sizeof(payload)); - PacketResponseNG resp; - clearCommandBuffer(); - if (WaitForResponseTimeout(CMD_HF_ICLASS_AUTH, &resp, 2000) == 0) { - if (verbose) PrintAndLogEx(WARNING, "Command execute timeout"); - return false; - } - - if (resp.status != PM3_SUCCESS) { - if (verbose) PrintAndLogEx(ERR, "failed to communicate with card"); - return false; - } - - iclass_readblock_resp_t *packet = (iclass_readblock_resp_t *)resp.data.asBytes; - - if (packet->isOK == 0) { - if (verbose) PrintAndLogEx(FAILED, "authentication error"); - return false; - } - - if (div_key) - memcpy(div_key, packet->div_key, sizeof(packet->div_key)); - - if (MAC) - memcpy(MAC, packet->mac, sizeof(packet->mac)); - - if (verbose) - PrintAndLogEx(SUCCESS, "authing with %s: %s", rawkey ? "raw key" : "diversified key", sprint_hex(div_key, 8)); - - return true; -} - static int CmdHFiClassDump(const char *Cmd) { uint8_t KEY[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; @@ -1688,6 +1468,7 @@ static int CmdHFiClassDump(const char *Cmd) { bool have_credit_key = false; bool elite = false; bool rawkey = false; + bool use_replay = false; bool errors = false; bool auth = false; uint8_t cmdp = 0; @@ -1755,12 +1536,23 @@ static int CmdHFiClassDump(const char *Cmd) { rawkey = true; cmdp++; break; + case 'n': + PrintAndLogEx(SUCCESS, "Using " _YELLOW_("replay NR/MAC mode")); + use_replay = true; + cmdp++; + break; default: PrintAndLogEx(WARNING, "Unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); errors = true; break; } } + + if ((use_replay + rawkey + elite) > 1) { + PrintAndLogEx(FAILED, "Can not use a combo of 'e', 'r', 'n'"); + errors = true; + } + if (errors) return usage_hf_iclass_dump(); uint32_t flags = (FLAG_ICLASS_READER_INIT | FLAG_ICLASS_READER_CLEARTRACE); @@ -1831,6 +1623,7 @@ static int CmdHFiClassDump(const char *Cmd) { .req.use_raw = rawkey, .req.use_elite = elite, .req.use_credit_key = false, + .req.use_replay = use_replay, .req.send_reply = true, .req.do_auth = auth, .end_block = app_limit1, @@ -1974,9 +1767,6 @@ write_dump: PrintAndLogEx(INFO, "Reading AA2 failed. dumping AA1 data to file"); // print the dump - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "------+----+-------------------------+----------"); - PrintAndLogEx(INFO, " CSN |0x00| " _GREEN_("%s") "|", sprint_hex(tag_data, 8)); printIclassDumpContents(tag_data, 1, (bytes_got / 8), bytes_got); // use CSN as filename @@ -1997,49 +1787,13 @@ write_dump: return PM3_SUCCESS; } -static int iclass_write_block(uint8_t blockno, uint8_t *bldata, uint8_t *KEY, bool use_credit_key, bool elite, bool rawkey, bool verbose) { - /* - uint8_t MAC[4] = {0x00, 0x00, 0x00, 0x00}; - uint8_t div_key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - if (select_and_auth(KEY, MAC, div_key, use_credit_key, elite, rawkey, verbose) == false) { - return PM3_ESOFT; - } +static int iclass_write_block(uint8_t blockno, uint8_t *bldata, uint8_t *KEY, bool use_credit_key, bool elite, bool rawkey, bool replay, bool verbose) { - calc_wb_mac(blockno, bldata, div_key, MAC); - - struct p { - uint8_t blockno; - uint8_t data[12]; - } PACKED payload; - payload.blockno = blockno; - - memcpy(payload.data, bldata, 8); - memcpy(payload.data + 8, MAC, 4); - - - // - typedef struct { - uint8_t key[8]; - bool use_raw; - bool use_elite; - bool use_credit_key; - bool send_reply; - bool do_auth; - uint8_t blockno; - } PACKED iclass_auth_req_t; - - // iCLASS write block request data structure - typedef struct { - iclass_auth_req_t req; - uint8_t data[8]; - } PACKED iclass_writeblock_req_t; - - - */ iclass_writeblock_req_t payload = { .req.use_raw = rawkey, .req.use_elite = elite, .req.use_credit_key = use_credit_key, + .req.use_replay = replay, .req.blockno = blockno, .req.send_reply = true, .req.do_auth = true, @@ -2058,9 +1812,8 @@ static int iclass_write_block(uint8_t blockno, uint8_t *bldata, uint8_t *KEY, bo if (resp.status != PM3_SUCCESS) { if (verbose) PrintAndLogEx(ERR, "failed to communicate with card"); - return PM3_EWRONGANSWER; + return resp.status; } - return (resp.data.asBytes[0] == 1) ? PM3_SUCCESS : PM3_ESOFT; } @@ -2075,6 +1828,7 @@ static int CmdHFiClass_WriteBlock(const char *Cmd) { bool use_credit_key = false; bool elite = false; bool rawkey = false; + bool use_replay = false; bool errors = false; bool verbose = false; uint8_t cmdp = 0; @@ -2128,6 +1882,13 @@ static int CmdHFiClass_WriteBlock(const char *Cmd) { rawkey = true; cmdp++; break; + /* + case 'n': + PrintAndLogEx(SUCCESS, "Using " _YELLOW_("replay NR/MAC mode")); + use_replay = true; + cmdp++; + break; + */ case 'v': verbose = true; cmdp++; @@ -2141,21 +1902,29 @@ static int CmdHFiClass_WriteBlock(const char *Cmd) { if (got_blockno == false) errors = true; + if ((use_replay + rawkey + elite) > 1) { + PrintAndLogEx(FAILED, "Can not use a combo of 'e', 'r', 'n'"); + errors = true; + } + if (errors || cmdp < 6) return usage_hf_iclass_writeblock(); - int isok = iclass_write_block(blockno, bldata, KEY, use_credit_key, elite, rawkey, verbose); - if (isok == PM3_SUCCESS) - PrintAndLogEx(SUCCESS, "Wrote block %02X successful", blockno); - else - PrintAndLogEx(FAILED, "Writing failed"); + int isok = iclass_write_block(blockno, bldata, KEY, use_credit_key, elite, rawkey, use_replay, verbose); + switch (isok) { + case PM3_SUCCESS: + PrintAndLogEx(SUCCESS, "Wrote block %02X successful", blockno); + break; + case PM3_ETEAROFF: + if (verbose) + PrintAndLogEx(INFO, "Writing tear off triggered"); + break; + default: + PrintAndLogEx(FAILED, "Writing failed"); + break; + } return isok; } -/* -static int CmdHFiClassClone(const char *Cmd) { - return PM3_SUCCESS; -} -*/ static int CmdHFiClassRestore(const char *Cmd) { char filename[FILE_PATH_SIZE] = { 0x00 }; char tempStr[50] = {0}; @@ -2207,7 +1976,7 @@ static int CmdHFiClassRestore(const char *Cmd) { } else if (dataLen == 1) { keyNbr = param_get8(Cmd, cmdp + 1); if (keyNbr < ICLASS_KEYS_MAX) { - PrintAndLogEx(SUCCESS, "Using key[%d] %s", keyNbr, sprint_hex(iClass_Key_Table[keyNbr], 8)); + PrintAndLogEx(SUCCESS, "Using key[%d] " _GREEN_("%s"), keyNbr, sprint_hex(iClass_Key_Table[keyNbr], 8)); memcpy(KEY, iClass_Key_Table[keyNbr], 8); } else { PrintAndLogEx(WARNING, "\nERROR: Credit KeyNbr is invalid\n"); @@ -2244,14 +2013,19 @@ static int CmdHFiClassRestore(const char *Cmd) { if (errors || cmdp < 8) return usage_hf_iclass_restore(); + if (rawkey + elite > 1) { + PrintAndLogEx(FAILED, "Can not use both 'e', 'r'"); + return PM3_EINVARG; + } + if (startblock < 5) { PrintAndLogEx(WARNING, "you cannot write key blocks this way. yet... make your start block > 4"); return PM3_EINVARG; } - int total_bytes = (((endblock - startblock) + 1) * 12); + uint32_t payload_size = sizeof(iclass_restore_req_t) + (sizeof(iclass_restore_item_t) * (endblock - startblock + 1)); - if (total_bytes > PM3_CMD_DATA_SIZE - 2) { + if (payload_size > PM3_CMD_DATA_SIZE) { PrintAndLogEx(NORMAL, "Trying to write too many blocks at once. Max: %d", PM3_CMD_DATA_SIZE / 8); return PM3_EINVARG; } @@ -2269,103 +2043,82 @@ static int CmdHFiClassRestore(const char *Cmd) { return PM3_EFILE; } - if (bytes_read < sizeof(iclass_block_t) * (endblock - startblock + 1)) { - PrintAndLogEx(ERR, "file wrong size"); + if (bytes_read < ((endblock - startblock + 1) * 8)) { + PrintAndLogEx(ERR, "file is smaller than your suggested block range ( " _RED_("0x%02x..0x%02x")" )", + startblock, endblock + ); free(dump); return PM3_EFILE; } + iclass_restore_req_t *payload = calloc(1, payload_size); + payload->req.use_raw = rawkey; + payload->req.use_elite = elite; + payload->req.use_credit_key = use_credit_key; + payload->req.use_replay = false; + payload->req.blockno = startblock; + payload->req.send_reply = true; + payload->req.do_auth = true; + memcpy(payload->req.key, KEY, 8); + + payload->item_cnt = (endblock - startblock + 1); + // read data from file from block 6 --- 19 // we will use this struct [data 8 bytes][MAC 4 bytes] for each block calculate all mac number for each data // then copy to usbcommand->asbytes; // max is 32 - 6 = 28 block. 28 x 12 bytes gives 336 bytes - iclass_block_t tag_data[PM3_CMD_DATA_SIZE / 12]; - memcpy(tag_data, dump + startblock * 8, sizeof(iclass_block_t) * (endblock - startblock + 1)); + for (uint8_t i = 0; i < payload->item_cnt; i++) { + payload->blocks[i].blockno = startblock + i; + memcpy(payload->blocks[i].data, dump + (startblock * 8) + (i * 8), sizeof(payload->blocks[i].data)); + } free(dump); - uint8_t MAC[4] = {0x00, 0x00, 0x00, 0x00}; - uint8_t div_key[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - - int i; - int numberAuthRetries = ICLASS_AUTH_RETRY; - do { - if (select_and_auth(KEY, MAC, div_key, use_credit_key, elite, rawkey, verbose)) - break; - } while (numberAuthRetries--); - - if (numberAuthRetries <= 0) { - PrintAndLogEx(ERR, "failed to authenticate"); - DropField(); - return PM3_ESOFT; - } - - uint8_t data[total_bytes]; - - // calculate all mac for every the block we will write - for (i = startblock; i <= endblock; i++) { - - calc_wb_mac(i, tag_data[i - startblock].d, div_key, MAC); - // usb command d start pointer = d + (i - 6) * 12 - // memcpy(pointer,tag_data[i - 6],8) 8 bytes - // memcpy(pointer + 8,mac,sizoof(mac) 4 bytes; - // next one - uint8_t *ptr = data + (i - startblock) * 12; - memcpy(ptr, &(tag_data[i - startblock].d[0]), 8); - memcpy(ptr + 8, MAC, 4); - } - if (verbose) { - PrintAndLogEx(INFO, "------+--------------------------+-------------"); - PrintAndLogEx(INFO, "block | data | mac"); - PrintAndLogEx(INFO, "------+--------------------------+-------------"); - uint8_t p[12]; - for (i = 0; i <= endblock - startblock; i++) { - memcpy(p, data + (i * 12), 12); - char *s = calloc(70, sizeof(uint8_t)); - snprintf(s, 70, "| %s ", sprint_hex(p, 8)); - snprintf(s + strlen(s), 70 - strlen(s), "| %s", sprint_hex(p + 8, 4)); - PrintAndLogEx(NORMAL, " %02X %s", i + startblock, s); - free(s); + PrintAndLogEx(INFO, "Preparing to restore block range 0x%02x..0x%02x", startblock, endblock); + + PrintAndLogEx(INFO, "------+----------------------"); + PrintAndLogEx(INFO, "block | data"); + PrintAndLogEx(INFO, "------+----------------------"); + + for (uint8_t i = 0; i < payload->item_cnt; i++) { + iclass_restore_item_t item = payload->blocks[i]; + PrintAndLogEx(INFO, " %02X | %s", item.blockno, sprint_hex_inrow(item.data, sizeof(item.data))); } } - struct p { - uint8_t startblock; - uint8_t endblock; - uint8_t data[PM3_CMD_DATA_SIZE - 2]; - } PACKED payload; - - payload.startblock = startblock; - payload.endblock = endblock; - memcpy(payload.data, data, total_bytes); + PrintAndLogEx(INFO, "restore started..."); PacketResponseNG resp; clearCommandBuffer(); - SendCommandNG(CMD_HF_ICLASS_CLONE, (uint8_t *)&payload, total_bytes + 2); + SendCommandNG(CMD_HF_ICLASS_RESTORE, (uint8_t *)payload, payload_size); - if (WaitForResponseTimeout(CMD_HF_ICLASS_CLONE, &resp, 2000) == 0) { + if (WaitForResponseTimeout(CMD_HF_ICLASS_RESTORE, &resp, 2500) == 0) { PrintAndLogEx(WARNING, "command execute timeout"); DropField(); + free(payload); return PM3_ETIMEOUT; } if (resp.status == PM3_SUCCESS) { - if (resp.data.asBytes[0] == 1) - PrintAndLogEx(SUCCESS, "Restore successful"); - else - PrintAndLogEx(WARNING, "Restore failed"); + PrintAndLogEx(SUCCESS, "iCLASS restore " _GREEN_("successful")); + PrintAndLogEx(HINT, "Try `" _YELLOW_("hf iclass rdbl ") "` to verify data on card"); + } else { + PrintAndLogEx(WARNING, "iCLASS restore " _RED_("failed")); } + + free(payload); return resp.status; } -static int iclass_read_block(uint8_t *KEY, uint8_t blockno, uint8_t keyType, bool elite, bool rawkey, bool verbose, bool auth, uint8_t *out) { +static int iclass_read_block(uint8_t *KEY, uint8_t blockno, uint8_t keyType, bool elite, bool rawkey, bool replay, bool verbose, bool auth, uint8_t *out) { iclass_auth_req_t payload = { .use_raw = rawkey, .use_elite = elite, .use_credit_key = (keyType == 0x18), + .use_replay = replay, .blockno = blockno, .send_reply = true, .do_auth = auth, @@ -2414,6 +2167,7 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) { bool got_blockno = false; bool elite = false; bool rawkey = false; + bool use_replay = false; bool errors = false; bool auth = false; bool verbose = false; @@ -2462,6 +2216,11 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) { rawkey = true; cmdp++; break; + case 'n': + PrintAndLogEx(SUCCESS, "Using " _YELLOW_("replay NR/MAC mode")); + use_replay = true; + cmdp++; + break; case 'v': verbose = true; cmdp++; @@ -2475,6 +2234,11 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) { if (got_blockno == false) errors = true; + if ((use_replay + rawkey + elite) > 1) { + PrintAndLogEx(FAILED, "Can not use a combo of 'e', 'r', 'n'"); + errors = true; + } + if (errors) return usage_hf_iclass_readblock(); if (verbose) { @@ -2490,7 +2254,7 @@ static int CmdHFiClass_ReadBlock(const char *Cmd) { } uint8_t data[8] = {0}; - int res = iclass_read_block(KEY, blockno, keyType, elite, rawkey, verbose, auth, data); + int res = iclass_read_block(KEY, blockno, keyType, elite, rawkey, use_replay, verbose, auth, data); if (res != PM3_SUCCESS) return res; @@ -2631,9 +2395,20 @@ void printIclassDumpContents(uint8_t *iclass_dump, uint8_t startblock, uint8_t e , filemaxblock ); */ + uint8_t pagemap = get_pagemap(hdr); + + int i = startblock; - PrintAndLogEx(INFO, "------+----+-------------------------+----------"); + + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, " blk| data | ascii |lck| info"); + PrintAndLogEx(INFO, "----+-------------------------+----------+---+--------------"); + PrintAndLogEx(INFO, "0x00| " _GREEN_("%s") " | | CSN ", sprint_hex_ascii(iclass_dump, 8)); + + if (i != 1) + PrintAndLogEx(INFO, "...."); + while (i <= endblock) { uint8_t *blk = iclass_dump + (i * 8); @@ -2673,50 +2448,56 @@ void printIclassDumpContents(uint8_t *iclass_dump, uint8_t startblock, uint8_t e bl_lock = true; } - PrintAndLogEx(INFO, " %c |0x%02X| %s", (bl_lock) ? 'x' : ' ', i, sprint_hex_ascii(blk, 8)); + const char *lockstr = (bl_lock) ? _RED_("x") : " "; + + if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) { + const char *info_nonks[] = {"CSN", "Config", "AIA", "User"}; + const char *s = info_nonks[3]; + if (i < 3) { + s = info_nonks[i]; + } + + PrintAndLogEx(INFO, "0x%02X| %s | %s | %s ", i, sprint_hex_ascii(blk, 8), lockstr, s); + } else { + const char *info_ks[] = {"CSN", "Config", "E-purse", "Debit", "Credit", "AIA", "User"}; + const char *s = info_ks[6]; + if (i < 6) { + s = info_ks[i]; + } + PrintAndLogEx(INFO, "0x%02X| %s | %s | %s ", i, sprint_hex_ascii(blk, 8), lockstr, s); + } i++; } - PrintAndLogEx(INFO, "------+----+-------------------------+----------"); + PrintAndLogEx(INFO, "----+-------------------------+----------+---+--------------"); + PrintAndLogEx(NORMAL, ""); } 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; @@ -2732,13 +2513,9 @@ static int CmdHFiClassView(const char *Cmd) { PrintAndLogEx(INFO, "start " _YELLOW_("0x%02x") " end " _YELLOW_("0x%02x"), (startblock == 0) ? 6 : startblock, endblock); } + PrintAndLogEx(NORMAL, ""); print_picopass_header((picopass_hdr *) dump); print_picopass_info((picopass_hdr *) dump); - - PrintAndLogEx(NORMAL, ""); - uint8_t *csn = dump; - PrintAndLogEx(INFO, "------+----+-------------------------+----------"); - PrintAndLogEx(INFO, " CSN |0x00| " _GREEN_("%s") "|", sprint_hex(csn, 8)); printIclassDumpContents(dump, startblock, endblock, bytes_read); free(dump); return PM3_SUCCESS; @@ -2914,12 +2691,15 @@ static int saveKeys(char *filename) { static int printKeys(void) { PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "idx| key"); + PrintAndLogEx(INFO, "---+------------------------"); for (uint8_t i = 0; i < ICLASS_KEYS_MAX; i++) { if (memcmp(iClass_Key_Table[i], "\x00\x00\x00\x00\x00\x00\x00\x00", 8) == 0) - PrintAndLogEx(INFO, "%u: %s", i, sprint_hex(iClass_Key_Table[i], 8)); + PrintAndLogEx(INFO, " %u |", i); else - PrintAndLogEx(INFO, "%u: "_YELLOW_("%s"), i, sprint_hex(iClass_Key_Table[i], 8)); + PrintAndLogEx(INFO, " %u | " _YELLOW_("%s"), i, sprint_hex(iClass_Key_Table[i], 8)); } + PrintAndLogEx(INFO, "---+------------------------"); PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } @@ -3037,105 +2817,15 @@ static void add_key(uint8_t *key) { } } -static int CmdHFiClassCheckKeys(const char *Cmd) { - // empty string - if (strlen(Cmd) == 0) return usage_hf_iclass_chk(); - - uint8_t CSN[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - uint8_t CCNR[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; - - // elite key, raw key, standard key - bool use_elite = false; - bool use_raw = false; - bool use_credit_key = false; - bool found_key = false; - //bool found_credit = false; - bool got_csn = false; - bool errors = false; - uint8_t cmdp = 0x00; - - char filename[FILE_PATH_SIZE] = {0}; - uint8_t fileNameLen = 0; - - uint64_t t1 = msclock(); - - while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { - switch (tolower(param_getchar(Cmd, cmdp))) { - case 'h': - return usage_hf_iclass_chk(); - case 'f': - fileNameLen = param_getstr(Cmd, cmdp + 1, filename, sizeof(filename)); - if (fileNameLen < 1) { - PrintAndLogEx(WARNING, _RED_("no filename found after f")); - errors = true; - } - cmdp += 2; - break; - case 'e': - use_elite = true; - cmdp++; - break; - case 'c': - use_credit_key = true; - cmdp++; - break; - case 'r': - use_raw = true; - cmdp++; - break; - default: - PrintAndLogEx(WARNING, "unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); - errors = true; - break; - } - } - if (errors) return usage_hf_iclass_chk(); - - uint8_t *keyBlock = NULL; - uint32_t keycount = 0; - - // load keys - int res = loadFileDICTIONARY_safe(filename, (void **)&keyBlock, 8, &keycount); - if (res != PM3_SUCCESS || keycount == 0) { - free(keyBlock); - return res; - } +/* +static int iclass_chk_keys(uint8_t *keyBlock, uint32_t keycount) { iclass_premac_t *pre = calloc(keycount, sizeof(iclass_premac_t)); - if (!pre) { - free(keyBlock); + if (pre == NULL) { return PM3_EMALLOC; } - // Get CSN / UID and CCNR - PrintAndLogEx(SUCCESS, "Reading tag CSN / CCNR..."); - for (uint8_t i = 0; i < ICLASS_AUTH_RETRY && !got_csn; i++) { - got_csn = select_only(CSN, CCNR, false); - if (got_csn == false) - PrintAndLogEx(WARNING, "one more try"); - } - - if (got_csn == false) { - PrintAndLogEx(WARNING, "Tried 10 times. Can't select card, aborting..."); - free(keyBlock); - DropField(); - return PM3_ESOFT; - } - - PrintAndLogEx(SUCCESS, " CSN: " _GREEN_("%s"), sprint_hex(CSN, sizeof(CSN))); - PrintAndLogEx(SUCCESS, " CCNR: " _GREEN_("%s"), sprint_hex(CCNR, sizeof(CCNR))); - - PrintAndLogEx(SUCCESS, "Generating diversified keys %s", (use_elite || use_raw) ? NOLF : ""); - if (use_elite) - PrintAndLogEx(NORMAL, "using " _YELLOW_("elite algo")); - if (use_raw) - PrintAndLogEx(NORMAL, "using " _YELLOW_("raw mode")); - - GenerateMacFrom(CSN, CCNR, use_raw, use_elite, keyBlock, keycount, pre); - - PrintAndLogEx(SUCCESS, "Searching for " _YELLOW_("%s") " key...", (use_credit_key) ? "CREDIT" : "DEBIT"); - // max 42 keys inside USB_COMMAND. 512/4 = 103 mac uint32_t chunksize = keycount > (PM3_CMD_DATA_SIZE / 4) ? (PM3_CMD_DATA_SIZE / 4) : keycount; bool lastChunk = false; @@ -3219,7 +2909,195 @@ static int CmdHFiClassCheckKeys(const char *Cmd) { break; } - } // end chunks of keys + } + return PM3_SUCCESS; +} +*/ + +static int CmdHFiClassCheckKeys(const char *Cmd) { + + // empty string + if (strlen(Cmd) == 0) return usage_hf_iclass_chk(); + + uint8_t CSN[8] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + uint8_t CCNR[12] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + + // elite key, raw key, standard key + bool use_elite = false; + bool use_raw = false; + bool use_credit_key = false; + bool found_key = false; + //bool found_credit = false; + bool got_csn = false; + bool errors = false; + uint8_t cmdp = 0x00; + + char filename[FILE_PATH_SIZE] = {0}; + uint8_t fileNameLen = 0; + + uint64_t t1 = msclock(); + + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h': + return usage_hf_iclass_chk(); + case 'f': + fileNameLen = param_getstr(Cmd, cmdp + 1, filename, sizeof(filename)); + if (fileNameLen < 1) { + PrintAndLogEx(WARNING, _RED_("no filename found after f")); + errors = true; + } + cmdp += 2; + break; + case 'e': + use_elite = true; + cmdp++; + break; + case 'c': + use_credit_key = true; + cmdp++; + break; + case 'r': + use_raw = true; + cmdp++; + break; + default: + PrintAndLogEx(WARNING, "unknown parameter '%c'\n", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + if (errors) return usage_hf_iclass_chk(); + + uint8_t *keyBlock = NULL; + uint32_t keycount = 0; + + // load keys + int res = loadFileDICTIONARY_safe(filename, (void **)&keyBlock, 8, &keycount); + if (res != PM3_SUCCESS || keycount == 0) { + free(keyBlock); + return res; + } + + // Get CSN / UID and CCNR + PrintAndLogEx(SUCCESS, "Reading tag CSN / CCNR..."); + for (uint8_t i = 0; i < ICLASS_AUTH_RETRY && !got_csn; i++) { + got_csn = select_only(CSN, CCNR, false); + if (got_csn == false) + PrintAndLogEx(WARNING, "one more try"); + } + + if (got_csn == false) { + PrintAndLogEx(WARNING, "Tried 10 times. Can't select card, aborting..."); + free(keyBlock); + DropField(); + return PM3_ESOFT; + } + + iclass_premac_t *pre = calloc(keycount, sizeof(iclass_premac_t)); + if (pre == NULL) { + return PM3_EMALLOC; + } + + + PrintAndLogEx(SUCCESS, " CSN: " _GREEN_("%s"), sprint_hex(CSN, sizeof(CSN))); + PrintAndLogEx(SUCCESS, " CCNR: " _GREEN_("%s"), sprint_hex(CCNR, sizeof(CCNR))); + + PrintAndLogEx(SUCCESS, "Generating diversified keys %s", (use_elite || use_raw) ? NOLF : ""); + if (use_elite) + PrintAndLogEx(NORMAL, "using " _YELLOW_("elite algo")); + if (use_raw) + PrintAndLogEx(NORMAL, "using " _YELLOW_("raw mode")); + + GenerateMacFrom(CSN, CCNR, use_raw, use_elite, keyBlock, keycount, pre); + + PrintAndLogEx(SUCCESS, "Searching for " _YELLOW_("%s") " key...", (use_credit_key) ? "CREDIT" : "DEBIT"); + + + // max 42 keys inside USB_COMMAND. 512/4 = 103 mac + uint32_t chunksize = keycount > (PM3_CMD_DATA_SIZE / 4) ? (PM3_CMD_DATA_SIZE / 4) : keycount; + bool lastChunk = false; + + // fast push mode + conn.block_after_ACK = true; + + // keep track of position of found key + uint8_t found_offset = 0; + uint32_t key_offset = 0; + // main keychunk loop + for (key_offset = 0; key_offset < keycount; key_offset += chunksize) { + + uint64_t t2 = msclock(); + uint8_t timeout = 0; + + if (kbd_enter_pressed()) { + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(WARNING, "Aborted via keyboard!"); + goto out; + } + + uint32_t keys = ((keycount - key_offset) > chunksize) ? chunksize : keycount - key_offset; + + // last chunk? + if (keys == keycount - key_offset) { + lastChunk = true; + // Disable fast mode on last command + conn.block_after_ACK = false; + } + uint32_t flags = lastChunk << 8; + // bit 16 + // - 1 indicates credit key + // - 0 indicates debit key (default) + flags |= (use_credit_key << 16); + + clearCommandBuffer(); + SendCommandOLD(CMD_HF_ICLASS_CHKKEYS, flags, keys, 0, pre + key_offset, 4 * keys); + PacketResponseNG resp; + + bool looped = false; + while (!WaitForResponseTimeout(CMD_HF_ICLASS_CHKKEYS, &resp, 2000)) { + timeout++; + PrintAndLogEx(NORMAL, "." NOLF); + if (timeout > 120) { + PrintAndLogEx(WARNING, "\nNo response from Proxmark3. Aborting..."); + goto out; + } + looped = true; + } + + if (looped) + PrintAndLogEx(NORMAL, ""); + + found_offset = resp.oldarg[1] & 0xFF; + uint8_t isOK = resp.oldarg[0] & 0xFF; + + t2 = msclock() - t2; + switch (isOK) { + case 1: { + found_key = true; + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(SUCCESS, "Found valid key " _GREEN_("%s") + , sprint_hex(keyBlock + (key_offset + found_offset) * 8, 8) + ); + break; + } + case 0: { + PrintAndLogEx(INPLACE, "Chunk [%d/%d]", key_offset, keycount); + break; + } + case 99: { + } + default: { + break; + } + } + + // both keys found. + if (found_key) { + break; + } + + } out: t1 = msclock() - t1; @@ -3520,19 +3398,27 @@ static int CmdHFiClassPermuteKey(const char *Cmd) { uint8_t key[8] = {0}; 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; + bool isReverse = arg_get_lit(ctx, 1); + + CLIGetHexWithReturn(ctx, 2, data, &len); + + CLIParserFree(ctx); memcpy(key, data, 8); @@ -3550,6 +3436,28 @@ static int CmdHFiClassPermuteKey(const char *Cmd) { return PM3_SUCCESS; } +static int CmdHFiClassAutopwn(const char *Cmd) { + + CLIParserContext *ctx; + CLIParserInit(&ctx, "hf iclass autopwn", + "Tries to check keys, if found, dump card and save file", + "hf iclass autopwn\n"); + + void *argtable[] = { + arg_param_begin, + arg_param_end + }; + CLIExecWithReturn(ctx, Cmd, argtable, true); + CLIParserFree(ctx); + + // Check keys. + + // dump + + PrintAndLogEx(INFO, "to be implemented"); + return PM3_SUCCESS; +} + static command_t CommandTable[] = { {"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("operations") " ---------------------"}, {"help", CmdHelp, AlwaysAvailable, "This help"}, @@ -3564,11 +3472,10 @@ static command_t CommandTable[] = { {"wrbl", CmdHFiClass_WriteBlock, IfPm3Iclass, "[options..] Write Picopass / iCLASS block"}, {"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("recovery") " ---------------------"}, - {"chk", CmdHFiClassCheckKeys, AlwaysAvailable, "[options..] Check keys"}, + {"autopwn", CmdHFiClassAutopwn, IfPm3Iclass, "[options..] Automatic key recovery tool for iCLASS"}, + {"chk", CmdHFiClassCheckKeys, IfPm3Iclass, "[options..] Check keys"}, {"loclass", CmdHFiClass_loclass, AlwaysAvailable, "[options..] Use loclass to perform bruteforce reader attack"}, {"lookup", CmdHFiClassLookUp, AlwaysAvailable, "[options..] Uses authentication trace to check for key in dictionary file"}, - {"replay", CmdHFiClassReader_Replay, IfPm3Iclass, " Read Picopass / iCLASS tag via replay attack"}, - {"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("simulation") " ---------------------"}, {"sim", CmdHFiClassSim, IfPm3Iclass, "[options..] Simulate iCLASS tag"}, {"eload", CmdHFiClassELoad, IfPm3Iclass, "[f ] Load Picopass / iCLASS dump file into emulator memory"}, @@ -3580,7 +3487,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} @@ -3632,33 +3539,33 @@ int info_iclass(void) { picopass_ns_hdr *ns_hdr = (picopass_ns_hdr *)resp.data.asBytes; PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " --------------------------"); - PrintAndLogEx(INFO, "-------------------------------------------------------------"); + PrintAndLogEx(INFO, "--------------------- " _CYAN_("Tag Information") " ----------------------"); + PrintAndLogEx(INFO, "------------------------------------------------------------"); if (readStatus & FLAG_ICLASS_CSN) { - PrintAndLogEx(SUCCESS, " CSN: " _GREEN_("%s") " (uid)", sprint_hex(hdr->csn, sizeof(hdr->csn))); + PrintAndLogEx(SUCCESS, " CSN: " _GREEN_("%s") " uid", sprint_hex(hdr->csn, sizeof(hdr->csn))); } if (readStatus & FLAG_ICLASS_CONF) { - PrintAndLogEx(SUCCESS, " Config: %s (Card configuration)", sprint_hex((uint8_t *)&hdr->conf, sizeof(hdr->conf))); + PrintAndLogEx(SUCCESS, " Config: %s card configuration", sprint_hex((uint8_t *)&hdr->conf, sizeof(hdr->conf))); } // page mapping. If fuse0|1 == 0x01, card is in non-secure mode, with CSN, CONF, AIA as top 3 blocks. // page9 in http://www.proxmark.org/files/Documents/13.56%20MHz%20-%20iClass/DS%20Picopass%202KS%20V1-0.pdf uint8_t pagemap = get_pagemap(hdr); if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) { - PrintAndLogEx(SUCCESS, " AIA: %s (Application Issuer area)", sprint_hex(ns_hdr->app_issuer_area, sizeof(ns_hdr->app_issuer_area))); + PrintAndLogEx(SUCCESS, " AIA: %s application issuer area", sprint_hex(ns_hdr->app_issuer_area, sizeof(ns_hdr->app_issuer_area))); } else { if (readStatus & FLAG_ICLASS_CC) { - PrintAndLogEx(SUCCESS, "E-purse: %s (Card challenge, CC)", sprint_hex(hdr->epurse, sizeof(hdr->epurse))); + PrintAndLogEx(SUCCESS, "E-purse: %s Card challenge, CC", sprint_hex(hdr->epurse, sizeof(hdr->epurse))); } - PrintAndLogEx(SUCCESS, " Kd: %s (Debit key, hidden)", sprint_hex(hdr->key_d, sizeof(hdr->key_d))); - PrintAndLogEx(SUCCESS, " Kc: %s (Credit key, hidden)", sprint_hex(hdr->key_c, sizeof(hdr->key_c))); + PrintAndLogEx(SUCCESS, " Kd: %s debit key, hidden", sprint_hex(hdr->key_d, sizeof(hdr->key_d))); + PrintAndLogEx(SUCCESS, " Kc: %s credit key, hidden", sprint_hex(hdr->key_c, sizeof(hdr->key_c))); if (readStatus & FLAG_ICLASS_AIA) { - PrintAndLogEx(SUCCESS, " AIA: %s (Application Issuer area)", sprint_hex(hdr->app_issuer_area, sizeof(hdr->app_issuer_area))); + PrintAndLogEx(SUCCESS, " AIA: %s application issuer area", sprint_hex(hdr->app_issuer_area, sizeof(hdr->app_issuer_area))); } } @@ -3666,7 +3573,7 @@ int info_iclass(void) { print_picopass_info(hdr); } - PrintAndLogEx(INFO, "------ " _CYAN_("Fingerprint") " ------"); + PrintAndLogEx(INFO, "------------------------ " _CYAN_("Fingerprint") " -----------------------"); uint8_t aia[8]; if (pagemap == PICOPASS_NON_SECURE_PAGEMODE) @@ -3681,18 +3588,17 @@ int info_iclass(void) { bool se_enabled = (memcmp(aia, "\xff\xff\xff\x00\x06\xff\xff\xff", 8) == 0); if (isHidRange) { - PrintAndLogEx(SUCCESS, "CSN is in HID range"); + PrintAndLogEx(SUCCESS, " CSN.......... " _YELLOW_("HID range")); if (legacy) - PrintAndLogEx(SUCCESS, "Credential : " _GREEN_("iCLASS legacy")); + PrintAndLogEx(SUCCESS, " Credential... " _GREEN_("iCLASS legacy")); if (se_enabled) - PrintAndLogEx(SUCCESS, "Credential : " _GREEN_("iCLASS SE")); - + PrintAndLogEx(SUCCESS, " Credential... " _GREEN_("iCLASS SE")); } else { - PrintAndLogEx(SUCCESS, _YELLOW_("PicoPass")" (CSN is not in HID range)"); + PrintAndLogEx(SUCCESS, " CSN..-....... " _YELLOW_("outside HID range")); } uint8_t cardtype = get_mem_config(hdr); - PrintAndLogEx(SUCCESS, " Card type : " _GREEN_("%s"), card_types[cardtype]); + PrintAndLogEx(SUCCESS, " Card type.... " _GREEN_("%s"), card_types[cardtype]); } DropField(); diff --git a/client/src/cmdhflegic.c b/client/src/cmdhflegic.c index 5d9147896..39a542cc9 100644 --- a/client/src/cmdhflegic.c +++ b/client/src/cmdhflegic.c @@ -629,6 +629,10 @@ static int CmdLegicWrbl(const char *Cmd) { while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h': { + errors = true; + break; + } case 'd': { // peek at length of the input string so we can // figure out how many elements to malloc in "data" @@ -679,10 +683,6 @@ static int CmdLegicWrbl(const char *Cmd) { cmdp += 2; break; } - case 'h': { - errors = true; - break; - } case 'y': { autoconfirm = true; break; @@ -695,6 +695,13 @@ static int CmdLegicWrbl(const char *Cmd) { } } + //Validations + if (errors || cmdp == 0) { + if (data) + free(data); + return usage_legic_wrbl(); + } + // OUT-OF-BOUNDS checks // UID 4+1 bytes can't be written to. if (offset < 5) { @@ -704,13 +711,6 @@ static int CmdLegicWrbl(const char *Cmd) { return PM3_EOUTOFBOUND; } - //Validations - if (errors || cmdp == 0) { - if (data) - free(data); - return usage_legic_wrbl(); - } - // tagtype legic_card_select_t card; if (legic_get_type(&card) != PM3_SUCCESS) { @@ -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..599884120 100644 --- a/client/src/cmdhfmf.c +++ b/client/src/cmdhfmf.c @@ -627,6 +627,76 @@ static void decode_print_st(uint16_t blockno, uint8_t *data) { } } + +static uint16_t NumOfBlocks(char card) { + switch (card) { + case '0' : + return MIFARE_MINI_MAXBLOCK; + case '1' : + return MIFARE_1K_MAXBLOCK; + case '2' : + return MIFARE_2K_MAXBLOCK; + case '4' : + return MIFARE_4K_MAXBLOCK; + default : + return 0; + } +} + +static uint8_t NumOfSectors(char card) { + switch (card) { + case '0' : + return MIFARE_MINI_MAXSECTOR; + case '1' : + return MIFARE_1K_MAXSECTOR; + case '2' : + return MIFARE_2K_MAXSECTOR; + case '4' : + return MIFARE_4K_MAXSECTOR; + default : + return 0; + } +} + +static uint8_t FirstBlockOfSector(uint8_t sectorNo) { + if (sectorNo < 32) { + return sectorNo * 4; + } else { + return 32 * 4 + (sectorNo - 32) * 16; + } +} + +static uint8_t NumBlocksPerSector(uint8_t sectorNo) { + if (sectorNo < 32) { + return 4; + } else { + return 16; + } +} + +static uint8_t GetSectorFromBlockNo(uint8_t blockNo) { + if (blockNo < 128) + return blockNo / 4; + else + return 32 + ((128 - blockNo) / 16); +} + +static char GetFormatFromSector(uint8_t sectorNo) { + switch (sectorNo) { + case MIFARE_MINI_MAXSECTOR: + return '0'; + case MIFARE_1K_MAXSECTOR: + return '1'; + case MIFARE_2K_MAXSECTOR: + return '2'; + case MIFARE_4K_MAXSECTOR: + return '4'; + default : + return ' '; + } +} + + static int CmdHF14AMfDarkside(const char *Cmd) { uint8_t blockno = 0, key_type = MIFARE_AUTH_KEYA; uint64_t key = 0; @@ -825,12 +895,9 @@ static int CmdHF14AMfRdSc(const char *Cmd) { PrintAndLogEx(NORMAL, "isOk:%02x", isOK); if (isOK) { - uint8_t blocks = 4; - uint8_t start = sectorNo * 4; - if (sectorNo > 32) { - blocks = 16; - start = 128 + (sectorNo - 32) * 16; - } + uint8_t blocks = NumBlocksPerSector(sectorNo); + uint8_t start = FirstBlockOfSector(sectorNo); + for (int i = 0; i < blocks; i++) { PrintAndLogEx(NORMAL, "%3d | %s", start + i, sprint_hex(data + (i * 16), 16)); } @@ -843,74 +910,6 @@ static int CmdHF14AMfRdSc(const char *Cmd) { return PM3_SUCCESS; } -static uint16_t NumOfBlocks(char card) { - switch (card) { - case '0' : - return MIFARE_MINI_MAXBLOCK; - case '1' : - return MIFARE_1K_MAXBLOCK; - case '2' : - return MIFARE_2K_MAXBLOCK; - case '4' : - return MIFARE_4K_MAXBLOCK; - default : - return 0; - } -} - -static uint8_t NumOfSectors(char card) { - switch (card) { - case '0' : - return MIFARE_MINI_MAXSECTOR; - case '1' : - return MIFARE_1K_MAXSECTOR; - case '2' : - return MIFARE_2K_MAXSECTOR; - case '4' : - return MIFARE_4K_MAXSECTOR; - default : - return 0; - } -} - -static uint8_t FirstBlockOfSector(uint8_t sectorNo) { - if (sectorNo < 32) { - return sectorNo * 4; - } else { - return 32 * 4 + (sectorNo - 32) * 16; - } -} - -static uint8_t NumBlocksPerSector(uint8_t sectorNo) { - if (sectorNo < 32) { - return 4; - } else { - return 16; - } -} - -static uint8_t GetSectorFromBlockNo(uint8_t blockNo) { - if (blockNo < 128) - return blockNo / 4; - else - return 32 + ((128 - blockNo) / 16); -} - -static char GetFormatFromSector(uint8_t sectorNo) { - switch (sectorNo) { - case MIFARE_MINI_MAXSECTOR: - return '0'; - case MIFARE_1K_MAXSECTOR: - return '1'; - case MIFARE_2K_MAXSECTOR: - return '2'; - case MIFARE_4K_MAXSECTOR: - return '4'; - default : - return ' '; - } -} - static int FastDumpWithEcFill(uint8_t numsectors) { PacketResponseNG resp; @@ -1002,6 +1001,7 @@ static int CmdHF14AMfDump(const char *Cmd) { return PM3_ESOFT; strcpy(keyFilename, fptr); + free(fptr); } if ((f = fopen(keyFilename, "rb")) == NULL) { @@ -1163,6 +1163,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 +1227,7 @@ static int CmdHF14AMfRestore(const char *Cmd) { return 1; strcpy(keyFilename, fptr); + free(fptr); } if ((fkeys = fopen(keyFilename, "rb")) == NULL) { @@ -1260,6 +1262,7 @@ static int CmdHF14AMfRestore(const char *Cmd) { return 1; strcpy(dataFilename, fptr); + free(fptr); } if ((fdump = fopen(dataFilename, "rb")) == NULL) { @@ -1570,8 +1573,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 +1780,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 +2020,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 +2142,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 +2151,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 +2265,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 +2410,7 @@ noValidKeyFound: PrintAndLogEx(FAILED, "No usable key was found!"); free(keyBlock); free(e_sector); + free(fptr); return PM3_ESOFT; } } @@ -2516,11 +2524,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 +2561,7 @@ tryNested: default: { PrintAndLogEx(ERR, "unknown Error.\n"); free(e_sector); + free(fptr); return PM3_ESOFT; } } @@ -2582,6 +2593,7 @@ tryHardnested: // If the nested attack fails then we try the hardnested attack } } free(e_sector); + free(fptr); return PM3_ESOFT; } @@ -2606,11 +2618,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 +2690,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 +2700,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 +2724,7 @@ all_found: free(dump); free(e_sector); + free(fptr); return PM3_SUCCESS; } @@ -2982,6 +3001,7 @@ out: if (createMfcKeyDump(fptr, sectorsCnt, e_sector) != PM3_SUCCESS) { PrintAndLogEx(ERR, "Failed to save keys to file"); } + free(fptr); } } @@ -3285,6 +3305,7 @@ out: if (createMfcKeyDump(fptr, SectorsCnt, e_sector) != PM3_SUCCESS) { PrintAndLogEx(ERR, "Failed to save keys to file"); } + free(fptr); } free(keyBlock); @@ -3649,7 +3670,7 @@ static int CmdHF14AMfEGetSc(const char *Cmd) { PrintAndLogEx(NORMAL, "----+------------------------------------------------"); uint8_t blocks = 4; uint8_t start = sector * 4; - if (sector > 32) { + if (sector >= 32) { blocks = 16; start = 128 + (sector - 32) * 16; } @@ -4040,7 +4061,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); } @@ -4344,7 +4364,7 @@ static int CmdHF14AMfCGetSc(const char *Cmd) { PrintAndLogEx(NORMAL, "----+------------------------------------------------"); uint8_t blocks = 4; uint8_t start = sector * 4; - if (sector > 32) { + if (sector >= 32) { blocks = 16; start = 128 + (sector - 32) * 16; } @@ -4732,6 +4752,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 +5195,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/cmdhfmfp.c b/client/src/cmdhfmfp.c index e72799bc4..fd0f6c93a 100644 --- a/client/src/cmdhfmfp.c +++ b/client/src/cmdhfmfp.c @@ -233,6 +233,7 @@ static int plus_print_version(uint8_t *version) { PrintAndLogEx(SUCCESS, " Production date: week " _GREEN_("%02x") " / " _GREEN_("20%02x"), version[7 + 7 + 7 + 5], version[7 + 7 + 7 + 5 + 1]); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "--- " _CYAN_("Hardware Information")); + PrintAndLogEx(INFO, " Raw : %s", sprint_hex(version, 7)); PrintAndLogEx(INFO, " Vendor Id: " _YELLOW_("%s"), getTagInfo(version[0])); PrintAndLogEx(INFO, " Type: %s", getTypeStr(version[1])); PrintAndLogEx(INFO, " Subtype: " _YELLOW_("0x%02X"), version[2]); @@ -241,6 +242,7 @@ static int plus_print_version(uint8_t *version) { PrintAndLogEx(INFO, " Protocol: %s", getProtocolStr(version[6], true)); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "--- " _CYAN_("Software Information")); + PrintAndLogEx(INFO, " Raw : %s", sprint_hex(version + 7, 6)); PrintAndLogEx(INFO, " Vendor Id: " _YELLOW_("%s"), getTagInfo(version[7])); PrintAndLogEx(INFO, " Type: %s", getTypeStr(version[8])); PrintAndLogEx(INFO, " Subtype: " _YELLOW_("0x%02X"), version[9]); @@ -265,13 +267,21 @@ static int get_plus_version(uint8_t *version, int *version_len) { static int CmdHFMFPInfo(const char *Cmd) { - if (Cmd && strlen(Cmd) > 0) - PrintAndLogEx(WARNING, "command don't have any parameters.\n"); - PrintAndLogEx(NORMAL, ""); PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------"); PrintAndLogEx(INFO, "-------------------------------------------------------------"); + // Mifare Plus info + SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT, 0, 0, NULL, 0); + PacketResponseNG resp; + WaitForResponse(CMD_ACK, &resp); + + iso14a_card_select_t card; + memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t)); + + uint64_t select_status = resp.oldarg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision + + bool supportVersion = false; bool supportSignature = false; @@ -284,17 +294,11 @@ static int CmdHFMFPInfo(const char *Cmd) { } else { // info about 14a part infoHF14A(false, false, false); + + // Historical bytes. + } - // Mifare Plus info - SendCommandMIX(CMD_HF_ISO14443A_READER, ISO14A_CONNECT, 0, 0, NULL, 0); - PacketResponseNG resp; - WaitForResponse(CMD_ACK, &resp); - - iso14a_card_select_t card; - memcpy(&card, (iso14a_card_select_t *)resp.data.asBytes, sizeof(iso14a_card_select_t)); - - uint64_t select_status = resp.oldarg[0]; // 0: couldn't read, 1: OK, with ATS, 2: OK, no ATS, 3: proprietary Anticollision // Signature originality check uint8_t signature[56] = {0}; diff --git a/client/src/cmdhfmfu.c b/client/src/cmdhfmfu.c index 0e242a029..55e03a848 100644 --- a/client/src/cmdhfmfu.c +++ b/client/src/cmdhfmfu.c @@ -21,10 +21,11 @@ #include "generator.h" #include "mifare/ndef.h" #include "cliparser.h" +#include "cmdmain.h" #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 +169,14 @@ 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 [k] "); + PrintAndLogEx(NORMAL, " k - keep field on (only if a password is provided too)"); + 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 +242,14 @@ static int usage_hf_mfu_otp_tearoff(void) { PrintAndLogEx(NORMAL, " s