Merge branch 'master' into allin

update
This commit is contained in:
tharexde 2020-10-22 01:01:59 +02:00
commit 069018e72a
175 changed files with 155010 additions and 25622 deletions

1
.lsan_suppressions Normal file
View file

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

55
.vscode/launch.json vendored Normal file
View file

@ -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",
}
}
]
}

72
.vscode/tasks.json vendored
View file

@ -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"
}
]
}

View file

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

View file

@ -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' {} \;

View file

@ -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,6 +43,12 @@ INSTALLDOCSRELPATH ?= share/doc/proxmark3
platform = $(shell uname)
DETECTED_OS=$(platform)
ifeq ($(shell $(CC) -v 2>&1 | grep -c "clang version"), 1)
DETECTED_COMPILER = clang
else
DETECTED_COMPILER = gcc
endif
ifeq ($(platform),Darwin)
AR= /usr/bin/ar rcs
RANLIB= /usr/bin/ranlib
@ -48,19 +57,38 @@ else
RANLIB= ranlib
endif
DEFCXXFLAGS = -Wall -Werror -O3 -pipe
DEFCFLAGS = -Wall -Werror -O3 -fstrict-aliasing -pipe
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

View file

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

View file

@ -30,7 +30,7 @@
| ------------------- |:-------------------:| -------------------:|
|[Notes on UART](/doc/uart_notes.md)|[Notes on Termux / Android](/doc/termux_notes.md)|[Notes on paths](/doc/path_notes.md)|
|[Notes on 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

View file

@ -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) {
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
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
}
}
$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,41 +174,11 @@ 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
@ -143,21 +186,8 @@ clone_script:
ExecUpdate "ProxSpace: installing required packages..." $false
Add-AppveyorMessage -Message "ProxSpace download and update took $(([System.Environment]::TickCount-$env:PSInstallTime) / 1000) sec" -Category Information
$psversion = (Select-String -Pattern 'PSVERSION=' -SimpleMatch -Path "$env:proxspace_path\msys2\ps\09-proxspace_setup.post").Line.Split("""")[1]
Write-Host "ProxSpace version: $psversion" -ForegroundColor Yellow
Add-AppveyorMessage -Message "ProxSpace download and update took $(([System.Environment]::TickCount-$PSInstallTime) / 1000) sec" -Category Information
GitClone "ProxSpace: Cloning repository <$env:appveyor_repo_name> to $env:appveyor_build_folder ..." $env:appveyor_build_folder
Receive-Job -Wait -Job $WSLjob
GitClone "WSL: Cloning repository <$env:appveyor_repo_name> to $env:wsl_git_path ..." $env:wsl_git_path
install:
build_script:
- 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
}
@ -203,9 +234,18 @@ build_script:
}
}
#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 -Job $WSLjob
Receive-Job -Wait -Name WSLInstall -ErrorAction SilentlyContinue
Receive-Job -Wait -Job $WSLjob
test_script:
- ps: >-

View file

@ -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");

View file

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

View file

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

View file

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

View file

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

View file

@ -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();
}

View file

@ -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,20 +1549,19 @@ static void PacketReceived(PacketCommandNG *packet) {
break;
}
case CMD_HF_ICLASS_SIMULATE: {
SimulateIClass(packet->oldarg[0], packet->oldarg[1], packet->oldarg[2], packet->data.asBytes);
break;
}
case CMD_HF_ICLASS_READER: {
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);
*/
SimulateIClass(packet->oldarg[0], packet->oldarg[1], packet->oldarg[2], packet->data.asBytes);
break;
}
case CMD_HF_ICLASS_READER: {
ReaderIClass(packet->oldarg[0]);
break;
}
case CMD_HF_ICLASS_EML_MEMSET: {
@ -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: {

View file

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

View file

@ -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,22 +956,26 @@ 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);
// wait for T0 * EM4X50_T_TAG_TWA (write access time)
wait_timer(FPGA_TIMER_0, T0 * EM4X50_T_TAG_TWA);
// 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 true;
return PM3_SUCCESS;
}
}
} else {
if (DBGLEVEL >= DBG_DEBUG)
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);
@ -998,16 +1004,17 @@ static bool write_password(uint32_t password, uint32_t new_password) {
if (check_ack(false))
if (check_ack(false))
return true;
return PM3_SUCCESS;
}
}
} else {
if (DBGLEVEL >= DBG_DEBUG)
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) {

View file

@ -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();
}

View file

@ -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,6 +1489,12 @@ bool authenticate_iclass_tag(iclass_auth_req_t *payload, picopass_hdr *hdr, uint
memcpy(ccnr, hdr->epurse, sizeof(hdr->epurse));
if (payload->use_replay) {
memcpy(pmac, payload->key + 4, 4);
memcpy(cmd_check + 1, payload->key, 8);
} else {
if (payload->use_raw)
memcpy(div_key, payload->key, 8);
else
@ -1602,7 +1512,7 @@ bool authenticate_iclass_tag(iclass_auth_req_t *payload, picopass_hdr *hdr, uint
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_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);
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] failed", b);
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);
}
}

View file

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

View file

@ -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) {
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,11 +2929,16 @@ void ReaderIso14443a(PacketCommandNG *c) {
ReaderTransmit(cmd, len, NULL); // 8 bits, odd parity
}
}
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))
iso14a_set_trigger(false);

View file

@ -784,6 +784,7 @@ static RAMFUNC int Handle14443bSamplesFromTag(int ci, int cq) {
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
if (Demod.posCount < 10) { // refine signal approximation during first 10 samples
Demod.sumI += ci;
Demod.sumQ += cq;
@ -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
@ -1103,7 +1104,7 @@ static void CodeIso14443bAsReader(const uint8_t *cmd, int len) {
// 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);
@ -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);
@ -1892,6 +1895,10 @@ void SendRawCommand14443B_Ex(PacketCommandNG *c) {
uint32_t eof_time = 0;
CodeAndTransmit14443bAsReader(cmd, len, &start_time, &eof_time);
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();
@ -1899,6 +1906,7 @@ void SendRawCommand14443B_Ex(PacketCommandNG *c) {
sendlen = MIN(Demod.len, PM3_CMD_DATA_SIZE);
reply_mix(CMD_HF_ISO14443B_COMMAND, status, sendlen, 0, Demod.output, sendlen);
}
}
out:
// turn off trigger (LED_A)

View file

@ -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,16 +1471,22 @@ 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);
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);
int res = 0;
if (recv != NULL) {
res = GetIso15693AnswerFromTag(recv, max_recv_len, timeout, eof_time);
}
}
return res;
}
@ -1586,11 +1594,16 @@ 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);
int recvlen = SendDataTag(cmd, sizeof(cmd), true, true, answer, ISO15693_MAX_RESPONSE_LENGTH, start_time, ISO15693_READER_TIMEOUT, &eof_time);
if (recvlen == PM3_ETEAROFF) { // tearoff occured
reply_mix(CMD_ACK, recvlen, 0, 0, NULL, 0);
} else {
start_time = eof_time + DELAY_ISO15693_VICC_TO_VCD_READER;
// we should do a better check than this
if (answerLen >= 12) {
if (recvlen >= 12) {
uint8_t uid[8];
uid[0] = answer[9]; // always E0
uid[1] = answer[8]; // IC Manufacturer code
@ -1613,14 +1626,17 @@ void ReaderIso15693(uint32_t parameter) {
// 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);
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);
}
}
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,13 +1855,12 @@ 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);
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) {
@ -1849,29 +1868,16 @@ void DirectTag15693Command(uint32_t datalen, uint32_t speed, uint32_t recv, uint
recvlen = SendDataTagEOF((recv ? recvbuf : NULL), sizeof(recvbuf), start_time, ISO15693_READER_TIMEOUT, &eof_time);
}
// for the time being, switch field off to protect rdv4.0
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);
}
}
// 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);
}
}
/*

View file

@ -2369,6 +2369,7 @@ int copy_em410x_to_t55xx(uint8_t card, uint8_t clock, uint32_t id_hi, uint32_t i
#define FWD_CMD_LOGIN 0xC
#define FWD_CMD_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;
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);
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?
WaitMS(7);
// No, when write is denied, err preamble comes much sooner
//WaitUS(10820); // tPC+tWEE
DoPartialAcquisition(20, false, 6000, 1000);
DoPartialAcquisition(0, false, 6000, 1000);
StopTicks();
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);
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();
}

View file

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

View file

@ -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);
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -1927,10 +1927,8 @@ struct arg_file *arg_filen(
#include <stdlib.h>
#include <limits.h>
#include <ctype.h>
#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 <stdint.h>
#include <limits.h>
#include <inttypes.h>
static uint64_t strtollu0X(const char *str,
const char * *endptr,
char X,
int base) {
uint64_t val; /* stores result */
int s = 1; /* sign is +1 or -1 */
const char *ptr = str; /* ptr to current position in str */
/* skip leading whitespace */
while (ISSPACE(*ptr))
ptr++;
// printf("1) %s\n",ptr);
/* scan optional sign character */
switch (*ptr) {
case '+':
ptr++;
s = 1;
break;
case '-':
ptr++;
s = -1;
break;
default:
s = 1;
break;
}
// printf("2) %s\n",ptr);
/* '0X' prefix */
if ((*ptr++) != '0') {
/* printf("failed to detect '0'\n"); */
*endptr = str;
return 0;
}
// printf("3) %s\n",ptr);
if (toupper(*ptr++) != toupper(X)) {
/* printf("failed to detect '%c'\n",X); */
*endptr = str;
return 0;
}
// printf("4) %s\n",ptr);
/* attempt conversion on remainder of string using strtol() */
val = strtoull(ptr, (char * *)endptr, base);
if (*endptr == ptr) {
/* conversion failed */
*endptr = str;
return 0;
}
/* success */
return s * val;
}
static void arg_u64_resetfn(struct arg_u64 *parent) {
ARG_TRACE(("%s:resetfn(%p)\n", __FILE__, parent));
parent->count = 0;
}
static int arg_u64_scanfn(struct arg_u64 *parent, const char *argval) {
int errorcode = 0;
if (parent->count == parent->hdr.maxcount) {
/* maximum number of arguments exceeded */
errorcode = EMAXCOUNT;
} else if (!argval) {
/* a valid argument with no argument value was given. */
/* This happens when an optional argument value was invoked. */
/* leave parent arguiment value unaltered but still count the argument. */
parent->count++;
} else {
uint64_t val;
const char *end;
/* attempt to extract hex integer (eg: +0x123) from argval into val conversion */
val = strtollu0X(argval, &end, 'X', 16);
if (end == argval) {
/* hex failed, attempt octal conversion (eg +0o123) */
val = strtollu0X(argval, &end, 'O', 8);
if (end == argval) {
/* octal failed, attempt binary conversion (eg +0B101) */
val = strtollu0X(argval, &end, 'B', 2);
if (end == argval) {
/* binary failed, attempt decimal conversion with no prefix (eg 1234) */
val = strtoull(argval, (char * *)&end, 10);
if (end == argval) {
/* all supported number formats failed */
return EBADINT;
}
}
}
}
/* Safety check for integer overflow. WARNING: this check */
/* achieves nothing on machines where size(int)==size(long). */
if (val > ULLONG_MAX)
#ifdef __STDC_WANT_SECURE_LIB__
errorcode = EOVERFLOW_;
#else
errorcode = EOVERFLOW;
#endif
/* Detect any suffixes (KB,MB,GB) and multiply argument value appropriately. */
/* We need to be mindful of integer overflows when using such big numbers. */
if (detectsuffix(end, "KB")) { /* kilobytes */
if (val > (ULLONG_MAX / 1024))
#ifdef __STDC_WANT_SECURE_LIB__
errorcode = EOVERFLOW_; /* Overflow would occur if we proceed */
#else
errorcode = EOVERFLOW; /* Overflow would occur if we proceed */
#endif
else
val *= 1024; /* 1KB = 1024 */
} else if (detectsuffix(end, "MB")) { /* megabytes */
if (val > (ULLONG_MAX / 1048576))
#ifdef __STDC_WANT_SECURE_LIB__
errorcode = EOVERFLOW_; /* Overflow would occur if we proceed */
#else
errorcode = EOVERFLOW; /* Overflow would occur if we proceed */
#endif
else
val *= 1048576; /* 1MB = 1024*1024 */
} else if (detectsuffix(end, "GB")) { /* gigabytes */
if (val > (ULLONG_MAX / 1073741824))
#ifdef __STDC_WANT_SECURE_LIB__
errorcode = EOVERFLOW_; /* Overflow would occur if we proceed */
#else
errorcode = EOVERFLOW; /* Overflow would occur if we proceed */
#endif
else
val *= 1073741824; /* 1GB = 1024*1024*1024 */
} else if (!detectsuffix(end, ""))
errorcode = EBADINT; /* invalid suffix detected */
/* if success then store result in parent->uval[] array */
if (errorcode == 0)
parent->uval[parent->count++] = val;
}
/* printf("%s:scanfn(%p,%p) returns %d\n",__FILE__,parent,argval,errorcode); */
return errorcode;
}
static int arg_u64_checkfn(struct arg_u64 *parent) {
int errorcode = (parent->count < parent->hdr.mincount) ? EMINCOUNT : 0;
/*printf("%s:checkfn(%p) returns %d\n",__FILE__,parent,errorcode);*/
return errorcode;
}
static void arg_u64_errorfn(
struct arg_u64 *parent,
FILE *fp,
int errorcode,
const char *argval,
const char *progname) {
const char *shortopts = parent->hdr.shortopts;
const char *longopts = parent->hdr.longopts;
const char *datatype = parent->hdr.datatype;
/* make argval NULL safe */
argval = argval ? argval : "";
fprintf(fp, "%s: ", progname);
switch (errorcode) {
case EMINCOUNT:
fputs("missing option ", fp);
arg_print_option(fp, shortopts, longopts, datatype, "\n");
break;
case EMAXCOUNT:
fputs("excess option ", fp);
arg_print_option(fp, shortopts, longopts, argval, "\n");
break;
case EBADINT:
fprintf(fp, "invalid argument \"%s\" to option ", argval);
arg_print_option(fp, shortopts, longopts, datatype, "\n");
break;
#ifdef __STDC_WANT_SECURE_LIB__
case EOVERFLOW_:
#else
case EOVERFLOW:
#endif
fputs("integer overflow at option ", fp);
arg_print_option(fp, shortopts, longopts, datatype, " ");
fprintf(fp, "(%s is too large)\n", argval);
break;
}
}
struct arg_u64 *arg_u64_0(
const char *shortopts,
const char *longopts,
const char *datatype,
const char *glossary) {
return arg_u64_n(shortopts, longopts, datatype, 0, 1, glossary);
}
struct arg_u64 *arg_u64_1(
const char *shortopts,
const char *longopts,
const char *datatype,
const char *glossary) {
return arg_u64_n(shortopts, longopts, datatype, 1, 1, glossary);
}
struct arg_u64 *arg_u64_n(
const char *shortopts,
const char *longopts,
const char *datatype,
int mincount,
int maxcount,
const char *glossary) {
size_t nbytes;
struct arg_u64 *result;
/* foolproof things by ensuring maxcount is not less than mincount */
maxcount = (maxcount < mincount) ? mincount : maxcount;
nbytes = sizeof(struct arg_u64) /* storage for struct arg_u64 */
+ maxcount * sizeof(uint64_t); /* storage for uval[maxcount] array */
result = (struct arg_u64 *)malloc(nbytes);
if (result) {
/* init the arg_hdr struct */
result->hdr.flag = ARG_HASVALUE;
result->hdr.shortopts = shortopts;
result->hdr.longopts = longopts;
result->hdr.datatype = datatype ? datatype : "<u64>";
result->hdr.glossary = glossary;
result->hdr.mincount = mincount;
result->hdr.maxcount = maxcount;
result->hdr.parent = result;
result->hdr.resetfn = (arg_resetfn *)arg_u64_resetfn;
result->hdr.scanfn = (arg_scanfn *)arg_u64_scanfn;
result->hdr.checkfn = (arg_checkfn *)arg_u64_checkfn;
result->hdr.errorfn = (arg_errorfn *)arg_u64_errorfn;
/* store the uval[maxcount] array immediately after the arg_int struct */
result->uval = (uint64_t *)(result + 1);
result->count = 0;
}
ARG_TRACE(("arg_u64_n() returns %p\n", result));
return result;
}
/*******************************************************************************
* This file is part of the argtable3 library.
*
@ -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)
/* if (longopts)
arg_cat(&dest, "=", &ndest);
else if (shortopts)
arg_cat(&dest, " ", &ndest);
*/
*/
if (longopts)
arg_cat(&dest, " ", &ndest);
else if (shortopts)

View file

@ -35,6 +35,7 @@
#include <stdio.h> /* FILE */
#include <time.h> /* struct tm */
#include <stdint.h>
#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,
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_key *arg_key1(const char *keyword,
int flags,
struct arg_u64 *arg_u64_1(const char *shortopts,
const char *longopts,
const char *datatype,
const char *glossary);
struct arg_key *arg_keyn(const char *keyword,
int flags,
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,

View file

@ -13,6 +13,8 @@
#include <stdlib.h>
#include <util.h> // Get color constants
#include <ui.h> // get PrintAndLogEx
#include <ctype.h> // tolower
#include <inttypes.h> // PRIu64
#ifndef ARRAYLEN
# define ARRAYLEN(x) (sizeof(x)/sizeof((x)[0]))
@ -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);
ibuf += len;
}
tmp_buf[ibuf] = 0;
if (!ibuf)
return 0;
if (ibuf > maxdatalen) {
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(data, tmp_buf, ibuf);
memcpy(&tmpstr[ibuf], argstr->sval[i], len);
ibuf += len;
}
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, 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;
}

View file

@ -18,21 +18,38 @@
#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_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

View file

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

View file

@ -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,17 +427,21 @@ 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) {
/* the selected model solved all arguments */
@ -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

View file

@ -1203,3 +1203,9 @@ FEE2A3FBC5B6
# taurus avm
#
005078565703
#
# Ving?
#
0602721E8F06
FC0B50AF8700
F7BA51A9434E

View file

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

View file

@ -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',
}
---

View file

@ -0,0 +1,277 @@
local cmds = require('commands')
local getopt = require('getopt')
local lib14b = require('read14b')
local utils = require('utils')
local iso7816 = require('7816_error')
local ansicolors = require('ansicolors')
copyright = ''
author = 'Iceman'
version = 'v1.0.0'
desc = [[
This is a script to communicate with a MOBIB tag using the '14b raw' commands
]]
example = [[
script run hf_14b_mobib
script run hf_14b_mobib -b 11223344
]]
usage = [[
script run hf_14b_mobib -h -b
]]
arguments = [[
h this helptext
b raw bytes to send
]]
--[[
This script communicates with /armsrc/iso14443b.c,
Check there for details about data format and how commands are interpreted on the
device-side.
]]
local function calypso_parse(result)
local r = Command.parse(result)
if r.arg1 >= 0 then
local len = r.arg1 * 2
if len > 0 then
r.data = string.sub(r.data, 0, len);
return r, nil
end
end
return nil,nil
end
---
-- A debug printout-function
local function dbg(args)
if not DEBUG then return end
if type(args) == 'table' then
local i = 1
while args[i] do
dbg(args[i])
i = i+1
end
else
print('###', args)
end
end
---
-- This is only meant to be used when errors occur
local function oops(err)
print('ERROR: ', err)
lib14b.disconnect()
return nil, err
end
---
-- Usage help
local function help()
print(copyright)
print(author)
print(version)
print(desc)
print(ansicolors.cyan..'Usage'..ansicolors.reset)
print(usage)
print(ansicolors.cyan..'Arguments'..ansicolors.reset)
print(arguments)
print(ansicolors.cyan..'Example usage'..ansicolors.reset)
print(example)
end
--
-- helper function, give current count of items in lua-table.
local function tablelen(T)
local count = 0
for _ in pairs(T) do count = count + 1 end
return count
end
---
-- helper function, gives a sorted table from table t,
-- order can be a seperate sorting-order function.
local function spairs(t, order)
-- collect the keys
local keys = {}
for k in pairs(t) do keys[#keys+1] = k end
-- if order function given, sort by it by passing the table and keys a, b,
-- otherwise just sort the keys
if order then
table.sort(keys, function(a,b) return order(t, a, b) end)
else
table.sort(keys)
end
-- return the iterator function
local i = 0
return function()
i = i + 1
if keys[i] then
return keys[i], t[keys[i]]
end
end
end
---
-- Sends a usbpackage , "hf 14b raw"
-- if it reads the response, it converts it to a lua object "Command" first and the Data is cut to correct length.
local function calypso_send_cmd_raw(data, ignoreresponse )
local command, flags, result, err
flags = lib14b.ISO14B_COMMAND.ISO14B_APDU
data = data or "00"
command = Command:newMIX{
cmd = cmds.CMD_HF_ISO14443B_COMMAND,
arg1 = flags,
arg2 = #data/2, -- LEN of data, half the length of the ASCII-string hex string
data = data} -- data bytes (commands etc)
local use_cmd_ack = true
result, err = command:sendMIX(ignoreresponse, 2000, use_cmd_ack)
if result then
local count,cmd,arg0,arg1,arg2 = bin.unpack('LLLL', result)
if arg0 >= 0 then
return calypso_parse(result)
else
err = 'card response failed'
end
else
err = 'No response from card'
end
return result, err
end
---
-- calypso_card_num : Reads card number from ATR and
-- writes it in the tree in decimal format.
local function calypso_card_num(card)
if not card then return end
local card_num = tonumber( card.uid:sub(1,8),16 )
print('')
print('Card UID ' ..ansicolors.green..card.uid:format('%x')..ansicolors.reset)
print('Card Number ' ..ansicolors.green..string.format('%u', card_num)..ansicolors.reset)
print('-----------------------')
end
---
-- analyse CALYPSO apdu status bytes.
local function calypso_apdu_status(apdu)
-- last two is CRC
-- next two is APDU status bytes.
local mess = 'FAIL'
local sw = apdu:sub( #apdu-7, #apdu-4)
desc, err = iso7816.tostring(sw)
--print ('SW', sw, desc, err )
local status = ( sw == '9000' )
return status, desc, err
end
local CLA = '00'
local _calypso_cmds = {
['01.SELECT AID 1TIC.ICA'] = CLA..'a4 0400 08 315449432e494341',
['02.Select ICC file a'] = CLA..'a4 0000 02 3f00',
['03.Select ICC file b'] = CLA..'a4 0000 02 0002',
['04.ICC'] = CLA..'b2 0104 1d',
['05.Select Holder file'] = CLA..'a4 0000 02 3f1c',
['06.Holder1'] = CLA..'b2 0104 1d',
['07.Holder2'] = CLA..'b2 0204 1d',
['08.Select EnvHol file a'] = CLA..'a4 0000 00',
['09.Select EnvHol file b'] = CLA..'a4 0000 02 2000',
['10.Select EnvHol file c'] = CLA..'a4 0000 02 2001',
['11.EnvHol1'] = CLA..'b2 0104 1d',
['11.EnvHol2'] = CLA..'b2 0204 1d',
['12.Select EvLog file'] = CLA..'a4 0000 02 2010',
['13.EvLog1'] = CLA..'b2 0104 1d',
['14.EvLog2'] = CLA..'b2 0204 1d',
['15.EvLog3'] = CLA..'b2 0304 1d',
['16.Select ConList file'] = CLA..'a4 0000 02 2050',
['17.ConList'] = CLA..'b2 0104 1d',
['18.Select Contra file'] = CLA..'a4 0000 02 2020',
['19.Contra1'] = CLA..'b2 0104 1d',
['20.Contra2'] = CLA..'b2 0204 1d',
['21.Contra3'] = CLA..'b2 0304 1d',
['22.Contra4'] = CLA..'b2 0404 1d',
['23.Contra5'] = CLA..'b2 0504 1d',
['24.Contra6'] = CLA..'b2 0604 1d',
['25.Contra7'] = CLA..'b2 0704 1d',
['26.Contra8'] = CLA..'b2 0804 1d',
['27.Contra9'] = CLA..'b2 0904 1d',
['28.ContraA'] = CLA..'b2 0a04 1d',
['29.ContraB'] = CLA..'b2 0b04 1d',
['30.ContraC'] = CLA..'b2 0c04 1d',
['31.Select Counter file'] = CLA..'a4 0000 02 2069',
['32.Counter'] = CLA..'b2 0104 1d',
['33.Select LoadLog file a'] = CLA..'a4 0000 00',
['34.Select LoadLog file b'] = CLA..'a4 0000 02 1000',
['35.Select LoadLog file c'] = CLA..'a4 0000 02 1014',
['36.LoadLog'] = CLA..'b2 0104 1d',
['37.Select Purcha file'] = CLA..'a4 0000 02 1015',
['38.Purcha1'] = CLA..'b2 0104 1d',
['39.Purcha2'] = CLA..'b2 0204 1d',
['40.Purcha3'] = CLA..'b2 0304 1d',
['41.Select SpecEv file a'] = CLA..'a4 0000 00',
['42.Select SpecEv file b'] = CLA..'a4 0000 02 2000',
['43.Select SpecEv file c'] = CLA..'a4 0000 02 2040',
['44.SpecEv1'] = CLA..'b2 0104 1d',
['45.SpecEv2'] = CLA..'b2 0204 1d',
['46.SpecEv3'] = CLA..'b2 0304 1d',
['47.SpecEv4'] = CLA..'b2 0404 1d',
}
---
-- The main entry point
function main(args)
print( string.rep('--',20) )
print( string.rep('--',20) )
print()
local data, apdu, flags, uid, cid, result, err, card
-- Read the parameters
for o, a in getopt.getopt(args, 'h') do
if o == 'h' then return help() end
if o == 'b' then bytes = a end
end
-- lib14b.connect()
-- Select 14b tag.
card, err = lib14b.waitFor14443b()
if not card then return oops(err) end
calypso_card_num(card)
cid = card.cid
for i, apdu in spairs(_calypso_cmds) do
print('>> '..ansicolors.yellow..i..ansicolors.reset)
apdu = apdu:gsub('%s+', '')
result, err = calypso_send_cmd_raw(apdu , false)
if err then
print('<< '..err)
else
if result then
local status, desc, err = calypso_apdu_status(result.data)
local d = result.data:sub(3, (#result.data - 8))
if status then
print('<< '..d..' ('..ansicolors.green..'ok'..ansicolors.reset..')')
else
print('<< '..d..' '..ansicolors.red..err..ansicolors.reset )
end
else
print('<< no answer')
end
end
end
lib14b.disconnect()
end
---
-- a simple selftest function, tries to convert
function selftest()
DEBUG = true
dbg('Performing test')
dbg('Tests done')
end
-- Flip the switch here to perform a sanity check.
-- It read a nonce in two different ways, as specified in the usage-section
if '--test'==args then
selftest()
else
-- Call the main
main(args)
end

View file

@ -0,0 +1,176 @@
local getopt = require('getopt')
local ansicolors = require('ansicolors')
copyright = 'Iceman'
author = 'Iceman'
version = 'v0.9.9'
desc = [[
This is scripts loops though a tear attack and reads expected value.
]]
example = [[
1. script run tearoff -n 2 -s 200 -e 400 -a 5
]]
usage = [[
script run tearoff [-h] [-n <steps us>] [-a <addr>] [-p <pwd>] [-s <start us>] [-e <end us>] [-r <read>] [-w <write>]
]]
arguments = [[
-h This help
-n <steps us> steps in milliseconds for each tearoff
-a <addr> address to target on card
-p <pwd> (optional) use a password
-s <delay us> initial start delay
-e <delay us> end delay, must be larger than start delay
-r <read value> 4 hex bytes value to be read
-w <write value> 4 hex bytes value to be written
end
]]
---
-- This is only meant to be used when errors occur
local function oops(err)
print('ERROR:', err)
core.clearCommandBuffer()
return nil, err
end
---
-- Usage help
local function help()
print(copyright)
print(author)
print(version)
print(desc)
print(ansicolors.cyan..'Usage'..ansicolors.reset)
print(usage)
print(ansicolors.cyan..'Arguments'..ansicolors.reset)
print(arguments)
print(ansicolors.cyan..'Example usage'..ansicolors.reset)
print(example)
end
local function main(args)
--[[
Basically do the following,
1. hw tear
2. lf em 4x05_write
3. lf em 4x05_read
The first two commands doesn't need a feedback from the system, so going with core.console commands.
Since the read needs demodulation of signal I opted to add that function from cmdlfem4x.c to the core lua scripting
core.em4x05_read(addr, password)
--]]
local n, addr, password, sd, ed, wr_value, rd_value
for o, a in getopt.getopt(args, 'he:s:a:p:n:r:w:') do
if o == 'h' then return help() end
if o == 'n' then n = a end
if o == 'a' then addr = a end
if o == 'p' then password = a end
if o == 'e' then ed = tonumber(a) end
if o == 's' then sd = tonumber(a) end
if o == 'w' then wr_value = a end
if o == 'r' then rd_value = a end
end
rd_value = rd_value or 'FFFFFFFF'
wr_value = wr_value or 'FFFFFFFF'
addr = addr or 5
password = password or ''
n = n or 2
sd = sd or 2000
ed = ed or 2100
if #password ~= 8 then
password = ''
end
if #wr_value ~= 8 then
wr_value = 'FFFFFFFF'
end
if #rd_value ~= 8 then
rd_value = 'FFFFFFFF'
end
if sd > ed then
return oops('start delay can\'t be larger than end delay', sd, ed)
end
print('Starting EM4x05 tear off')
print('target addr', addr)
if password then
print('target pwd', password)
end
print('target stepping', n)
print('target delay', sd ,ed)
print('read value', rd_value)
print('write value', wr_value)
local res_tear = 0
local res_nowrite = 0
local set_tearoff_delay = 'hw tearoff --delay %d'
local enable_tearoff = 'hw tearoff --on'
local wr_template = 'lf em 4x05_write %s %s %s'
-- init addr to value
core.console(wr_template:format(addr, wr_value, password))
if sd == ed then
ed = n
n = 0
end
for step = sd, ed, n do
io.flush()
if core.kbd_enter_pressed() then
print("aborted by user")
break
end
core.clearCommandBuffer()
-- reset addr to known value, if not locked into.
if n ~= 0 then
c = wr_template:format(addr, wr_value, password)
core.console(c)
end
local c = set_tearoff_delay:format(step)
core.console(c);
core.console(enable_tearoff)
c = wr_template:format(addr, wr_value, password)
core.console(c)
local word, err = core.em4x05_read(addr, password)
if err then
return oops(err)
end
local wordstr = ('%08X'):format(word)
if wordstr ~= wr_value then
if wordstr ~= rd_value then
print((ansicolors.red..'TEAR OFF occurred:'..ansicolors.reset..' %08X'):format(word))
res_tear = res_tear + 1
else
print((ansicolors.cyan..'TEAR OFF occurred:'..ansicolors.reset..' %08X'):format(word))
res_nowrite = res_nowrite + 1
end
else
print((ansicolors.green..'Good write occurred:'..ansicolors.reset..' %08X'):format(word))
end
end
end
--[[
In the future, we may implement so that scripts are invoked directly
into a 'main' function, instead of being executed blindly. For future
compatibility, I have done so, but I invoke my main from here.
--]]
main(args)

View file

@ -0,0 +1,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 <steps us>] [-p <pwd>] [-s <start us>] [-e <end us>]
]]
arguments = [[
-h This help
-n <steps us> steps in milliseconds for each tear-off
-p <pwd> (optional) use a password
-s <delay us> initial start delay
-e <delay us> end delay, must be larger or equal to start delay
end
]]
local set_tearoff_delay = 'hw tearoff --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)

View file

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

View file

@ -18,7 +18,7 @@ desc = [[
\ / \ /
`---' `---'
*SUPPORTED TAGS: pyramid, awid, fdx, jablotron, noralsy, presco, visa2000, 14a, hid
*SUPPORTED TAGS: pyramid, awid, fdxb, jablotron, noralsy, presco, visa2000, 14a, hid
This script uses the Proxmark3 implementations of simulation to bruteforce given ranges of id.
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

View file

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

View file

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

View file

@ -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 <filename w/o ext>]");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h this help");
PrintAndLogEx(NORMAL, " w save as wave format (.wav)");
PrintAndLogEx(NORMAL, " f <filename> save file name");
PrintAndLogEx(NORMAL, "Samples:");
PrintAndLogEx(NORMAL, " data save f mytrace - save graphbuffer to file");
PrintAndLogEx(NORMAL, " data save f mytrace w - save graphbuffer to wave file");
return PM3_SUCCESS;
}
static int usage_data_scale(void) {
PrintAndLogEx(NORMAL, "Set cursor display scale.");
PrintAndLogEx(NORMAL, "Setting the scale makes the differential `dt` reading between the yellow and purple markers meaningful. ");
PrintAndLogEx(NORMAL, "once the scale is set, the differential reading between brackets is the time duration in seconds.");
PrintAndLogEx(NORMAL, "For example, if acquiring in 125kHz, use scale 125.");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: data scale [h] <kHz>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h this help");
PrintAndLogEx(NORMAL, " <kHz> sets scale of carrier frequency expressed in kHz");
PrintAndLogEx(NORMAL, "Samples:");
PrintAndLogEx(NORMAL, " data scale 125 - if sampled in 125kHz");
return PM3_SUCCESS;
}
static int usage_data_printdemodbuf(void) {
PrintAndLogEx(NORMAL, "Usage: data printdemodbuffer x o <offset> l <length>");
PrintAndLogEx(NORMAL, "Usage: data print x o <offset> l <length>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h this help");
PrintAndLogEx(NORMAL, " i invert Demodbuffer before printing");
@ -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] <clock>");
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 (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;
if (slen) {
if (Cmd[0] == 's') {
st = true;
Cmd++;
} else if (Cmd[1] == 's') {
} else if (slen > 1 && Cmd[1] == 's') {
st = true;
Cmd += 2;
}
int clk = 0;
int invert = 0;
int maxErr = 100;
size_t maxLen = 0;
bool amplify = false;
char amp = tolower(param_getchar(Cmd, 0));
sscanf(Cmd, "%i %i %i %zu %c", &clk, &invert, &maxErr, &maxLen, &amp);
amplify = amp == 'a';
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, "<dec>", "factor to reduce sample set (default 2)"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
int n = arg_get_int_def(ctx, 1, 2);
CLIParserFree(ctx);
for (size_t i = 0; i < (GraphTraceLen / n); ++i)
GraphBuffer[i] = GraphBuffer[i * n];
GraphTraceLen /= n;
PrintAndLogEx(SUCCESS, "decimated by " _GREEN_("%u"), n);
RepaintGraphWindow();
return PM3_SUCCESS;
}
@ -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, "<dec>", "factor to repeat each sample (default 2)"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
int factor = arg_get_int_def(ctx, 1, 2);
CLIParserFree(ctx);
//We have memory, don't we?
int swap[MAX_GRAPH_TRACE_LEN] = {0};
uint32_t g_index = 0, s_index = 0;
while (g_index < GraphTraceLen && s_index + factor < MAX_GRAPH_TRACE_LEN) {
int count = 0;
for (count = 0; count < factor && s_index + count < MAX_GRAPH_TRACE_LEN; count++)
swap[s_index + count] = GraphBuffer[g_index];
for (count = 0; count < factor && s_index + count < MAX_GRAPH_TRACE_LEN; count++) {
swap[s_index + count] = (
(double)(factor - count) / (factor - 1)) * GraphBuffer[g_index] +
((double)count / factor) * GraphBuffer[g_index + 1]
;
}
s_index += count;
g_index++;
}
@ -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", "<filename>", "file to load"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
char *path;
int fnlen = 0;
char filename[FILE_PATH_SIZE] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
CLIParserFree(ctx);
char *path = NULL;
if (searchFile(&path, TRACES_SUBDIR, filename, ".pm3", true) != PM3_SUCCESS) {
if (searchFile(&path, TRACES_SUBDIR, filename, "", false) != PM3_SUCCESS) {
return PM3_EFILE;
@ -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", "<fn w/o ext>", "save file name"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
if (!has_name) errors = true;
bool as_wave = arg_get_lit(ctx, 1);
if (errors || cmdp == 0) return usage_data_save();
int fnlen = 0;
char filename[FILE_PATH_SIZE] = {0};
// CLIGetStrWithReturn(ctx, 2, (uint8_t *)filename, &fnlen);
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", "<float>", "sets timescale factor according to sampling rate"),
arg_str0("u", "unit", "<string>", "time unit to display (max 10 chars)"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
CursorScaleFactor = arg_get_dbl_def(ctx, 1, 1);
if (CursorScaleFactor <= 0) {
PrintAndLogEx(FAILED, "bad, can't have negative or zero 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, "<digits> -- Converts binary to hexadecimal"},
{"bitsamples", CmdBitsamples, IfPm3Present, "Get raw samples as bitstring"},
{"buffclear", CmdBuffClear, AlwaysAvailable, "Clears bigbuff on deviceside and graph window"},
{"convertbitstream", CmdConvertBitStream, AlwaysAvailable, "Convert GraphBuffer's 0/1 values to 127 / -127"},
{"dec", CmdDec, AlwaysAvailable, "Decimate samples"},
{"detectclock", CmdDetectClockRate, AlwaysAvailable, "[<a|f|n|p>] Detect ASK, FSK, NRZ, PSK clock rate of wave in GraphBuffer"},
{"-----------", 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)"},
{"getbitstream", CmdGetBitStream, AlwaysAvailable, "Convert GraphBuffer's >=1 values to 1 and <1 to 0"},
{"grid", CmdGrid, AlwaysAvailable, "<x> <y> -- overlay grid on graph window, use zero value to turn off either"},
{"hexsamples", CmdHexsamples, IfPm3Present, "<bytes> [<offset>] -- Dump big buffer as hex bytes"},
{"hex2bin", Cmdhex2bin, AlwaysAvailable, "<hexadecimal> -- Converts hexadecimal to binary"},
{"manrawdecode", Cmdmandecoderaw, AlwaysAvailable, "Manchester decode binary stream in DemodBuffer"},
{"modulation", CmdDataModulationSearch, AlwaysAvailable, "Identify LF signal for clock and modulation"},
{"rawdemod", CmdRawDemod, AlwaysAvailable, "Demodulate the data in the GraphBuffer and output binary"},
{"-----------", CmdHelp, AlwaysAvailable, "------------------------- " _CYAN_("Graph") "-------------------------"},
{"askedgedetect", CmdAskEdgeDetect, AlwaysAvailable, "[threshold] Adjust Graph for manual ASK demod using the length of sample differences to detect the edge of a wave (use 20-45, def:25)"},
{"autocorr", CmdAutoCorr, AlwaysAvailable, "Autocorrelation over window"},
{"dirthreshold", CmdDirectionalThreshold, AlwaysAvailable, "<thres up> <thres down> -- Max rising higher up-thres/ Min falling lower down-thres, keep rest as prev."},
{"decimate", CmdDecimate, AlwaysAvailable, "Decimate samples"},
{"undecimate", CmdUndecimate, AlwaysAvailable, "Un-decimate samples"},
{"hide", CmdHide, AlwaysAvailable, "Hide graph window"},
{"hpf", CmdHpf, AlwaysAvailable, "Remove DC offset from trace"},
{"load", CmdLoad, AlwaysAvailable, "<filename> -- Load trace (to graph window"},
{"iir", CmdDataIIR, AlwaysAvailable, "apply IIR buttersworth filter on plotdata"},
{"grid", CmdGrid, AlwaysAvailable, "<x> <y> -- overlay grid on graph window, use zero value to turn off either"},
{"ltrim", CmdLtrim, AlwaysAvailable, "<samples> -- Trim samples from left of trace"},
{"rtrim", CmdRtrim, AlwaysAvailable, "<location to end trace> -- Trim samples from right of trace"},
{"mtrim", CmdMtrim, AlwaysAvailable, "<start> <stop> -- Trim out samples from the specified start to the specified stop"},
{"manrawdecode", Cmdmandecoderaw, AlwaysAvailable, "[invert] [maxErr] -- Manchester decode binary stream in DemodBuffer"},
{"norm", CmdNorm, AlwaysAvailable, "Normalize max/min to +/-128"},
{"plot", CmdPlot, AlwaysAvailable, "Show graph window (hit 'h' in window for keystroke help)"},
{"printdemodbuffer", CmdPrintDemodBuff, AlwaysAvailable, "[x] [o] <offset> [l] <length> -- print the data in the DemodBuffer - 'x' for hex output"},
{"rawdemod", CmdRawDemod, AlwaysAvailable, "[modulation] ... <options> -see help (h option) -- Demodulate the data in the GraphBuffer and output binary"},
{"samples", CmdSamples, IfPm3Present, "[512 - 40000] -- Get raw samples for graph window (GraphBuffer)"},
{"save", CmdSave, AlwaysAvailable, "Save trace (from graph window)"},
{"rtrim", CmdRtrim, AlwaysAvailable, "<location to end trace> -- Trim samples from right of trace"},
{"setgraphmarkers", CmdSetGraphMarkers, AlwaysAvailable, "[orange_marker] [blue_marker] (in graph window)"},
{"scale", CmdScale, AlwaysAvailable, "<int> -- Set cursor display scale in carrier frequency expressed in kHz"},
{"setdebugmode", CmdSetDebugMode, AlwaysAvailable, "<0|1|2> -- Set Debugging Level on client side"},
{"shiftgraphzero", CmdGraphShiftZero, AlwaysAvailable, "<shift> -- Shift 0 for Graphed wave + or - shift value"},
{"dirthreshold", CmdDirectionalThreshold, AlwaysAvailable, "<thres up> <thres down> -- Max rising higher up-thres/ Min falling lower down-thres, keep rest as prev."},
{"tune", CmdTuneSamples, IfPm3Present, "Get hw tune samples for graph window"},
{"undec", CmdUndec, AlwaysAvailable, "Un-decimate samples by 2"},
{"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"},
{"iir", CmdDataIIR, AlwaysAvailable, "apply IIR buttersworth filter on plotdata"},
{"convertbitstream", CmdConvertBitStream, AlwaysAvailable, "Convert GraphBuffer's 0/1 values to 127 / -127"},
{"getbitstream", CmdGetBitStream, AlwaysAvailable, "Convert GraphBuffer's >=1 values to 1 and <1 to 0"},
{"-----------", CmdHelp, AlwaysAvailable, "------------------------- " _CYAN_("General") "-------------------------"},
{"bin2hex", Cmdbin2hex, AlwaysAvailable, "Converts binary to hexadecimal"},
{"bitsamples", CmdBitsamples, IfPm3Present, "Get raw samples as bitstring"},
{"clear", CmdBuffClear, AlwaysAvailable, "Clears bigbuf on deviceside and graph window"},
{"hexsamples", CmdHexsamples, IfPm3Present, "<bytes> [<offset>] -- Dump big buffer as hex bytes"},
{"hex2bin", Cmdhex2bin, AlwaysAvailable, "Converts hexadecimal to binary"},
{"load", CmdLoad, AlwaysAvailable, "Load contents of file into graph window"},
{"ndef", CmdDataNDEF, AlwaysAvailable, "Decode NDEF records"},
{"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}
};

View file

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

View file

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

View file

@ -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*)&param, 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 ((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 or 4K";
tip = "-> MIFARE Plus X 2K/4K (SL3)";
} else if (memcmp(card.ats + pos, "\xC1\x05\x2F\x2F\x00\x35\xC7", 7) == 0) {
tip = "-> MIFARE Plus S 2K or 4K";
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;

View file

@ -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,20 +105,24 @@ 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) {
@ -108,7 +130,6 @@ 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"
);
@ -117,16 +138,22 @@ static int CmdHF14BSim(const char *Cmd) {
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;
}
@ -161,27 +188,26 @@ 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("r", "noresponse", "do not read response from card"),
arg_int0("t", "timeout", "<dec>", "timeout in ms"),
arg_lit0("v", "verbose", "verbose"),
arg_strx0(NULL, NULL, "<data (hex)>", "bytes to send"),
arg_strx0("d", "data", "<hex>", "data, bytes to send"),
arg_param_end
};
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;
@ -585,7 +627,7 @@ static void print_ct_general_info(void *vcard) {
iso14b_cts_card_select_t card;
memcpy(&card, (iso14b_cts_card_select_t *)vcard, sizeof(iso14b_cts_card_select_t));
uint32_t uid32 = (card.uid[0] |card.uid[1] << 8 |card.uid[2] << 16 | card.uid[3] << 24);
uint32_t uid32 = (card.uid[0] | card.uid[1] << 8 | card.uid[2] << 16 | card.uid[3] << 24);
PrintAndLogEx(SUCCESS, "ASK C-Ticket");
PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s") " ( " _YELLOW_("%010u") " )", sprint_hex(card.uid, sizeof(card.uid)), uid32);
PrintAndLogEx(SUCCESS, " Product Code: %02X", card.pc);
@ -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;
}
@ -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;
}
@ -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;
@ -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", "<head (CLA INS P1 P2) hex>", "make apdu with head from this field and data from data field. Must be 4 bytes length: <CLA INS P1 P2>"),
arg_str0("m", "make", "<hex>", "make apdu with head from this field and data from data field. Must be 4 bytes length: <CLA INS P1 P2>"),
arg_lit0("e", "extended", "make extended length apdu if `m` parameter included"),
arg_int0("l", "le", "<Le (int)>", "Le apdu parameter if `m` parameter included"),
arg_strx1(NULL, NULL, "<APDU (hex) | data (hex)>", "data if `m` parameter included"),
arg_int0("l", "le", "<int>", "Le apdu parameter if `m` parameter included"),
arg_strx1(NULL, "hex", "<hex>", "<APDU | data> if `m` parameter included"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);

View file

@ -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 <UID>\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 <uid|u|*> <afi>\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] <uid|s|u|*> <page>\n"
PrintAndLogEx(NORMAL, "Usage: hf 15 rdbl [options] <uid|s|u|*> <page>\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] <uid|s|u|*> <page> <hexdata>\n"
PrintAndLogEx(NORMAL, "Usage: hf 15 wrbl [options] <uid|s|u|*> <page> <hexdata>\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 <count> 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 <uid>\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"},

View file

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

View file

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

View file

@ -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) {
@ -904,11 +924,12 @@ 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."},
{"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}
};

File diff suppressed because it is too large Load diff

View file

@ -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[] = {

View file

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

View file

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

View file

@ -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);
}
/*

View file

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

View file

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

View file

@ -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 <key number>");
PrintAndLogEx(NORMAL, " 0 (default): 3DES standard key");
PrintAndLogEx(NORMAL, " 1 : all 0x00 key");
PrintAndLogEx(NORMAL, " 2 : 0x00-0x0F key");
PrintAndLogEx(NORMAL, " 3 : nfc key");
PrintAndLogEx(NORMAL, " 4 : all 0x01 key");
PrintAndLogEx(NORMAL, " 5 : all 0xff key");
PrintAndLogEx(NORMAL, " 6 : 0x00-0xFF key");
PrintAndLogEx(NORMAL, "Tests 3DES password on Mifare Ultralight-C tag.");
PrintAndLogEx(NORMAL, "If password is not specified, a set of known defaults will be tested.");
PrintAndLogEx(NORMAL, "Usage: hf mfu cauth [k] <password (32 hex symbols)>");
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 <time> : (optional) start time to run the test - default 0 us");
PrintAndLogEx(NORMAL, " d <data> : (optional) data to full-write before trying the OTP test - default 0x00");
PrintAndLogEx(NORMAL, " t <data> : (optional) data to write while running the OTP test - default 0x00");
PrintAndLogEx(NORMAL, " m <data> : (optional) exit criteria, if block matches this value");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " hf mfu otptear b 3");
PrintAndLogEx(NORMAL, " hf mfu otptear b 8 i 100 l 3000 s 1000");
PrintAndLogEx(NORMAL, " hf mfu otptear b 3 i 1 l 200");
PrintAndLogEx(NORMAL, " hf mfu otptear b 3 i 100 l 2500 s 200 d FFFFFFFF t EEEEEEEE");
PrintAndLogEx(NORMAL, " hf mfu otptear b 3 i 100 l 2500 s 200 d FFFFFFFF t EEEEEEEE m 00000000 -> such quite when OTP is reset");
return PM3_SUCCESS;
}
@ -344,21 +344,28 @@ static int ul_send_cmd_raw(uint8_t *cmd, uint8_t cmdlen, uint8_t *response, uint
return resplen;
}
static int ul_select(iso14a_card_select_t *card) {
static bool ul_select(iso14a_card_select_t *card) {
ul_switch_on_field();
PacketResponseNG resp;
bool ans = WaitForResponseTimeout(CMD_ACK, &resp, 1500);
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500) == false) {
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
DropField();
return false;
} else {
if (!ans || resp.oldarg[0] < 1) {
uint16_t len = (resp.oldarg[1] & 0xFFFF);
if (len == 0) {
PrintAndLogEx(WARNING, "iso14443a card select failed");
DropField();
return 0;
return false;
}
if (card)
memcpy(card, resp.data.asBytes, sizeof(iso14a_card_select_t));
return 1;
}
return true;
}
// This read command will at least return 16bytes.
@ -408,6 +415,18 @@ static int ulc_authentication(uint8_t *key, bool switch_off_field) {
return 0;
}
static int try_default_3des_keys(uint8_t **correct_key) {
PrintAndLogEx(INFO, "Trying some default 3des keys");
for (uint8_t i = 0; i < ARRAYLEN(default_3des_keys); ++i) {
uint8_t *key = default_3des_keys[i];
if (ulc_authentication(key, true)) {
*correct_key = key;
return 1;
}
}
return 0;
}
static int ulev1_requestAuthentication(uint8_t *pwd, uint8_t *pack, uint16_t packLength) {
uint8_t cmd[] = {MIFARE_ULEV1_AUTH, pwd[0], pwd[1], pwd[2], pwd[3]};
@ -868,13 +887,13 @@ static int ulev1_print_counters(void) {
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Counters"));
uint8_t tear[1] = {0};
uint8_t counter[3] = {0, 0, 0};
uint16_t len = 0;
int len = 0;
for (uint8_t i = 0; i < 3; ++i) {
ulev1_readTearing(i, tear, sizeof(tear));
len = ulev1_readCounter(i, counter, sizeof(counter));
if (len == 3) {
PrintAndLogEx(INFO, " [%0d]: %s", i, sprint_hex(counter, 3));
PrintAndLogEx(SUCCESS, " - %02X tearing (" _GREEN_("%s") ")", tear[0], (tear[0] == 0xBD) ? "ok" : "failure");
PrintAndLogEx(SUCCESS, " - %02X tearing (%s)", tear[0], (tear[0] == 0xBD) ? _GREEN_("ok") : _RED_("failure"));
}
}
return len;
@ -1016,11 +1035,10 @@ static int ulc_magic_test(){
iso14a_card_select_t card;
uint8_t nonce1[11] = {0x00};
uint8_t nonce2[11] = {0x00};
int status = ul_select(&card);
if ( !status ){
if ( !ul_select(&card) ){
return UL_ERROR;
}
status = ulc_requestAuthentication(nonce1, sizeof(nonce1));
int status = ulc_requestAuthentication(nonce1, sizeof(nonce1));
if ( status > 0 ) {
status = ulc_requestAuthentication(nonce2, sizeof(nonce2));
returnValue = ( !memcmp(nonce1, nonce2, 11) ) ? UL_C_MAGIC : UL_C;
@ -1317,16 +1335,11 @@ static int CmdHF14AMfUInfo(const char *Cmd) {
if (hasAuthKey) return PM3_SUCCESS;
// also try to diversify default keys.. look into CmdHF14AMfGenDiverseKeys
PrintAndLogEx(INFO, "Trying some default 3des keys");
for (uint8_t i = 0; i < ARRAYLEN(default_3des_keys); ++i) {
key = default_3des_keys[i];
if (ulc_authentication(key, true)) {
if (try_default_3des_keys(&key)) {
PrintAndLogEx(SUCCESS, "Found default 3des key: ");
uint8_t keySwap[16];
memcpy(keySwap, SwapEndian64(key, 16, 8), 16);
ulc_print_3deskey(keySwap);
return PM3_SUCCESS;
}
}
return PM3_SUCCESS;
}
@ -1614,7 +1627,7 @@ static int CmdHF14AMfUWrBl(const char *Cmd) {
PrintAndLogEx(WARNING, "Command execute timeout");
}
return 0;
return PM3_SUCCESS;
}
//
// Read Single Block
@ -2389,28 +2402,39 @@ static int CmdHF14AMfUSim(const char *Cmd) {
//-------------------------------------------------------------------------------
//
// Ultralight C Authentication Demo {currently uses hard-coded key}
// Ultralight C Authentication
//
static int CmdHF14AMfUCAuth(const char *Cmd) {
uint8_t keyNo = 3;
bool errors = false;
char cmdp = tolower(param_getchar(Cmd, 0));
//Change key to user defined one
if (cmdp == 'k') {
keyNo = param_get8(Cmd, 1);
if (keyNo >= ARRAYLEN(default_3des_keys))
errors = true;
uint8_t cmdp = 0;
char c = tolower(param_getchar(Cmd, 0));
if (c == 'h') {
return usage_hf_mfu_ucauth();
}
bool keep_field_on = false;
if (c == 'k') {
keep_field_on = true;
cmdp++;
}
if (cmdp == 'h') errors = true;
uint8_t key_buf[16];
uint8_t *key;
int succeeded;
if (errors) return usage_hf_mfu_ucauth();
// If no hex key is specified, try all known ones
if (strlen(Cmd + cmdp) == 0) {
succeeded = try_default_3des_keys(&key);
// Else try user-supplied
} else {
if (param_gethex(Cmd, cmdp, key_buf, 32)) {
PrintAndLogEx(WARNING, "Password must include 32 HEX symbols");
return PM3_EINVARG;
}
succeeded = ulc_authentication(key_buf, ! keep_field_on);
key = key_buf;
}
uint8_t *key = default_3des_keys[keyNo];
if (ulc_authentication(key, true))
if (succeeded)
PrintAndLogEx(SUCCESS, "Authentication successful. 3des key: %s", sprint_hex(key, 16));
else
PrintAndLogEx(WARNING, "Authentication failed");
@ -2809,7 +2833,8 @@ static int CmdHF14AMfUPwdGen(const char *Cmd) {
static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
uint8_t blockNoUint = 8;
uint8_t cmdp = 0;
bool errors = 0;
bool errors = 0, use_match = false;
uint8_t match[4] = {0x00};
uint8_t teardata[8] = {0x00};
uint32_t interval = 500; // time in us
uint32_t timeLimit = 3000; // time in us
@ -2821,7 +2846,6 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
return usage_hf_mfu_otp_tearoff();
case 'b':
blockNoUint = param_get8(Cmd, cmdp + 1);
//iceman, which blocks can be targeted? UID blocks?
if (blockNoUint < 2) {
PrintAndLogEx(WARNING, "Wrong block number");
errors = true;
@ -2830,10 +2854,6 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
break;
case 'i':
interval = param_get32ex(Cmd, cmdp + 1, interval, 10);
if (interval == 0) {
PrintAndLogEx(WARNING, "Wrong interval number");
errors = true;
}
cmdp += 2;
break;
case 'l':
@ -2842,6 +2862,10 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
PrintAndLogEx(WARNING, "Wrong time limit number");
errors = true;
}
if (timeLimit > 43000) {
PrintAndLogEx(WARNING, "You can't set delay out of 1..43000 range!");
errors = true;
}
cmdp += 2;
break;
case 's':
@ -2866,6 +2890,14 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
}
cmdp += 2;
break;
case 'm':
if (param_gethex(Cmd, cmdp + 1, match, 8)) {
PrintAndLogEx(WARNING, "Block data must include 8 HEX symbols");
errors = true;
}
use_match = true;
cmdp += 2;
break;
default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
@ -2875,52 +2907,120 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
if (errors) return usage_hf_mfu_otp_tearoff();
PrintAndLogEx(INFO, "Starting TearOff test - Selected Block no: %u", blockNoUint);
PrintAndLogEx(INFO, "----------------- " _CYAN_("MFU Tear off") " ---------------------");
PrintAndLogEx(INFO, "Starting Tear-off test");
PrintAndLogEx(INFO, "Target block no: %u", blockNoUint);
PrintAndLogEx(INFO, "Target inital block data : %s", sprint_hex_inrow(teardata, 4));
PrintAndLogEx(INFO, "Target write block data : %s", sprint_hex_inrow(teardata + 4, 4));
PrintAndLogEx(INFO, "----------------------------------------------------");
uint8_t isOK;
bool got_pre = false, got_post = false, lock_on = false;
uint8_t pre[4] = {0};
uint8_t post[4] = {0};
uint32_t actualTime = startTime;
int phase_clear = -1;
int phase_newwr = -1;
uint8_t retries = 0;
while (actualTime <= (timeLimit - interval)) {
PrintAndLogEx(INFO, "Using tear-off at: %" PRIu32 " us", actualTime);
PrintAndLogEx(INFO, "Reading block BEFORE attack");
if (kbd_enter_pressed()) {
PrintAndLogEx(INFO, "\naborted via keyboard!\n");
break;
}
PrintAndLogEx(INFO, "Using tear-off delay " _GREEN_("%" PRIu32) " us", actualTime);
clearCommandBuffer();
SendCommandMIX(CMD_HF_MIFAREU_READBL, blockNoUint, 0, 0, NULL, 0);
PacketResponseNG resp;
got_pre = false;
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
uint8_t isOK = resp.oldarg[0] & 0xff;
isOK = resp.oldarg[0] & 0xFF;
if (isOK) {
uint8_t *d = resp.data.asBytes;
PrintAndLogEx(NORMAL, "\nBlock# | Data | Ascii");
PrintAndLogEx(NORMAL, "-----------------------------");
PrintAndLogEx(NORMAL, "%02d/0x%02X | %s| %s\n", blockNoUint, blockNoUint, sprint_hex(d, 4), sprint_ascii(d, 4));
memcpy(pre, resp.data.asBytes, sizeof(pre));
got_pre = true;
}
}
PrintAndLogEx(INFO, ".....");
clearCommandBuffer();
SendCommandMIX(CMD_HF_MFU_OTP_TEAROFF, blockNoUint, actualTime, 0, teardata, 8);
if (!WaitForResponseTimeout(CMD_HF_MFU_OTP_TEAROFF, &resp, 4000)) {
// we be getting ACK that we are silently ignoring here..
if (!WaitForResponseTimeout(CMD_HF_MFU_OTP_TEAROFF, &resp, 2000)) {
PrintAndLogEx(WARNING, "Failed");
return PM3_ESOFT;
}
PrintAndLogEx(INFO, "Reading block AFTER attack");
if (resp.status != PM3_SUCCESS) {
PrintAndLogEx(WARNING, "Tear off reporting failure to select tag");
continue;
}
got_post = false;
clearCommandBuffer();
SendCommandMIX(CMD_HF_MIFAREU_READBL, blockNoUint, 0, 0, NULL, 0);
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
uint8_t isOK = resp.oldarg[0] & 0xff;
isOK = resp.oldarg[0] & 0xFF;
if (isOK) {
uint8_t *d = resp.data.asBytes;
PrintAndLogEx(NORMAL, "\nBlock# | Data | Ascii");
PrintAndLogEx(NORMAL, "-----------------------------");
PrintAndLogEx(NORMAL, "%02d/0x%02X | %s| %s\n", blockNoUint, blockNoUint, sprint_hex(d, 4), sprint_ascii(d, 4));
memcpy(post, resp.data.asBytes, sizeof(post));
got_post = true;
}
}
if (got_pre && got_post) {
char prestr[20] = {0};
snprintf(prestr, sizeof(prestr), "%s", sprint_hex_inrow(pre, sizeof(pre)));
char poststr[20] = {0};
snprintf(poststr, sizeof(poststr), "%s", sprint_hex_inrow(post, sizeof(post)));
if (memcmp(pre, post, sizeof(pre)) == 0) {
PrintAndLogEx(INFO, "Current %02d (0x%02X) %s"
, blockNoUint
, blockNoUint
, poststr
);
} else {
// skip first message, since its the reset write.
if (actualTime == startTime) {
PrintAndLogEx(INFO, "Inital write");
} else {
PrintAndLogEx(INFO, _CYAN_("Tear off occured") " : %02d (0x%02X) %s vs " _RED_("%s")
, blockNoUint
, blockNoUint
, prestr
, poststr
);
lock_on = true;
if (phase_clear == -1)
phase_clear = actualTime;
// new write phase must be atleast 100us later..
if (phase_clear > -1 && phase_newwr == -1 && actualTime > (phase_clear + 100))
phase_newwr = actualTime;
}
}
if (use_match && memcmp(pre, match, sizeof(pre)) == 0) {
PrintAndLogEx(SUCCESS, "Block matches!\n");
break;
}
} else {
if (got_pre == false)
PrintAndLogEx(FAILED, "Failed to read block BEFORE");
if (got_post == false)
PrintAndLogEx(FAILED, "Failed to read block AFTER");
}
/* TEMPORALLY DISABLED
uint8_t d0, d1, d2, d3;
d0 = *resp.data.asBytes;
@ -2933,10 +3033,426 @@ static int CmdHF14AMfuOtpTearoff(const char *Cmd) {
PrintAndLogEx(NORMAL, "---------------------------------\n");
}
*/
if (startTime != timeLimit) {
actualTime += interval;
} else {
if (lock_on == false) {
if (++retries == 20) {
actualTime++;
timeLimit++;
startTime++;
retries = 0;
PrintAndLogEx(INFO, _CYAN_("Retried %u times, increased delay with 1us"), retries);
}
}
}
}
PrintAndLogEx(INFO, "----------------------------------------------------");
if (phase_clear > - 1) {
PrintAndLogEx(INFO, "New phase boundary around " _YELLOW_("%d") " us", phase_clear);
}
if (phase_newwr > - 1) {
PrintAndLogEx(INFO, "New phase boundary around " _YELLOW_("%d") " us", phase_newwr);
}
PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS;
}
/*
static int counter_reset_tear(iso14a_card_select_t *card, uint8_t cnt_no) {
PrintAndLogEx(INFO, "Reset tear check");
uint8_t cw[6] = { MIFARE_ULEV1_INCR_CNT, cnt_no, 0x00, 0x00, 0x00, 0x00};
uint8_t ct[1] = {0};
uint8_t resp[10] = {0};
if (ul_select(card) == false) {
PrintAndLogEx(FAILED, "failed to select card, exiting...");
return PM3_ESOFT;
}
if (ul_send_cmd_raw(cw, sizeof(cw), resp, sizeof(resp)) < 0) {
PrintAndLogEx(FAILED, "failed to write all ZEROS");
return PM3_ESOFT;
}
if (ulev1_readTearing(cnt_no, ct, sizeof(ct)) < 0) {
PrintAndLogEx(FAILED, "AFTER, failed to read ANTITEAR, exiting...");
return PM3_ESOFT;
}
DropField();
if (ct[0] != 0xBD) {
PrintAndLogEx(INFO, "Resetting seem to have failed, WHY!?");
return PM3_ESOFT;
}
return PM3_SUCCESS;
}
*/
/*
static int CmdHF14AMfuEv1CounterTearoff(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf mfu countertear",
"Tear-off test against a Ev1 counter",
"hf mfu countertear\n"
"hf mfu countertear -s 200 -l 2500 -> target counter 0, start delay 200\n"
"hf mfu countertear -i 2 -s 200 -l 400 -> target counter 0, start delay 200\n"
);
void *argtable[] = {
arg_param_begin,
arg_int0("c", "cnt", "<0,1,2>", "Target this EV1 counter (0,1,2)"),
arg_int0("i", "inc", "<dec>", "time interval to increase in each iteration - default 10 us"),
arg_int0("l", "limit", "<dec>", "test upper limit time - default 3000 us"),
arg_int0("s", "start", "<dec>", "test start time - default 0 us"),
arg_int0(NULL, "fix", "<dec>", "test fixed loop delay"),
arg_str0("x", "hex", NULL, "3 byte hex to increase counter with"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
int interval = 0;
int time_limit, start_time = 0;
int counter = arg_get_int_def(ctx, 1, 0);
int fixed = arg_get_int_def(ctx, 5, -1);
if ( fixed == -1 ) {
interval = arg_get_int_def(ctx, 2, 10);
time_limit = arg_get_int_def(ctx, 3, 3000);
start_time = arg_get_int_def(ctx, 4, 0);
} else {
start_time = fixed;
interval = 0;
time_limit = fixed;
}
uint8_t newvalue[5] = {0};
int newvaluelen = 0;
CLIGetHexWithReturn(ctx, 6, newvalue, &newvaluelen);
CLIParserFree(ctx);
// Validations
if (start_time > (time_limit - interval)) {
PrintAndLogEx(WARNING, "Wrong start time number");
return PM3_EINVARG;
}
if (time_limit < interval) {
PrintAndLogEx(WARNING, "Wrong time limit number");
return PM3_EINVARG;
}
if (time_limit > 43000) {
PrintAndLogEx(WARNING, "You can't set delay out of 1..43000 range!");
return PM3_EINVARG;
}
uint8_t cnt_no = 0;
if (counter < 0 || counter > 2) {
PrintAndLogEx(WARNING, "Counter must 0, 1 or 2");
return PM3_EINVARG;
}
cnt_no = (uint8_t)counter;
iso14a_card_select_t card;
// reset counter tear
counter_reset_tear(&card, cnt_no);
if (ul_select(&card) == false) {
PrintAndLogEx(INFO, "failed to select card, exiting...");
return PM3_ESOFT;
}
uint8_t inital_cnt[3] = {0, 0, 0};
int len = ulev1_readCounter(cnt_no, inital_cnt, sizeof(inital_cnt));
if ( len != sizeof(inital_cnt) ) {
PrintAndLogEx(WARNING, "failed to read counter");
return PM3_ESOFT;
}
uint8_t inital_tear[1] = {0};
len = ulev1_readTearing(cnt_no, inital_tear, sizeof(inital_tear));
DropField();
if ( len != sizeof(inital_tear) ) {
PrintAndLogEx(WARNING, "failed to read ANTITEAR, exiting... %d", len);
return PM3_ESOFT;
}
uint32_t wr_value = ( newvalue[0] | newvalue[1] << 8 | newvalue[2] << 16 );
uint32_t inital_value = ( inital_cnt[0] | inital_cnt[1] << 8 | inital_cnt[2] << 16 );;
PrintAndLogEx(INFO, "----------------- " _CYAN_("MFU Ev1 Counter Tear off") " ---------------------");
PrintAndLogEx(INFO, "Target counter no [ " _GREEN_("%u") " ]", counter);
PrintAndLogEx(INFO, " counter value [ " _GREEN_("%s") " ]", sprint_hex_inrow(inital_cnt, sizeof(inital_cnt)));
PrintAndLogEx(INFO, " anti-tear value [ " _GREEN_("%02X") " ]", inital_tear[0]);
PrintAndLogEx(INFO, " increase value [ " _GREEN_("%s") " ]", sprint_hex_inrow(newvalue, newvaluelen));
PrintAndLogEx(INFO, "----------------------------------------------------");
uint8_t pre_tear = 0, post_tear = 0;
uint8_t pre[3] = {0};
uint8_t post[3] = {0};
uint32_t actual_time = start_time;
uint32_t a = 0, b = 0;
uint32_t loop = 0;
uint16_t late = 0;
while (actual_time <= (time_limit - interval)) {
DropField();
loop++;
if (kbd_enter_pressed()) {
PrintAndLogEx(INFO, "\naborted via keyboard!\n");
break;
}
PrintAndLogEx(INPLACE, "Using tear-off delay " _GREEN_("%" PRIu32) " us (attempt %u)", actual_time, loop);
if (ul_select(&card) == false) {
PrintAndLogEx(FAILED, "BEFORE, failed to select card, looping...");
continue;
}
uint8_t cntresp[3] = {0, 0, 0};
int rlen = ulev1_readCounter(cnt_no, cntresp, sizeof(cntresp));
if ( rlen == sizeof(cntresp) ) {
memcpy(pre, cntresp, sizeof(pre));
} else {
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(FAILED, "BEFORE, failed to read COUNTER, exiting...");
break;
}
uint8_t tear[1] = {0};
int tlen = ulev1_readTearing(cnt_no, tear, sizeof(tear));
if ( tlen == sizeof(tear) ) {
pre_tear = tear[0];
} else {
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(FAILED, "BEFORE, failed to read ANTITEAR, exiting... %d", tlen);
break;
}
DropField();
struct p {
uint8_t counter;
uint32_t tearoff_time;
uint8_t value[3];
} PACKED payload;
payload.counter = cnt_no;
payload.tearoff_time = actual_time;
memcpy(payload.value, newvalue, sizeof(payload.value));
clearCommandBuffer();
PacketResponseNG resp;
SendCommandNG(CMD_HF_MFU_COUNTER_TEAROFF, (uint8_t*)&payload, sizeof(payload));
if (!WaitForResponseTimeout(CMD_HF_MFU_COUNTER_TEAROFF, &resp, 2000)) {
PrintAndLogEx(WARNING, "\ntear off command failed");
continue;
}
if (ul_select(&card) == false) {
PrintAndLogEx(FAILED, "AFTER, failed to select card, exiting...");
break;
}
rlen = ulev1_readCounter(cnt_no, cntresp, sizeof(cntresp));
if ( rlen == sizeof(cntresp) ) {
memcpy(post, cntresp, sizeof(post));
} else {
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(FAILED, "AFTER, failed to read COUNTER, exiting...");
break;
}
tear[0] = 0;
tlen = ulev1_readTearing(cnt_no, tear, sizeof(tear));
if ( tlen == sizeof(tear) ) {
post_tear = tear[0];
} else {
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(FAILED, "AFTER, failed to read ANTITEAR, exiting...");
break;
}
DropField();
char prestr[20] = {0};
snprintf(prestr, sizeof(prestr), "%s", sprint_hex_inrow(pre, sizeof(pre)));
char poststr[20] = {0};
snprintf(poststr, sizeof(poststr), "%s", sprint_hex_inrow(post, sizeof(post)));
bool post_tear_check = (post_tear == 0xBD);
a = (pre[0] | pre[1] << 8 | pre[2] << 16);
b = (post[0] | post[1] << 8 | post[2] << 16);
// A != B
if (memcmp(pre, post, sizeof(pre)) != 0) {
PrintAndLogEx(NORMAL, "");
if (inital_value != a ) {
if ( inital_value != b )
PrintAndLogEx(INFO, "pre %08x, post %08x != inital %08x | tear: 0x%02X == 0x%02X", a, b, inital_value, pre_tear, post_tear);
else
PrintAndLogEx(INFO, "pre %08x != inital and post %08x == inital %08x | tear: 0x%02X == 0x%02X", a, b, inital_value, pre_tear, post_tear);
} else {
if ( inital_value != b )
PrintAndLogEx(INFO, "pre %08x == inital and post %08x != inital %08x | tear: 0x%02X == 0x%02X", a, b, inital_value, pre_tear, post_tear);
}
if ( b == 0 ) {
PrintAndLogEx(INFO, _CYAN_("Tear off occured (ZEROS value!) -> ") "%s vs " _GREEN_("%s") " Tear status: 0x%02X == 0x%02X ( %s )"
, prestr
, poststr
, pre_tear
, post_tear
, post_tear_check ? _GREEN_("OK") : _RED_("DETECTED")
);
break;
}
if ( a > b ) {
PrintAndLogEx(INFO, _CYAN_("Tear off occured " _RED_("( LESS )") " -> ") "%s vs " _GREEN_("%s") " Tear status: 0x%02X == 0x%02X ( %s )"
, prestr
, poststr
, pre_tear
, post_tear
, post_tear_check ? _GREEN_("OK") : _RED_("DETECTED")
);
if (counter_reset_tear(&card, cnt_no) != PM3_SUCCESS){
PrintAndLogEx(FAILED, "failed to reset tear, exiting...");
break;
}
uint32_t bar = (0x1000000 - b) + 2;
// wr_value = bar;
// newvalue[0] = (bar) & 0xFF;
// newvalue[1] = ((bar >> 8) & 0xFF);
// newvalue[2] = ((bar >> 16) & 0xFF);
wr_value = 0;
newvalue[0] = 0;
newvalue[1] = 0;
newvalue[2] = 0;
PrintAndLogEx(INFO, " 0x1000000 - 0x%x == 0x%x", b, bar);
PrintAndLogEx(INFO, " new increase value 0x%x" , wr_value);
PrintAndLogEx(INFO, " because BAR + post == 0x%x" , bar + b);
PrintAndLogEx(INFO, "New increase value " _YELLOW_("%s"), sprint_hex_inrow(newvalue, newvaluelen));
continue;
} else {
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, _CYAN_("Tear off occured (+1) (too late) -> ") "%s vs %s Tear: 0x%02X == 0x%02X ( %s )"
, prestr
, poststr
, pre_tear
, post_tear
, post_tear_check ? _GREEN_("OK") : _RED_("DETECTED")
);
if ( post_tear_check && b == inital_value) {
PrintAndLogEx(INFO, "Reverted to previous value");
break;
}
if ( wr_value != 0 ) {
//uint32_t bar = (0x1000000 - b) + 2;
wr_value = 0;
newvalue[0] = 0;
newvalue[1] = 0;
newvalue[2] = 0;
if ( b >= (inital_value + (2 * wr_value))) {
PrintAndLogEx(INFO, "Large " _YELLOW_("( JUMP )") " detected");
// wr_value = bar;
// newvalue[0] = (bar) & 0xFF;
// newvalue[1] = ((bar >> 8) & 0xFF);
// newvalue[2] = ((bar >> 16) & 0xFF);
} else {
// wr_value = bar;
// newvalue[0] = (bar) & 0xFF;
// newvalue[1] = ((bar >> 8) & 0xFF);
// newvalue[2] = ((bar >> 16) & 0xFF);
// wr_value = 0;
// newvalue[0] = 0;
// newvalue[1] = 0;
// newvalue[2] = 0;
}
}
PrintAndLogEx(INFO, "New increase value " _YELLOW_("%s"), sprint_hex_inrow(newvalue, newvaluelen));
//actual_time--;
late++;
}
} else {
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(INFO, _CYAN_("Status: same value! -> ") "%s == %s Tear: 0x%02X == 0x%02X ( %s )"
, prestr
, poststr
, pre_tear
, post_tear
, post_tear_check ? _GREEN_("OK") : _RED_("DETECTED")
);
if ( post_tear_check ) {
if ( a == b ) {
//actual_time--;
continue;
}
if ( b == inital_value ) {
PrintAndLogEx(INFO, "Reverted to previous value");
break;
}
} else {
if (counter_reset_tear(&card, cnt_no) != PM3_SUCCESS){
PrintAndLogEx(FAILED, "failed to reset tear, exiting...");
break;
}
}
}
actual_time += interval;
}
DropField();
PrintAndLogEx(INFO, " Sent %u tear offs ", loop);
counter_reset_tear(&card, cnt_no);
PrintAndLogEx(INFO, "hf 14a raw -s -c 3900 --> read counter 0");
PrintAndLogEx(INFO, "hf 14a raw -s -c 3e00 --> read tearing 0");
PrintAndLogEx(NORMAL, "");
char read_cnt_str[30];
sprintf(read_cnt_str, "hf 14a raw -s -c 39%02x", counter);
CommandReceived(read_cnt_str);
char read_tear_str[30];
sprintf(read_tear_str, "hf 14a raw -s -c 3e%02x", counter);
CommandReceived(read_tear_str);
return PM3_SUCCESS;
}
*/
static int CmdHF14MfuNDEF(const char *Cmd) {
@ -3068,6 +3584,7 @@ static command_t CommandTable[] = {
{"gen", CmdHF14AMfUGenDiverseKeys, AlwaysAvailable, "Generate 3des mifare diversified keys"},
{"pwdgen", CmdHF14AMfUPwdGen, AlwaysAvailable, "Generate pwd from known algos"},
{"otptear", CmdHF14AMfuOtpTearoff, IfPm3Iso14443a, "Tear-off test on OTP bits"},
// {"countertear", CmdHF14AMfuEv1CounterTearoff, IfPm3Iso14443a, "Tear-off test on Ev1 Counter bits"},
{"ndef", CmdHF14MfuNDEF, IfPm3Iso14443a, "Prints NDEF records from card"},
{NULL, NULL, NULL, NULL}
};

View file

@ -215,15 +215,20 @@ int infoHF_ST(void) {
int aSELECT_AID_n = 0;
param_gethex_to_eol("00a4040007d276000085010100", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n);
int res = ExchangeAPDU14a(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
if (res)
if (res) {
DropField();
return res;
}
if (resplen < 2)
if (resplen < 2) {
DropField();
return PM3_ESOFT;
}
uint16_t sw = get_sw(response, resplen);
if (sw != 0x9000) {
PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField();
return PM3_ESOFT;
}
@ -235,12 +240,15 @@ int infoHF_ST(void) {
int aSELECT_FILE_CC_n = 0;
param_gethex_to_eol("00a4000c02e103", 0, aSELECT_FILE_CC, sizeof(aSELECT_FILE_CC), &aSELECT_FILE_CC_n);
res = ExchangeAPDU14a(aSELECT_FILE_CC, aSELECT_FILE_CC_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
if (res)
if (res) {
DropField();
return res;
}
sw = get_sw(response, resplen);
if (sw != 0x9000) {
PrintAndLogEx(ERR, "Selecting CC file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField();
return PM3_ESOFT;
}
@ -248,12 +256,15 @@ int infoHF_ST(void) {
int aREAD_CC_n = 0;
param_gethex_to_eol("00b000000f", 0, aREAD_CC, sizeof(aREAD_CC), &aREAD_CC_n);
res = ExchangeAPDU14a(aREAD_CC, aREAD_CC_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
if (res)
if (res) {
DropField();
return res;
}
sw = get_sw(response, resplen);
if (sw != 0x9000) {
PrintAndLogEx(ERR, "reading CC file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField();
return PM3_ESOFT;
}
@ -265,12 +276,15 @@ int infoHF_ST(void) {
int aSELECT_FILE_SYS_n = 0;
param_gethex_to_eol("00a4000c02e101", 0, aSELECT_FILE_SYS, sizeof(aSELECT_FILE_SYS), &aSELECT_FILE_SYS_n);
res = ExchangeAPDU14a(aSELECT_FILE_SYS, aSELECT_FILE_SYS_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
if (res)
if (res) {
DropField();
return res;
}
sw = get_sw(response, resplen);
if (sw != 0x9000) {
PrintAndLogEx(ERR, "Selecting system file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField();
return PM3_ESOFT;
}
@ -280,12 +294,15 @@ int infoHF_ST(void) {
int aREAD_SYS_n = 0;
param_gethex_to_eol("00b0000012", 0, aREAD_SYS, sizeof(aREAD_SYS), &aREAD_SYS_n);
res = ExchangeAPDU14a(aREAD_SYS, aREAD_SYS_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
if (res)
if (res) {
DropField();
return res;
}
sw = get_sw(response, resplen);
if (sw != 0x9000) {
PrintAndLogEx(ERR, "reading system file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField();
return PM3_ESOFT;
}
print_st_system_info(response, resplen - 2);
@ -325,8 +342,8 @@ static int cmd_hf_st_sim(const char *Cmd) {
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
CLIGetHexWithReturn(ctx, 1, uid, &uidlen);
CLIParserFree(ctx);
if (uidlen != 7) {
PrintAndLogEx(ERR, "UID must be 7 hex bytes");
@ -350,12 +367,12 @@ static int cmd_hf_st_ndef(const char *Cmd) {
void *argtable[] = {
arg_param_begin,
arg_str0("p", "password", "<hex>", "16 byte read password"),
arg_str0("p", "pwd", "<hex>", "16 byte read password"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, true);
CLIGetHexWithReturn(ctx, 1, pwd, &pwdlen);
CLIParserFree(ctx);
if (pwdlen == 0) {
with_pwd = false;
@ -377,15 +394,20 @@ static int cmd_hf_st_ndef(const char *Cmd) {
int aSELECT_AID_n = 0;
param_gethex_to_eol("00a4040007d276000085010100", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n);
int res = ExchangeAPDU14a(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
if (res)
if (res) {
DropField();
return res;
}
if (resplen < 2)
if (resplen < 2) {
DropField();
return PM3_ESOFT;
}
uint16_t sw = get_sw(response, resplen);
if (sw != 0x9000) {
PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField();
return PM3_ESOFT;
}
@ -397,12 +419,15 @@ static int cmd_hf_st_ndef(const char *Cmd) {
int aSELECT_FILE_NDEF_n = 0;
param_gethex_to_eol("00a4000c020001", 0, aSELECT_FILE_NDEF, sizeof(aSELECT_FILE_NDEF), &aSELECT_FILE_NDEF_n);
res = ExchangeAPDU14a(aSELECT_FILE_NDEF, aSELECT_FILE_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
if (res)
if (res) {
DropField();
return res;
}
sw = get_sw(response, resplen);
if (sw != 0x9000) {
PrintAndLogEx(ERR, "Selecting NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField();
return PM3_ESOFT;
}
@ -412,8 +437,10 @@ static int cmd_hf_st_ndef(const char *Cmd) {
int aVERIFY_n = 0;
param_gethex_to_eol("0020000100", 0, aVERIFY, sizeof(aVERIFY), &aVERIFY_n);
res = ExchangeAPDU14a(aVERIFY, aVERIFY_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
if (res)
if (res) {
DropField();
return res;
}
sw = get_sw(response, resplen);
if (sw == 0x6300) {
@ -421,12 +448,15 @@ static int cmd_hf_st_ndef(const char *Cmd) {
param_gethex_to_eol("0020000110", 0, aVERIFY, sizeof(aVERIFY), &aVERIFY_n);
memcpy(aVERIFY + aVERIFY_n, pwd, pwdlen);
res = ExchangeAPDU14a(aVERIFY, aVERIFY_n + pwdlen, activate_field, keep_field_on, response, sizeof(response), &resplen);
if (res)
if (res) {
DropField();
return res;
}
sw = get_sw(response, resplen);
if (sw != 0x9000) {
PrintAndLogEx(ERR, "Verify password failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField();
return PM3_ESOFT;
}
}
@ -437,12 +467,15 @@ static int cmd_hf_st_ndef(const char *Cmd) {
int aREAD_NDEF_n = 0;
param_gethex_to_eol("00b000001d", 0, aREAD_NDEF, sizeof(aREAD_NDEF), &aREAD_NDEF_n);
res = ExchangeAPDU14a(aREAD_NDEF, aREAD_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
if (res)
if (res) {
DropField();
return res;
}
sw = get_sw(response, resplen);
if (sw != 0x9000) {
PrintAndLogEx(ERR, "reading NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField();
return PM3_ESOFT;
}
@ -483,36 +516,31 @@ static int cmd_hf_st_protect(const char *Cmd) {
disable_protection = arg_get_lit(ctx, 2);
read_protection = arg_get_lit(ctx, 3);
write_protection = arg_get_lit(ctx, 4);
CLIGetHexWithReturn(ctx, 5, pwd, &pwdlen);
CLIParserFree(ctx);
//Validations
if (enable_protection && disable_protection) {
PrintAndLogEx(ERR, "Must specify either enable or disable protection, not both");
return PM3_EINVARG;
} else {
}
if (enable_protection) {
state[0] = 0x28;
}
if (disable_protection) {
state[0] = 0x26;
}
}
if (read_protection && write_protection) {
PrintAndLogEx(ERR, "Must specify either read or write protection, not both");
return PM3_EINVARG;
} else {
}
if (read_protection) {
state[2] = 0x01;
}
if (write_protection) {
state[2] = 0x02;
}
}
if (pwdlen != 16) {
PrintAndLogEx(ERR, "Missing 16 byte password");
@ -529,15 +557,20 @@ static int cmd_hf_st_protect(const char *Cmd) {
int aSELECT_AID_n = 0;
param_gethex_to_eol("00a4040007d276000085010100", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n);
int res = ExchangeAPDU14a(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
if (res)
if (res) {
DropField();
return res;
}
if (resplen < 2)
if (resplen < 2) {
DropField();
return PM3_ESOFT;
}
uint16_t sw = get_sw(response, resplen);
if (sw != 0x9000) {
PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField();
return PM3_ESOFT;
}
@ -549,12 +582,15 @@ static int cmd_hf_st_protect(const char *Cmd) {
int aSELECT_FILE_NDEF_n = 0;
param_gethex_to_eol("00a4000c020001", 0, aSELECT_FILE_NDEF, sizeof(aSELECT_FILE_NDEF), &aSELECT_FILE_NDEF_n);
res = ExchangeAPDU14a(aSELECT_FILE_NDEF, aSELECT_FILE_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
if (res)
if (res) {
DropField();
return res;
}
sw = get_sw(response, resplen);
if (sw != 0x9000) {
PrintAndLogEx(ERR, "Selecting NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField();
return PM3_ESOFT;
}
@ -565,12 +601,15 @@ static int cmd_hf_st_protect(const char *Cmd) {
param_gethex_to_eol("0020000210", 0, aVERIFY, sizeof(aVERIFY), &aVERIFY_n);
memcpy(aVERIFY + aVERIFY_n, pwd, pwdlen);
res = ExchangeAPDU14a(aVERIFY, aVERIFY_n + pwdlen, activate_field, keep_field_on, response, sizeof(response), &resplen);
if (res)
if (res) {
DropField();
return res;
}
sw = get_sw(response, resplen);
if (sw != 0x9000) {
PrintAndLogEx(ERR, "Verify password failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField();
return PM3_ESOFT;
}
@ -581,12 +620,15 @@ static int cmd_hf_st_protect(const char *Cmd) {
param_gethex_to_eol("00", 0, aPROTECT, sizeof(aPROTECT), &aPROTECT_n);
memcpy(aPROTECT + aPROTECT_n, state, statelen);
res = ExchangeAPDU14a(aPROTECT, aPROTECT_n + statelen, activate_field, keep_field_on, response, sizeof(response), &resplen);
if (res)
if (res) {
DropField();
return res;
}
sw = get_sw(response, resplen);
if (sw != 0x9000) {
PrintAndLogEx(ERR, "changing protection failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField();
return PM3_ESOFT;
}
@ -625,25 +667,20 @@ static int cmd_hf_st_pwd(const char *Cmd) {
change_read_password = arg_get_lit(ctx, 1);
change_write_password = arg_get_lit(ctx, 2);
CLIGetHexWithReturn(ctx, 3, pwd, &pwdlen);
CLIGetHexWithReturn(ctx, 4, newpwd, &newpwdlen);
CLIParserFree(ctx);
if (change_read_password && change_write_password) {
PrintAndLogEx(ERR, "Must specify either read or write, not both");
CLIParserFree(ctx);
return PM3_EINVARG;
} else {
}
if (change_read_password) {
changePwd[2] = 0x01;
}
if (change_write_password) {
changePwd[2] = 0x02;
}
}
CLIParserFree(ctx);
if (pwdlen != 16) {
PrintAndLogEx(ERR, "Original write password must be 16 hex bytes");
@ -664,15 +701,20 @@ static int cmd_hf_st_pwd(const char *Cmd) {
int aSELECT_AID_n = 0;
param_gethex_to_eol("00a4040007d276000085010100", 0, aSELECT_AID, sizeof(aSELECT_AID), &aSELECT_AID_n);
int res = ExchangeAPDU14a(aSELECT_AID, aSELECT_AID_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
if (res)
if (res) {
DropField();
return res;
}
if (resplen < 2)
if (resplen < 2) {
DropField();
return PM3_ESOFT;
}
uint16_t sw = get_sw(response, resplen);
if (sw != 0x9000) {
PrintAndLogEx(ERR, "Selecting NDEF aid failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField();
return PM3_ESOFT;
}
@ -684,12 +726,15 @@ static int cmd_hf_st_pwd(const char *Cmd) {
int aSELECT_FILE_NDEF_n = 0;
param_gethex_to_eol("00a4000c020001", 0, aSELECT_FILE_NDEF, sizeof(aSELECT_FILE_NDEF), &aSELECT_FILE_NDEF_n);
res = ExchangeAPDU14a(aSELECT_FILE_NDEF, aSELECT_FILE_NDEF_n, activate_field, keep_field_on, response, sizeof(response), &resplen);
if (res)
if (res) {
DropField();
return res;
}
sw = get_sw(response, resplen);
if (sw != 0x9000) {
PrintAndLogEx(ERR, "Selecting NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField();
return PM3_ESOFT;
}
@ -700,12 +745,15 @@ static int cmd_hf_st_pwd(const char *Cmd) {
param_gethex_to_eol("0020000210", 0, aVERIFY, sizeof(aVERIFY), &aVERIFY_n);
memcpy(aVERIFY + aVERIFY_n, pwd, pwdlen);
res = ExchangeAPDU14a(aVERIFY, aVERIFY_n + pwdlen, activate_field, keep_field_on, response, sizeof(response), &resplen);
if (res)
if (res) {
DropField();
return res;
}
sw = get_sw(response, resplen);
if (sw != 0x9000) {
PrintAndLogEx(ERR, "Verify password failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField();
return PM3_ESOFT;
}
@ -718,24 +766,29 @@ static int cmd_hf_st_pwd(const char *Cmd) {
memcpy(aCHG_PWD + aCHG_PWD_n, changePwd, changePwdlen);
memcpy(aCHG_PWD + aCHG_PWD_n + changePwdlen, newpwd, newpwdlen);
res = ExchangeAPDU14a(aCHG_PWD, aCHG_PWD_n + changePwdlen + newpwdlen, activate_field, keep_field_on, response, sizeof(response), &resplen);
if (res)
if (res) {
DropField();
return res;
}
sw = get_sw(response, resplen);
if (sw != 0x9000) {
PrintAndLogEx(ERR, "password change failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
DropField();
return PM3_ESOFT;
}
PrintAndLogEx(SUCCESS, " %s password changed", ((changePwd[2] & 0x01) == 0x01) ? _YELLOW_("read") : _YELLOW_("write"));
return PM3_SUCCESS;
}
static int cmd_hf_st_list(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
CmdTraceList("7816");
return PM3_SUCCESS;
char args[128] = {0};
if (strlen(Cmd) == 0) {
snprintf(args, sizeof(args), "-t 7816");
} else {
strncpy(args, Cmd, sizeof(args) - 1);
}
return CmdTraceList(args);
}
static command_t CommandTable[] = {

View file

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

View file

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

View file

@ -13,6 +13,7 @@
#include "util.h"
#include "fileutils.h"
#include "util_posix.h" // msleep
#include "cliparser.h"
// Currently the largest pixel 880*528 only needs 58.08K bytes
#define WSMAPSIZE 60000
@ -90,23 +91,6 @@ static model_t models[] = {
static int CmdHelp(const char *Cmd);
static int usage_hf_waveshare_loadbmp(void) {
PrintAndLogEx(NORMAL, "Load BMP file to Waveshare NFC ePaper.");
PrintAndLogEx(NORMAL, "Usage: hf waveshare loadbmp [h] f <filename[.bmp]> m <model_nr> [s]");
PrintAndLogEx(NORMAL, " Options :");
PrintAndLogEx(NORMAL, " f <fn> : " _YELLOW_("filename[.bmp]") " to upload to tag");
PrintAndLogEx(NORMAL, " m <nr> : " _YELLOW_("model number") " of your tag");
PrintAndLogEx(NORMAL, " s : save dithered version in filename-[n].bmp, only for RGB BMP");
for (uint8_t i = 0; i < MEND; i++) {
PrintAndLogEx(NORMAL, " m %2i : %s", i, models[i].desc);
}
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" hf waveshare loadbmp m 0 f myfile"));
PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS;
}
static int picture_bit_depth(const uint8_t *bmp, const size_t bmpsize, const uint8_t model_nr) {
if (bmpsize < sizeof(BMP_HEADER))
return PM3_ESOFT;
@ -138,9 +122,15 @@ static int read_bmp_bitmap(const uint8_t *bmp, const size_t bmpsize, uint8_t mod
uint8_t color_flag = pbmpheader->Color_1;
// Get BMP file data pointer
uint32_t offset = pbmpheader->offset;
uint16_t width = pbmpheader->BMP_Width;
uint16_t height = pbmpheader->BMP_Height;
if ((width + 8) * height > WSMAPSIZE * 8) {
PrintAndLogEx(WARNING, "The file is too large, aborting!");
return PM3_ESOFT;
}
uint16_t X, Y;
uint16_t Image_Width_Byte = (pbmpheader->BMP_Width % 8 == 0) ? (pbmpheader->BMP_Width / 8) : (pbmpheader->BMP_Width / 8 + 1);
uint16_t Image_Width_Byte = (width % 8 == 0) ? (width / 8) : (width / 8 + 1);
uint16_t Bmp_Width_Byte = (Image_Width_Byte % 4 == 0) ? Image_Width_Byte : ((Image_Width_Byte / 4 + 1) * 4);
*black = calloc(WSMAPSIZE, sizeof(uint8_t));
@ -148,10 +138,10 @@ static int read_bmp_bitmap(const uint8_t *bmp, const size_t bmpsize, uint8_t mod
return PM3_EMALLOC;
}
// Write data into RAM
for (Y = 0; Y < pbmpheader->BMP_Height; Y++) { // columns
for (Y = 0; Y < height; Y++) { // columns
for (X = 0; X < Bmp_Width_Byte; X++) { // lines
if ((X < Image_Width_Byte) && ((X + (pbmpheader->BMP_Height - Y - 1) * Image_Width_Byte) < WSMAPSIZE)) {
(*black)[X + (pbmpheader->BMP_Height - Y - 1) * Image_Width_Byte] = color_flag ? bmp[offset] : ~bmp[offset];
if ((X < Image_Width_Byte) && ((X + (height - Y - 1) * Image_Width_Byte) < WSMAPSIZE)) {
(*black)[X + (height - Y - 1) * Image_Width_Byte] = color_flag ? bmp[offset] : ~bmp[offset];
}
offset++;
}
@ -241,7 +231,7 @@ static void dither_rgb_inplace(int16_t *chanR, int16_t *chanG, int16_t *chanB, u
int16_t oldR = chanR[XX + Y * width];
int16_t oldG = chanG[XX + Y * width];
int16_t oldB = chanB[XX + Y * width];
uint8_t newR, newG, newB;
uint8_t newR = 0, newG = 0, newB = 0;
nearest_color(oldR, oldG, oldB, palette, palettelen, &newR, &newG, &newB);
chanR[XX + Y * width] = newR;
chanG[XX + Y * width] = newG;
@ -361,7 +351,7 @@ static void map8to1(uint8_t *colormap, uint16_t width, uint16_t height, uint8_t
static int read_bmp_rgb(uint8_t *bmp, const size_t bmpsize, uint8_t model_nr, uint8_t **black, uint8_t **red, char *filename, bool save_conversions) {
BMP_HEADER *pbmpheader = (BMP_HEADER *)bmp;
// check file is full color
if (pbmpheader->bpp != 24) {
if ((pbmpheader->bpp != 24) && (pbmpheader->bpp != 32)) {
return PM3_ESOFT;
}
@ -381,6 +371,10 @@ static int read_bmp_rgb(uint8_t *bmp, const size_t bmpsize, uint8_t model_nr, ui
uint32_t offset = pbmpheader->offset;
uint16_t width = pbmpheader->BMP_Width;
uint16_t height = pbmpheader->BMP_Height;
if ((width + 8) * height > WSMAPSIZE * 8) {
PrintAndLogEx(WARNING, "The file is too large, aborting!");
return PM3_ESOFT;
}
int16_t *chanR = calloc(width * height, sizeof(int16_t));
if (chanR == NULL) {
@ -406,6 +400,8 @@ static int read_bmp_rgb(uint8_t *bmp, const size_t bmpsize, uint8_t model_nr, ui
chanB[X + (height - Y - 1) * width] = bmp[offset++];
chanG[X + (height - Y - 1) * width] = bmp[offset++];
chanR[X + (height - Y - 1) * width] = bmp[offset++];
if (pbmpheader->bpp == 32) // Skip Alpha chan
offset++;
}
// Skip line padding
offset += width % 4;
@ -442,6 +438,8 @@ static int read_bmp_rgb(uint8_t *bmp, const size_t bmpsize, uint8_t model_nr, ui
bmp[offset++] = chanB[X + (height - Y - 1) * width] & 0xFF;
bmp[offset++] = chanG[X + (height - Y - 1) * width] & 0xFF;
bmp[offset++] = chanR[X + (height - Y - 1) * width] & 0xFF;
if (pbmpheader->bpp == 32) // Fill Alpha chan
bmp[offset++] = 0xFF;
}
// Skip line padding
offset += width % 4;
@ -506,6 +504,8 @@ static int read_bmp_rgb(uint8_t *bmp, const size_t bmpsize, uint8_t model_nr, ui
bmp[offset++] = chanGrey[X + (height - Y - 1) * width] & 0xFF;
bmp[offset++] = chanGrey[X + (height - Y - 1) * width] & 0xFF;
bmp[offset++] = chanGrey[X + (height - Y - 1) * width] & 0xFF;
if (pbmpheader->bpp == 32) // Fill Alpha chan
bmp[offset++] = 0xFF;
}
// Skip line padding
offset += width % 4;
@ -542,7 +542,8 @@ static void read_black(uint32_t i, uint8_t *l, uint8_t model_nr, uint8_t *black)
}
}
static void read_red(uint32_t i, uint8_t *l, uint8_t model_nr, uint8_t *red) {
for (uint8_t j = 0; j < models[model_nr].len; j++) {
// spurious warning with GCC10 (-Wstringop-overflow) when j is uint8_t, even if all len are < 128
for (uint16_t j = 0; j < models[model_nr].len; j++) {
if (model_nr == M1in54B) {
//1.54B needs to flip the red picture data, other screens do not need to flip data
l[3 + j] = ~red[i * models[model_nr].len + j];
@ -565,7 +566,7 @@ static int transceive_blocking(uint8_t *txBuf, uint16_t txBufLen, uint8_t *rxBuf
if (WaitForResponseTimeout(CMD_ACK, &resp, 2000)) {
if (resp.oldarg[0] > rxBufLen) {
PrintAndLogEx(WARNING, "Received %"PRIu32 " bytes, rxBuf too small (%u)", resp.oldarg[0], rxBufLen);
PrintAndLogEx(WARNING, "Received %"PRIu64 " bytes, rxBuf too small (%u)", resp.oldarg[0], rxBufLen);
memcpy(rxBuf, resp.data.asBytes, rxBufLen);
*actLen = rxBufLen;
return PM3_ESOFT;
@ -646,21 +647,30 @@ static int start_drawing_1in54B(uint8_t model_nr, uint8_t *black, uint8_t *red)
static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) {
uint8_t progress = 0;
uint8_t step0[2] = {0xcd, 0x0d};
uint8_t step1[3] = {0xcd, 0x00, 10}; //select e-paper type and reset e-paper 4:2.13inch e-Paper 7:2.9inch e-Paper 10:4.2inch e-Paper 14:7.5inch e-Paper
uint8_t step2[2] = {0xcd, 0x01}; //e-paper normal mode type
uint8_t step3[2] = {0xcd, 0x02}; //e-paper config1
uint8_t step4[2] = {0xcd, 0x03}; //e-paper power on
uint8_t step5[2] = {0xcd, 0x05}; //e-paper config2
uint8_t step6[2] = {0xcd, 0x06}; //EDP load to main
uint8_t step7[2] = {0xcd, 0x07}; //Data preparation
uint8_t step8[123] = {0xcd, 0x08, 0x64}; //Data start command 2.13inch(0x10:Send 16 data at a time) 2.9inch(0x10:Send 16 data at a time) 4.2inch(0x64:Send 100 data at a time) 7.5inch(0x78:Send 120 data at a time)
uint8_t step9[2] = {0xcd, 0x18}; //e-paper power on
uint8_t step10[2] = {0xcd, 0x09}; //Refresh e-paper
uint8_t step11[2] = {0xcd, 0x0a}; //wait for ready
uint8_t step12[2] = {0xcd, 0x04}; //e-paper power off command
uint8_t step1[3] = {0xcd, 0x00, 10}; // select e-paper type and reset e-paper
// 4 :2.13inch e-Paper
// 7 :2.9inch e-Paper
// 10 :4.2inch e-Paper
// 14 :7.5inch e-Paper
uint8_t step2[2] = {0xcd, 0x01}; // e-paper normal mode type
uint8_t step3[2] = {0xcd, 0x02}; // e-paper config1
uint8_t step4[2] = {0xcd, 0x03}; // e-paper power on
uint8_t step5[2] = {0xcd, 0x05}; // e-paper config2
uint8_t step6[2] = {0xcd, 0x06}; // EDP load to main
uint8_t step7[2] = {0xcd, 0x07}; // Data preparation
uint8_t step8[123] = {0xcd, 0x08, 0x64}; // Data start command
// 2.13inch(0x10:Send 16 data at a time)
// 2.9inch(0x10:Send 16 data at a time)
// 4.2inch(0x64:Send 100 data at a time)
// 7.5inch(0x78:Send 120 data at a time)
uint8_t step9[2] = {0xcd, 0x18}; // e-paper power on
uint8_t step10[2] = {0xcd, 0x09}; // Refresh e-paper
uint8_t step11[2] = {0xcd, 0x0a}; // wait for ready
uint8_t step12[2] = {0xcd, 0x04}; // e-paper power off command
uint8_t step13[124] = {0xcd, 0x19, 121};
// uint8_t step13[2]={0xcd,0x0b}; //Judge whether the power supply is turned off successfully
// uint8_t step14[2]={0xcd,0x0c}; //The end of the transmission
// uint8_t step13[2]={0xcd,0x0b}; // Judge whether the power supply is turned off successfully
// uint8_t step14[2]={0xcd,0x0c}; // The end of the transmission
uint8_t rx[20];
uint16_t actrxlen[20], i = 0;
@ -690,11 +700,21 @@ static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) {
return PM3_ESOFT;
}
if ((card.uidlen != 7) || (memcmp(card.uid, "WSDZ10m", 7) != 0)) {
if ((card.uidlen != 7) || ((memcmp(card.uid, "FSTN10m", 7) != 0) && (memcmp(card.uid, "WSDZ10m", 7) != 0))) {
PrintAndLogEx(WARNING, "Card doesn't look like Waveshare tag");
DropField();
return PM3_ESOFT;
}
if (((model_nr != M1in54B) && (memcmp(card.uid, "FSTN10m", 7) == 0))) {
PrintAndLogEx(WARNING, "Card is a Waveshare tag 1.54\", not %s", models[model_nr].desc);
DropField();
return PM3_ESOFT;
}
if (((model_nr == M1in54B) && (memcmp(card.uid, "FSTN10m", 7) != 0))) {
PrintAndLogEx(WARNING, "Card is not a Waveshare tag 1.54\", check your model number");
DropField();
return PM3_ESOFT;
}
PrintAndLogEx(DEBUG, "model_nr = %d", model_nr);
int ret;
PrintAndLogEx(DEBUG, "Step0");
@ -918,6 +938,7 @@ static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) {
msleep(200);
}
PrintAndLogEx(DEBUG, "Step11: Wait tag to be ready");
PrintAndLogEx(INPLACE, "E-paper Reflashing, Waiting");
if (model_nr == M2in13B || model_nr == M1in54B) { // Black, white and red screen refresh time is longer, wait first
msleep(9000);
} else if (model_nr == M7in5HD) {
@ -947,7 +968,7 @@ static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) {
} else {
fail_num++;
PrintAndLogEx(INPLACE, "E-paper Reflashing, Waiting");
msleep(100);
msleep(400);
}
}
}
@ -963,53 +984,60 @@ static int start_drawing(uint8_t model_nr, uint8_t *black, uint8_t *red) {
return PM3_SUCCESS;
}
static int CmdHF14AWSLoadBmp(const char *Cmd) {
char filename[FILE_PATH_SIZE] = {0};
uint8_t cmdp = 0;
bool errors = false;
size_t filenamelen = 0;
uint8_t model_nr = 0xff;
bool save_conversions = false;
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h':
return usage_hf_waveshare_loadbmp();
case 'f':
filenamelen = param_getstr(Cmd, cmdp + 1, filename, FILE_PATH_SIZE);
if (filenamelen > FILE_PATH_SIZE - 5)
filenamelen = FILE_PATH_SIZE - 5;
cmdp += 2;
break;
case 'm':
model_nr = param_get8(Cmd, cmdp + 1);
cmdp += 2;
break;
case 's':
save_conversions = true;
cmdp += 1;
break;
default:
PrintAndLogEx(WARNING, "Unknown parameter: " _RED_("'%c'"), param_getchar(Cmd, cmdp));
errors = true;
break;
}
char desc[800] = {0};
for (uint8_t i = 0; i < MEND; i++) {
snprintf(desc + strlen(desc),
sizeof(desc) - strlen(desc),
"hf waveshare loadbmp -f myfile -m %2u -> %s ( %u, %u )\n",
i,
models[i].desc,
models[i].width,
models[i].height
);
}
CLIParserContext *ctx;
CLIParserInit(&ctx, "hf waveshare loadbmp",
"Load BMP file to Waveshare NFC ePaper.",
desc
);
char modeldesc[40];
snprintf(modeldesc, sizeof(modeldesc), "model number [0 - %u] of your tag", MEND - 1);
void *argtable[] = {
arg_param_begin,
arg_int1("m", NULL, "<nr>", modeldesc),
arg_lit0("s", "save", "save dithered version in filename-[n].bmp, only for RGB BMP"),
arg_str1("f", "file", "<filename>", "filename[.bmp] to upload to tag"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
int model_nr = arg_get_int_def(ctx, 1, -1);
bool save_conversions = arg_get_lit(ctx, 2);
int fnlen = 0;
char filename[FILE_PATH_SIZE] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 3), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
CLIParserFree(ctx);
//Validations
if (filenamelen < 1) {
if (fnlen < 1) {
PrintAndLogEx(WARNING, "Missing filename");
errors = true;
return PM3_EINVARG;
}
if (model_nr == 0xff) {
if (model_nr == -1) {
PrintAndLogEx(WARNING, "Missing model");
errors = true;
} else if (model_nr >= MEND) {
PrintAndLogEx(WARNING, "Unknown model");
errors = true;
return PM3_EINVARG;
}
if (model_nr >= MEND) {
PrintAndLogEx(WARNING, "Unknown model");
return PM3_EINVARG;
}
if (errors || cmdp == 0) return usage_hf_waveshare_loadbmp();
uint8_t *bmp = NULL;
uint8_t *black = NULL;
@ -1038,11 +1066,13 @@ static int CmdHF14AWSLoadBmp(const char *Cmd) {
return PM3_ESOFT;
}
} else if (depth == 32) {
PrintAndLogEx(ERR, "Error, BMP color depth %i not supported. Remove alpha channel.", depth);
PrintAndLogEx(DEBUG, "BMP file is a RGBA, we will ignore the Alpha channel");
if (read_bmp_rgb(bmp, bytes_read, model_nr, &black, &red, filename, save_conversions) != PM3_SUCCESS) {
free(bmp);
return PM3_ESOFT;
}
} else {
PrintAndLogEx(ERR, "Error, BMP color depth %i not supported", depth);
PrintAndLogEx(ERR, "Error, BMP color depth %i not supported. Must be 1 (BW), 24 (RGB) or 32 (RGBA)", depth);
free(bmp);
return PM3_ESOFT;
}

View file

@ -15,12 +15,14 @@
#include <ctype.h>
#include "cmdparser.h" // command_t
#include "cliparser.h"
#include "comms.h"
#include "usart_defs.h"
#include "ui.h"
#include "cmdhw.h"
#include "cmddata.h"
#include "commonutil.h"
#include "pm3_cmd.h"
static int CmdHelp(const char *Cmd);
@ -515,6 +517,78 @@ static int CmdStatus(const char *Cmd) {
return PM3_SUCCESS;
}
int handle_tearoff(tearoff_params_t *params, bool verbose) {
if (params == NULL)
return PM3_EINVARG;
clearCommandBuffer();
SendCommandNG(CMD_SET_TEAROFF, (uint8_t *)params, sizeof(tearoff_params_t));
PacketResponseNG resp;
if (WaitForResponseTimeout(CMD_SET_TEAROFF, &resp, 500) == false) {
PrintAndLogEx(WARNING, "Tear-off command timeout.");
return PM3_ETIMEOUT;
}
if (resp.status == PM3_SUCCESS) {
if (params->delay_us > 0 && verbose)
PrintAndLogEx(INFO, "Tear-off hook configured with delay of " _GREEN_("%i us"), params->delay_us);
if (params->on && verbose)
PrintAndLogEx(INFO, "Tear-off hook " _GREEN_("enabled"));
if (params->off && verbose)
PrintAndLogEx(INFO, "Tear-off hook " _RED_("disabled"));
} else if (verbose)
PrintAndLogEx(WARNING, "Tear-off command failed.");
return resp.status;
}
static int CmdTearoff(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "hw tearoff",
"Configure a tear-off hook for the next write command supporting tear-off\n"
"After having been triggered by a write command, the tear-off hook is deactivated\n"
"Delay (in us) must be between 1 and 43000 (43ms). Precision is about 1/3us.",
"hw tearoff --delay 1200 --> define delay of 1200us\n"
"hw tearoff --on --> (re)activate a previously defined delay\n"
"hw tearoff --off --> deactivate a previously activated but not yet triggered hook\n");
void *argtable[] = {
arg_param_begin,
arg_int0(NULL, "delay", "<dec>", "Delay in us before triggering tear-off, must be between 1 and 43000"),
arg_lit0(NULL, "on", "Activate tear-off hook"),
arg_lit0(NULL, "off", "Deactivate tear-off hook"),
arg_lit0("s", "silent", "less verbose output"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
tearoff_params_t params;
int delay = arg_get_int_def(ctx, 1, -1);
params.on = arg_get_lit(ctx, 2);
params.off = arg_get_lit(ctx, 3);
bool silent = arg_get_lit(ctx, 4);
CLIParserFree(ctx);
if (delay != -1) {
if ((delay < 1) || (delay > 43000)) {
PrintAndLogEx(WARNING, "You can't set delay out of 1..43000 range!");
return PM3_EINVARG;
}
} else {
delay = 0; // will be ignored by ARM
}
params.delay_us = delay;
if (params.on && params.off) {
PrintAndLogEx(WARNING, "You can't set both --on and --off!");
return PM3_EINVARG;
}
return handle_tearoff(&params, !silent);
}
static int CmdTia(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
PrintAndLogEx(INFO, "Triggering new Timing Interval Acquisition (TIA)...");
@ -621,6 +695,7 @@ static command_t CommandTable[] = {
{"setmux", CmdSetMux, IfPm3Present, "Set the ADC mux to a specific value"},
{"standalone", CmdStandalone, IfPm3Present, "Jump to the standalone mode"},
{"status", CmdStatus, IfPm3Present, "Show runtime status information about the connected Proxmark3"},
{"tearoff", CmdTearoff, IfPm3Present, "Program a tearoff hook for the next command supporting tearoff"},
{"tia", CmdTia, IfPm3Present, "Trigger a Timing Interval Acquisition to re-adjust the RealTimeCounter divider"},
{"tune", CmdTune, IfPm3Present, "Measure antenna tuning"},
{"version", CmdVersion, IfPm3Present, "Show version information about the connected Proxmark3"},
@ -717,18 +792,18 @@ void pm3_version(bool verbose, bool oneliner) {
PrintAndLogEx(NORMAL, "\n [ " _YELLOW_("PROXMARK3") " ]");
if (IfPm3Rdv4Fw() == false) {
PrintAndLogEx(NORMAL, " firmware.........................%s", _GREEN_("PM3OTHER"));
PrintAndLogEx(NORMAL, " firmware.................. %s", _YELLOW_("PM3OTHER"));
if (IfPm3FpcUsartHost()) {
PrintAndLogEx(NORMAL, " FPC USART for BT add-on..........%s", _GREEN_("present"));
PrintAndLogEx(NORMAL, " FPC USART for BT add-on... %s", _GREEN_("present"));
}
} else {
PrintAndLogEx(NORMAL, " firmware.........................%s", _GREEN_("PM3RDV4"));
PrintAndLogEx(NORMAL, " external flash...................%s", IfPm3Flash() ? _GREEN_("present") : _YELLOW_("absent"));
PrintAndLogEx(NORMAL, " smartcard reader.................%s", IfPm3Smartcard() ? _GREEN_("present") : _YELLOW_("absent"));
PrintAndLogEx(NORMAL, " FPC USART for BT add-on..........%s", IfPm3FpcUsartHost() ? _GREEN_("present") : _YELLOW_("absent"));
PrintAndLogEx(NORMAL, " firmware.................. %s", _YELLOW_("PM3RDV4"));
PrintAndLogEx(NORMAL, " external flash............ %s", IfPm3Flash() ? _GREEN_("present") : _YELLOW_("absent"));
PrintAndLogEx(NORMAL, " smartcard reader.......... %s", IfPm3Smartcard() ? _GREEN_("present") : _YELLOW_("absent"));
PrintAndLogEx(NORMAL, " FPC USART for BT add-on... %s", IfPm3FpcUsartHost() ? _GREEN_("present") : _YELLOW_("absent"));
}
if (IfPm3FpcUsartDevFromUsb()) {
PrintAndLogEx(NORMAL, " FPC USART for developer..........%s", _GREEN_("present"));
PrintAndLogEx(NORMAL, " FPC USART for developer... %s", _GREEN_("present"));
}
PrintAndLogEx(NORMAL, "");

View file

@ -12,9 +12,11 @@
#define CMDHW_H__
#include "common.h"
#include "pm3_cmd.h"
int CmdHW(const char *Cmd);
int handle_tearoff(tearoff_params_t *params, bool verbose);
void pm3_version(bool verbose, bool oneliner);
#endif

View file

@ -30,13 +30,15 @@
#include "cmddata.h" // for `lf search`
#include "cmdlfawid.h" // for awid menu
#include "cmdlfem4x.h" // for em4x menu
#include "cmdlfem4x05.h" // for em4x05 / 4x69
#include "cmdlfem4x50.h" // for em4x50
#include "cmdlfhid.h" // for hid menu
#include "cmdlfhitag.h" // for hitag menu
#include "cmdlfidteck.h" // for idteck menu
#include "cmdlfio.h" // for ioprox menu
#include "cmdlfcotag.h" // for COTAG meny
#include "cmdlffdx.h" // for fdx-b menu
#include "cmdlfdestron.h" // for FDX-A FECAVA Destron menu
#include "cmdlffdxb.h" // for FDX-B menu
#include "cmdlfgallagher.h" // for GALLAGHER menu
#include "cmdlfguard.h" // for gproxii menu
#include "cmdlfindala.h" // for indala menu
@ -1195,7 +1197,7 @@ int CmdLFpskSim(const char *Cmd) {
if (clk == 0) clk = GetPskClock("", false);
PrintAndLogEx(INFO, "clk: %d", clk);
if (!carrier) carrier = GetPskCarrier("", false);
if (!carrier) carrier = GetPskCarrier(false);
PrintAndLogEx(INFO, "carrier: %d", carrier);
} else {
@ -1346,7 +1348,7 @@ static bool CheckChipType(bool getDeviceData) {
//check for em4x05/em4x69 chips first
uint32_t word = 0;
if (EM4x05IsBlock0(&word)) {
if (em4x05_isblock0(&word)) {
PrintAndLogEx(SUCCESS, "Chipset detection: " _GREEN_("EM4x05 / EM4x69"));
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf em 4x05`") " commands");
retval = true;
@ -1447,6 +1449,7 @@ int CmdLFfind(const char *Cmd) {
}
if (demodVisa2k(true) == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Visa2000 ID") " found!"); goto out;}
if (demodDestron(true) == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("FDX-A FECAVA Destron ID") " found!"); goto out;} // to do before HID
if (demodHID(true) == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("HID Prox ID") " found!"); goto out;}
if (demodAWID(true) == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("AWID ID") " found!"); goto out;}
if (demodIOProx(true) == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("IO Prox ID") " found!"); goto out;}
@ -1454,7 +1457,7 @@ int CmdLFfind(const char *Cmd) {
if (demodNexWatch(true) == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("NexWatch ID") " found!"); goto out;}
if (demodIndala(true) == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Indala ID") " found!"); goto out;}
if (demodEM410x(true) == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("EM410x ID") " found!"); goto out;}
if (demodFDX(true) == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("FDX-B ID") " found!"); goto out;}
if (demodFDXB(true) == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("FDX-B ID") " found!"); goto out;}
if (demodGuard(true) == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Guardall G-Prox II ID") " found!"); goto out; }
if (demodIdteck(true) == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Idteck ID") " found!"); goto out;}
if (demodJablotron(true) == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Jablotron ID") " found!"); goto out;}
@ -1526,8 +1529,9 @@ static command_t CommandTable[] = {
{"-----------", CmdHelp, AlwaysAvailable, "-------------- " _CYAN_("Direct") " --------------"},
{"awid", CmdLFAWID, AlwaysAvailable, "{ AWID RFIDs... }"},
{"cotag", CmdLFCOTAG, AlwaysAvailable, "{ COTAG CHIPs... }"},
{"destron", CmdLFDestron, AlwaysAvailable, "{ FDX-A Destron RFIDs... }"},
{"em", CmdLFEM4X, AlwaysAvailable, "{ EM4X CHIPs & RFIDs... }"},
{"fdx", CmdLFFdx, AlwaysAvailable, "{ FDX-B RFIDs... }"},
{"fdxb", CmdLFFdxB, AlwaysAvailable, "{ FDX-B RFIDs... }"},
{"gallagher", CmdLFGallagher, AlwaysAvailable, "{ GALLAGHER RFIDs... }"},
{"gproxii", CmdLFGuard, AlwaysAvailable, "{ Guardall Prox II RFIDs... }"},
{"hid", CmdLFHID, AlwaysAvailable, "{ HID Prox RFIDs... }"},

189
client/src/cmdlfdestron.c Normal file
View file

@ -0,0 +1,189 @@
//-----------------------------------------------------------------------------
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// Low frequency FDX-A FECAVA Destron tag commands
//-----------------------------------------------------------------------------
#include "cmdlfdestron.h"
#include <ctype.h> //tolower
#include <string.h> // memcpy
#include "commonutil.h" // ARRAYLEN
#include "common.h"
#include "cmdparser.h" // command_t
#include "comms.h"
#include "ui.h"
#include "cmddata.h"
#include "cmdlf.h"
#include "lfdemod.h" // preamble test
#include "protocols.h" // t55xx defines
#include "cmdlft55xx.h" // clone..
#include "cmdlf.h" // cmdlfconfig
#include "cliparser.h" // cli parse input
#include "parity.h"
#define DESTRON_FRAME_SIZE 96
#define DESTRON_PREAMBLE_SIZE 16
static int CmdHelp(const char *Cmd);
int demodDestron(bool verbose) {
(void) verbose; // unused so far
//PSK1
if (FSKrawDemod(0, 0, 0, 0, false) != PM3_SUCCESS) {
PrintAndLogEx(DEBUG, "DEBUG: Error - Destron: FSK Demod failed");
return PM3_ESOFT;
}
size_t size = DemodBufferLen;
int ans = detectDestron(DemodBuffer, &size);
if (ans < 0) {
if (ans == -1)
PrintAndLogEx(DEBUG, "DEBUG: Error - Destron: too few bits found");
else if (ans == -2)
PrintAndLogEx(DEBUG, "DEBUG: Error - Destron: preamble not found");
else if (ans == -3)
PrintAndLogEx(DEBUG, "DEBUG: Error - Destron: Size not correct: %zu", size);
else
PrintAndLogEx(DEBUG, "DEBUG: Error - Destron: ans: %d", ans);
return PM3_ESOFT;
}
setDemodBuff(DemodBuffer, DESTRON_FRAME_SIZE, ans);
setClockGrid(g_DemodClock, g_DemodStartIdx + (ans * g_DemodClock));
uint8_t bits[DESTRON_FRAME_SIZE - DESTRON_PREAMBLE_SIZE] = {0};
size_t bitlen = DESTRON_FRAME_SIZE - DESTRON_PREAMBLE_SIZE;
memcpy(bits, DemodBuffer + 16, DESTRON_FRAME_SIZE - DESTRON_PREAMBLE_SIZE);
uint8_t alignPos = 0;
uint16_t errCnt = manrawdecode(bits, &bitlen, 0, &alignPos);
if (errCnt > 0) {
PrintAndLogEx(DEBUG, "DEBUG: Error - Destron: Manchester decoding errors: %d", ans);
return PM3_ESOFT;
}
uint8_t data[5] = {0};
uint8_t parity_err = 0;
for (int i = 0; i < sizeof(data); i++) {
data[i] = bytebits_to_byte(bits + i * 8, 8);
parity_err += oddparity8(data[i]);
data[i] &= 0x7F;
}
if (parity_err > 0) {
PrintAndLogEx(DEBUG, "DEBUG: Error - Destron: parity errors: %d", parity_err);
return PM3_ESOFT;
}
PrintAndLogEx(SUCCESS, "FDX-A FECAVA Destron: " _GREEN_("%02X%02X%02X%02X%02X"), data[0], data[1], data[2], data[3], data[4]);
return PM3_SUCCESS;
}
static int CmdDestronDemod(const char *Cmd) {
(void)Cmd;
return demodDestron(true);
}
static int CmdDestronRead(const char *Cmd) {
lf_read(false, 16000);
return demodDestron(true);
}
static int CmdDestronClone(const char *Cmd) {
uint32_t blocks[4] = {0};
uint8_t data[8];
int datalen = 0;
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf destron clone",
"Enables cloning of Destron card with specified uid onto T55x7",
"lf destron clone 1A2B3C4D5E"
);
void *argtable[] = {
arg_param_begin,
arg_strx1(NULL, NULL, "<uid (hex)>", NULL),
arg_param_end
};
//TODO add selection of chip for Q5 or T55x7
CLIExecWithReturn(ctx, Cmd, argtable, false);
CLIGetHexWithReturn(ctx, 1, data, &datalen);
CLIParserFree(ctx);
uint8_t data_ex[12 + 24] = {0}; // ManchesterEncode need extra room
for (int i = 0; i < datalen; i++) {
data_ex[i + 1] = ~data [i] | (evenparity8(data[i]) << 7);
}
for (int i = 0; i < 3; i++) {
blocks[i + 1] = manchesterEncode2Bytes((data_ex[i * 2] << 8) + data_ex[i * 2 + 1]);
}
// inject preamble
blocks[1] = (blocks[1] & 0xFFFF) | 0xAAE20000;
PrintAndLogEx(INFO, "Preparing to clone Destron tag with ID: %s", sprint_hex(data, datalen));
blocks[0] = T55x7_BITRATE_RF_50 | T55x7_MODULATION_FSK2 | 3 << T55x7_MAXBLOCK_SHIFT;
print_blocks(blocks, ARRAYLEN(blocks));
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf Destron read`") " to verify");
return res;
}
static int CmdDestronSim(const char *Cmd) {
PrintAndLogEx(INFO, " To be implemented, feel free to contribute!");
return PM3_SUCCESS;
}
static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"},
{"demod", CmdDestronDemod, AlwaysAvailable, "Demodulate an Destron tag from the GraphBuffer"},
{"read", CmdDestronRead, IfPm3Lf, "Attempt to read and extract tag data from the antenna"},
{"clone", CmdDestronClone, IfPm3Lf, "Clone Destron tag to T55x7"},
{"sim", CmdDestronSim, IfPm3Lf, "Simulate Destron tag"},
{NULL, NULL, NULL, NULL}
};
static int CmdHelp(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
CmdsHelp(CommandTable);
return PM3_SUCCESS;
}
int CmdLFDestron(const char *Cmd) {
clearCommandBuffer();
return CmdsParse(CommandTable, Cmd);
}
// find Destron preamble in already demoded data
int detectDestron(uint8_t *dest, size_t *size) {
//make sure buffer has data
if (*size < 64)
return -1;
size_t found_size = *size;
size_t start_idx = 0;
uint8_t preamble[DESTRON_PREAMBLE_SIZE] = {1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0};
// preamble not found
if (!preambleSearch(dest, preamble, sizeof(preamble), &found_size, &start_idx)) {
return -2;
}
PrintAndLogEx(DEBUG, "DEBUG: detectDestron FSK found preamble");
*size = found_size;
// wrong demoded size
if (*size != 96)
return -3;
return (int)start_idx;
}
int readDestronUid(void) {
return (CmdDestronRead("") == PM3_SUCCESS);
}

19
client/src/cmdlfdestron.h Normal file
View file

@ -0,0 +1,19 @@
//-----------------------------------------------------------------------------
//
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// Low frequency FDX-A FECAVA Destron tag commands
//-----------------------------------------------------------------------------
#ifndef CMDLFDESTRON_H__
#define CMDLFDESTRON_H__
#include "common.h"
int CmdLFDestron(const char *Cmd);
int detectDestron(uint8_t *bits, size_t *size);
int demodDestron(bool verbose);
int readDestronUid(void);
#endif

View file

@ -9,6 +9,7 @@
//-----------------------------------------------------------------------------
#include "cmdlfem4x.h"
#include "cmdlfem4x05.h"
#include "cmdlfem4x50.h"
#include <stdio.h>
@ -30,6 +31,9 @@
#include "cmddata.h"
#include "cmdlf.h"
#include "lfdemod.h"
#include "generator.h"
#include "cliparser.h"
#include "cmdhw.h"
static uint64_t g_em410xid = 0;
@ -116,75 +120,6 @@ static int usage_lf_em410x_brute(void) {
return PM3_SUCCESS;
}
//////////////// 4205 / 4305 commands
static int usage_lf_em4x05_dump(void) {
PrintAndLogEx(NORMAL, "Dump EM4x05/EM4x69. Tag must be on antenna. ");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf em 4x05_dump [h] [f <filename prefix>] <pwd>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h - this help");
PrintAndLogEx(NORMAL, " f <filename prefix> - overide filename prefix (optional). Default is based on UID");
PrintAndLogEx(NORMAL, " pwd - password (hex) (optional)");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf em 4x05_dump");
PrintAndLogEx(NORMAL, " lf em 4x05_dump 11223344");
PrintAndLogEx(NORMAL, " lf em 4x05_dump f card1 11223344");
return PM3_SUCCESS;
}
static int usage_lf_em4x05_wipe(void) {
PrintAndLogEx(NORMAL, "Wipe EM4x05/EM4x69. Tag must be on antenna. ");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf em 4x05_wipe [h] <pwd>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h - this help");
PrintAndLogEx(NORMAL, " c - chip type : 0 em4205");
PrintAndLogEx(NORMAL, " 1 em4305 (default)");
PrintAndLogEx(NORMAL, " pwd - password (hex) (optional)");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf em 4x05_wipe");
PrintAndLogEx(NORMAL, " lf em 4x05_wipe 11223344");
return PM3_SUCCESS;
}
static int usage_lf_em4x05_read(void) {
PrintAndLogEx(NORMAL, "Read EM4x05/EM4x69. Tag must be on antenna. ");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf em 4x05_read [h] <address> <pwd>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h - this help");
PrintAndLogEx(NORMAL, " address - memory address to read. (0-15)");
PrintAndLogEx(NORMAL, " pwd - password (hex) (optional)");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf em 4x05_read 1");
PrintAndLogEx(NORMAL, " lf em 4x05_read 1 11223344");
return PM3_SUCCESS;
}
static int usage_lf_em4x05_write(void) {
PrintAndLogEx(NORMAL, "Write EM4x05/4x69. Tag must be on antenna. ");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf em 4x05_write [h] <address> <data> <pwd>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h - this help");
PrintAndLogEx(NORMAL, " address - memory address to write to. (0-15)");
PrintAndLogEx(NORMAL, " data - data to write (hex)");
PrintAndLogEx(NORMAL, " pwd - password (hex) (optional)");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf em 4x05_write 1 deadc0de");
PrintAndLogEx(NORMAL, " lf em 4x05_write 1 deadc0de 11223344");
return PM3_SUCCESS;
}
static int usage_lf_em4x05_info(void) {
PrintAndLogEx(NORMAL, "Tag information EM4205/4305/4469//4569 tags. Tag must be on antenna.");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf em 4x05_info [h] <pwd>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h - this help");
PrintAndLogEx(NORMAL, " pwd - password (hex) (optional)");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, " lf em 4x05_info");
PrintAndLogEx(NORMAL, " lf em 4x05_info deadc0de");
return PM3_SUCCESS;
}
/* Read the ID of an EM410x tag.
* Format:
* 1111 1111 1 <-- standard non-repeatable header
@ -691,712 +626,6 @@ static int CmdEM410xClone(const char *Cmd) {
return resp.status;
}
//**************** Start of EM4x50 Code ************************
// even parity COLUMN
static bool EM_ColParityTest(uint8_t *bs, size_t size, uint8_t rows, uint8_t cols, uint8_t pType) {
if (rows * cols > size) return false;
uint8_t colP = 0;
for (uint8_t c = 0; c < cols - 1; c++) {
for (uint8_t r = 0; r < rows; r++) {
colP ^= bs[(r * cols) + c];
}
if (colP != pType) return false;
colP = 0;
}
return true;
}
#define EM_PREAMBLE_LEN 6
// download samples from device and copy to Graphbuffer
static bool downloadSamplesEM(void) {
// 8 bit preamble + 32 bit word response (max clock (128) * 40bits = 5120 samples)
uint8_t got[6000];
if (!GetFromDevice(BIG_BUF, got, sizeof(got), 0, NULL, 0, NULL, 2500, false)) {
PrintAndLogEx(WARNING, "(downloadSamplesEM) command execution time out");
return false;
}
setGraphBuf(got, sizeof(got));
// set signal properties low/high/mean/amplitude and is_noise detection
computeSignalProperties(got, sizeof(got));
RepaintGraphWindow();
if (getSignalProperties()->isnoise) {
PrintAndLogEx(DEBUG, "No tag found - signal looks like noise");
return false;
}
return true;
}
// em_demod
static bool doPreambleSearch(size_t *startIdx) {
// sanity check
if (DemodBufferLen < EM_PREAMBLE_LEN) {
PrintAndLogEx(DEBUG, "DEBUG: Error - EM4305 demodbuffer too small");
return false;
}
// set size to 20 to only test first 14 positions for the preamble
size_t size = (20 > DemodBufferLen) ? DemodBufferLen : 20;
*startIdx = 0;
// skip first two 0 bits as they might have been missed in the demod
uint8_t preamble[EM_PREAMBLE_LEN] = {0, 0, 1, 0, 1, 0};
if (!preambleSearchEx(DemodBuffer, preamble, EM_PREAMBLE_LEN, &size, startIdx, true)) {
PrintAndLogEx(DEBUG, "DEBUG: Error - EM4305 preamble not found :: %zu", *startIdx);
return false;
}
return true;
}
static bool detectFSK(void) {
// detect fsk clock
if (GetFskClock("", false) == 0) {
PrintAndLogEx(DEBUG, "DEBUG: Error - EM: FSK clock failed");
return false;
}
// demod
int ans = FSKrawDemod(0, 0, 0, 0, false);
if (ans != PM3_SUCCESS) {
PrintAndLogEx(DEBUG, "DEBUG: Error - EM: FSK Demod failed");
return false;
}
return true;
}
// PSK clocks should be easy to detect ( but difficult to demod a non-repeating pattern... )
static bool detectPSK(void) {
int ans = GetPskClock("", false);
if (ans <= 0) {
PrintAndLogEx(DEBUG, "DEBUG: Error - EM: PSK clock failed");
return false;
}
//demod
//try psk1 -- 0 0 6 (six errors?!?)
ans = PSKDemod(0, 0, 6, false);
if (ans != PM3_SUCCESS) {
PrintAndLogEx(DEBUG, "DEBUG: Error - EM: PSK1 Demod failed");
//try psk1 inverted
ans = PSKDemod(0, 1, 6, false);
if (ans != PM3_SUCCESS) {
PrintAndLogEx(DEBUG, "DEBUG: Error - EM: PSK1 inverted Demod failed");
return false;
}
}
// either PSK1 or PSK1 inverted is ok from here.
// lets check PSK2 later.
return true;
}
// try manchester - NOTE: ST only applies to T55x7 tags.
static bool detectASK_MAN(void) {
bool stcheck = false;
if (ASKDemod_ext(0, 0, 0, 0, false, false, false, 1, &stcheck) != PM3_SUCCESS) {
PrintAndLogEx(DEBUG, "DEBUG: Error - EM: ASK/Manchester Demod failed");
return false;
}
return true;
}
static bool detectASK_BI(void) {
int ans = ASKbiphaseDemod(0, 0, 1, 50, false);
if (ans != PM3_SUCCESS) {
PrintAndLogEx(DEBUG, "DEBUG: Error - EM: ASK/biphase normal demod failed");
ans = ASKbiphaseDemod(0, 1, 1, 50, false);
if (ans != PM3_SUCCESS) {
PrintAndLogEx(DEBUG, "DEBUG: Error - EM: ASK/biphase inverted demod failed");
return false;
}
}
return true;
}
static bool detectNRZ(void) {
int ans = NRZrawDemod(0, 0, 1, false);
if (ans != PM3_SUCCESS) {
PrintAndLogEx(DEBUG, "DEBUG: Error - EM: NRZ normal demod failed");
ans = NRZrawDemod(0, 1, 1, false);
if (ans != PM3_SUCCESS) {
PrintAndLogEx(DEBUG, "DEBUG: Error - EM: NRZ inverted demod failed");
return false;
}
}
return true;
}
// param: idx - start index in demoded data.
static int setDemodBufferEM(uint32_t *word, size_t idx) {
//test for even parity bits.
uint8_t parity[45] = {0};
memcpy(parity, DemodBuffer, 45);
if (!EM_ColParityTest(DemodBuffer + idx + EM_PREAMBLE_LEN, 45, 5, 9, 0)) {
PrintAndLogEx(DEBUG, "DEBUG: Error - End Parity check failed");
return PM3_ESOFT;
}
// test for even parity bits and remove them. (leave out the end row of parities so 36 bits)
if (!removeParity(DemodBuffer, idx + EM_PREAMBLE_LEN, 9, 0, 36)) {
PrintAndLogEx(DEBUG, "DEBUG: Error - EM, failed removing parity");
return PM3_ESOFT;
}
setDemodBuff(DemodBuffer, 32, 0);
*word = bytebits_to_byteLSBF(DemodBuffer, 32);
return PM3_SUCCESS;
}
// FSK, PSK, ASK/MANCHESTER, ASK/BIPHASE, ASK/DIPHASE, NRZ
// should cover 90% of known used configs
// the rest will need to be manually demoded for now...
static int demodEM4x05resp(uint32_t *word) {
size_t idx = 0;
*word = 0;
if (detectASK_MAN() && doPreambleSearch(&idx))
return setDemodBufferEM(word, idx);
if (detectASK_BI() && doPreambleSearch(&idx))
return setDemodBufferEM(word, idx);
if (detectNRZ() && doPreambleSearch(&idx))
return setDemodBufferEM(word, idx);
if (detectFSK() && doPreambleSearch(&idx))
return setDemodBufferEM(word, idx);
if (detectPSK()) {
if (doPreambleSearch(&idx))
return setDemodBufferEM(word, idx);
psk1TOpsk2(DemodBuffer, DemodBufferLen);
if (doPreambleSearch(&idx))
return setDemodBufferEM(word, idx);
}
return PM3_ESOFT;
}
//////////////// 4205 / 4305 commands
#include "util_posix.h" // msclock
static int EM4x05ReadWord_ext(uint8_t addr, uint32_t pwd, bool usePwd, uint32_t *word) {
struct {
uint32_t password;
uint8_t address;
uint8_t usepwd;
} PACKED payload;
payload.password = pwd;
payload.address = addr;
payload.usepwd = usePwd;
clearCommandBuffer();
SendCommandNG(CMD_LF_EM4X_READWORD, (uint8_t *)&payload, sizeof(payload));
PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_LF_EM4X_READWORD, &resp, 10000)) {
PrintAndLogEx(WARNING, "(EM4x05ReadWord_ext) timeout while waiting for reply.");
return PM3_ETIMEOUT;
}
if (downloadSamplesEM() == false) {
return PM3_ESOFT;
}
return demodEM4x05resp(word);
}
static int CmdEM4x05Demod(const char *Cmd) {
// uint8_t ctmp = tolower(param_getchar(Cmd, 0));
// if (ctmp == 'h') return usage_lf_em4x05_demod();
uint32_t word = 0;
return demodEM4x05resp(&word);
}
static int CmdEM4x05Dump(const char *Cmd) {
uint8_t addr = 0;
uint32_t pwd = 0;
bool usePwd = false;
uint8_t cmdp = 0;
uint8_t bytes[4] = {0};
uint32_t data[16];
char preferredName[FILE_PATH_SIZE] = {0};
char optchk[10];
while (param_getchar(Cmd, cmdp) != 0x00) {
switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h':
return usage_lf_em4x05_dump();
break;
case 'f': // since f could match in password, lets confirm it is 1 character only for an option
param_getstr(Cmd, cmdp, optchk, sizeof(optchk));
if (strlen(optchk) == 1) { // Have a single character f so filename no password
param_getstr(Cmd, cmdp + 1, preferredName, FILE_PATH_SIZE);
cmdp += 2;
break;
} // if not a single 'f' dont break and flow onto default as should be password
default : // for backwards-compatibility options should be > 'f' else assume its the hex password`
// for now use default input of 1 as invalid (unlikely 1 will be a valid password...)
pwd = param_get32ex(Cmd, cmdp, 1, 16);
if (pwd != 1)
usePwd = true;
cmdp++;
};
}
int success = PM3_SUCCESS;
int status;
uint32_t lock_bits = 0x00; // no blocks locked
uint32_t word = 0;
PrintAndLogEx(NORMAL, "Addr | data | ascii |lck| info");
PrintAndLogEx(NORMAL, "-----+----------+-------+---+-----");
// To flag any blocks locked we need to read blocks 14 and 15 first
// dont swap endin until we get block lock flags.
status = EM4x05ReadWord_ext(14, pwd, usePwd, &word);
if (status != PM3_SUCCESS)
success = PM3_ESOFT; // If any error ensure fail is set so not to save invalid data
if (word != 0x00)
lock_bits = word;
data[14] = word;
status = EM4x05ReadWord_ext(15, pwd, usePwd, &word);
if (status != PM3_SUCCESS)
success = PM3_ESOFT; // If any error ensure fail is set so not to save invalid data
if (word != 0x00) // assume block 15 is the current lock block
lock_bits = word;
data[15] = word;
// Now read blocks 0 - 13 as we have 14 and 15
for (; addr < 14; addr++) {
if (addr == 2) {
if (usePwd) {
data[addr] = BSWAP_32(pwd);
num_to_bytes(pwd, 4, bytes);
PrintAndLogEx(NORMAL, " %02u | %08X | %s | %c | password", addr, pwd, sprint_ascii(bytes, 4), ((lock_bits >> addr) & 1) ? 'x' : ' ');
} else {
data[addr] = 0x00; // Unknown password, but not used to set to zeros
PrintAndLogEx(NORMAL, " 02 | | | | " _RED_("cannot read"));
}
} else {
// success &= EM4x05ReadWord_ext(addr, pwd, usePwd, &word);
status = EM4x05ReadWord_ext(addr, pwd, usePwd, &word); // Get status for single read
if (status != PM3_SUCCESS)
success = PM3_ESOFT; // If any error ensure fail is set so not to save invalid data
data[addr] = BSWAP_32(word);
if (status == PM3_SUCCESS) {
num_to_bytes(word, 4, bytes);
PrintAndLogEx(NORMAL, " %02d | %08X | %s | %c |", addr, word, sprint_ascii(bytes, 4), ((lock_bits >> addr) & 1) ? 'x' : ' ');
} else
PrintAndLogEx(NORMAL, " %02d | | | | " _RED_("Fail"), addr);
}
}
// Print blocks 14 and 15
// Both lock bits are protected with bit idx 14 (special case)
PrintAndLogEx(NORMAL, " %02d | %08X | %s | %c | Lock", 14, data[14], sprint_ascii(bytes, 4), ((lock_bits >> 14) & 1) ? 'x' : ' ');
PrintAndLogEx(NORMAL, " %02d | %08X | %s | %c | Lock", 15, data[15], sprint_ascii(bytes, 4), ((lock_bits >> 14) & 1) ? 'x' : ' ');
// Update endian for files
data[14] = BSWAP_32(data[14]);
data[15] = BSWAP_32(data[15]);
if (success == PM3_SUCCESS) { // all ok save dump to file
// saveFileEML will add .eml extension to filename
// saveFile (binary) passes in the .bin extension.
if (strcmp(preferredName, "") == 0) // Set default filename, if not set by user
sprintf(preferredName, "lf-4x05-%08X-dump", BSWAP_32(data[1]));
saveFileEML(preferredName, (uint8_t *)data, 16 * sizeof(uint32_t), sizeof(uint32_t));
saveFile(preferredName, ".bin", data, sizeof(data));
}
return success;
}
static int CmdEM4x05Read(const char *Cmd) {
uint8_t addr;
uint32_t pwd;
bool usePwd = false;
uint8_t ctmp = tolower(param_getchar(Cmd, 0));
if (strlen(Cmd) == 0 || ctmp == 'h') return usage_lf_em4x05_read();
addr = param_get8ex(Cmd, 0, 50, 10);
pwd = param_get32ex(Cmd, 1, 0xFFFFFFFF, 16);
if (addr > 15) {
PrintAndLogEx(NORMAL, "Address must be between 0 and 15");
return PM3_ESOFT;
}
if (pwd == 0xFFFFFFFF) {
PrintAndLogEx(NORMAL, "Reading address %02u", addr);
} else {
usePwd = true;
PrintAndLogEx(NORMAL, "Reading address %02u | password %08X", addr, pwd);
}
uint32_t word = 0;
int status = EM4x05ReadWord_ext(addr, pwd, usePwd, &word);
if (status == PM3_SUCCESS)
PrintAndLogEx(NORMAL, "Address %02d | %08X - %s", addr, word, (addr > 13) ? "Lock" : "");
else
PrintAndLogEx(NORMAL, "Read Address %02d | " _RED_("Fail"), addr);
return status;
}
static int CmdEM4x05Write(const char *Cmd) {
uint8_t ctmp = tolower(param_getchar(Cmd, 0));
if (strlen(Cmd) == 0 || ctmp == 'h') return usage_lf_em4x05_write();
bool usePwd = false;
uint8_t addr;
uint32_t data, pwd;
addr = param_get8ex(Cmd, 0, 50, 10);
data = param_get32ex(Cmd, 1, 0, 16);
pwd = param_get32ex(Cmd, 2, 0xFFFFFFFF, 16);
if (addr > 15) {
PrintAndLogEx(NORMAL, "Address must be between 0 and 15");
return PM3_EINVARG;
}
if (pwd == 0xFFFFFFFF)
PrintAndLogEx(NORMAL, "Writing address %d data %08X", addr, data);
else {
usePwd = true;
PrintAndLogEx(NORMAL, "Writing address %d data %08X using password %08X", addr, data, pwd);
}
struct {
uint32_t password;
uint32_t data;
uint8_t address;
uint8_t usepwd;
} PACKED payload;
payload.password = pwd;
payload.data = data;
payload.address = addr;
payload.usepwd = usePwd;
clearCommandBuffer();
SendCommandNG(CMD_LF_EM4X_WRITEWORD, (uint8_t *)&payload, sizeof(payload));
PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_LF_EM4X_WRITEWORD, &resp, 2000)) {
PrintAndLogEx(ERR, "Error occurred, device did not respond during write operation.");
return PM3_ETIMEOUT;
}
if (!downloadSamplesEM())
return PM3_ENODATA;
//need 0 bits demoded (after preamble) to verify write cmd
uint32_t dummy = 0;
int status = demodEM4x05resp(&dummy);
if (status == PM3_SUCCESS)
PrintAndLogEx(SUCCESS, "Success writing to tag");
PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf em 4x05_read`") " to verify");
return status;
}
static int CmdEM4x05Wipe(const char *Cmd) {
uint8_t addr = 0;
uint32_t pwd = 0;
uint8_t cmdp = 0;
uint8_t chipType = 1; // em4305
uint32_t chipInfo = 0x00040072; // Chip info/User Block normal 4305 Chip Type
uint32_t chipUID = 0x614739AE; // UID normally readonly, but just in case
uint32_t blockData = 0x00000000; // UserBlock/Password (set to 0x00000000 for a wiped card1
uint32_t config = 0x0001805F; // Default config (no password)
int success = PM3_SUCCESS;
char cmdStr [100];
char optchk[10];
while (param_getchar(Cmd, cmdp) != 0x00) {
// check if cmd is a 1 byte option
param_getstr(Cmd, cmdp, optchk, sizeof(optchk));
if (strlen(optchk) == 1) { // Have a single character so option not part of password
switch (tolower(param_getchar(Cmd, cmdp))) {
case 'c': // chip type
if (param_getchar(Cmd, cmdp) != 0x00)
chipType = param_get8ex(Cmd, cmdp + 1, 0, 10);
cmdp += 2;
break;
case 'h': // return usage_lf_em4x05_wipe();
default : // Unknown or 'h' send help
return usage_lf_em4x05_wipe();
break;
};
} else { // Not a single character so assume password
pwd = param_get32ex(Cmd, cmdp, 1, 16);
cmdp++;
}
}
switch (chipType) {
case 0 : // em4205
chipInfo = 0x00040070;
config = 0x0001805F;
break;
case 1 : // em4305
chipInfo = 0x00040072;
config = 0x0001805F;
break;
default : // Type 0/Default : EM4305
chipInfo = 0x00040072;
config = 0x0001805F;
}
// block 0 : User Data or Chip Info
sprintf(cmdStr, "%d %08X %08X", 0, chipInfo, pwd);
CmdEM4x05Write(cmdStr);
// block 1 : UID - this should be read only for EM4205 and EM4305 not sure about others
sprintf(cmdStr, "%d %08X %08X", 1, chipUID, pwd);
CmdEM4x05Write(cmdStr);
// block 2 : password
sprintf(cmdStr, "%d %08X %08X", 2, blockData, pwd);
CmdEM4x05Write(cmdStr);
pwd = blockData; // Password should now have changed, so use new password
// block 3 : user data
sprintf(cmdStr, "%d %08X %08X", 3, blockData, pwd);
CmdEM4x05Write(cmdStr);
// block 4 : config
sprintf(cmdStr, "%d %08X %08X", 4, config, pwd);
CmdEM4x05Write(cmdStr);
// Remainder of user/data blocks
for (addr = 5; addr < 14; addr++) {// Clear user data blocks
sprintf(cmdStr, "%d %08X %08X", addr, blockData, pwd);
CmdEM4x05Write(cmdStr);
}
return success;
}
static void printEM4x05config(uint32_t wordData) {
uint16_t datarate = (((wordData & 0x3F) + 1) * 2);
uint8_t encoder = ((wordData >> 6) & 0xF);
char enc[14];
memset(enc, 0, sizeof(enc));
uint8_t PSKcf = (wordData >> 10) & 0x3;
char cf[10];
memset(cf, 0, sizeof(cf));
uint8_t delay = (wordData >> 12) & 0x3;
char cdelay[33];
memset(cdelay, 0, sizeof(cdelay));
uint8_t numblks = EM4x05_GET_NUM_BLOCKS(wordData);
uint8_t LWR = numblks + 5 - 1; //last word read
switch (encoder) {
case 0:
snprintf(enc, sizeof(enc), "NRZ");
break;
case 1:
snprintf(enc, sizeof(enc), "Manchester");
break;
case 2:
snprintf(enc, sizeof(enc), "Biphase");
break;
case 3:
snprintf(enc, sizeof(enc), "Miller");
break;
case 4:
snprintf(enc, sizeof(enc), "PSK1");
break;
case 5:
snprintf(enc, sizeof(enc), "PSK2");
break;
case 6:
snprintf(enc, sizeof(enc), "PSK3");
break;
case 7:
snprintf(enc, sizeof(enc), "Unknown");
break;
case 8:
snprintf(enc, sizeof(enc), "FSK1");
break;
case 9:
snprintf(enc, sizeof(enc), "FSK2");
break;
default:
snprintf(enc, sizeof(enc), "Unknown");
break;
}
switch (PSKcf) {
case 0:
snprintf(cf, sizeof(cf), "RF/2");
break;
case 1:
snprintf(cf, sizeof(cf), "RF/8");
break;
case 2:
snprintf(cf, sizeof(cf), "RF/4");
break;
case 3:
snprintf(cf, sizeof(cf), "unknown");
break;
}
switch (delay) {
case 0:
snprintf(cdelay, sizeof(cdelay), "no delay");
break;
case 1:
snprintf(cdelay, sizeof(cdelay), "BP/8 or 1/8th bit period delay");
break;
case 2:
snprintf(cdelay, sizeof(cdelay), "BP/4 or 1/4th bit period delay");
break;
case 3:
snprintf(cdelay, sizeof(cdelay), "no delay");
break;
}
uint8_t readLogin = (wordData & EM4x05_READ_LOGIN_REQ) >> 18;
uint8_t readHKL = (wordData & EM4x05_READ_HK_LOGIN_REQ) >> 19;
uint8_t writeLogin = (wordData & EM4x05_WRITE_LOGIN_REQ) >> 20;
uint8_t writeHKL = (wordData & EM4x05_WRITE_HK_LOGIN_REQ) >> 21;
uint8_t raw = (wordData & EM4x05_READ_AFTER_WRITE) >> 22;
uint8_t disable = (wordData & EM4x05_DISABLE_ALLOWED) >> 23;
uint8_t rtf = (wordData & EM4x05_READER_TALK_FIRST) >> 24;
uint8_t pigeon = (wordData & (1 << 26)) >> 26;
PrintAndLogEx(INFO, "ConfigWord: %08X (Word 4)\n", wordData);
PrintAndLogEx(INFO, "Config Breakdown:");
PrintAndLogEx(INFO, " Data Rate: %02u | "_YELLOW_("RF/%u"), wordData & 0x3F, datarate);
PrintAndLogEx(INFO, " Encoder: %u | " _YELLOW_("%s"), encoder, enc);
PrintAndLogEx(INFO, " PSK CF: %u | %s", PSKcf, cf);
PrintAndLogEx(INFO, " Delay: %u | %s", delay, cdelay);
PrintAndLogEx(INFO, " LastWordR: %02u | Address of last word for default read - meaning %u blocks are output", LWR, numblks);
PrintAndLogEx(INFO, " ReadLogin: %u | Read login is %s", readLogin, readLogin ? _YELLOW_("required") : _GREEN_("not required"));
PrintAndLogEx(INFO, " ReadHKL: %u | Read housekeeping words login is %s", readHKL, readHKL ? _YELLOW_("required") : _GREEN_("not required"));
PrintAndLogEx(INFO, "WriteLogin: %u | Write login is %s", writeLogin, writeLogin ? _YELLOW_("required") : _GREEN_("not required"));
PrintAndLogEx(INFO, " WriteHKL: %u | Write housekeeping words login is %s", writeHKL, writeHKL ? _YELLOW_("required") : _GREEN_("not Required"));
PrintAndLogEx(INFO, " R.A.W.: %u | Read after write is %s", raw, raw ? "on" : "off");
PrintAndLogEx(INFO, " Disable: %u | Disable command is %s", disable, disable ? "accepted" : "not accepted");
PrintAndLogEx(INFO, " R.T.F.: %u | Reader talk first is %s", rtf, rtf ? _YELLOW_("enabled") : "disabled");
PrintAndLogEx(INFO, " Pigeon: %u | Pigeon mode is %s\n", pigeon, pigeon ? _YELLOW_("enabled") : "disabled");
}
static void printEM4x05info(uint32_t block0, uint32_t serial) {
uint8_t chipType = (block0 >> 1) & 0xF;
uint8_t cap = (block0 >> 5) & 3;
uint16_t custCode = (block0 >> 9) & 0x3FF;
char ctstr[50];
snprintf(ctstr, sizeof(ctstr), "\n Chip Type: %u | ", chipType);
switch (chipType) {
case 9:
snprintf(ctstr + strlen(ctstr), sizeof(ctstr) - strlen(ctstr), _YELLOW_("%s"), "EM4305");
break;
case 8:
snprintf(ctstr + strlen(ctstr), sizeof(ctstr) - strlen(ctstr), _YELLOW_("%s"), "EM4205");
break;
case 4:
snprintf(ctstr + strlen(ctstr), sizeof(ctstr) - strlen(ctstr), _YELLOW_("%s"), "Unknown");
break;
case 2:
snprintf(ctstr + strlen(ctstr), sizeof(ctstr) - strlen(ctstr), _YELLOW_("%s"), "EM4469");
break;
//add more here when known
default:
snprintf(ctstr + strlen(ctstr), sizeof(ctstr) - strlen(ctstr), _YELLOW_("%s"), "Unknown");
break;
}
PrintAndLogEx(SUCCESS, "%s", ctstr);
switch (cap) {
case 3:
PrintAndLogEx(SUCCESS, " Cap Type: %u | 330pF", cap);
break;
case 2:
PrintAndLogEx(SUCCESS, " Cap Type: %u | %spF", cap, (chipType == 2) ? "75" : "210");
break;
case 1:
PrintAndLogEx(SUCCESS, " Cap Type: %u | 250pF", cap);
break;
case 0:
PrintAndLogEx(SUCCESS, " Cap Type: %u | no resonant capacitor", cap);
break;
default:
PrintAndLogEx(SUCCESS, " Cap Type: %u | unknown", cap);
break;
}
PrintAndLogEx(SUCCESS, " Cust Code: %03u | %s", custCode, (custCode == 0x200) ? "Default" : "Unknown");
if (serial != 0)
PrintAndLogEx(SUCCESS, "\n Serial #: " _YELLOW_("%08X"), serial);
}
static void printEM4x05ProtectionBits(uint32_t word) {
for (uint8_t i = 0; i < 15; i++) {
PrintAndLogEx(INFO, " Word: %02u | %s", i, (((1 << i) & word) || i < 2) ? _RED_("write Locked") : "unlocked");
if (i == 14)
PrintAndLogEx(INFO, " Word: %02u | %s", i + 1, (((1 << i) & word) || i < 2) ? _RED_("write locked") : "unlocked");
}
}
//quick test for EM4x05/EM4x69 tag
bool EM4x05IsBlock0(uint32_t *word) {
return (EM4x05ReadWord_ext(0, 0, false, word) == PM3_SUCCESS);
}
static int CmdEM4x05Info(const char *Cmd) {
#define EM_SERIAL_BLOCK 1
#define EM_CONFIG_BLOCK 4
#define EM_PROT1_BLOCK 14
#define EM_PROT2_BLOCK 15
uint32_t pwd;
uint32_t word = 0, block0 = 0, serial = 0;
bool usePwd = false;
uint8_t ctmp = tolower(param_getchar(Cmd, 0));
if (ctmp == 'h') return usage_lf_em4x05_info();
// for now use default input of 1 as invalid (unlikely 1 will be a valid password...)
pwd = param_get32ex(Cmd, 0, 0xFFFFFFFF, 16);
if (pwd != 0xFFFFFFFF)
usePwd = true;
// read word 0 (chip info)
// block 0 can be read even without a password.
if (EM4x05IsBlock0(&block0) == false)
return PM3_ESOFT;
// read word 1 (serial #) doesn't need pwd
// continue if failed, .. non blocking fail.
EM4x05ReadWord_ext(EM_SERIAL_BLOCK, 0, false, &serial);
printEM4x05info(block0, serial);
// read word 4 (config block)
// needs password if one is set
if (EM4x05ReadWord_ext(EM_CONFIG_BLOCK, pwd, usePwd, &word) != PM3_SUCCESS)
return PM3_ESOFT;
printEM4x05config(word);
// read word 14 and 15 to see which is being used for the protection bits
if (EM4x05ReadWord_ext(EM_PROT1_BLOCK, pwd, usePwd, &word) != PM3_SUCCESS) {
return PM3_ESOFT;
}
// if status bit says this is not the used protection word
if (!(word & 0x8000)) {
if (EM4x05ReadWord_ext(EM_PROT2_BLOCK, pwd, usePwd, &word) != PM3_SUCCESS)
return PM3_ESOFT;
}
//something went wrong
if (!(word & 0x8000))
return PM3_ESOFT;
printEM4x05ProtectionBits(word);
return PM3_SUCCESS;
}
static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "This help"},
{"----------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("EM 410x") " -----------------------"},
@ -1409,12 +638,16 @@ static command_t CommandTable[] = {
{"410x_spoof", CmdEM410xWatchnSpoof, IfPm3Lf, "watches for EM410x 125/134 kHz tags, and replays them. (option 'h' for 134)" },
{"410x_clone", CmdEM410xClone, IfPm3Lf, "write EM410x UID to T55x7 or Q5/T5555 tag"},
{"----------", CmdHelp, AlwaysAvailable, "-------------------- " _CYAN_("EM 4x05 / 4x69") " -------------------"},
{"4x05_chk", CmdEM4x05Chk, IfPm3Lf, "Check passwords from dictionary"},
{"4x05_demod", CmdEM4x05Demod, AlwaysAvailable, "demodulate a EM4x05/EM4x69 tag from the GraphBuffer"},
{"4x05_dump", CmdEM4x05Dump, IfPm3Lf, "dump EM4x05/EM4x69 tag"},
{"4x05_wipe", CmdEM4x05Wipe, IfPm3Lf, "wipe EM4x05/EM4x69 tag"},
{"4x05_info", CmdEM4x05Info, IfPm3Lf, "tag information EM4x05/EM4x69"},
{"4x05_read", CmdEM4x05Read, IfPm3Lf, "read word data from EM4x05/EM4x69"},
{"4x05_write", CmdEM4x05Write, IfPm3Lf, "write word data to EM4x05/EM4x69"},
{"4x05_unlock", CmdEM4x05Unlock, IfPm3Lf, "execute tear off against EM4x05/EM4x69"},
{"4x05_sniff", CmdEM4x05Sniff, AlwaysAvailable, "Attempt to recover em4x05 commands from sample buffer"},
{"4x05_brute", CmdEM4x05Brute, IfPm3Lf, "Bruteforce password"},
{"----------", CmdHelp, AlwaysAvailable, "----------------------- " _CYAN_("EM 4x50") " -----------------------"},
{"4x50_dump", CmdEM4x50Dump, IfPm3EM4x50, "dump EM4x50 tag"},
{"4x50_info", CmdEM4x50Info, IfPm3EM4x50, "tag information EM4x50"},

View file

@ -16,9 +16,8 @@
int CmdLFEM4X(const char *Cmd);
int demodEM410x(bool verbose);
bool EM4x05IsBlock0(uint32_t *word);
void printEM410x(uint32_t hi, uint64_t id);
int AskEm410xDecode(bool verbose, uint32_t *hi, uint64_t *lo);
int AskEm410xDemod(int clk, int invert, int maxErr, size_t maxLen, bool amplify, uint32_t *hi, uint64_t *lo, bool verbose);

2046
client/src/cmdlfem4x05.c Normal file

File diff suppressed because it is too large Load diff

79
client/src/cmdlfem4x05.h Normal file
View file

@ -0,0 +1,79 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2010 iZsh <izsh at fail0verflow.com>
// 2016, 2017 marshmellow, iceman
// This code is licensed to you under the terms of the GNU GPL, version 2 or,
// at your option, any later version. See the LICENSE.txt file for the text of
// the license.
//-----------------------------------------------------------------------------
// Low frequency EM4x05 commands
//-----------------------------------------------------------------------------
#ifndef CMDLFEM4X05_H__
#define CMDLFEM4X05_H__
#include "common.h"
#define EM_SERIAL_BLOCK 1
#define EM_CONFIG_BLOCK 4
#define EM4305_PROT1_BLOCK 14
#define EM4305_PROT2_BLOCK 15
#define EM4469_PROT_BLOCK 3
// config blocks
#define EM4305_DEFAULT_CONFIG_BLOCK (EM4x05_SET_BITRATE(32) | EM4x05_MODULATION_MANCHESTER | EM4x05_SET_NUM_BLOCKS(4) ) // ASK/MAN , data rate 32, 4 data blocks
//#define EM4305_DEFAULT_CONFIG_BLOCK (EM4x05_SET_BITRATE(32) | EM4x05_MODULATION_BIPHASE | EM4x05_SET_NUM_BLOCKS(4) ) // ASK/BIPHASE , data rate 32, 4 data blocks
#define EM4305_EM_UNIQUE_CONFIG_BLOCK (EM4x05_SET_BITRATE(64) | EM4x05_MODULATION_MANCHESTER | EM4x05_SET_NUM_BLOCKS(2) ) // ASK/MAN, EM4x02/unique - data rate 64, 2 data blocks
#define EM4305_PAXTON_CONFIG_BLOCK (EM4x05_SET_BITRATE(64) | EM4x05_MODULATION_MANCHESTER | EM4x05_SET_NUM_BLOCKS(2) ) // ASK/MAN, EM4x02/paxton - data rate 64, 2 data blocks
#define EM4305_VISA2000_CONFIG_BLOCK (EM4x05_SET_BITRATE(64) | EM4x05_MODULATION_MANCHESTER | EM4x05_SET_NUM_BLOCKS(3) ) // ASK, data rate 64, 3 data blocks
#define EM4305_VIKING_CONFIG_BLOCK (EM4x05_SET_BITRATE(32) | EM4x05_MODULATION_MANCHESTER | EM4x05_SET_NUM_BLOCKS(2) ) // ASK/MAN, data rate 32, 2 data blocks
#define EM4305_NORALSY_CONFIG_BLOCK (EM4x05_SET_BITRATE(32) | EM4x05_MODULATION_MANCHESTER | EM4x05_SET_NUM_BLOCKS(3) ) // ASK, data rate 32, 3 data blocks
#define EM4305_PRESCO_CONFIG_BLOCK (EM4x05_SET_BITRATE(32) | EM4x05_MODULATION_MANCHESTER | EM4x05_SET_NUM_BLOCKS(4) ) // ASK/MAN, data rate 32, 4 data blocks
#define EM4305_SECURAKEY_CONFIG_BLOCK (EM4x05_SET_BITRATE(40) | EM4x05_MODULATION_MANCHESTER | EM4x05_SET_NUM_BLOCKS(3) ) // ASK/MAN, data rate 40, 3 data blocks
#define EM4305_HID_26_CONFIG_BLOCK (EM4x05_SET_BITRATE(50) | EM4x05_MODULATION_FSK2 | EM4x05_SET_NUM_BLOCKS(3) ) // FSK2a, hid 26 bit, data rate 50, 3 data blocks
#define EM4305_PARADOX_CONFIG_BLOCK (EM4x05_SET_BITRATE(50) | EM4x05_MODULATION_FSK2 | EM4x05_SET_NUM_BLOCKS(3) ) // FSK2a, hid 26 bit, data rate 50, 3 data blocks
#define EM4305_AWID_CONFIG_BLOCK (EM4x05_SET_BITRATE(50) | EM4x05_MODULATION_FSK2 | EM4x05_SET_NUM_BLOCKS(3) ) // FSK2a, hid 26 bit, data rate 50, 3 data blocks
#define EM4305_PYRAMID_CONFIG_BLOCK (EM4x05_SET_BITRATE(50) | EM4x05_MODULATION_FSK2 | EM4x05_SET_NUM_BLOCKS(4) ) // FSK2a, Pyramid 26 bit, data rate 50, 4 data blocks
#define EM4305_IOPROX_CONFIG_BLOCK (EM4x05_SET_BITRATE(64) | EM4x05_MODULATION_FSK2 | EM4x05_SET_NUM_BLOCKS(2) ) // FSK2a, data rate 64, 2 data blocks
#define EM4305_INDALA_64_CONFIG_BLOCK (EM4x05_SET_BITRATE(64) | EM4x05_MODULATION_PSK1 | EM4x05_PSK_RF_2 | EM4x05_SET_NUM_BLOCKS(2) ) // PSK1, indala 64 bit, psk carrier FC * 2, data rate 32, maxblock 2
#define EM4305_INDALA_224_CONFIG_BLOCK (EM4x05_SET_BITRATE(64) | EM4x05_MODULATION_PSK1 | EM4x05_PSK_RF_2 | EM4x05_SET_NUM_BLOCKS(7) ) // PSK1, indala 224 bit, psk carrier FC * 2, data rate 32, maxblock 7
#define EM4305_MOTOROLA_CONFIG_BLOCK (EM4x05_SET_BITRATE(32) | EM4x05_MODULATION_PSK1 | EM4x05_PSK_RF_2 | EM4x05_SET_NUM_BLOCKS(2) ) // PSK1, data rate 32, 2 data blocks
#define EM4305_NEXWATCH_CONFIG_BLOCK (EM4x05_SET_BITRATE(64) | EM4x05_MODULATION_PSK1 | EM4x05_PSK_RF_2 | EM4x05_SET_NUM_BLOCKS(3) ) // PSK1 data rate 16, psk carrier FC * 2, 3 data blocks
#define EM4305_KERI_CONFIG_BLOCK (EM4x05_SET_BITRATE(64) | EM4x05_MODULATION_PSK1 | EM4x05_PSK_RF_2 | EM4x05_SET_NUM_BLOCKS(2) ) // PSK1, 2 data blocks
#define EM4305_JABLOTRON_CONFIG_BLOCK (EM4x05_SET_BITRATE(64) | EM4x05_MODULATION_BIPHASE | EM4x05_SET_NUM_BLOCKS(2) ) // Biphase, data rate 64, 2 data blocks
#define EM4305_GUARDPROXII_CONFIG_BLOCK (EM4x05_SET_BITRATE(64) | EM4x05_MODULATION_BIPHASE | EM4x05_SET_NUM_BLOCKS(3) ) // Biphase, data rate 64, Direct modulation, 3 data blocks
#define EM4305_NEDAP_64_CONFIG_BLOCK (EM4x05_SET_BITRATE(64) | EM4x05_MODULATION_BIPHASE | EM4x05_SET_NUM_BLOCKS(2) ) // Biphase, data rate 64, 2 data blocks
#define EM4305_NEDAP_128_CONFIG_BLOCK (EM4x05_SET_BITRATE(64) | EM4x05_MODULATION_BIPHASE | EM4x05_SET_NUM_BLOCKS(4) ) // Biphase, data rate 64, 4 data blocks
#define EM4305_PAC_CONFIG_BLOCK (EM4x05_SET_BITRATE(32) | EM4x05_MODULATION_NRZ | EM4x05_SET_NUM_BLOCKS(4) ) // NRZ, data rate 32, 4 data blocks
#define EM4305_VERICHIP_CONFIG_BLOCK (EM4x05_SET_BITRATE(40) | EM4x05_MODULATION_NRZ | EM4x05_SET_NUM_BLOCKS(4) ) // NRZ, data rate 40, 4 data blocks
typedef enum {
EM_UNKNOWN,
EM_4205,
EM_4305,
EM_4X69,
} em_tech_type_t;
int CmdLFEM4X05(const char *Cmd);
bool em4x05_isblock0(uint32_t *word);
int em4x05_read_word_ext(uint8_t addr, uint32_t pwd, bool use_pwd, uint32_t *word);
int em4x05_write_word_ext(uint8_t addr, uint32_t pwd, bool use_pwd, uint32_t data);
int em4x05_clone_tag(uint32_t *blockdata, uint8_t numblocks, uint32_t pwd, bool use_pwd);
int CmdEM4x05Demod(const char *Cmd);
int CmdEM4x05Dump(const char *Cmd);
int CmdEM4x05Read(const char *Cmd);
int CmdEM4x05Write(const char *Cmd);
int CmdEM4x05Wipe(const char *Cmd);
int CmdEM4x05Info(const char *Cmd);
int CmdEM4x05Chk(const char *Cmd);
int CmdEM4x05Unlock(const char *Cmd);
int CmdEM4x05Sniff(const char *Cmd);
int CmdEM4x05Brute(const char *Cmd);
#endif

View file

@ -16,7 +16,7 @@
#include "em4x50.h"
static int usage_lf_em4x50_info(void) {
PrintAndLogEx(NORMAL, "Read all information of EM4x50. Tag nust be on antenna.");
PrintAndLogEx(NORMAL, "Read all information of EM4x50. Tag must be on antenna.");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf em 4x50_info [h] [v] [p <pwd>]");
PrintAndLogEx(NORMAL, "Options:");
@ -307,7 +307,7 @@ int CmdEM4x50Info(const char *Cmd) {
SendCommandNG(CMD_LF_EM4X50_INFO, (uint8_t *)&etd, sizeof(etd));
PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) {
if (!WaitForResponseTimeout(CMD_LF_EM4X50_INFO, &resp, TIMEOUT)) {
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
return PM3_ETIMEOUT;
}
@ -380,11 +380,14 @@ int CmdEM4x50Write(const char *Cmd) {
clearCommandBuffer();
SendCommandNG(CMD_LF_EM4X50_WRITE, (uint8_t *)&etd, sizeof(etd));
PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) {
if (!WaitForResponseTimeout(CMD_LF_EM4X50_WRITE, &resp, TIMEOUT)) {
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
return PM3_ETIMEOUT;
}
if (resp.status == PM3_ETEAROFF)
return PM3_SUCCESS;
bool isOK = (resp.status & STATUS_SUCCESS) >> 1;
if (isOK == false) {
PrintAndLogEx(FAILED, "writing " _RED_("failed"));
@ -455,10 +458,14 @@ int CmdEM4x50WritePassword(const char *Cmd) {
clearCommandBuffer();
SendCommandNG(CMD_LF_EM4X50_WRITE_PASSWORD, (uint8_t *)&etd, sizeof(etd));
if (!WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) {
if (!WaitForResponseTimeout(CMD_LF_EM4X50_WRITE_PASSWORD, &resp, TIMEOUT)) {
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
return PM3_ETIMEOUT;
}
if (resp.status == PM3_ETEAROFF)
return PM3_SUCCESS;
success = (bool)resp.status;
// print response
@ -487,7 +494,7 @@ int em4x50_read(em4x50_data_t *etd, em4x50_word_t *out, bool verbose) {
SendCommandNG(CMD_LF_EM4X50_READ, (uint8_t *)&edata, sizeof(edata));
PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) {
if (!WaitForResponseTimeout(CMD_LF_EM4X50_READ, &resp, TIMEOUT)) {
PrintAndLogEx(WARNING, "(em4x50) timeout while waiting for reply.");
return PM3_ETIMEOUT;
}
@ -628,7 +635,7 @@ int CmdEM4x50Dump(const char *Cmd) {
clearCommandBuffer();
SendCommandNG(CMD_LF_EM4X50_INFO, (uint8_t *)&etd, sizeof(etd));
PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, TIMEOUT)) {
if (!WaitForResponseTimeout(CMD_LF_EM4X50_INFO, &resp, TIMEOUT)) {
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
return PM3_ETIMEOUT;
}
@ -699,9 +706,19 @@ int CmdEM4x50Wipe(const char *Cmd) {
return usage_lf_em4x50_wipe();
clearCommandBuffer();
<<<<<<< HEAD
SendCommandNG(CMD_LF_EM4X50_WIPE, (uint8_t *)&password, sizeof(password));
WaitForResponse(CMD_ACK, &resp);
=======
SendCommandNG(CMD_LF_EM4X50_WIPE, (uint8_t *)&etd, sizeof(etd));
if (!WaitForResponseTimeout(CMD_LF_EM4X50_WIPE, &resp, 2 * TIMEOUT)) {
PrintAndLogEx(WARNING, "\ntimeout while waiting for reply.\n");
return PM3_ETIMEOUT;
}
>>>>>>> master
// print response
bool isOK = resp.status;
if (isOK) {

View file

@ -8,7 +8,7 @@
// Differential Biphase, rf/32, 128 bits (known)
//-----------------------------------------------------------------------------
#include "cmdlffdx.h"
#include "cmdlffdxb.h"
#include <inttypes.h>
#include <string.h>
@ -48,9 +48,9 @@
static int CmdHelp(const char *Cmd);
static int usage_lf_fdx_clone(void) {
static int usage_lf_fdxb_clone(void) {
PrintAndLogEx(NORMAL, "Clone a FDX-B animal tag to a T55x7 or Q5/T5555 tag.");
PrintAndLogEx(NORMAL, "Usage: lf fdx clone [h] [c <country code>] [a <national code>] [e <extended>] <s> <Q5>");
PrintAndLogEx(NORMAL, "Usage: lf fdxb clone [h] [c <country code>] [a <national code>] [e <extended>] <s> <Q5>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : This help");
PrintAndLogEx(NORMAL, " c <country> : (dec) Country code");
@ -60,15 +60,15 @@ static int usage_lf_fdx_clone(void) {
PrintAndLogEx(NORMAL, " <Q5> : Specify writing to Q5/T5555 tag");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" lf fdx clone c 999 n 112233 s"));
PrintAndLogEx(NORMAL, _YELLOW_(" lf fdx clone c 999 n 112233 e 16a"));
PrintAndLogEx(NORMAL, _YELLOW_(" lf fdxb clone c 999 n 112233 s"));
PrintAndLogEx(NORMAL, _YELLOW_(" lf fdxb clone c 999 n 112233 e 16a"));
return PM3_SUCCESS;
}
static int usage_lf_fdx_read(void) {
static int usage_lf_fdxb_read(void) {
PrintAndLogEx(NORMAL, "Read FDX-B animal tag");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf fdx read [h] [@]");
PrintAndLogEx(NORMAL, "Usage: lf fdxb read [h] [@]");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : This help");
PrintAndLogEx(NORMAL, " @ : run continuously until a key is pressed (optional)");
@ -76,11 +76,11 @@ static int usage_lf_fdx_read(void) {
return PM3_SUCCESS;
}
static int usage_lf_fdx_sim(void) {
static int usage_lf_fdxb_sim(void) {
PrintAndLogEx(NORMAL, "Enables simulation of FDX-B animal tag");
PrintAndLogEx(NORMAL, "Simulation runs until the button is pressed or another USB command is issued.");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf fdx sim [h] [c <country code>] [n <national code>] [e <extended>] <s> <Q5>");
PrintAndLogEx(NORMAL, "Usage: lf fdxb sim [h] [c <country code>] [n <national code>] [e <extended>] <s> <Q5>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : This help");
PrintAndLogEx(NORMAL, " c <country> : (dec) Country code");
@ -90,8 +90,8 @@ static int usage_lf_fdx_sim(void) {
PrintAndLogEx(NORMAL, " <Q5> : Specify writing to Q5/T5555 tag");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" lf fdx sim c 999 n 112233 s"));
PrintAndLogEx(NORMAL, _YELLOW_(" lf fdx sim c 999 n 112233 e 16a"));
PrintAndLogEx(NORMAL, _YELLOW_(" lf fdxb sim c 999 n 112233 s"));
PrintAndLogEx(NORMAL, _YELLOW_(" lf fdxb sim c 999 n 112233 e 16a"));
return PM3_SUCCESS;
}
@ -215,9 +215,275 @@ static int CmdFDXBdemodBI(const char *Cmd) {
}
*/
// For the country part:
// wget -q -O - "https://en.wikipedia.org/w/index.php?title=List_of_ISO_3166_country_codes&action=raw" | awk '/id=/{match($0, /\[\[([^\]|]*)/, a); name=a[1];getline;getline;getline;getline;getline;match($0, /numeric#([0-9]*)/, a);num=a[1]; if (num != "") {printf " { %3u, \"%s\" },\n", num, name}}'
// Beware the bottom of the list contains also Manufacturers list
const fdxbCountryMapping_t fdxbCountryMapping[] = {
{ 4, "Afghanistan" },
{ 8, "Albania" },
{ 12, "Algeria" },
{ 16, "American Samoa" },
{ 20, "Andorra" },
{ 24, "Angola" },
{ 660, "Anguilla" },
{ 10, "Antarctica" },
{ 28, "Antigua and Barbuda" },
{ 32, "Argentina" },
{ 51, "Armenia" },
{ 533, "Aruba" },
{ 40, "Austria" },
{ 31, "Azerbaijan" },
{ 44, "The Bahamas" },
{ 48, "Bahrain" },
{ 50, "Bangladesh" },
{ 52, "Barbados" },
{ 112, "Belarus" },
{ 56, "Belgium" },
{ 84, "Belize" },
{ 204, "Benin" },
{ 60, "Bermuda" },
{ 64, "Bhutan" },
{ 68, "Bolivia" },
{ 535, "Bonaire" },
{ 70, "Bosnia and Herzegovina" },
{ 72, "Botswana" },
{ 74, "Bouvet Island" },
{ 76, "Brazil" },
{ 86, "British Indian Ocean Territory" },
{ 100, "Bulgaria" },
{ 854, "Burkina Faso" },
{ 132, "Cape Verde" },
{ 116, "Cambodia" },
{ 120, "Cameroon" },
{ 124, "Canada" },
{ 140, "Central African Republic" },
{ 148, "Chad" },
{ 152, "Chile" },
{ 156, "China" },
{ 170, "Colombia" },
{ 174, "Comoros" },
{ 180, "Democratic Republic of the Congo" },
{ 178, "Republic of the Congo" },
{ 184, "Cook Islands" },
{ 384, "Ivory Coast" },
{ 191, "Croatia" },
{ 192, "Cuba" },
{ 531, "Curaçao" },
{ 196, "Cyprus" },
{ 203, "Czech Republic" },
{ 262, "Djibouti" },
{ 212, "Dominica" },
{ 214, "Dominican Republic" },
{ 818, "Egypt" },
{ 222, "El Salvador" },
{ 232, "Eritrea" },
{ 233, "Estonia" },
{ 748, "Eswatini" },
{ 231, "Ethiopia" },
{ 238, "Falkland Islands" },
{ 234, "Faroe Islands" },
{ 242, "Fiji" },
{ 246, "Finland" },
{ 250, "France" },
{ 254, "French Guiana" },
{ 258, "French Polynesia" },
{ 260, "French Southern Territories" },
{ 266, "Gabon" },
{ 270, "The Gambia" },
{ 268, "Georgia (country)" },
{ 276, "Germany" },
{ 288, "Ghana" },
{ 292, "Gibraltar" },
{ 304, "Greenland" },
{ 308, "Grenada" },
{ 312, "Guadeloupe" },
{ 316, "Guam" },
{ 320, "Guatemala" },
{ 831, "Bailiwick of Guernsey" },
{ 324, "Guinea" },
{ 624, "Guinea-Bissau" },
{ 328, "Guyana" },
{ 332, "Haiti" },
{ 336, "Holy See" },
{ 340, "Honduras" },
{ 344, "Hong Kong" },
{ 348, "Hungary" },
{ 352, "Iceland" },
{ 356, "India" },
{ 360, "Indonesia" },
{ 364, "Iran (Islamic Republic of)" },
{ 368, "Iraq" },
{ 372, "Republic of Ireland" },
{ 833, "Isle of Man" },
{ 376, "Israel" },
{ 380, "Italy" },
{ 832, "Jersey" },
{ 400, "Jordan" },
{ 398, "Kazakhstan" },
{ 404, "Kenya" },
{ 296, "Kiribati" },
{ 408, "North Korea" },
{ 410, "South Korea" },
{ 414, "Kuwait" },
{ 417, "Kyrgyzstan" },
{ 418, "Laos" },
{ 428, "Latvia" },
{ 422, "Lebanon" },
{ 426, "Lesotho" },
{ 430, "Liberia" },
{ 434, "Libya" },
{ 438, "Liechtenstein" },
{ 440, "Lithuania" },
{ 442, "Luxembourg" },
{ 446, "Macau" },
{ 807, "North Macedonia" },
{ 450, "Madagascar" },
{ 454, "Malawi" },
{ 458, "Malaysia" },
{ 462, "Maldives" },
{ 466, "Mali" },
{ 470, "Malta" },
{ 584, "Marshall Islands" },
{ 474, "Martinique" },
{ 478, "Mauritania" },
{ 480, "Mauritius" },
{ 175, "Mayotte" },
{ 484, "Mexico" },
{ 583, "Federated States of Micronesia" },
{ 498, "Moldova" },
{ 492, "Monaco" },
{ 496, "Mongolia" },
{ 499, "Montenegro" },
{ 500, "Montserrat" },
{ 504, "Morocco" },
{ 508, "Mozambique" },
{ 104, "Myanmar" },
{ 516, "Namibia" },
{ 520, "Nauru" },
{ 524, "Nepal" },
{ 528, "Kingdom of the Netherlands" },
{ 540, "New Caledonia" },
{ 554, "New Zealand" },
{ 558, "Nicaragua" },
{ 562, "Niger" },
{ 566, "Nigeria" },
{ 570, "Niue" },
{ 574, "Norfolk Island" },
{ 578, "Norway" },
{ 512, "Oman" },
{ 586, "Pakistan" },
{ 585, "Palau" },
{ 275, "State of Palestine" },
{ 591, "Panama" },
{ 598, "Papua New Guinea" },
{ 600, "Paraguay" },
{ 608, "Philippines" },
{ 612, "Pitcairn Islands" },
{ 616, "Poland" },
{ 620, "Portugal" },
{ 630, "Puerto Rico" },
{ 634, "Qatar" },
{ 638, "Réunion" },
{ 642, "Romania" },
{ 643, "Russia" },
{ 646, "Rwanda" },
{ 654, "Saint Helena" },
{ 659, "Saint Kitts and Nevis" },
{ 662, "Saint Lucia" },
{ 663, "Collectivity of Saint Martin" },
{ 666, "Saint Pierre and Miquelon" },
{ 670, "Saint Vincent and the Grenadines" },
{ 882, "Samoa" },
{ 674, "San Marino" },
{ 678, "São Tomé and Príncipe" },
{ 682, "Saudi Arabia" },
{ 688, "Serbia" },
{ 690, "Seychelles" },
{ 694, "Sierra Leone" },
{ 702, "Singapore" },
{ 703, "Slovakia" },
{ 705, "Slovenia" },
{ 90, "Solomon Islands" },
{ 706, "Somalia" },
{ 710, "South Africa" },
{ 239, "South Georgia and the South Sandwich Islands" },
{ 724, "Spain" },
{ 144, "Sri Lanka" },
{ 729, "Sudan" },
{ 740, "Suriname" },
{ 744, "Svalbard" },
{ 752, "Sweden" },
{ 756, "Switzerland" },
{ 760, "Syria" },
{ 158, "Taiwan" },
{ 762, "Tajikistan" },
{ 834, "Tanzania" },
{ 764, "Thailand" },
{ 626, "East Timor" },
{ 768, "Togo" },
{ 772, "Tokelau" },
{ 776, "Tonga" },
{ 780, "Trinidad and Tobago" },
{ 788, "Tunisia" },
{ 792, "Turkey" },
{ 795, "Turkmenistan" },
{ 796, "Turks and Caicos Islands" },
{ 798, "Tuvalu" },
{ 800, "Uganda" },
{ 804, "Ukraine" },
{ 784, "United Arab Emirates" },
{ 826, "United Kingdom" },
{ 581, "United States Minor Outlying Islands" },
{ 840, "United States" },
{ 860, "Uzbekistan" },
{ 548, "Vanuatu" },
{ 704, "Vietnam" },
{ 92, "British Virgin Islands" },
{ 850, "United States Virgin Islands" },
{ 732, "Western Sahara" },
{ 887, "Yemen" },
{ 894, "Zambia" },
{ 716, "Zimbabwe" },
// Manufacturers list:
{ 952, "JECTA" },
{ 953, "Cromasa Identificacion electronica S.A."},
{ 955, "Reseaumatique" },
{ 956, "Trovan Ltd. (ACK Reunite)" },
{ 958, "Pet ID" },
{ 959, "Global ID Technologies" },
{ 961, "Mannings I.A.I.D." },
{ 963, "Korth Eletro Mecanica LTDA" },
{ 965, "4D Technology Co. Ltd" },
{ 966, "PetCode" },
{ 967, "Rfdynamics / M4S ID in Canada" },
{ 968, "AEG / EIDAP in Canada" },
{ 972, "Planet ID" },
{ 975, "Sokymat" },
{ 977, "AVID" },
{ 978, "Ordicam" },
{ 981, "Microfindr, Datamars, Found Animals, Crystal Tag, Banfield, Bayer resQ, Peeva" },
{ 982, "24 Pet Watch (Allflex)" },
{ 985, "HomeAgain (Destron Fearing/Digital Angel)" },
{ 991, "Peeva" },
{ 999, "Test range" },
{ 0, "N/A" } // must be the last entry
};
static const char *mapFDBX(uint16_t countryCode) {
uint16_t i = 0;
while (fdxbCountryMapping[i].code > 0) {
if (countryCode == fdxbCountryMapping[i].code) {
return fdxbCountryMapping[i].desc;
}
i++;
}
return fdxbCountryMapping[i].desc;
}
//see ASKDemod for what args are accepted
//almost the same demod as cmddata.c/CmdFDXBdemodBI
int demodFDX(bool verbose) {
int demodFDXB(bool verbose) {
//Differential Biphase / di-phase (inverted biphase)
//get binary from ask wave
if (ASKbiphaseDemod(0, 32, 1, 100, false) != PM3_SUCCESS) {
@ -253,18 +519,34 @@ int demodFDX(bool verbose) {
//got a good demod
uint8_t offset;
// ISO: bits 27..64
uint64_t NationalCode = ((uint64_t)(bytebits_to_byteLSBF(DemodBuffer + 32, 6)) << 32) | bytebits_to_byteLSBF(DemodBuffer, 32);
offset = 38;
// ISO: bits 17..26
uint16_t countryCode = bytebits_to_byteLSBF(DemodBuffer + offset, 10);
offset += 10;
// ISO: bits 16
uint8_t dataBlockBit = DemodBuffer[offset];
offset++;
uint32_t reservedCode = bytebits_to_byteLSBF(DemodBuffer + offset, 14);
// ISO: bits 15
uint8_t rudiBit = DemodBuffer[offset];
offset += 14;
offset++;
// ISO: bits 10..14
uint32_t reservedCode = bytebits_to_byteLSBF(DemodBuffer + offset, 5);
offset += 5;
// ISO: bits 5..9
uint32_t userInfo = bytebits_to_byteLSBF(DemodBuffer + offset, 5);
offset += 5;
// ISO: bits 2..4
uint32_t replacementNr = bytebits_to_byteLSBF(DemodBuffer + offset, 3);
offset += 3;
uint8_t animalBit = DemodBuffer[offset];
offset++;
@ -283,12 +565,15 @@ int demodFDX(bool verbose) {
return PM3_SUCCESS;
}
PrintAndLogEx(SUCCESS, "FDX-B / ISO 11784/5 Animal");
PrintAndLogEx(SUCCESS, "Animal ID " _GREEN_("%04u-%012"PRIu64), countryCode, NationalCode);
PrintAndLogEx(SUCCESS, "Animal ID " _GREEN_("%03u-%012"PRIu64), countryCode, NationalCode);
PrintAndLogEx(SUCCESS, "National Code " _GREEN_("%012" PRIu64) " (0x%" PRIX64 ")", NationalCode, NationalCode);
PrintAndLogEx(SUCCESS, "Country Code " _GREEN_("%04u"), countryCode);
PrintAndLogEx(SUCCESS, "Country Code " _GREEN_("%03u") " - %s", countryCode, mapFDBX(countryCode));
PrintAndLogEx(SUCCESS, "Reserved/RFU %u (0x%04X)", reservedCode, reservedCode);
PrintAndLogEx(SUCCESS, " Animal bit set? %s", animalBit ? _YELLOW_("True") : "False");
PrintAndLogEx(SUCCESS, " Data block? %s [value 0x%X]", dataBlockBit ? _YELLOW_("True") : "False", extended);
PrintAndLogEx(SUCCESS, " RUDI bit? %s", rudiBit ? _YELLOW_("True") " (advanced transponder)" : "False");
PrintAndLogEx(SUCCESS, " User Info? %u %s", userInfo, userInfo == 0 ? "(RFU)" : "");
PrintAndLogEx(SUCCESS, " Replacement No? %u %s", replacementNr, replacementNr == 0 ? "(RFU)" : "");
uint8_t c[] = {0, 0};
compute_crc(CRC_11784, raw, sizeof(raw), &c[0], &c[1]);
@ -321,12 +606,12 @@ int demodFDX(bool verbose) {
return PM3_SUCCESS;
}
static int CmdFdxDemod(const char *Cmd) {
static int CmdFdxBDemod(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
return demodFDX(true);
return demodFDXB(true);
}
static int CmdFdxRead(const char *Cmd) {
static int CmdFdxBRead(const char *Cmd) {
sample_config config;
memset(&config, 0, sizeof(sample_config));
int retval = lf_getconfig(&config);
@ -341,7 +626,7 @@ static int CmdFdxRead(const char *Cmd) {
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h':
return usage_lf_fdx_read();
return usage_lf_fdxb_read();
case '@':
continuous = true;
cmdp++;
@ -354,7 +639,7 @@ static int CmdFdxRead(const char *Cmd) {
}
//Validations
if (errors) return usage_lf_fdx_read();
if (errors) return usage_lf_fdxb_read();
int16_t tmp_div = config.divisor;
if (tmp_div != LF_DIVISOR_134) {
config.divisor = LF_DIVISOR_134;
@ -375,7 +660,7 @@ static int CmdFdxRead(const char *Cmd) {
PrintAndLogEx(ERR, "failed to get LF read from device");
return retval;
}
ret = demodFDX(!continuous); // be verbose only if not in continuous mode
ret = demodFDXB(!continuous); // be verbose only if not in continuous mode
if (kbd_enter_pressed()) {
break;
}
@ -392,7 +677,7 @@ static int CmdFdxRead(const char *Cmd) {
return ret;
}
static int CmdFdxClone(const char *Cmd) {
static int CmdFdxBClone(const char *Cmd) {
uint32_t country_code = 0, extended = 0;
uint64_t national_code = 0;
@ -402,7 +687,7 @@ static int CmdFdxClone(const char *Cmd) {
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h':
return usage_lf_fdx_clone();
return usage_lf_fdxb_clone();
case 'c': {
country_code = param_get32ex(Cmd, cmdp + 1, 0, 10);
cmdp += 2;
@ -436,7 +721,7 @@ static int CmdFdxClone(const char *Cmd) {
}
}
}
if (errors || strlen(Cmd) == 0) return usage_lf_fdx_clone();
if (errors || strlen(Cmd) == 0) return usage_lf_fdxb_clone();
verify_values(&national_code, &country_code, &extended, &is_animal);
@ -448,7 +733,7 @@ static int CmdFdxClone(const char *Cmd) {
PrintAndLogEx(INFO, " RFU 0");
uint8_t *bits = calloc(128, sizeof(uint8_t));
if (getFDXBits(national_code, country_code, is_animal, has_extended, extended, bits) != PM3_SUCCESS) {
if (getFDXBBits(national_code, country_code, is_animal, has_extended, extended, bits) != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Error with tag bitstream generation.");
free(bits);
return PM3_ESOFT;
@ -473,11 +758,11 @@ static int CmdFdxClone(const char *Cmd) {
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf fdx read`") " to verify");
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf fdxb read`") " to verify");
return res;
}
static int CmdFdxSim(const char *Cmd) {
static int CmdFdxBSim(const char *Cmd) {
uint32_t country_code = 0, extended = 0;
uint64_t national_code = 0;
@ -487,7 +772,7 @@ static int CmdFdxSim(const char *Cmd) {
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h':
return usage_lf_fdx_sim();
return usage_lf_fdxb_sim();
case 'c': {
country_code = param_get32ex(Cmd, cmdp + 1, 0, 10);
cmdp += 2;
@ -516,7 +801,7 @@ static int CmdFdxSim(const char *Cmd) {
}
}
}
if (errors) return usage_lf_fdx_sim();
if (errors) return usage_lf_fdxb_sim();
verify_values(&national_code, &country_code, &extended, &is_animal);
@ -530,7 +815,7 @@ static int CmdFdxSim(const char *Cmd) {
PrintAndLogEx(SUCCESS, "Simulating FDX-B animal ID: " _GREEN_("%04u-%"PRIu64), country_code, national_code);
uint8_t *bits = calloc(128, sizeof(uint8_t));
if (getFDXBits(national_code, country_code, is_animal, (extended > 0), extended, bits) != PM3_SUCCESS) {
if (getFDXBBits(national_code, country_code, is_animal, (extended > 0), extended, bits) != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Error with tag bitstream generation.");
free(bits);
return PM3_ESOFT;
@ -562,10 +847,10 @@ static int CmdFdxSim(const char *Cmd) {
static command_t CommandTable[] = {
{"help", CmdHelp, AlwaysAvailable, "this help"},
{"demod", CmdFdxDemod, AlwaysAvailable, "demodulate a FDX-B ISO11784/85 tag from the GraphBuffer"},
{"read", CmdFdxRead, IfPm3Lf, "attempt to read at 134kHz and extract tag data"},
{"clone", CmdFdxClone, IfPm3Lf, "clone animal ID tag to T55x7 or Q5/T5555"},
{"sim", CmdFdxSim, IfPm3Lf, "simulate Animal ID tag"},
{"demod", CmdFdxBDemod, AlwaysAvailable, "demodulate a FDX-B ISO11784/85 tag from the GraphBuffer"},
{"read", CmdFdxBRead, IfPm3Lf, "attempt to read at 134kHz and extract tag data"},
{"clone", CmdFdxBClone, IfPm3Lf, "clone animal ID tag to T55x7 or Q5/T5555"},
{"sim", CmdFdxBSim, IfPm3Lf, "simulate Animal ID tag"},
{NULL, NULL, NULL, NULL}
};
@ -575,7 +860,7 @@ static int CmdHelp(const char *Cmd) {
return PM3_SUCCESS;
}
int CmdLFFdx(const char *Cmd) {
int CmdLFFdxB(const char *Cmd) {
clearCommandBuffer();
return CmdsParse(CommandTable, Cmd);
}
@ -589,12 +874,12 @@ int detectFDXB(uint8_t *dest, size_t *size) {
uint8_t preamble[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
if (!preambleSearch(dest, preamble, sizeof(preamble), size, &startIdx))
return -2; //preamble not found
if (*size != 128) return -3; //wrong demoded size
if (*size < 128) return -3; //wrong demoded size
//return start position
return (int)startIdx;
}
int getFDXBits(uint64_t national_code, uint16_t country_code, uint8_t is_animal, uint8_t is_extended, uint32_t extended, uint8_t *bits) {
int getFDXBBits(uint64_t national_code, uint16_t country_code, uint8_t is_animal, uint8_t is_extended, uint32_t extended, uint8_t *bits) {
// add preamble ten 0x00 and one 0x01
memset(bits, 0x00, 10);
@ -634,7 +919,7 @@ int getFDXBits(uint64_t national_code, uint16_t country_code, uint8_t is_animal,
raw[i] = bytebits_to_byte(bits + 11 + i * 9, 8);
init_table(CRC_11784);
uint16_t crc = crc16_fdx(raw, 8);
uint16_t crc = crc16_fdxb(raw, 8);
num_to_bytebitsLSBF(crc >> 0, 8, bits + 83);
num_to_bytebitsLSBF(crc >> 8, 8, bits + 92);

View file

@ -6,15 +6,20 @@
//-----------------------------------------------------------------------------
// Low frequency fdx-b tag commands
//-----------------------------------------------------------------------------
#ifndef CMDLFFDX_H__
#define CMDLFFDX_H__
#ifndef CMDLFFDXB_H__
#define CMDLFFDXB_H__
#include "common.h"
int CmdLFFdx(const char *Cmd);
typedef struct {
uint16_t code;
const char *desc;
} fdxbCountryMapping_t;
int CmdLFFdxB(const char *Cmd);
int detectFDXB(uint8_t *dest, size_t *size);
int demodFDX(bool verbose);
int getFDXBits(uint64_t national_code, uint16_t country_code, uint8_t is_animal, uint8_t is_extended, uint32_t extended, uint8_t *bits);
int demodFDXB(bool verbose);
int getFDXBBits(uint64_t national_code, uint16_t country_code, uint8_t is_animal, uint8_t is_extended, uint32_t extended, uint8_t *bits);
#endif

View file

@ -186,7 +186,7 @@ static int CmdGuardClone(const char *Cmd) {
// Q5
bool q5 = tolower(param_getchar(Cmd, 3)) == 'q';
if (q5)
blocks[0] = T5555_FIXED | T5555_MODULATION_FSK2 | T5555_SET_BITRATE(50) | 3 << T5555_MAXBLOCK_SHIFT;
blocks[0] = T5555_FIXED | T5555_MODULATION_BIPHASE | T5555_SET_BITRATE(64) | 3 << T5555_MAXBLOCK_SHIFT;
blocks[1] = bytebits_to_byte(bs, 32);
blocks[2] = bytebits_to_byte(bs + 32, 32);

View file

@ -37,6 +37,7 @@
#include "util_posix.h"
#include "lfdemod.h"
#include "wiegand_formats.h"
#include "wiegand_formatutils.h"
#ifndef BITS
# define BITS 96
@ -135,61 +136,8 @@ int demodHID(bool verbose) {
return PM3_ESOFT;
}
if (hi2 != 0) { //extra large HID tags
PrintAndLogEx(SUCCESS, "HID Prox - " _GREEN_("%x%08x%08x (%u)"), hi2, hi, lo, (lo >> 1) & 0xFFFF);
} else { //standard HID tags <38 bits
uint8_t fmtLen = 0;
uint32_t cc = 0;
uint32_t fc = 0;
uint32_t cardnum = 0;
uint8_t oem = 0;
if (((hi >> 5) & 1) == 1) {//if bit 38 is set then < 37 bit format is used
uint32_t lo2 = 0;
lo2 = (((hi & 31) << 12) | (lo >> 20)); //get bits 21-37 to check for format len bit
uint8_t idx3 = 1;
while (lo2 > 1) { //find last bit set to 1 (format len bit)
lo2 >>= 1;
idx3++;
}
fmtLen = idx3 + 19;
fc = 0;
cardnum = 0;
if (fmtLen == 26) {
cardnum = (lo >> 1) & 0xFFFF;
fc = (lo >> 17) & 0xFF;
}
if (fmtLen == 32 && (lo & 0x40000000)) { //if 32 bit and Kastle bit set
cardnum = (lo >> 1) & 0xFFFF;
fc = (lo >> 17) & 0xFF;
cc = (lo >> 25) & 0x1F;
}
if (fmtLen == 34) {
cardnum = (lo >> 1) & 0xFFFF;
fc = ((hi & 1) << 15) | (lo >> 17);
}
if (fmtLen == 35) {
cardnum = (lo >> 1) & 0xFFFFF;
fc = ((hi & 1) << 11) | (lo >> 21);
}
if (fmtLen == 36) {
oem = (lo >> 1) & 0x3;
cardnum = (lo >> 3) & 0xFFFF;
fc = (hi & 0x7) << 13 | ((lo >> 19) & 0xFFFF);
}
} else { //if bit 38 is not set then 37 bit format is used
fmtLen = 37;
cardnum = (lo >> 1) & 0x7FFFF;
fc = ((hi & 0xF) << 12) | (lo >> 20);
}
if (fmtLen == 32 && (lo & 0x40000000)) { //if 32 bit and Kastle bit set
PrintAndLogEx(SUCCESS,
"HID Prox (Kastle format) - " _GREEN_("%x%08x (%u)") " - len: " _GREEN_("32") " bit CC: " _GREEN_("%u") " FC: " _GREEN_("%u") " Card: " _GREEN_("%u"), hi, lo, (lo >> 1) & 0xFFFF, cc, fc, cardnum);
} else {
PrintAndLogEx(SUCCESS,
"HID Prox - " _GREEN_("%x%08x (%u)") " - len: " _GREEN_("%u") " bit - OEM: " _GREEN_("%03u") " FC: " _GREEN_("%u")" Card: " _GREEN_("%u"),
hi, lo, cardnum, fmtLen, oem, fc, cardnum);
}
}
wiegand_message_t packed = initialize_message_object(hi2, hi, lo);
HIDTryUnpack(&packed, false);
PrintAndLogEx(DEBUG, "DEBUG: HID idx: %d, Len: %zu, Printing Demod Buffer: ", idx, size);
if (g_debugMode)
@ -206,7 +154,7 @@ static int CmdHIDDemod(const char *Cmd) {
// this read is the "normal" read, which download lf signal and tries to demod here.
static int CmdHIDRead(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
lf_read(false, 12000);
lf_read(false, 16000);
return demodHID(true);
}
@ -239,62 +187,85 @@ static int CmdHIDWatch(const char *Cmd) {
}
static int CmdHIDSim(const char *Cmd) {
int idlen = 0;
uint8_t id[10] = {0};
lf_hidsim_t payload;
payload.longFMT = 0;
uint32_t hi2 = 0, hi = 0, lo = 0;
uint32_t i = 0;
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf hid sim",
"Enables simulation of HID card with card number.",
"lf hid sim 2006ec0c86"
"lf hid sim -r 2006ec0c86 -> HID 10301 26 bit\n"
"lf hid sim -r 2e0ec00c87 -> HID Corporate 35 bit\n"
"lf hid sim -r 01f0760643c3 -> HID P10001 40 bit\n"
"lf hid sim -r 01400076000c86 -> HID Corporate 48 bit\n"
"lf hid sim -w H10301 --fc 118 --cn 1603 -> HID 10301 26 bit\n"
);
void *argtable[] = {
arg_param_begin,
arg_lit0("l", "long", "Simulate HID tag with long ID"),
arg_str1(NULL, NULL, "<hex>", "HID tag ID"),
arg_str0("w", "wiegand", "<format>", "see " _YELLOW_("`wiegand list`") " for available formats"),
arg_u64_0(NULL, "fc", "<dec>", "facility code"),
arg_u64_0(NULL, "cn", "<dec>", "card number"),
arg_int0("i", NULL, "<dec>", "issue level"),
arg_int0("o", "oem", "<dec>", "OEM code"),
arg_strx0("r", "raw", "<hex>", "raw bytes"),
// arg_lit0("q", "Q5", "optional - specify writing to Q5/T5555 tag"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
bool long_id = arg_get_lit(ctx, 1);
char format[16] = {0};
int format_len = 0;
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)format, sizeof(format), &format_len);
CLIGetHexWithReturn(ctx, 2, id, &idlen);
wiegand_card_t card;
memset(&card, 0, sizeof(wiegand_card_t));
card.FacilityCode = arg_get_u32_def(ctx, 2, 0);
card.CardNumber = arg_get_u32_def(ctx, 3, 0);
card.IssueLevel = arg_get_u32_def(ctx, 4, 0);
card.OEM = arg_get_u32_def(ctx, 5, 0);
int raw_len = 0;
char raw[40] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 6), (uint8_t *)raw, sizeof(raw), &raw_len);
//bool q5 = arg_get_lit(ctx, 7);
CLIParserFree(ctx);
if (long_id) {
for (i=0; i < idlen; ++i) {
hi2 = (hi2 << 4) | (hi >> 28);
hi = (hi << 4) | (lo >> 28);
lo = (lo << 4) | (id[i] >> 4); //get first 4 bits
wiegand_message_t packed;
memset(&packed, 0, sizeof(wiegand_message_t));
hi2 = (hi2 << 4) | (hi >> 28);
hi = (hi << 4) | (lo >> 28);
lo = (lo << 4) | (id[i] & 0xf); //get last 4 bits
// format validation
int format_idx = HIDFindCardFormat((char *)format);
if (format_idx == -1 && raw_len == 0) {
PrintAndLogEx(WARNING, "Unknown format: " _YELLOW_("%s"), format);
return PM3_EINVARG;
}
PrintAndLogEx(INFO, "Simulating HID tag with long ID: " _GREEN_("%x%08x%08x"), hi2, hi, lo);
payload.longFMT = 1;
if (raw_len) {
uint32_t top = 0, mid = 0, bot = 0;
hexstring_to_u96(&top, &mid, &bot, raw);
packed.Top = top;
packed.Mid = mid;
packed.Bot = bot;
} else {
for (i=0; i < idlen; ++i) {
hi = (hi << 4) | (lo >> 28);
lo = (lo << 4) | (id[i] >> 4); //get first 4 bits
hi = (hi << 4) | (lo >> 28);
lo = (lo << 4) | (id[i] & 0xf); //get last 4 bits
if (HIDPack(format_idx, &card, &packed) == false) {
PrintAndLogEx(WARNING, "The card data could not be encoded in the selected format.");
return PM3_ESOFT;
}
PrintAndLogEx(SUCCESS, "Simulating HID tag with ID: " _GREEN_("%x%08x"), hi, lo);
hi2 = 0;
}
if (raw_len == 0) {
PrintAndLogEx(INFO, "Simulating HID tag");
HIDTryUnpack(&packed, false);
} else {
PrintAndLogEx(INFO, "Simulating HID tag using raw " _GREEN_("%s"), raw);
}
PrintAndLogEx(INFO, "Press pm3-button to abort simulation");
payload.hi2 = hi2;
payload.hi = hi;
payload.lo = lo;
lf_hidsim_t payload;
payload.hi2 = packed.Top;
payload.hi = packed.Mid;
payload.lo = packed.Bot;
payload.longFMT = (packed.Mid > 0xFFF);
clearCommandBuffer();
SendCommandNG(CMD_LF_HID_SIMULATE, (uint8_t *)&payload, sizeof(payload));
@ -303,66 +274,92 @@ static int CmdHIDSim(const char *Cmd) {
PrintAndLogEx(INFO, "Done");
if (resp.status != PM3_EOPABORTED)
return resp.status;
return PM3_SUCCESS;
}
static int CmdHIDClone(const char *Cmd) {
int idlen = 0;
uint8_t id[10] = {0};
uint32_t hi2 = 0, hi = 0, lo = 0;
uint32_t i = 0;
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf hid clone",
"Clone HID to T55x7. Tag must be on antenna!",
"lf hid clone 2006ec0c86\n"
"lf hid clone -l 2006ec0c86"
"lf hid clone -r 2006ec0c86 -> HID 10301 26 bit\n"
"lf hid clone -r 2e0ec00c87 -> HID Corporate 35 bit\n"
"lf hid clone -r 01f0760643c3 -> HID P10001 40 bit\n"
"lf hid clone -r 01400076000c86 -> HID Corporate 48 bit\n"
"lf hid clone -w H10301 --fc 118 --cn 1603 -> HID 10301 26 bit\n"
);
void *argtable[] = {
arg_param_begin,
arg_lit0("l", "long", "84bit HID long ID"),
arg_str1(NULL, NULL, "<hex>", "HID tag ID"),
arg_str0("w", "wiegand", "<format>", "see " _YELLOW_("`wiegand list`") " for available formats"),
arg_u64_0(NULL, "fc", "<dec>", "facility code"),
arg_u64_0(NULL, "cn", "<dec>", "card number"),
arg_int0("i", NULL, "<dec>", "issue level"),
arg_int0("o", "oem", "<dec>", "OEM code"),
arg_strx0("r", "raw", "<hex>", "raw bytes"),
// arg_lit0("q", "Q5", "optional - specify writing to Q5/T5555 tag"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
bool long_id = arg_get_lit(ctx, 1);
char format[16] = {0};
int format_len = 0;
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)format, sizeof(format), &format_len);
CLIGetHexWithReturn(ctx, 2, id, &idlen);
wiegand_card_t card;
memset(&card, 0, sizeof(wiegand_card_t));
card.FacilityCode = arg_get_u32_def(ctx, 2, 0);
card.CardNumber = arg_get_u32_def(ctx, 3, 0);
card.IssueLevel = arg_get_u32_def(ctx, 4, 0);
card.OEM = arg_get_u32_def(ctx, 5, 0);
int raw_len = 0;
char raw[40] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 6), (uint8_t *)raw, sizeof(raw), &raw_len);
//bool q5 = arg_get_lit(ctx, 7);
CLIParserFree(ctx);
uint8_t longid[1] = {0};
wiegand_message_t packed;
memset(&packed, 0, sizeof(wiegand_message_t));
if (long_id) {
for (i=0; i < idlen; ++i) {
hi2 = (hi2 << 4) | (hi >> 28);
hi = (hi << 4) | (lo >> 28);
lo = (lo << 4) | (id[i] >> 4); //get first 4 bits
hi2 = (hi2 << 4) | (hi >> 28);
hi = (hi << 4) | (lo >> 28);
lo = (lo << 4) | (id[i] & 0xf); //get last 4 bits
// format validation
int format_idx = HIDFindCardFormat((char *)format);
if (format_idx == -1 && raw_len == 0) {
PrintAndLogEx(WARNING, "Unknown format: " _YELLOW_("%s"), format);
return PM3_EINVARG;
}
PrintAndLogEx(INFO, "Preparing to clone HID tag with long ID: " _GREEN_("%x%08x%08x"), hi2, hi, lo);
longid[0] = 1;
if (raw_len) {
uint32_t top = 0, mid = 0, bot = 0;
hexstring_to_u96(&top, &mid, &bot, raw);
packed.Top = top;
packed.Mid = mid;
packed.Bot = bot;
} else {
for (i=0; i < idlen; ++i) {
hi = (hi << 4) | (lo >> 28);
lo = (lo << 4) | (id[i] >> 4); //get first 4 bits
if (HIDPack(format_idx, &card, &packed) == false) {
PrintAndLogEx(WARNING, "The card data could not be encoded in the selected format.");
return PM3_ESOFT;
}
}
hi = (hi << 4) | (lo >> 28);
lo = (lo << 4) | (id[i] & 0xf); //get last 4 bits
}
PrintAndLogEx(INFO, "Preparing to clone HID tag with ID: " _GREEN_("%x%08x"), hi, lo);
hi2 = 0;
if (raw_len == 0) {
PrintAndLogEx(INFO, "Preparing to clone HID tag");
HIDTryUnpack(&packed, false);
} else {
PrintAndLogEx(INFO, "Preparing to clone HID tag using raw " _YELLOW_("%s"), raw);
}
lf_hidsim_t payload;
payload.hi2 = packed.Top;
payload.hi = packed.Mid;
payload.lo = packed.Bot;
payload.longFMT = (packed.Mid > 0xFFF);
clearCommandBuffer();
SendCommandMIX(CMD_LF_HID_CLONE, hi2, hi, lo, longid, sizeof(longid));
SendCommandNG(CMD_LF_HID_CLONE, (uint8_t *)&payload, sizeof(payload));
PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf hid read`") " to verify");
return PM3_SUCCESS;
@ -399,20 +396,20 @@ static int CmdHIDBrute(const char *Cmd) {
"Enables bruteforce of HID readers with specified facility code.\n"
"This is a attack against reader. if cardnumber is given, it starts with it and goes up / down one step\n"
"if cardnumber is not given, it starts with 1 and goes up to 65535",
"lf hid brute -w H10301 -f 224\n"
"lf hid brute -w H10301 -f 21 -d 2000\n"
"lf hid brute -v -w H10301 -f 21 -c 200 -d 2000\n"
"lf hid brute -w H10301 --fc 224\n"
"lf hid brute -w H10301 --fc 21 -d 2000\n"
"lf hid brute -v -w H10301 --fc 21 --cn 200 -d 2000\n"
);
void *argtable[] = {
arg_param_begin,
arg_lit0("v", "verbose", "verbose logging, show all tries"),
arg_str1("w", "wiegand", "format", "see " _YELLOW_("`wiegand list`") " for available formats"),
arg_int0("f", "fn", "dec", "facility code"),
arg_int0("c", "cn", "dec", "card number to start with"),
arg_int0("i", NULL, "dec", "issue level"),
arg_int0("o", "oem", "dec", "OEM code"),
arg_int0("d", "delay", "dec", "delay betweens attempts in ms. Default 1000ms"),
arg_str1("w", "wiegand", "<format>", "see " _YELLOW_("`wiegand list`") " for available formats"),
arg_int0(NULL, "fn", "<dec>", "facility code"),
arg_int0(NULL, "cn", "<dec>", "card number to start with"),
arg_int0("i", "issue", "<dec>", "issue level"),
arg_int0("o", "oem", "<dec>", "OEM code"),
arg_int0("d", "delay", "<dec>", "delay betweens attempts in ms. Default 1000ms"),
arg_lit0(NULL, "up", "direction to increment card number. (default is both directions)"),
arg_lit0(NULL, "down", "direction to decrement card number. (default is both directions)"),
arg_param_end
@ -420,12 +417,13 @@ static int CmdHIDBrute(const char *Cmd) {
CLIExecWithReturn(ctx, Cmd, argtable, false);
bool verbose = arg_get_lit(ctx, 1);
formatLen = sizeof(format);
CLIGetStrWithReturn(ctx, 2, format, &formatLen);
format_idx = HIDFindCardFormat((char*) format);
format_idx = HIDFindCardFormat((char *) format);
if (format_idx == -1) {
PrintAndLogEx(WARNING, "Unknown format: " _YELLOW_("%s"), format);
CLIParserFree(ctx);
return PM3_EINVARG;
}
@ -435,6 +433,8 @@ static int CmdHIDBrute(const char *Cmd) {
cn_hi.OEM = arg_get_int_def(ctx, 6, 0);
delay = arg_get_int_def(ctx, 7, 1000);
CLIParserFree(ctx);
if (arg_get_lit(ctx, 8) && arg_get_lit(ctx, 9)) {
direction = 0;
} else if (arg_get_lit(ctx, 8)) {

View file

@ -149,9 +149,14 @@ static int usage_hitag_checkchallenges(void) {
}
static int CmdLFHitagList(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
CmdTraceList("hitag2");
return PM3_SUCCESS;
char args[128] = {0};
if (strlen(Cmd) == 0) {
snprintf(args, sizeof(args), "-t hitag2");
} else {
strncpy(args, Cmd, sizeof(args) - 1);
}
return CmdTraceList(args);
/*
uint8_t *got = calloc(PM3_CMD_DATA_SIZE, sizeof(uint8_t));

View file

@ -567,13 +567,9 @@ static int CmdIndalaSim(const char *Cmd) {
static int CmdIndalaClone(const char *Cmd) {
bool is_long_uid = false, got_cn = false, got_26 = false;
bool is_t5555 = false;
int32_t cardnumber;
uint32_t blocks[8] = {0};
uint8_t max = 0;
uint8_t data[7 * 4];
int datalen = 0;
uint8_t fc = 0;
uint16_t cn = 0;
@ -597,13 +593,16 @@ static int CmdIndalaClone(const char *Cmd) {
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
is_long_uid = arg_get_lit(ctx, 1);
bool is_long_uid = arg_get_lit(ctx, 1);
// raw param
int datalen = 0;
uint8_t data[(7 * 4) + 1 ];
CLIGetHexWithReturn(ctx, 3, data, &datalen);
is_t5555 = arg_get_lit(ctx, 4);
bool is_t5555 = arg_get_lit(ctx, 4);
bool got_cn = false, got_26 = false;
if (is_long_uid == false) {
// Heden param
@ -618,11 +617,13 @@ static int CmdIndalaClone(const char *Cmd) {
CLIParserFree(ctx);
PrintAndLogEx(INFO, "Target chip " _YELLOW_("%s"), (is_t5555) ? "Q5/T5555" : "T55x7");
if (is_long_uid) {
// 224 BIT UID
// config for Indala (RF/32;PSK2 with RF/2;Maxblock=7)
PrintAndLogEx(INFO, "Preparing to clone Indala 224bit tag");
PrintAndLogEx(INFO, "RawID %s", sprint_hex(data, datalen));
PrintAndLogEx(INFO, "Using raw " _GREEN_("%s"), sprint_hex_inrow(data, datalen));
if (is_t5555)
blocks[0] = T5555_FIXED | T5555_SET_BITRATE(32) | T5555_MODULATION_PSK2 | (7 << T5555_MAXBLOCK_SHIFT);
@ -656,6 +657,7 @@ static int CmdIndalaClone(const char *Cmd) {
if (getIndalaBits(fc, cn, bits) != PM3_SUCCESS) {
PrintAndLogEx(ERR, "Error with tag bitstream generation.");
free(bits);
return PM3_ESOFT;
}
@ -674,7 +676,7 @@ static int CmdIndalaClone(const char *Cmd) {
// config for Indala 64 format (RF/32;PSK1 with RF/2;Maxblock=2)
PrintAndLogEx(INFO, "Preparing to clone Indala 64bit tag");
PrintAndLogEx(INFO, "RawID %s", sprint_hex(data, datalen));
PrintAndLogEx(INFO, "Using raw " _GREEN_("%s"), sprint_hex_inrow(data, datalen));
if (is_t5555)
blocks[0] = T5555_FIXED | T5555_SET_BITRATE(32) | T5555_MODULATION_PSK1 | (2 << T5555_MAXBLOCK_SHIFT);

View file

@ -8,15 +8,13 @@
// PSK1, RF/128, RF/2, 64 bits long
//-----------------------------------------------------------------------------
#include "cmdlfkeri.h"
#include <string.h>
#include <inttypes.h>
#include <ctype.h>
#include <stdlib.h>
#include "commonutil.h" // ARRAYLEN
#include "cmdparser.h" // command_t
#include "cliparser.h"
#include "comms.h"
#include "ui.h"
#include "cmddata.h"
@ -24,45 +22,9 @@
#include "protocols.h" // for T55xx config register definitions
#include "lfdemod.h" // preamble test
#include "cmdlft55xx.h" // verifywrite
#include "cmdlfem4x05.h" //
static int CmdHelp(const char *Cmd);
static int usage_lf_keri_clone(void) {
PrintAndLogEx(NORMAL, "clone a KERI tag to a T55x7 or Q5/T5555 tag\n");
PrintAndLogEx(NORMAL, "Usage: lf keri clone [h] <id> <Q5>");
PrintAndLogEx(NORMAL, "Usage extended: lf keri clone [h] t <m|i> [f <fc>] [c <cardnumber>] <Q5>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : This help");
PrintAndLogEx(NORMAL, " <id> : Keri Internal ID");
PrintAndLogEx(NORMAL, " <Q5> : specify writing to Q5/T5555 tag");
// New format
PrintAndLogEx(NORMAL, " <t> [m|i] : Type m - MS, i - Internal ID");
PrintAndLogEx(NORMAL, " <f> <fc> : Facility Code");
PrintAndLogEx(NORMAL, " <c> <cn> : Card Number");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" lf keri clone 112233"));
PrintAndLogEx(NORMAL, _YELLOW_(" lf keri clone t i fc 6 cn 12345"));
PrintAndLogEx(NORMAL, _YELLOW_(" lf keri clone t m f 6 c 12345"));
PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS;
}
static int usage_lf_keri_sim(void) {
PrintAndLogEx(NORMAL, "Enables simulation of KERI card with specified card number.");
PrintAndLogEx(NORMAL, "Simulation runs until the button is pressed or another USB command is issued.");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Usage: lf keri sim [h] <id>");
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " h : This help");
PrintAndLogEx(NORMAL, " <id> : Keri Internal ID");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" lf keri sim 112233"));
PrintAndLogEx(NORMAL, "");
return PM3_SUCCESS;
}
typedef enum {Scramble = 0, Descramble = 1} KeriMSScramble_t;
static int CmdKeriMSScramble(KeriMSScramble_t Action, uint32_t *FC, uint32_t *ID, uint32_t *CardID) {
@ -161,17 +123,6 @@ int demodKeri(bool verbose) {
setDemodBuff(DemodBuffer, size, idx);
setClockGrid(g_DemodClock, g_DemodStartIdx + (idx * g_DemodClock));
//got a good demod
uint32_t raw1 = bytebits_to_byte(DemodBuffer, 32);
uint32_t raw2 = bytebits_to_byte(DemodBuffer + 32, 32);
//get internal id
// uint32_t ID = bytebits_to_byte(DemodBuffer + 29, 32);
// Due to the 3 sync bits being at the start of the capture
// We can take the last 32bits as the internal ID.
uint32_t ID = raw2;
ID &= 0x7FFFFFFF;
/*
000000000000000000000000000001XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX111
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^1###############################^^^
@ -186,25 +137,40 @@ int demodKeri(bool verbose) {
Might be a hash of FC & CN to generate Internal ID
*/
PrintAndLogEx(SUCCESS, "KERI - Internal ID: " _GREEN_("%u") ", Raw: %08X%08X", ID, raw1, raw2);
/*
Descramble Data.
*/
uint32_t fc = 0;
uint32_t cardid = 0;
// Just need to the low 32 bits without the 111 trailer
CmdKeriMSScramble(Descramble, &fc, &cardid, &raw2);
PrintAndLogEx(SUCCESS, "Descrambled MS - FC: " _GREEN_("%d") " Card: " _GREEN_("%d"), fc, cardid);
//got a good demod
uint32_t raw1 = bytebits_to_byte(DemodBuffer, 32);
uint32_t raw2 = bytebits_to_byte(DemodBuffer + 32, 32);
if (invert) {
PrintAndLogEx(INFO, "Had to Invert - probably KERI");
for (size_t i = 0; i < size; i++)
DemodBuffer[i] ^= 1;
raw1 = bytebits_to_byte(DemodBuffer, 32);
raw2 = bytebits_to_byte(DemodBuffer + 32, 32);
CmdPrintDemodBuff("x");
}
//get internal id
// uint32_t ID = bytebits_to_byte(DemodBuffer + 29, 32);
// Due to the 3 sync bits being at the start of the capture
// We can take the last 32bits as the internal ID.
uint32_t ID = raw2;
ID &= 0x7FFFFFFF;
PrintAndLogEx(SUCCESS, "KERI - Internal ID: " _GREEN_("%u") ", Raw: %08X%08X", ID, raw1, raw2);
// Just need to the low 32 bits without the 111 trailer
CmdKeriMSScramble(Descramble, &fc, &cardid, &raw2);
PrintAndLogEx(SUCCESS, "Descrambled MS - FC: " _GREEN_("%d") " Card: " _GREEN_("%d"), fc, cardid);
return PM3_SUCCESS;
}
@ -221,9 +187,10 @@ static int CmdKeriRead(const char *Cmd) {
static int CmdKeriClone(const char *Cmd) {
bool q5 = false;
uint8_t cmdidx = 0;
char keritype = 'i'; // default to internalid
bool q5 = false, em = false;
uint8_t keritype[2] = {'i'}; // default to internalid
int typeLen = 0;
uint32_t fc = 0;
uint32_t cid = 0;
uint32_t internalid = 0;
@ -240,42 +207,49 @@ static int CmdKeriClone(const char *Cmd) {
// dynamic bitrate used
blocks[0] |= 0xF << 18;
char cmdp = tolower(param_getchar(Cmd, 0));
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_keri_clone();
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf keri clone",
"clone a KERI tag to a T55x7, Q5/T5555 or EM4305/4469 tag",
"lf keri clone -t i --id 12345\n"
"lf keri clone -t m --fc 6 --id 12345\n");
// Assume old format for backwards compatibility and only parameter is the internal id
cid = param_get32ex(Cmd, 0, 0, 10);
void *argtable[] = {
arg_param_begin,
arg_lit0("q", "q5", "specify writing to Q5/T5555 tag"),
arg_str0("t", "type", "<m|i>", "Type m - MS, i - Internal ID"),
arg_int0(NULL, "fc", "<dec>", "Facility Code"),
arg_int1(NULL, "id", "<dec>", "Keri ID"),
arg_lit0(NULL, "em", "specify writing to EM4305/4469 tag"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
// find other options
while (param_getchar(Cmd, cmdidx) != 0x00) { // && !errors) {
switch (tolower(param_getchar(Cmd, cmdidx))) {
case 'h': // help
return usage_lf_keri_clone();
case 't': // format type
keritype = tolower(param_getchar(Cmd, cmdidx + 1));
cmdidx += 2;
break;
case 'f': // fc
fc = param_get32ex(Cmd, cmdidx + 1, 0, 10);
cmdidx += 2;
break;
case 'c': // cardid
cid = param_get32ex(Cmd, cmdidx + 1, 0, 10);
cmdidx += 2;
break;
case 'q': // q5
char cardtype[16] = {"T55x7"};
if (arg_get_lit(ctx, 1)) {
blocks[0] = T5555_FIXED | T5555_MODULATION_PSK1 | T5555_SET_BITRATE(32) | T5555_PSK_RF_2 | 2 << T5555_MAXBLOCK_SHIFT;
snprintf(cardtype, sizeof(cardtype) ,"Q5/T5555");
q5 = true;
cmdidx++;
break;
default:
// Skip unknown
cmdidx++;
}
if (arg_get_lit(ctx, 5)) {
blocks[0] = EM4305_KERI_CONFIG_BLOCK;
snprintf(cardtype, sizeof(cardtype) ,"EM4305/4469");
em = true;
}
typeLen = sizeof(keritype);
CLIGetStrWithReturn(ctx, 2, keritype, &typeLen);
fc = arg_get_int_def(ctx, 3, 0);
cid = arg_get_int_def(ctx, 4, 0);
CLIParserFree(ctx);
if (q5 && em) {
PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
return PM3_EINVARG;
}
// Setup card data/build internal id
switch (keritype) {
switch (keritype[0]) {
case 'i' : // Internal ID
// MSB is ONE
internalid = cid | 0x80000000;
@ -283,19 +257,28 @@ static int CmdKeriClone(const char *Cmd) {
case 'm' : // MS
CmdKeriMSScramble(Scramble, &fc, &cid, &internalid);
break;
default :
PrintAndLogEx(ERR, "Invalid type");
return PM3_EINVARG;
}
// Prepare and write to card
// 3 LSB is ONE
uint64_t data = ((uint64_t)internalid << 3) + 7;
PrintAndLogEx(INFO, "Preparing to clone KERI to " _YELLOW_("%s") " with Internal Id " _YELLOW_("%" PRIx32), (q5) ? "Q5/T5555" : "T55x7", internalid);
PrintAndLogEx(INFO, "Preparing to clone KERI to " _YELLOW_("%s") " with Internal Id " _YELLOW_("%" PRIx32), cardtype, internalid);
blocks[1] = data >> 32;
blocks[2] = data & 0xFFFFFFFF;
print_blocks(blocks, ARRAYLEN(blocks));
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
int res;
if (em) {
res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false);
} else {
res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
}
PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf keri read`") " to verify");
return res;
@ -303,11 +286,23 @@ static int CmdKeriClone(const char *Cmd) {
static int CmdKeriSim(const char *Cmd) {
char cmdp = tolower(param_getchar(Cmd, 0));
if (strlen(Cmd) == 0 || cmdp == 'h')
return usage_lf_keri_sim();
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf keri sim",
"Enables simulation of KERI card with card number.",
"lf keri sim --id 112233"
);
void *argtable[] = {
arg_param_begin,
arg_int1(NULL, "id", "<dec>", "KERI Internal ID"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
uint64_t internalid = arg_get_int_def(ctx, 1, 0);
CLIParserFree(ctx);
uint64_t internalid = param_get32ex(Cmd, 0, 0, 10);
internalid |= 0x80000000;
internalid <<= 3;
internalid += 7;

View file

@ -156,26 +156,36 @@ static int CmdMotorolaClone(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "lf motorola clone",
"Enables cloning of Motorola card with specified uid onto T55x7\n"
"defaults to 64.",
"lf motorola clone a0000000a0002021"
"clone Motorola UID to T55x7 or Q5/T5555 tag\n"
"defaults to 64 bit format",
"lf motorola clone -r a0000000a0002021"
);
void *argtable[] = {
arg_param_begin,
arg_strx1(NULL, NULL, "<uid (hex)>", NULL),
arg_strx1("r", "raw", "<hex>", "raw bytes"),
arg_lit0("q", "Q5", "optional - specify writing to Q5/T5555 tag"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
CLIGetHexWithReturn(ctx, 1, data, &datalen);
bool is_t5555 = arg_get_lit(ctx, 2);
CLIParserFree(ctx);
//TODO add selection of chip for Q5 or T55x7
// data[0] = T5555_FIXED | T5555_SET_BITRATE(32 | T5555_MODULATION_PSK1 | 2 << T5555_MAXBLOCK_SHIFT;
PrintAndLogEx(INFO, "Target chip " _YELLOW_("%s"), (is_t5555) ? "Q5/T5555" : "T55x7");
// config for Motorola 64 format (RF/32;PSK1 with RF/2; Maxblock=2)
PrintAndLogEx(INFO, "Preparing to clone Motorola 64bit tag with RawID %s", sprint_hex(data, datalen));
PrintAndLogEx(INFO, "Preparing to clone Motorola 64bit tag");
PrintAndLogEx(INFO, "Using raw " _GREEN_("%s"), sprint_hex_inrow(data, datalen));
if (is_t5555)
blocks[0] = T5555_FIXED | T5555_SET_BITRATE(32) | T5555_MODULATION_PSK1 | 2 << T5555_MAXBLOCK_SHIFT;
else
blocks[0] = T55x7_BITRATE_RF_32 | T55x7_MODULATION_PSK1 | (2 << T55x7_MAXBLOCK_SHIFT);
blocks[1] = bytes_to_num(data, 4);
blocks[2] = bytes_to_num(data + 4, 4);

View file

@ -186,7 +186,7 @@ static int usage_t55xx_dump(void) {
PrintAndLogEx(NORMAL, "Options:");
PrintAndLogEx(NORMAL, " p <password> - OPTIONAL password 4bytes (8 hex symbols)");
PrintAndLogEx(NORMAL, " o - OPTIONAL override, force pwd read despite danger to card");
PrintAndLogEx(NORMAL, " f <prefix> - overide filename prefix (optional). Default is based on blk 0");
PrintAndLogEx(NORMAL, " f <prefix> - override filename prefix (optional). Default is based on blk 0");
print_usage_t55xx_downloadlink(T55XX_DLMODE_SINGLE, config.downlink_mode);
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
@ -378,12 +378,12 @@ static int usage_t55xx_dangerraw(void) {
static int usage_t55xx_clonehelp(void) {
PrintAndLogEx(NORMAL, "For cloning specific techs on T55xx tags, see commands available in corresponding LF sub-menus, e.g.:");
PrintAndLogEx(NORMAL, _GREEN_("lf awid clone"));
// todo: rename to clone
PrintAndLogEx(NORMAL, _GREEN_("lf destron clone"));
PrintAndLogEx(NORMAL, _GREEN_("lf em 410x_clone"));
// todo: implement restore
// PrintAndLogEx(NORMAL, _GREEN_("lf em 4x05_write"));
// PrintAndLogEx(NORMAL, _GREEN_("lf em 4x50_write"));
PrintAndLogEx(NORMAL, _GREEN_("lf fdx clone"));
PrintAndLogEx(NORMAL, _GREEN_("lf fdxb clone"));
PrintAndLogEx(NORMAL, _GREEN_("lf gallagher clone"));
PrintAndLogEx(NORMAL, _GREEN_("lf gproxii clone"));
PrintAndLogEx(NORMAL, _GREEN_("lf hid clone"));
@ -598,7 +598,7 @@ bool t55xxAquireAndDetect(bool usepwd, uint32_t password, uint32_t known_block0,
if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password, m) == false)
continue;
if (tryDetectModulationEx(m, verbose, known_block0, (usepwd) ? password : -1) == false)
if (t55xxTryDetectModulationEx(m, verbose, known_block0, (usepwd) ? password : -1) == false)
continue;
config.downlink_mode = m;
@ -861,7 +861,7 @@ int T55xxReadBlockEx(uint8_t block, bool page1, bool usepwd, uint8_t override, u
if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, false, 0, downlink_mode) == false)
return PM3_ERFTRANS;
if (tryDetectModulationEx(downlink_mode, false, 0, password) == false) {
if (t55xxTryDetectModulationEx(downlink_mode, false, 0, password) == false) {
PrintAndLogEx(WARNING, "Safety check: Could not detect if PWD bit is set in config block. Exits.");
return PM3_EWRONGANSWER;
} else {
@ -1081,7 +1081,7 @@ static int CmdT55xxDetect(const char *Cmd) {
if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, (try_with_pwd && usepwd), password, m) == false)
continue;
if (tryDetectModulationEx(m, T55XX_PrintConfig, 0, (try_with_pwd && usepwd) ? password : -1) == false)
if (t55xxTryDetectModulationEx(m, T55XX_PrintConfig, 0, (try_with_pwd && usepwd) ? password : -1) == false)
continue;
found = true;
@ -1090,7 +1090,7 @@ static int CmdT55xxDetect(const char *Cmd) {
}
} else {
if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, usepwd, password, downlink_mode)) {
found = tryDetectModulationEx(downlink_mode, T55XX_PrintConfig, 0, (usepwd) ? password : -1);
found = t55xxTryDetectModulationEx(downlink_mode, T55XX_PrintConfig, 0, (usepwd) ? password : -1);
}
}
@ -1105,7 +1105,7 @@ static int CmdT55xxDetect(const char *Cmd) {
} while (try_with_pwd);
} else {
found = tryDetectModulation(downlink_mode, T55XX_PrintConfig);
found = t55xxTryDetectModulation(downlink_mode, T55XX_PrintConfig);
}
if (found == false) {
@ -1117,11 +1117,11 @@ static int CmdT55xxDetect(const char *Cmd) {
}
// detect configuration?
bool tryDetectModulation(uint8_t downlink_mode, bool print_config) {
return tryDetectModulationEx(downlink_mode, print_config, 0, -1);
bool t55xxTryDetectModulation(uint8_t downlink_mode, bool print_config) {
return t55xxTryDetectModulationEx(downlink_mode, print_config, 0, -1);
}
bool tryDetectModulationEx(uint8_t downlink_mode, bool print_config, uint32_t wanted_conf, uint64_t pwd) {
bool t55xxTryDetectModulationEx(uint8_t downlink_mode, bool print_config, uint32_t wanted_conf, uint64_t pwd) {
t55xx_conf_block_t tests[15];
int bitRate = 0, clk = 0, firstClockEdge = 0;
@ -3079,7 +3079,7 @@ static int CmdT55xxChkPwds(const char *Cmd) {
PrintAndLogEx(SUCCESS, "\nFound a candidate [ " _YELLOW_("%08"PRIX32) " ]", packet->candidate);
if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, packet->candidate, downlink_mode)) {
found = tryDetectModulationEx(downlink_mode, T55XX_PrintConfig, 0, packet->candidate);
found = t55xxTryDetectModulationEx(downlink_mode, T55XX_PrintConfig, 0, packet->candidate);
if (found) {
PrintAndLogEx(SUCCESS, "Found valid password [ " _GREEN_("%08"PRIX32) " ]", packet->candidate);
@ -3105,7 +3105,7 @@ static int CmdT55xxChkPwds(const char *Cmd) {
continue;
}
found = tryDetectModulationEx(dl_mode, T55XX_PrintConfig, 0, cardPassword);
found = t55xxTryDetectModulationEx(dl_mode, T55XX_PrintConfig, 0, cardPassword);
if (found) {
PrintAndLogEx(SUCCESS, "Found valid password : [ " _GREEN_("%08"PRIX32) " ]", cardPassword);
dl_mode = 4; // Exit other downlink mode checks
@ -3150,7 +3150,7 @@ static int CmdT55xxChkPwds(const char *Cmd) {
continue;
}
found = tryDetectModulationEx(dl_mode, T55XX_PrintConfig, 0, curr_password);
found = t55xxTryDetectModulationEx(dl_mode, T55XX_PrintConfig, 0, curr_password);
if (found) {
PrintAndLogEx(SUCCESS, "Found valid password: [ " _GREEN_("%08"PRIX32) " ]", curr_password);
dl_mode = 4; // Exit other downlink mode checks
@ -3267,7 +3267,7 @@ uint8_t tryOnePassword(uint32_t password, uint8_t downlink_mode) {
if (AcquireData(T55x7_PAGE0, T55x7_CONFIGURATION_BLOCK, true, password, dl_mode)) {
// if (getSignalProperties()->isnoise == false) {
// } else {
if (tryDetectModulationEx(dl_mode, T55XX_PrintConfig, 0, password)) {
if (t55xxTryDetectModulationEx(dl_mode, T55XX_PrintConfig, 0, password)) {
return 1 + (dl_mode << 1);
}
// }

View file

@ -105,21 +105,23 @@ typedef struct {
uint32_t dw;
} t5555_tracedata_t;
typedef struct {
enum {
typedef enum {
DEMOD_NRZ = 0x00,
DEMOD_PSK1 = 0x01,
DEMOD_PSK2 = 0x02,
DEMOD_PSK3 = 0x03,
DEMOD_FSK1 = 0x04,
DEMOD_FSK1a = 0x05,
DEMOD_FSK2 = 0x06,
DEMOD_FSK2 = 0x05,
DEMOD_FSK1a = 0x06,
DEMOD_FSK2a = 0x07,
DEMOD_FSK = 0xF0, //generic FSK (auto detect FCs)
DEMOD_ASK = 0x08,
DEMOD_BI = 0x10,
DEMOD_BIa = 0x18,
} modulation;
} t55xx_modulation;
typedef struct {
t55xx_modulation modulation;
bool inverted;
uint8_t offset;
uint32_t block0;
@ -180,9 +182,9 @@ int t55xxWrite(uint8_t block, bool page1, bool usepwd, bool testMode, uint32_t p
bool GetT55xxBlockData(uint32_t *blockdata);
bool DecodeT55xxBlock(void);
bool tryDetectModulation(uint8_t downlink_mode, bool print_config);
//bool tryDetectModulationEx(uint8_t downlink_mode, bool print_config, uint32_t wanted_conf);
bool tryDetectModulationEx(uint8_t downlink_mode, bool print_config, uint32_t wanted_conf, uint64_t pwd);
bool t55xxTryDetectModulation(uint8_t downlink_mode, bool print_config);
//bool t55xxTryDetectModulationEx(uint8_t downlink_mode, bool print_config, uint32_t wanted_conf);
bool t55xxTryDetectModulationEx(uint8_t downlink_mode, bool print_config, uint32_t wanted_conf, uint64_t pwd);
bool testKnownConfigBlock(uint32_t block0);
bool tryDetectP1(bool getData);

View file

@ -10,12 +10,11 @@
//-----------------------------------------------------------------------------
#include "cmdlfvisa2000.h"
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <inttypes.h>
#include <stdio.h>
#include "commonutil.h" // ARRAYLEN
#include "common.h"
#include "cmdparser.h" // command_t
@ -27,6 +26,7 @@
#include "protocols.h" // for T55xx config register definitions
#include "lfdemod.h" // parityTest
#include "cmdlft55xx.h" // write verify
#include "cmdlfem4x05.h" //
#define BL0CK1 0x56495332
@ -39,10 +39,12 @@ static int usage_lf_visa2k_clone(void) {
PrintAndLogEx(NORMAL, " h : This help");
PrintAndLogEx(NORMAL, " <card ID> : Visa2k card ID");
PrintAndLogEx(NORMAL, " <Q5> : specify writing to Q5/T5555 tag");
PrintAndLogEx(NORMAL, " <em4305> : specify writing to EM4305/4469 tag");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" lf visa2000 clone 112233"));
PrintAndLogEx(NORMAL, _YELLOW_(" lf visa2000 clone 112233 q5") " -- encode for Q5/T5555");
PrintAndLogEx(NORMAL, _YELLOW_(" lf visa2000 clone 112233 em4305") " -- encode for EM4305/4469");
return PM3_SUCCESS;
}
@ -180,18 +182,38 @@ static int CmdVisa2kClone(const char *Cmd) {
id = param_get32ex(Cmd, 0, 0, 10);
//Q5
char cardtype[16] = {"T55x7"};
// Q5
bool q5 = tolower(param_getchar(Cmd, 1)) == 'q';
if (q5)
if (q5) {
blocks[0] = T5555_FIXED | T5555_MODULATION_MANCHESTER | T5555_SET_BITRATE(64) | T5555_ST_TERMINATOR | 3 << T5555_MAXBLOCK_SHIFT;
snprintf(cardtype, sizeof(cardtype) ,"Q5/T5555");
}
// EM4305
bool em = tolower(param_getchar(Cmd, 1)) == 'e';
if (em) {
blocks[0] = EM4305_VISA2000_CONFIG_BLOCK;
snprintf(cardtype, sizeof(cardtype) ,"EM4305/4469");
}
if (q5 && em) {
PrintAndLogEx(FAILED, "Can't specify both Q5 and EM4305 at the same time");
return PM3_EINVARG;
}
blocks[2] = id;
blocks[3] = (visa_parity(id) << 4) | visa_chksum(id);
PrintAndLogEx(INFO, "Preparing to clone Visa2000 to " _YELLOW_("%s") " with CardId: %"PRIu64, (q5) ? "Q5/T5555" : "T55x7", id);
PrintAndLogEx(INFO, "Preparing to clone Visa2000 to " _YELLOW_("%s") " with CardId: %"PRIu64, cardtype, id);
print_blocks(blocks, ARRAYLEN(blocks));
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
int res;
if (em) {
res = em4x05_clone_tag(blocks, ARRAYLEN(blocks), 0, false);
} else {
res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
}
PrintAndLogEx(SUCCESS, "Done");
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf visa2000 read`") " to verify");
return res;

View file

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

View file

@ -791,14 +791,14 @@ static int CmdSmartReader(const char *Cmd) {
static int CmdSmartSetClock(const char *Cmd) {
uint8_t cmdp = 0;
bool errors = false;
uint8_t clock1 = 0;
uint8_t new_clk = 0;
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h':
return usage_sm_setclock();
case 'c':
clock1 = param_get8ex(Cmd, cmdp + 1, 2, 10);
if (clock1 > 2)
new_clk = param_get8ex(Cmd, cmdp + 1, 2, 10);
if (new_clk > 2)
errors = true;
cmdp += 2;
@ -813,21 +813,26 @@ static int CmdSmartSetClock(const char *Cmd) {
//Validations
if (errors || cmdp == 0) return usage_sm_setclock();
struct {
uint32_t new_clk;
} PACKED payload;
payload.new_clk = new_clk;
clearCommandBuffer();
SendCommandMIX(CMD_SMART_SETCLOCK, clock1, 0, 0, NULL, 0);
SendCommandNG(CMD_SMART_SETCLOCK, (uint8_t*)&payload, sizeof(payload));
PacketResponseNG resp;
if (!WaitForResponseTimeout(CMD_ACK, &resp, 2500)) {
if (!WaitForResponseTimeout(CMD_SMART_SETCLOCK, &resp, 2500)) {
PrintAndLogEx(WARNING, "smart card select failed");
return PM3_ETIMEOUT;
}
uint8_t isok = resp.oldarg[0] & 0xFF;
if (!isok) {
if (resp.status != PM3_SUCCESS) {
PrintAndLogEx(WARNING, "smart card set clock failed");
return PM3_ESOFT;
}
switch (clock1) {
switch (new_clk) {
case 0:
PrintAndLogEx(SUCCESS, "Clock changed to 16MHz giving 10800 baudrate");
break;
@ -844,9 +849,13 @@ static int CmdSmartSetClock(const char *Cmd) {
}
static int CmdSmartList(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
CmdTraceList("7816");
return PM3_SUCCESS;
char args[128] = {0};
if (strlen(Cmd) == 0) {
snprintf(args, sizeof(args), "-t 7816");
} else {
strncpy(args, Cmd, sizeof(args) - 1);
}
return CmdTraceList(args);
}
static void smart_brute_prim(void) {

View file

@ -19,6 +19,7 @@
#include "fileutils.h" // for saveFile
#include "cmdlfhitag.h" // annotate hitag
#include "pm3_cmd.h" // tracelog_hdr_t
#include "cliparser.h" // args..
static int CmdHelp(const char *Cmd);
@ -26,56 +27,6 @@ static int CmdHelp(const char *Cmd);
static uint8_t *g_trace;
static long g_traceLen = 0;
static int usage_trace_list(void) {
PrintAndLogEx(NORMAL, "List protocol data in trace buffer.");
PrintAndLogEx(NORMAL, "Usage: trace list <protocol> [f][c| <0|1>");
PrintAndLogEx(NORMAL, " f - show frame delay times as well");
PrintAndLogEx(NORMAL, " c - mark CRC bytes");
PrintAndLogEx(NORMAL, " r - show relative times (gap and duration)");
PrintAndLogEx(NORMAL, " u - display times in microseconds instead of clock cycles");
PrintAndLogEx(NORMAL, " x - show hexdump to convert to pcap(ng) or to import into Wireshark using encapsulation type \"ISO 14443\"");
PrintAndLogEx(NORMAL, " syntax to use: `text2pcap -t \"%%S.\" -l 264 -n <input-text-file> <output-pcapng-file>`");
PrintAndLogEx(NORMAL, " <0|1> - use data from Tracebuffer, if not set, try to collect a trace from Proxmark3 device.");
PrintAndLogEx(NORMAL, "Supported <protocol> values:");
PrintAndLogEx(NORMAL, " raw - just show raw data without annotations");
PrintAndLogEx(NORMAL, " 14a - interpret data as iso14443a communications");
PrintAndLogEx(NORMAL, " thinfilm - interpret data as Thinfilm communications");
PrintAndLogEx(NORMAL, " topaz - interpret data as Topaz communications");
PrintAndLogEx(NORMAL, " mf - interpret data as iso14443a communications and decrypt crypto1 stream");
PrintAndLogEx(NORMAL, " des - interpret data as DESFire communications");
PrintAndLogEx(NORMAL, " 14b - interpret data as iso14443b communications");
PrintAndLogEx(NORMAL, " 7816 - interpret data as iso7816-4 communications");
PrintAndLogEx(NORMAL, " 15 - interpret data as iso15693 communications");
PrintAndLogEx(NORMAL, " iclass - interpret data as iclass communications");
PrintAndLogEx(NORMAL, " legic - interpret data as LEGIC communications");
PrintAndLogEx(NORMAL, " felica - interpret data as ISO18092 / FeliCa communications");
PrintAndLogEx(NORMAL, " hitag1 - interpret data as Hitag1 communications");
PrintAndLogEx(NORMAL, " hitag2 - interpret data as Hitag2 communications");
PrintAndLogEx(NORMAL, " hitags - interpret data as HitagS communications");
PrintAndLogEx(NORMAL, " lto - interpret data as LTO-CM communications");
PrintAndLogEx(NORMAL, " cryptorf - interpret data as CryptoRF communitcations");
PrintAndLogEx(NORMAL, "");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" trace list 14a f"));
PrintAndLogEx(NORMAL, _YELLOW_(" trace list iclass"));
PrintAndLogEx(NORMAL, _YELLOW_(" trace list 14a 1"));
return PM3_SUCCESS;
}
static int usage_trace_load(void) {
PrintAndLogEx(NORMAL, "Load protocol data from binary file to trace buffer");
PrintAndLogEx(NORMAL, "Usage: trace load <filename>");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" trace load mytracefile.trace"));
return PM3_SUCCESS;
}
static int usage_trace_save(void) {
PrintAndLogEx(NORMAL, "Save protocol data from trace buffer to binary file");
PrintAndLogEx(NORMAL, "Usage: trace save <filename>");
PrintAndLogEx(NORMAL, "Examples:");
PrintAndLogEx(NORMAL, _YELLOW_(" trace save mytracefile.trace"));
return PM3_SUCCESS;
}
static bool is_last_record(uint16_t tracepos, uint16_t traceLen) {
return ((tracepos + TRACELOG_HDR_LEN) >= traceLen);
}
@ -159,10 +110,8 @@ static uint16_t printHexLine(uint16_t tracepos, uint16_t traceLen, uint8_t *trac
char temp_str2[3] = {0};
sprintf(data_len_str, "%04x", hdr->data_len);
strncat(temp_str1, data_len_str, 2);
temp_str1[2] = '\0';
strncat(temp_str2, data_len_str + 2, 2);
temp_str2[2] = '\0';
memmove(temp_str1, data_len_str, 2);
memmove(temp_str2, data_len_str + 2, 2);
PrintAndLogEx(NORMAL, "0.%010u", hdr->timestamp);
PrintAndLogEx(NORMAL, "000000 00 %s %s %s %s",
@ -203,7 +152,7 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
data_len = hdr->data_len;
if (tracepos + TRACELOG_HDR_LEN + data_len + TRACELOG_PARITY_LEN(hdr) > traceLen) {
PrintAndLogEx(DEBUG, "trace pos offset %"PRIu32 " larger than reported tracelen %u", tracepos + TRACELOG_HDR_LEN + data_len + TRACELOG_PARITY_LEN(hdr), traceLen);
PrintAndLogEx(DEBUG, "trace pos offset %"PRIu64 " larger than reported tracelen %u", tracepos + TRACELOG_HDR_LEN + data_len + TRACELOG_PARITY_LEN(hdr), traceLen);
return traceLen;
}
@ -212,7 +161,6 @@ static uint16_t printTraceLine(uint16_t tracepos, uint16_t traceLen, uint8_t *tr
duration *= 32;
}
uint8_t *frame = hdr->frame;
uint8_t *parityBytes = hdr->frame + data_len;
@ -568,11 +516,24 @@ static int SanityOfflineCheck( bool useTraceBuffer ){
static int CmdTraceLoad(const char *Cmd) {
char cmdp = tolower(param_getchar(Cmd, 0));
if (strlen(Cmd) < 1 || (strlen(Cmd) == 1 && cmdp == 'h')) return usage_trace_load();
CLIParserContext *ctx;
CLIParserInit(&ctx, "trace load",
"Load protocol data from binary file to trace buffer\n"
"File extension is (.trace)",
"trace load -f mytracefile"
);
char filename[FILE_PATH_SIZE];
param_getstr(Cmd, 0, filename, sizeof(filename));
void *argtable[] = {
arg_param_begin,
arg_strx0("f", "file", "<filename>", "trace file to load"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
int fnlen = 0;
char filename[FILE_PATH_SIZE] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
CLIParserFree(ctx);
if (g_trace)
free(g_trace);
@ -591,8 +552,24 @@ static int CmdTraceLoad(const char *Cmd) {
static int CmdTraceSave(const char *Cmd) {
char cmdp = tolower(param_getchar(Cmd, 0));
if (strlen(Cmd) < 1 || (strlen(Cmd) == 1 && cmdp == 'h')) return usage_trace_save();
CLIParserContext *ctx;
CLIParserInit(&ctx, "trace save",
"Save protocol data from trace buffer to binary file\n"
"File extension is (.trace)",
"trace save -f mytracefile"
);
void *argtable[] = {
arg_param_begin,
arg_strx0("f", "file", "<filename>", "trace file to load"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
int fnlen = 0;
char filename[FILE_PATH_SIZE] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 1), (uint8_t *)filename, FILE_PATH_SIZE, &fnlen);
CLIParserFree(ctx);
if (g_traceLen == 0) {
download_trace();
@ -603,68 +580,68 @@ static int CmdTraceSave(const char *Cmd) {
return PM3_SUCCESS;
}
char filename[FILE_PATH_SIZE];
param_getstr(Cmd, 0, filename, sizeof(filename));
saveFile(filename, ".trace", g_trace, g_traceLen);
return PM3_SUCCESS;
}
int CmdTraceList(const char *Cmd) {
CLIParserContext *ctx;
CLIParserInit(&ctx, "trace list",
"Annotate trace buffer with selected protocol data\n"
"You can load a trace from file (see `trace load -h`) or it be downloaded from device by default\n",
"trace list -t raw -> just show raw data without annotations\n"
"trace list -t 14a -> interpret as " _YELLOW_("ISO14443-A") " communications\n"
"trace list -t thinfilm -> interpret as " _YELLOW_("Thinfilm") " communications\n"
"trace list -t topaz -> interpret as " _YELLOW_("Topaz") " communications\n"
"trace list -t mf -> interpret as " _YELLOW_("MIFARE Classic") " communications and decrypt crypto1 stream\n"
"trace list -t des -> interpret as " _YELLOW_("MIFARE DESFire") " communications\n"
"trace list -t 14b -> interpret as " _YELLOW_("ISO14443-B") " communications\n"
"trace list -t 7816 -> interpret as " _YELLOW_("ISO7816-4") " communications\n"
"trace list -t 15 -> interpret as " _YELLOW_("ISO15693") " communications\n"
"trace list -t iclass -> interpret as " _YELLOW_("iCLASS") " communications\n"
"trace list -t legic -> interpret as " _YELLOW_("LEGIC") " communications\n"
"trace list -t felica -> interpret as " _YELLOW_("ISO18092 / FeliCa") " communications\n"
"trace list -t hitag1 -> interpret as " _YELLOW_("Hitag1") " communications\n"
"trace list -t hitag2 -> interpret as " _YELLOW_("Hitag2") " communications\n"
"trace list -t hitags -> interpret as " _YELLOW_("HitagS") " communications\n"
"trace list -t lto -> interpret as " _YELLOW_("LTO-CM") " communications\n"
"trace list -t cryptorf -> interpret as " _YELLOW_("CryptoRF") " communitcations\n"
"trace list -t 14a f -> show frame delay times\n"
"trace list -t 14a 1 -> use trace buffer "
);
void *argtable[] = {
arg_param_begin,
arg_lit0("1", "buffer", "use data from trace buffer"),
arg_lit0("f", NULL, "show frame delay times"),
arg_lit0("c", NULL, "mark CRC bytes"),
arg_lit0("r", NULL, "show relative times (gap and duration)"),
arg_lit0("u", NULL, "display times in microseconds instead of clock cycles"),
arg_lit0("x", NULL, "show hexdump to convert to pcap(ng)\n"
" or to import into Wireshark using encapsulation type \"ISO 14443\""),
arg_strx0("t", "type", NULL, "protocol to annotate the trace"),
arg_param_end
};
CLIExecWithReturn(ctx, Cmd, argtable, false);
bool use_buffer = arg_get_lit(ctx, 1);
bool show_wait_cycles = arg_get_lit(ctx, 2);
bool mark_crc = arg_get_lit(ctx, 3);
bool use_relative = arg_get_lit(ctx, 4);
bool use_us = arg_get_lit(ctx, 5);
bool show_hex = arg_get_lit(ctx, 6);
int tlen = 0;
char type[10] = {0};
CLIParamStrToBuf(arg_get_str(ctx, 7), (uint8_t *)type, sizeof(type), &tlen);
str_lower(type);
CLIParserFree(ctx);
clearCommandBuffer();
bool showWaitCycles = false, markCRCBytes = false;
bool showHex = false, isOnline = true;
bool use_us = false, use_relative = false;
bool errors = false;
uint8_t protocol = 0;
char type[10] = {0};
char cmdp = 0;
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
int slen = param_getstr(Cmd, cmdp, type, sizeof(type));
if (slen == 1) {
switch (tolower(param_getchar(Cmd, cmdp))) {
case 'h':
return usage_trace_list();
case 'f':
showWaitCycles = true;
cmdp++;
break;
case 'c':
markCRCBytes = true;
cmdp++;
break;
case 'x':
showHex = true;
cmdp++;
break;
case '0':
isOnline = true;
cmdp++;
break;
case '1':
isOnline = false;
cmdp++;
break;
case 'r':
use_relative = true;
cmdp++;
break;
case 'u':
use_us = true;
cmdp++;
break;
default:
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
errors = true;
break;
}
} else {
str_lower(type);
// no crc, no annotations
uint8_t protocol = -1;
// validate type of output
if (strcmp(type, "iclass") == 0) protocol = ICLASS;
@ -683,19 +660,9 @@ int CmdTraceList(const char *Cmd) {
else if (strcmp(type, "thinfilm") == 0) protocol = THINFILM;
else if (strcmp(type, "lto") == 0) protocol = LTO;
else if (strcmp(type, "cryptorf") == 0) protocol = PROTO_CRYPTORF;
else if (strcmp(type, "raw") == 0) protocol = -1; //No crc, no annotations
else errors = true;
else if (strcmp(type, "raw") == 0) protocol = -1;
cmdp++;
}
}
//if (!SanityOfflineCheck(isOnline)) return 1;
//Validations
if (errors) return usage_trace_list();
if (isOnline) {
if (use_buffer == false || (g_traceLen == 0)) {
download_trace();
}
@ -711,7 +678,7 @@ int CmdTraceList(const char *Cmd) {
printFelica(g_traceLen, g_trace);
} */
if (showHex) {
if (show_hex) {
while (tracepos < g_traceLen) {
tracepos = printHexLine(tracepos, g_traceLen, g_trace, protocol);
}
@ -788,12 +755,16 @@ int CmdTraceList(const char *Cmd) {
}
while (tracepos < g_traceLen) {
tracepos = printTraceLine(tracepos, g_traceLen, g_trace, protocol, showWaitCycles, markCRCBytes, prev_EOT, use_us);
tracepos = printTraceLine(tracepos, g_traceLen, g_trace, protocol, show_wait_cycles, mark_crc, prev_EOT, use_us);
if (kbd_enter_pressed())
break;
}
}
if (show_hex)
PrintAndLogEx(HINT, "syntax to use: " _YELLOW_("`text2pcap -t \"%%S.\" -l 264 -n <input-text-file> <output-pcapng-file>`"));
return PM3_SUCCESS;
}

View file

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

View file

@ -1435,7 +1435,7 @@ static int CmdEMVScan(const char *Cmd) {
uint8_t psenum = (channel == ECC_CONTACT) ? 1 : 2;
uint8_t filename[FILE_PATH_SIZE] = {0};
int filenamelen = 0;
int filenamelen = sizeof(filename);
CLIGetStrWithReturn(ctx, 12, filename, &filenamelen);
CLIParserFree(ctx);
@ -1772,8 +1772,13 @@ static int CmdEMVScan(const char *Cmd) {
}
static int CmdEMVList(const char *Cmd) {
(void)Cmd; // Cmd is not used so far
return CmdTraceList("7816");
char args[128] = {0};
if (strlen(Cmd) == 0) {
snprintf(args, sizeof(args), "-t 7816");
} else {
strncpy(args, Cmd, sizeof(args) - 1);
}
return CmdTraceList(args);
}
static int CmdEMVTest(const char *Cmd) {

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