mirror of
https://github.com/RfidResearchGroup/proxmark3.git
synced 2025-08-20 13:23:51 -07:00
commit
d05714f58d
48 changed files with 73363 additions and 582 deletions
|
@ -3,7 +3,10 @@ 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]
|
||||
- Add `hf 14a config` to deal with badly configured cards: invalid ATQA/BCC/SAK (@doegox)"
|
||||
- Add options to `lf read` and `lf cmdread` (@doegox)
|
||||
- Change options of `lf read` to match `lf cmdread`, this affects historical `d` and `s` options (@doegox)
|
||||
- Add `hf waveshare` to upload picture to Waveshare NFC-Powered e-Paper (@doegox)
|
||||
- Add `hf 14a config` to deal with badly configured cards: invalid ATQA/BCC/SAK (@doegox)
|
||||
- Mikron JSC Russia Ultralight EV1 41 pages tag type support (@McEloff)
|
||||
- Add test for Ultralight gen2 magic 'hf search' (@McEloff)
|
||||
- Add test for Ultralight EV1 gen2 magic 'hf search' (@McEloff)
|
||||
|
@ -101,7 +104,7 @@ This project uses the changelog in accordance with [keepchangelog](http://keepac
|
|||
- Change appveyor verbose (@doegox)
|
||||
- Change `lf nexwatch demod` - now detects type, and show parity /chksum (@iceman1001)
|
||||
- Change `lfsampling` - interruptible only when logging not yet triggered (@doegox)
|
||||
- Change `lf keri demod - more leanient when it comes to bits (@iceman1001)
|
||||
- Change `lf keri demod` - more leanient when it comes to bits (@iceman1001)
|
||||
- fix, proper filtering of RL markers (@doegox)
|
||||
- Change, clean deps [compiler trials] (@doegox)
|
||||
- Change, remove c99 restrictions [compiler trials] (@doegox)
|
||||
|
|
|
@ -32,8 +32,8 @@
|
|||
|[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 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 Color usage](/doc/colors_notes.md)|[Makefile vs CMake](/doc/md/Development/Makefile-vs-CMake.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)|
|
||||
|
||||
|
||||
## Build for non-RDV4 Proxmark3 platforms
|
||||
|
|
199
appveyor.yml
199
appveyor.yml
|
@ -1,6 +1,13 @@
|
|||
version: 3.0.1.{build}
|
||||
image: Visual Studio 2019
|
||||
clone_folder: C:\ProxSpace\pm3
|
||||
clone_folder: C:\ProxSpace\pm3\proxmark
|
||||
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_home_path: \ProxSpace\pm3
|
||||
|
||||
init:
|
||||
- ps: >-
|
||||
$psversiontable
|
||||
|
@ -25,41 +32,78 @@ init:
|
|||
# iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1'))
|
||||
clone_script:
|
||||
- ps: >-
|
||||
|
||||
Function ExecUpdate($Text, $firstStart) {
|
||||
Write-Host "$Text" -NoNewLine
|
||||
Start-Process "cmd.exe" "/c ""cd /D $env:proxspace_path && call msys2\ps\setup.cmd && msys2\msys2_shell.cmd -mingw64 -defterm -no-start -c ""exit"""""
|
||||
$StartTime=[System.Environment]::TickCount
|
||||
Start-Sleep -s 10
|
||||
while($true) {
|
||||
$cmdprocess = Get-Process "cmd" -ErrorAction SilentlyContinue
|
||||
|
||||
if (!$cmdprocess -Or $cmdprocess.HasExited) {
|
||||
Write-Host "[ 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 "Exit by pacman.conf" -ForegroundColor Green
|
||||
break
|
||||
}
|
||||
|
||||
if ([System.Environment]::TickCount-$StartTime -gt 1000000) {
|
||||
Write-host "Exit by timeout" -ForegroundColor Yellow
|
||||
break
|
||||
}
|
||||
|
||||
Start-Sleep -s 1
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host "Removing ProxSpace..." -NoNewLine
|
||||
|
||||
$CloneTime=[System.Environment]::TickCount
|
||||
|
||||
cd \
|
||||
|
||||
Remove-Item -Recurse -Force -Path c:\ProxSpace\*
|
||||
Remove-Item -Recurse -Force -Path $env:proxspace_path
|
||||
|
||||
Write-Host "[ OK ]" -ForegroundColor Green
|
||||
|
||||
Write-Host "Download ProxSpace..." -NoNewLine
|
||||
|
||||
Write-Host "Git clone ProxSpace..." -NoNewLine
|
||||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
|
||||
|
||||
git clone -q https://github.com/Gator96100/ProxSpace c:\ProxSpace
|
||||
Invoke-WebRequest "$env:proxspace_url" -outfile "$env:proxspace_zip_file"
|
||||
|
||||
Write-Host "[ OK ]" -ForegroundColor Green
|
||||
|
||||
Write-Host "Extracting ProxSpace..." -NoNewLine
|
||||
|
||||
if(!(Test-Path -Path C:\ProxSpace\pm3)){
|
||||
Expand-Archive -LiteralPath "$env:proxspace_zip_file" -DestinationPath "\"
|
||||
|
||||
New-Item -ItemType Directory -Force -Path C:\ProxSpace\pm3
|
||||
|
||||
}
|
||||
|
||||
Write-Host "Removing pm3 dir..." -NoNewLine
|
||||
|
||||
Remove-Item -Recurse -Force -Path c:\ProxSpace\pm3\*
|
||||
Remove-Item "$env:proxspace_zip_file"
|
||||
|
||||
Write-Host "[ OK ]" -ForegroundColor Green
|
||||
|
||||
Write-Host "Removing ps startup_check.sh ..." -NoNewLine
|
||||
Write-Host "Renaming ProxSpace folder..." -NoNewLine
|
||||
|
||||
Remove-Item -Recurse -Force -Path c:\ProxSpace\msys2\ps\startup_checks.sh
|
||||
Get-ChildItem -Path "\$env:proxspace_zip_folder_name" | Rename-Item -NewName (Split-Path $env:proxspace_path -Leaf)
|
||||
|
||||
Write-Host "[ OK ]" -ForegroundColor Green
|
||||
Write-Host "[ OK ]" -ForegroundColor Gree
|
||||
|
||||
ExecUpdate "Initial msys2 startup..." $true
|
||||
|
||||
ExecUpdate "Installing required packages..." $false
|
||||
|
||||
|
||||
$psversion = (Select-String -Pattern 'PSVERSION=' -SimpleMatch -Path "$env:proxspace_path\msys2\ps\09-proxspace_setup.post").Line.Split("""")[1]
|
||||
|
||||
Write-Host "ProxSpace version: $psversion" -ForegroundColor Yellow
|
||||
|
||||
Write-Host "Cloning repository <$env:appveyor_repo_name> to $env:appveyor_build_folder ..." -NoNewLine
|
||||
|
||||
|
@ -76,110 +120,20 @@ clone_script:
|
|||
|
||||
Write-Host "[ OK ]" -ForegroundColor Green
|
||||
|
||||
|
||||
Write-Host "Fill msys2\etc\fstab file..." -NoNewLine
|
||||
|
||||
New-Item c:\ProxSpace\msys2\etc\fstab -type file -force -value "# For a description of the file format, see the Users Guide`n# http://cygwin.com/cygwin-ug-net/using.html#mount-table`nnone / cygdrive binary,posix=0,noacl,user 0 0 `nC:\ProxSpace\pm3 /pm3 ntfs noacl 0 0 `nC:\ProxSpace\gcc-arm-none-eabi /gcc-arm-none-eabi ntfs noacl 0 0 `n"
|
||||
|
||||
Write-Host "[ OK ]" -ForegroundColor Green
|
||||
|
||||
|
||||
Write-Host "Update msys2 packages..."
|
||||
|
||||
$env:Path = "C:\ProxSpace\msys2\usr\bin;C:\ProxSpace\msys2\mingw32\bin;C:\ProxSpace\gcc-arm-none-eabi\bin;$env:Path"
|
||||
|
||||
Function ExecUpdate($Name, $Cmd, $ErrorLine) {
|
||||
|
||||
Write-Host "Exec [$Name]... " -NoNewLine
|
||||
#--- begin Job
|
||||
|
||||
$Job = Start-Job -Name "$Name" -ScriptBlock {
|
||||
$env:Path = "C:\ProxSpace\msys\bin;$env:Path"
|
||||
Set-Location $using:PWD
|
||||
|
||||
$sb=[scriptblock]::Create("$using:Cmd")
|
||||
#execute scriptblock
|
||||
$Cond=&$sb
|
||||
|
||||
return $Cond
|
||||
}
|
||||
|
||||
#--- end Job
|
||||
|
||||
$JobTime=[System.Environment]::TickCount
|
||||
while($true) {
|
||||
Try {
|
||||
$Res = Receive-Job -Job $Job -Keep 2>&1 6>&1
|
||||
}
|
||||
Catch {
|
||||
$Res = ""
|
||||
Write-host "error in Receive-Job"
|
||||
}
|
||||
|
||||
if ($Res -is "String" -and $Res -like "*$ErrorLine*"){
|
||||
Write-host "Exit by stop phrase" -ForegroundColor Green
|
||||
break
|
||||
}
|
||||
|
||||
if ($Res -is [Object]){
|
||||
[bool]$needexit = $false
|
||||
ForEach($line in $Res){
|
||||
if ($line -like "*$ErrorLine*"){
|
||||
Write-host "Exit by stop phrase [obj]" -ForegroundColor Green
|
||||
$needexit = $true
|
||||
break
|
||||
}
|
||||
}
|
||||
if ($needexit) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if(Wait-Job $Job -Timeout 5){
|
||||
Write-host "Exit by end job" -ForegroundColor Green
|
||||
break
|
||||
}
|
||||
|
||||
if ([System.Environment]::TickCount-$JobTime -gt 1000000) {
|
||||
Write-host "Exit by timeout" -ForegroundColor Yellow
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
Remove-Job -Force $Job
|
||||
}
|
||||
|
||||
cd C:\ProxSpace\
|
||||
|
||||
C:\ProxSpace\msys2\ps\setup.cmd
|
||||
|
||||
ExecUpdate "update1" "C:\ProxSpace\msys2\msys2_shell.cmd -mingw32 -defterm -no-start /dev/null" "terminate?MSYS2"
|
||||
|
||||
ExecUpdate "update2" "C:\ProxSpace\msys2\msys2_shell.cmd -mingw32 -defterm -no-start /dev/null" "terminate?MSYS2"
|
||||
|
||||
Add-AppveyorMessage -Message "ProxSpace download and update took $(([System.Environment]::TickCount-$CloneTime) / 1000) sec" -Category Information
|
||||
|
||||
Write-Host "Update " -NoNewLine
|
||||
|
||||
Write-Host "[ OK ]" -ForegroundColor Green
|
||||
install:
|
||||
build_script:
|
||||
- ps: >-
|
||||
$env:Path="C:\ProxSpace\msys2\usr\bin;C:\ProxSpace\msys2\mingw32\bin;C:\ProxSpace\gcc-arm-none-eabi\bin;c:\Python38;c:\Python38\Scripts;$env:Path"
|
||||
|
||||
$env:MINGW_HOME="C:\ProxSpace\msys2\mingw32"
|
||||
$pmfolder = Split-Path $env:appveyor_build_folder -Leaf
|
||||
|
||||
$env:MSYS_HOME="C:\ProxSpace\msys2"
|
||||
Function ExecMinGWCmd($Cmd) {
|
||||
cd $env:proxspace_path
|
||||
msys2\msys2_shell.cmd -mingw64 -defterm -no-start -c "cd $pmfolder && $Cmd"
|
||||
}
|
||||
|
||||
$env:MSYSTEM="MINGW32"
|
||||
|
||||
$env:MINGW_PREFIX="/mingw32"
|
||||
|
||||
$env:SHELL="/bin/bash"
|
||||
|
||||
$env:MSYSTEM_CHOST="i686-w64-mingw32"
|
||||
|
||||
cd C:\ProxSpace\pm3
|
||||
|
||||
Write-Host "---------- make ----------" -ForegroundColor Yellow
|
||||
|
||||
|
@ -187,20 +141,21 @@ build_script:
|
|||
|
||||
#make
|
||||
|
||||
bash -c -i 'echo $PATH;pwd;make clean;make V=1'
|
||||
cd $env:proxspace_path
|
||||
|
||||
msys2\ps\setup.cmd
|
||||
|
||||
ExecMinGWCmd "make clean;make V=1"
|
||||
|
||||
#some checks
|
||||
|
||||
if(!(Test-Path C:\ProxSpace\pm3\client\proxmark3.exe)){
|
||||
if(!(Test-Path "$env:proxspace_home_path\$pmfolder\client\proxmark3.exe")){
|
||||
|
||||
throw "Main file proxmark3.exe not exists."
|
||||
|
||||
}
|
||||
|
||||
cd c:\ProxSpace\pm3
|
||||
|
||||
bash -c -i 'make check'
|
||||
ExecMinGWCmd 'make check'
|
||||
|
||||
$testspass = ($LASTEXITCODE -eq 0)
|
||||
|
||||
|
@ -219,11 +174,9 @@ build_script:
|
|||
|
||||
$TestTime=[System.Environment]::TickCount
|
||||
|
||||
bash -c -i 'pwd;make clean;make PLATFORM_EXTRAS=BTADDON'
|
||||
ExecMinGWCmd 'make clean;make V=1 PLATFORM_EXTRAS=BTADDON'
|
||||
|
||||
cd c:\ProxSpace\pm3
|
||||
|
||||
bash -c -i 'make check'
|
||||
ExecMinGWCmd 'make check'
|
||||
|
||||
$testspass = ($LASTEXITCODE -eq 0)
|
||||
|
||||
|
@ -239,19 +192,17 @@ build_script:
|
|||
|
||||
Write-Host "---------- make clean ----------" -ForegroundColor Yellow
|
||||
|
||||
bash -c -i 'make clean'
|
||||
ExecMinGWCmd 'make clean'
|
||||
|
||||
Write-Host "---------- cmake ----------" -ForegroundColor Yellow
|
||||
|
||||
$TestTime=[System.Environment]::TickCount
|
||||
|
||||
cmd.exe /c 'C:\ProxSpace\msys2\msys2_shell.cmd -mingw32 -defterm -no-start -c "mkdir -p client/build; cd client/build; cmake -G""MSYS Makefiles"" ..; make VERBOSE=1;"'
|
||||
ExecMinGWCmd 'mkdir -p client/build; cd client/build; cmake -G""MSYS Makefiles"" ..; make VERBOSE=1;'
|
||||
|
||||
Write-Host "---------- cmake tests ----------" -ForegroundColor Yellow
|
||||
|
||||
cd c:\ProxSpace\pm3
|
||||
|
||||
bash -c -i './tools/pm3_tests.sh --clientbin client/build/proxmark3.exe client'
|
||||
ExecMinGWCmd './tools/pm3_tests.sh --clientbin client/build/proxmark3.exe client'
|
||||
|
||||
$testspass = ($LASTEXITCODE -eq 0)
|
||||
|
||||
|
|
|
@ -759,8 +759,8 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
}
|
||||
case CMD_LF_ACQ_RAW_ADC: {
|
||||
struct p {
|
||||
bool verbose;
|
||||
uint32_t samples;
|
||||
uint32_t samples : 31;
|
||||
bool verbose : 1;
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *)packet->data.asBytes;
|
||||
uint32_t bits = SampleLF(payload->verbose, payload->samples);
|
||||
|
@ -772,9 +772,11 @@ static void PacketReceived(PacketCommandNG *packet) {
|
|||
uint32_t delay;
|
||||
uint16_t ones;
|
||||
uint16_t zeros;
|
||||
uint32_t samples : 31;
|
||||
bool verbose : 1;
|
||||
} PACKED;
|
||||
struct p *payload = (struct p *)packet->data.asBytes;
|
||||
ModThenAcquireRawAdcSamples125k(payload->delay, payload->zeros, payload->ones, packet->data.asBytes + 8);
|
||||
ModThenAcquireRawAdcSamples125k(payload->delay, payload->zeros, payload->ones, packet->data.asBytes + sizeof(struct p), payload->verbose, payload->samples);
|
||||
break;
|
||||
}
|
||||
case CMD_LF_SNIFF_RAW_ADC: {
|
||||
|
|
|
@ -134,11 +134,11 @@ static hf14a_config hf14aconfig = { 0, 0, 0, 0, 0 } ;
|
|||
|
||||
void printHf14aConfig(void) {
|
||||
DbpString(_CYAN_("HF 14a config"));
|
||||
Dbprintf("[a] Anticol override......%s%s%s", (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..........%s%s%s", (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..........%s%s%s", (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..........%s%s%s", (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.........%s%s%s", (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") " (follow standard)" : "", (hf14aconfig.forcerats == 1) ? _RED_("Yes: Always do RATS") : "", (hf14aconfig.forcerats == 2) ? _RED_("Yes: Always skip RATS") : "");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -899,13 +899,15 @@ bool GetIso14443aCommandFromReader(uint8_t *received, uint8_t *par, int *len) {
|
|||
uint16_t check = 0;
|
||||
|
||||
for (;;) {
|
||||
if (check == 1000) {
|
||||
if (BUTTON_PRESS() || data_available())
|
||||
if (check == 4000) {
|
||||
// if (BUTTON_PRESS() || data_available())
|
||||
if (BUTTON_PRESS())
|
||||
return false;
|
||||
|
||||
check = 0;
|
||||
WDT_HIT();
|
||||
}
|
||||
++check;
|
||||
WDT_HIT();
|
||||
|
||||
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
|
||||
b = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
|
||||
|
@ -981,11 +983,15 @@ bool SimulateIso14443aInit(int tagType, int flags, uint8_t *data, tag_response_i
|
|||
// Prepare the optional second SAK (for 7 byte UID), drop the cascade bit
|
||||
static uint8_t rSAKc2[3] = { 0x00 };
|
||||
// dummy ATS (pseudo-ATR), answer to RATS
|
||||
static uint8_t rRATS[] = { 0x04, 0x58, 0x80, 0x02, 0x00, 0x00 };
|
||||
// static uint8_t rRATS[] = { 0x04, 0x58, 0x80, 0x02, 0x00, 0x00 };
|
||||
static uint8_t rRATS[] = { 0x05, 0x75, 0x80, 0x60, 0x02, 0x00, 0x00 };
|
||||
|
||||
// GET_VERSION response for EV1/NTAG
|
||||
static uint8_t rVERSION[10] = { 0x00 };
|
||||
// READ_SIG response for EV1/NTAG
|
||||
static uint8_t rSIGN[34] = { 0x00 };
|
||||
// PPS respoonse
|
||||
static uint8_t rPPS[3] = { 0xD0 };
|
||||
|
||||
switch (tagType) {
|
||||
case 1: { // MIFARE Classic 1k
|
||||
|
@ -1059,12 +1065,19 @@ bool SimulateIso14443aInit(int tagType, int flags, uint8_t *data, tag_response_i
|
|||
sak = 0x18;
|
||||
}
|
||||
break;
|
||||
case 9 : { // FM11RF005SH (Shanghai Metro)
|
||||
case 9: { // FM11RF005SH (Shanghai Metro)
|
||||
rATQA[0] = 0x03;
|
||||
rATQA[1] = 0x00;
|
||||
sak = 0x0A;
|
||||
}
|
||||
break;
|
||||
case 10: { // JCOP31/41 Rothult
|
||||
rATQA[0] = 0x42;
|
||||
rATQA[1] = 0x00;
|
||||
sak = 0x00;
|
||||
}
|
||||
break;
|
||||
|
||||
default: {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Error: unknown tagtype (%d)", tagType);
|
||||
return false;
|
||||
|
@ -1115,13 +1128,20 @@ bool SimulateIso14443aInit(int tagType, int flags, uint8_t *data, tag_response_i
|
|||
return false;
|
||||
}
|
||||
|
||||
// Calculate the BitCountCheck (BCC) for the first 4 bytes of the UID.
|
||||
// Calculate BCC for the first 4 bytes of the UID.
|
||||
rUIDc1[4] = rUIDc1[0] ^ rUIDc1[1] ^ rUIDc1[2] ^ rUIDc1[3];
|
||||
|
||||
rSAKc1[0] = sak;
|
||||
AddCrc14A(rSAKc1, sizeof(rSAKc1) - 2);
|
||||
|
||||
rSAKc2[0] = sak & 0xFB;
|
||||
if (tagType == 10) {
|
||||
rSAKc1[0] = 0x04;
|
||||
rSAKc2[0] = 0x20;
|
||||
} else {
|
||||
rSAKc1[0] = sak;
|
||||
rSAKc2[0] = sak & 0xFB;
|
||||
}
|
||||
|
||||
// crc
|
||||
AddCrc14A(rSAKc1, sizeof(rSAKc1) - 2);
|
||||
AddCrc14A(rSAKc2, sizeof(rSAKc2) - 2);
|
||||
|
||||
// Format byte = 0x58: FSCI=0x08 (FSC=256), TA(1) and TC(1) present,
|
||||
|
@ -1130,22 +1150,26 @@ bool SimulateIso14443aInit(int tagType, int flags, uint8_t *data, tag_response_i
|
|||
// TC(1) = 0x02: CID supported, NAD not supported
|
||||
AddCrc14A(rRATS, sizeof(rRATS) - 2);
|
||||
|
||||
#define TAG_RESPONSE_COUNT 8
|
||||
AddCrc14A(rPPS, sizeof(rPPS) - 2);
|
||||
|
||||
#define TAG_RESPONSE_COUNT 9
|
||||
static tag_response_info_t responses_init[TAG_RESPONSE_COUNT] = {
|
||||
{ .response = rATQA, .response_n = sizeof(rATQA) }, // Answer to request - respond with card type
|
||||
{ .response = rUIDc1, .response_n = sizeof(rUIDc1) }, // Anticollision cascade1 - respond with uid
|
||||
{ .response = rUIDc2, .response_n = sizeof(rUIDc2) }, // Anticollision cascade2 - respond with 2nd half of uid if asked
|
||||
{ .response = rSAKc1, .response_n = sizeof(rSAKc1) }, // Acknowledge select - cascade 1
|
||||
{ .response = rSAKc2, .response_n = sizeof(rSAKc2) }, // Acknowledge select - cascade 2
|
||||
{ .response = rRATS, .response_n = sizeof(rRATS) }, // dummy ATS (pseudo-ATR), answer to RATS
|
||||
{ .response = rVERSION, .response_n = sizeof(rVERSION) }, // EV1/NTAG GET_VERSION response
|
||||
{ .response = rSIGN, .response_n = sizeof(rSIGN) } // EV1/NTAG READ_SIG response
|
||||
{ .response = rATQA, .response_n = sizeof(rATQA) }, // Answer to request - respond with card type
|
||||
{ .response = rUIDc1, .response_n = sizeof(rUIDc1) }, // Anticollision cascade1 - respond with uid
|
||||
{ .response = rUIDc2, .response_n = sizeof(rUIDc2) }, // Anticollision cascade2 - respond with 2nd half of uid if asked
|
||||
{ .response = rSAKc1, .response_n = sizeof(rSAKc1) }, // Acknowledge select - cascade 1
|
||||
{ .response = rSAKc2, .response_n = sizeof(rSAKc2) }, // Acknowledge select - cascade 2
|
||||
{ .response = rRATS, .response_n = sizeof(rRATS) }, // dummy ATS (pseudo-ATR), answer to RATS
|
||||
{ .response = rVERSION, .response_n = sizeof(rVERSION) }, // EV1/NTAG GET_VERSION response
|
||||
{ .response = rSIGN, .response_n = sizeof(rSIGN) }, // EV1/NTAG READ_SIG response
|
||||
{ .response = rPPS, .response_n = sizeof(rPPS) } // PPS response
|
||||
};
|
||||
|
||||
// "precompile" responses. There are 8 predefined responses with a total of 68 bytes data to transmit.
|
||||
// "precompile" responses. There are 9 predefined responses with a total of 72 bytes data to transmit.
|
||||
// Coded responses need one byte per bit to transfer (data, parity, start, stop, correction)
|
||||
// 68 * 8 data bits, 68 * 1 parity bits, 8 start bits, 8 stop bits, 8 correction bits -- 636 bytes buffer
|
||||
#define ALLOCATED_TAG_MODULATION_BUFFER_SIZE 636
|
||||
// 72 * 8 data bits, 72 * 1 parity bits, 9 start bits, 9 stop bits, 9 correction bits -- 677 bytes buffer
|
||||
#define ALLOCATED_TAG_MODULATION_BUFFER_SIZE 675
|
||||
// 576 + 72 + 9 + 9 + 9 == 675
|
||||
|
||||
uint8_t *free_buffer = BigBuf_malloc(ALLOCATED_TAG_MODULATION_BUFFER_SIZE);
|
||||
// modulation buffer pointer and current buffer free space size
|
||||
|
@ -1173,7 +1197,7 @@ bool SimulateIso14443aInit(int tagType, int flags, uint8_t *data, tag_response_i
|
|||
#define RATS 5
|
||||
#define VERSION 6
|
||||
#define SIGNATURE 7
|
||||
|
||||
#define PPS 8
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1232,6 +1256,8 @@ void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data) {
|
|||
// We need to listen to the high-frequency, peak-detected path.
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_TAGSIM_LISTEN);
|
||||
|
||||
iso14a_set_timeout(201400); // 106 * 19ms default
|
||||
|
||||
int len = 0;
|
||||
|
||||
// To control where we are in the protocol
|
||||
|
@ -1246,8 +1272,8 @@ void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data) {
|
|||
#define ORDER_SELECT_CL2 30
|
||||
#define ORDER_EV1_COMP_WRITE 40
|
||||
#define ORDER_RATS 70
|
||||
uint8_t order = ORDER_NONE;
|
||||
|
||||
uint8_t order = ORDER_NONE;
|
||||
int retval = PM3_SUCCESS;
|
||||
|
||||
// Just to allow some checks
|
||||
|
@ -1258,27 +1284,26 @@ void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data) {
|
|||
// compatible write block number
|
||||
uint8_t wrblock = 0;
|
||||
|
||||
bool odd_reply = true;
|
||||
|
||||
clear_trace();
|
||||
set_tracing(true);
|
||||
LED_A_ON();
|
||||
|
||||
// main loop
|
||||
for (;;) {
|
||||
WDT_HIT();
|
||||
|
||||
tag_response_info_t *p_response = NULL;
|
||||
|
||||
// Clean receive command buffer
|
||||
if (!GetIso14443aCommandFromReader(receivedCmd, receivedCmdPar, &len)) {
|
||||
Dbprintf("Emulator stopped. Trace length: %d ", BigBuf_get_traceLen());
|
||||
if (GetIso14443aCommandFromReader(receivedCmd, receivedCmdPar, &len) == false) {
|
||||
Dbprintf("Emulator stopped. Trace length: %d ", BigBuf_get_traceLen());
|
||||
retval = PM3_EOPABORTED;
|
||||
break;
|
||||
}
|
||||
tag_response_info_t *p_response = NULL;
|
||||
|
||||
// Okay, look at the command now.
|
||||
int lastorder = order;
|
||||
|
||||
//
|
||||
// we need to check "ordered" states before, because received data may be same to any command - is wrong!!!
|
||||
//
|
||||
|
||||
if (order == ORDER_EV1_COMP_WRITE && len == 18) {
|
||||
// MIFARE_ULC_COMP_WRITE part 2
|
||||
// 16 bytes data + 2 bytes crc, only least significant 4 bytes are written
|
||||
|
@ -1361,28 +1386,22 @@ void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data) {
|
|||
order = ORDER_NONE; // back to work state
|
||||
p_response = NULL;
|
||||
|
||||
//
|
||||
// now check commands in received buffer
|
||||
//
|
||||
|
||||
} else if (receivedCmd[0] == ISO14443A_CMD_REQA && len == 1) { // Received a REQUEST
|
||||
p_response = &responses[ATQA];
|
||||
order = ORDER_REQA;
|
||||
} else if (receivedCmd[0] == ISO14443A_CMD_REQA && len == 1) { // Received a REQUEST, but in HALTED, skip
|
||||
odd_reply = !odd_reply;
|
||||
if (odd_reply)
|
||||
p_response = &responses[ATQA];
|
||||
} else if (receivedCmd[0] == ISO14443A_CMD_WUPA && len == 1) { // Received a WAKEUP
|
||||
p_response = &responses[ATQA];
|
||||
order = ORDER_WUPA;
|
||||
} else if (receivedCmd[1] == 0x20 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 2) { // Received request for UID (cascade 1)
|
||||
p_response = &responses[UIDC1];
|
||||
order = ORDER_SELECT_ALL_CL1;
|
||||
} else if (receivedCmd[1] == 0x20 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && len == 2) { // Received request for UID (cascade 2)
|
||||
p_response = &responses[UIDC2];
|
||||
order = ORDER_SELECT_ALL_CL2;
|
||||
} else if (receivedCmd[1] == 0x70 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT && len == 9) { // Received a SELECT (cascade 1)
|
||||
p_response = &responses[SAKC1];
|
||||
order = ORDER_SELECT_CL1;
|
||||
} else if (receivedCmd[1] == 0x70 && receivedCmd[0] == ISO14443A_CMD_ANTICOLL_OR_SELECT_2 && len == 9) { // Received a SELECT (cascade 2)
|
||||
p_response = &responses[SAKC2];
|
||||
order = ORDER_SELECT_CL2;
|
||||
} else if (receivedCmd[0] == ISO14443A_CMD_PPS) {
|
||||
p_response = &responses[PPS];
|
||||
} else if (receivedCmd[0] == ISO14443A_CMD_READBLOCK && len == 4) { // Received a (plain) READ
|
||||
uint8_t block = receivedCmd[1];
|
||||
// if Ultralight or NTAG (4 byte blocks)
|
||||
|
@ -1410,8 +1429,6 @@ void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data) {
|
|||
emlGetMemBt(emdata, block, 16);
|
||||
AddCrc14A(emdata, 16);
|
||||
EmSendCmd(emdata, sizeof(emdata));
|
||||
// EmSendCmd(data+(4*receivedCmd[1]),16);
|
||||
// Dbprintf("Read request from reader: %x %x",receivedCmd[0],receivedCmd[1]);
|
||||
// We already responded, do not send anything with the EmSendCmd14443aRaw() that is called below
|
||||
p_response = NULL;
|
||||
}
|
||||
|
@ -1433,8 +1450,7 @@ void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data) {
|
|||
p_response = NULL;
|
||||
} else if (receivedCmd[0] == MIFARE_ULC_WRITE && len == 8 && (tagType == 2 || tagType == 7)) { // Received a WRITE
|
||||
// cmd + block + 4 bytes data + 2 bytes crc
|
||||
bool isCrcCorrect = CheckCrc14A(receivedCmd, len);
|
||||
if (isCrcCorrect) {
|
||||
if (CheckCrc14A(receivedCmd, len)) {
|
||||
uint8_t block = receivedCmd[1];
|
||||
if (block > pages) {
|
||||
// send NACK 0x0 == invalid argument
|
||||
|
@ -1452,8 +1468,7 @@ void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data) {
|
|||
p_response = NULL;
|
||||
} else if (receivedCmd[0] == MIFARE_ULC_COMP_WRITE && len == 4 && (tagType == 2 || tagType == 7)) {
|
||||
// cmd + block + 2 bytes crc
|
||||
bool isCrcCorrect = CheckCrc14A(receivedCmd, len);
|
||||
if (isCrcCorrect) {
|
||||
if (CheckCrc14A(receivedCmd, len)) {
|
||||
wrblock = receivedCmd[1];
|
||||
if (wrblock > pages) {
|
||||
// send NACK 0x0 == invalid argument
|
||||
|
@ -1538,7 +1553,6 @@ void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data) {
|
|||
p_response = NULL;
|
||||
} else {
|
||||
p_response = &responses[RATS];
|
||||
order = ORDER_RATS;
|
||||
}
|
||||
} else if (receivedCmd[0] == MIFARE_ULC_AUTH_1) { // ULC authentication, or Desfire Authentication
|
||||
LogTrace(receivedCmd, Uart.len, Uart.startTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, true);
|
||||
|
@ -1566,73 +1580,103 @@ void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data) {
|
|||
AddCrc14A(cmd, sizeof(cmd) - 2);
|
||||
EmSendCmd(cmd, sizeof(cmd));
|
||||
p_response = NULL;
|
||||
|
||||
} else {
|
||||
// Check for ISO 14443A-4 compliant commands, look at left nibble
|
||||
switch (receivedCmd[0]) {
|
||||
case 0x02:
|
||||
case 0x03: { // IBlock (command no CID)
|
||||
|
||||
// clear old dynamic responses
|
||||
dynamic_response_info.response_n = 0;
|
||||
dynamic_response_info.modulation_n = 0;
|
||||
|
||||
// ST25TA512B IKEA Rothult
|
||||
if (tagType == 10) {
|
||||
// we replay 90 00 for all commands but the read bin and we deny the verify cmd.
|
||||
|
||||
if (memcmp("\x02\xa2\xb0\x00\x00\x1d\x51\x69", receivedCmd, 8) == 0) {
|
||||
dynamic_response_info.response[0] = receivedCmd[0];
|
||||
memcpy(dynamic_response_info.response + 1, "\x00\x1b\xd1\x01\x17\x54\x02\x7a\x68\xa2\x34\xcb\xd0\xe2\x03\xc7\x3e\x62\x0b\xe8\xc6\x3c\x85\x2c\xc5\x31\x31\x31\x32\x90\x00", 31);
|
||||
dynamic_response_info.response_n = 32;
|
||||
} else if (memcmp("\x02\x00\x20\x00\x01\x00\x6e\xa9", receivedCmd, 8) == 0) {
|
||||
dynamic_response_info.response[0] = receivedCmd[0];
|
||||
dynamic_response_info.response[1] = 0x63;
|
||||
dynamic_response_info.response[2] = 0x00;
|
||||
dynamic_response_info.response_n = 3;
|
||||
} else {
|
||||
dynamic_response_info.response[0] = receivedCmd[0];
|
||||
dynamic_response_info.response[1] = 0x90;
|
||||
dynamic_response_info.response[2] = 0x00;
|
||||
dynamic_response_info.response_n = 3;
|
||||
}
|
||||
break;
|
||||
case 0x0B:
|
||||
case 0x0A: { // IBlock (command CID)
|
||||
dynamic_response_info.response[0] = receivedCmd[0];
|
||||
dynamic_response_info.response[1] = 0x00;
|
||||
dynamic_response_info.response[2] = 0x90;
|
||||
dynamic_response_info.response[3] = 0x00;
|
||||
dynamic_response_info.response_n = 4;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
|
||||
case 0x1A:
|
||||
case 0x1B: { // Chaining command
|
||||
dynamic_response_info.response[0] = 0xaa | ((receivedCmd[0]) & 1);
|
||||
dynamic_response_info.response_n = 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xAA:
|
||||
case 0xBB: {
|
||||
dynamic_response_info.response[0] = receivedCmd[0] ^ 0x11;
|
||||
dynamic_response_info.response_n = 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xBA: { // ping / pong
|
||||
dynamic_response_info.response[0] = 0xAB;
|
||||
dynamic_response_info.response[1] = 0x00;
|
||||
dynamic_response_info.response_n = 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xCA:
|
||||
case 0xC2: { // Readers sends deselect command
|
||||
dynamic_response_info.response[0] = 0xCA;
|
||||
dynamic_response_info.response[1] = 0x00;
|
||||
dynamic_response_info.response_n = 2;
|
||||
}
|
||||
break;
|
||||
|
||||
default: {
|
||||
// Never seen this command before
|
||||
LogTrace(receivedCmd, Uart.len, Uart.startTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, true);
|
||||
if (DBGLEVEL >= DBG_DEBUG) {
|
||||
Dbprintf("Received unknown command (len=%d):", len);
|
||||
Dbhexdump(len, receivedCmd, false);
|
||||
// Check for ISO 14443A-4 compliant commands, look at left nibble
|
||||
switch (receivedCmd[0]) {
|
||||
case 0x02:
|
||||
case 0x03: { // IBlock (command no CID)
|
||||
dynamic_response_info.response[0] = receivedCmd[0];
|
||||
dynamic_response_info.response[1] = 0x90;
|
||||
dynamic_response_info.response[2] = 0x00;
|
||||
dynamic_response_info.response_n = 3;
|
||||
}
|
||||
// Do not respond
|
||||
dynamic_response_info.response_n = 0;
|
||||
order = ORDER_NONE; // back to work state
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x0B:
|
||||
case 0x0A: { // IBlock (command CID)
|
||||
dynamic_response_info.response[0] = receivedCmd[0];
|
||||
dynamic_response_info.response[1] = 0x00;
|
||||
dynamic_response_info.response[2] = 0x90;
|
||||
dynamic_response_info.response[3] = 0x00;
|
||||
dynamic_response_info.response_n = 4;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x1A:
|
||||
case 0x1B: { // Chaining command
|
||||
dynamic_response_info.response[0] = 0xaa | ((receivedCmd[0]) & 1);
|
||||
dynamic_response_info.response_n = 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xAA:
|
||||
case 0xBB: {
|
||||
dynamic_response_info.response[0] = receivedCmd[0] ^ 0x11;
|
||||
dynamic_response_info.response_n = 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xBA: { // ping / pong
|
||||
dynamic_response_info.response[0] = 0xAB;
|
||||
dynamic_response_info.response[1] = 0x00;
|
||||
dynamic_response_info.response_n = 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0xCA:
|
||||
case 0xC2: { // Readers sends deselect command
|
||||
dynamic_response_info.response[0] = 0xCA;
|
||||
dynamic_response_info.response[1] = 0x00;
|
||||
dynamic_response_info.response_n = 2;
|
||||
}
|
||||
break;
|
||||
|
||||
default: {
|
||||
// Never seen this command before
|
||||
LogTrace(receivedCmd, Uart.len, Uart.startTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.endTime * 16 - DELAY_AIR2ARM_AS_TAG, Uart.parity, true);
|
||||
if (DBGLEVEL >= DBG_DEBUG) {
|
||||
Dbprintf("Received unknown command (len=%d):", len);
|
||||
Dbhexdump(len, receivedCmd, false);
|
||||
}
|
||||
// Do not respond
|
||||
dynamic_response_info.response_n = 0;
|
||||
order = ORDER_NONE; // back to work state
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
if (dynamic_response_info.response_n > 0) {
|
||||
|
||||
// Copy the CID from the reader query
|
||||
dynamic_response_info.response[1] = receivedCmd[1];
|
||||
if (tagType != 10)
|
||||
dynamic_response_info.response[1] = receivedCmd[1];
|
||||
|
||||
// Add CRC bytes, always used in ISO 14443A-4 compliant cards
|
||||
AddCrc14A(dynamic_response_info.response, dynamic_response_info.response_n);
|
||||
|
@ -1648,16 +1692,15 @@ void SimulateIso14443aTag(uint8_t tagType, uint8_t flags, uint8_t *data) {
|
|||
}
|
||||
|
||||
// Count number of wakeups received after a halt
|
||||
if (order == ORDER_WUPA && lastorder == ORDER_HALTED) { happened++; }
|
||||
// if (order == ORDER_WUPA && lastorder == ORDER_HALTED) { happened++; }
|
||||
|
||||
// Count number of other messages after a halt
|
||||
if (order != ORDER_WUPA && lastorder == ORDER_HALTED) { happened2++; }
|
||||
// if (order != ORDER_WUPA && lastorder == ORDER_HALTED) { happened2++; }
|
||||
|
||||
cmdsRecvd++;
|
||||
|
||||
if (p_response != NULL) {
|
||||
EmSendPrecompiledCmd(p_response);
|
||||
}
|
||||
// Send response
|
||||
EmSendPrecompiledCmd(p_response);
|
||||
}
|
||||
|
||||
switch_off();
|
||||
|
@ -1958,7 +2001,7 @@ int EmSendCmd14443aRaw(uint8_t *resp, uint16_t respLen) {
|
|||
volatile uint8_t b;
|
||||
uint16_t i = 0;
|
||||
uint32_t ThisTransferTime;
|
||||
bool correctionNeeded;
|
||||
bool correction_needed;
|
||||
|
||||
// Modulate Manchester
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_HF_ISO14443A | FPGA_HF_ISO14443A_TAGSIM_MOD);
|
||||
|
@ -1966,21 +2009,23 @@ int EmSendCmd14443aRaw(uint8_t *resp, uint16_t respLen) {
|
|||
// Include correction bit if necessary
|
||||
if (Uart.bitCount == 7) {
|
||||
// Short tags (7 bits) don't have parity, determine the correct value from MSB
|
||||
correctionNeeded = Uart.output[0] & 0x40;
|
||||
correction_needed = Uart.output[0] & 0x40;
|
||||
} else {
|
||||
// The parity bits are left-aligned
|
||||
correctionNeeded = Uart.parity[(Uart.len - 1) / 8] & (0x80 >> ((Uart.len - 1) & 7));
|
||||
correction_needed = Uart.parity[(Uart.len - 1) / 8] & (0x80 >> ((Uart.len - 1) & 7));
|
||||
}
|
||||
// 1236, so correction bit needed
|
||||
i = (correctionNeeded) ? 0 : 1;
|
||||
i = (correction_needed) ? 0 : 1;
|
||||
|
||||
// clear receiving shift register and holding register
|
||||
while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY));
|
||||
b = AT91C_BASE_SSC->SSC_RHR;
|
||||
(void) b;
|
||||
while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_RXRDY));
|
||||
b = AT91C_BASE_SSC->SSC_RHR;
|
||||
(void) b;
|
||||
/*
|
||||
while (!(AT91C_BASE_SSC->SSC_SR & AT91C_SSC_TXRDY));
|
||||
b = AT91C_BASE_SSC->SSC_THR;
|
||||
(void) b;
|
||||
*/
|
||||
|
||||
// wait for the FPGA to signal fdt_indicator == 1 (the FPGA is ready to queue new data in its delay line)
|
||||
for (uint8_t j = 0; j < 5; j++) { // allow timeout - better late than never
|
||||
|
@ -2000,22 +2045,24 @@ int EmSendCmd14443aRaw(uint8_t *resp, uint16_t respLen) {
|
|||
FpgaSendQueueDelay = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
|
||||
}
|
||||
|
||||
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
|
||||
b = (uint16_t)(AT91C_BASE_SSC->SSC_RHR);
|
||||
(void)b;
|
||||
}
|
||||
/*
|
||||
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_RXRDY)) {
|
||||
b = (uint16_t)(AT91C_BASE_SSC->SSC_RHR);
|
||||
(void)b;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
// Ensure that the FPGA Delay Queue is empty before we switch to TAGSIM_LISTEN again:
|
||||
uint8_t fpga_queued_bits = FpgaSendQueueDelay >> 3;
|
||||
for (i = 0; i <= fpga_queued_bits / 8 + 1;) {
|
||||
for (i = 0; i <= (fpga_queued_bits >> 3) + 1;) {
|
||||
if (AT91C_BASE_SSC->SSC_SR & (AT91C_SSC_TXRDY)) {
|
||||
AT91C_BASE_SSC->SSC_THR = SEC_F;
|
||||
FpgaSendQueueDelay = (uint8_t)AT91C_BASE_SSC->SSC_RHR;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
LastTimeProxToAirStart = ThisTransferTime + (correctionNeeded ? 8 : 0);
|
||||
LastTimeProxToAirStart = ThisTransferTime + (correction_needed ? 8 : 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -2069,6 +2116,7 @@ int EmSendCmdEx(uint8_t *resp, uint16_t respLen, bool collision) {
|
|||
}
|
||||
|
||||
int EmSendPrecompiledCmd(tag_response_info_t *p_response) {
|
||||
if (p_response == NULL) return 0;
|
||||
int ret = EmSendCmd14443aRaw(p_response->modulation, p_response->modulation_n);
|
||||
// do the tracing for the previous reader request and this tag answer:
|
||||
uint8_t par[MAX_PARITY_SIZE] = {0x00};
|
||||
|
@ -2489,7 +2537,7 @@ int iso14443a_select_card(uint8_t *uid_ptr, iso14a_card_select_t *p_card, uint32
|
|||
} else if (hf14aconfig.forcebcc == 1) {
|
||||
sel_uid[6] = bcc;
|
||||
} // else use card BCC
|
||||
Dbprintf("Using BCC=" _YELLOW_("0x%02x") " to perform anticollision", sel_uid[6]);
|
||||
Dbprintf("Using BCC%d=" _YELLOW_("0x%02x") " to perform anticollision", cascade_level, sel_uid[6]);
|
||||
}
|
||||
} else {
|
||||
memcpy(sel_uid + 2, uid_resp, 4); // the provided UID
|
||||
|
|
|
@ -53,7 +53,7 @@ static uint32_t last_frame_end; /* ts of last bit of previews rx or tx frame */
|
|||
#define RWD_TIME_PAUSE 4 /* 18.9us */
|
||||
#define RWD_TIME_1 21 /* RWD_TIME_PAUSE 18.9us off + 80.2us on = 99.1us */
|
||||
#define RWD_TIME_0 13 /* RWD_TIME_PAUSE 18.9us off + 42.4us on = 61.3us */
|
||||
#define RWD_CMD_TIMEOUT 120 /* 120 * 99.1us (arbitrary value) */
|
||||
#define RWD_CMD_TIMEOUT 400 /* 120 * 99.1us (arbitrary value) */
|
||||
#define RWD_MIN_FRAME_LEN 6 /* Shortest frame is 6 bits */
|
||||
#define RWD_MAX_FRAME_LEN 23 /* Longest frame is 23 bits */
|
||||
|
||||
|
@ -68,6 +68,7 @@ static uint32_t last_frame_end; /* ts of last bit of previews rx or tx frame */
|
|||
// Note: inlining this function would fail with -Os
|
||||
static bool wait_for(bool value, const uint32_t timeout) {
|
||||
while ((bool)(AT91C_BASE_PIOA->PIO_PDSR & GPIO_SSC_DIN) != value) {
|
||||
WDT_HIT();
|
||||
if (GetCountSspClk() > timeout) {
|
||||
return false;
|
||||
}
|
||||
|
@ -215,7 +216,7 @@ static int32_t rx_frame(uint8_t *len) {
|
|||
last_frame_end -= 2;
|
||||
|
||||
// wait for first pause (start of frame)
|
||||
for (uint8_t i = 0; true; ++i) {
|
||||
for (uint16_t i = 0; true; ++i) {
|
||||
// increment prng every TAG_BIT_PERIOD
|
||||
last_frame_end += TAG_BIT_PERIOD;
|
||||
legic_prng_forward(1);
|
||||
|
|
|
@ -383,7 +383,7 @@ void loadT55xxConfig(void) {
|
|||
* @param period_1
|
||||
* @param command (in binary char array)
|
||||
*/
|
||||
void ModThenAcquireRawAdcSamples125k(uint32_t delay_off, uint32_t period_0, uint32_t period_1, uint8_t *command) {
|
||||
void ModThenAcquireRawAdcSamples125k(uint32_t delay_off, uint32_t period_0, uint32_t period_1, uint8_t *command, bool verbose, uint32_t samples) {
|
||||
|
||||
FpgaDownloadAndGo(FPGA_BITSTREAM_LF);
|
||||
|
||||
|
@ -475,7 +475,7 @@ void ModThenAcquireRawAdcSamples125k(uint32_t delay_off, uint32_t period_0, uint
|
|||
FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_READER | FPGA_LF_ADC_READER_FIELD);
|
||||
|
||||
// now do the read
|
||||
DoAcquisition_config(true, 0);
|
||||
DoAcquisition_config(verbose, samples);
|
||||
|
||||
// Turn off antenna
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
|
|
|
@ -15,8 +15,7 @@
|
|||
|
||||
#include "pm3_cmd.h" // struct
|
||||
|
||||
void AcquireRawAdcSamples125k(int divisor);
|
||||
void ModThenAcquireRawAdcSamples125k(uint32_t delay_off, uint32_t period_0, uint32_t period_1, uint8_t *command);
|
||||
void ModThenAcquireRawAdcSamples125k(uint32_t delay_off, uint32_t period_0, uint32_t period_1, uint8_t *command, bool verbose, uint32_t samples);
|
||||
void ReadTItag(void);
|
||||
void WriteTItag(uint32_t idhi, uint32_t idlo, uint16_t crc);
|
||||
|
||||
|
|
|
@ -329,7 +329,7 @@ uint32_t DoAcquisition(uint8_t decimation, uint8_t bits_per_sample, bool avg, in
|
|||
if (verbose) {
|
||||
if (checked == -1) {
|
||||
Dbprintf("lf sampling aborted");
|
||||
} else if (cancel_counter == cancel_after) {
|
||||
} else if ((cancel_counter == cancel_after) && (cancel_after > 0)){
|
||||
Dbprintf("lf sampling cancelled after %u", cancel_counter);
|
||||
}
|
||||
|
||||
|
|
|
@ -2242,6 +2242,8 @@ void MifareCIdent(void) {
|
|||
uint8_t rec[1] = {0x00};
|
||||
uint8_t recpar[1] = {0x00};
|
||||
uint8_t rats[4] = { ISO14443A_CMD_RATS, 0x80, 0x31, 0x73 };
|
||||
uint8_t rdbl[4] = { ISO14443A_CMD_READBLOCK, 0xF0, 0x8D, 0x5f};
|
||||
uint8_t rdbl0[4] = { ISO14443A_CMD_READBLOCK, 0x00, 0x02, 0xa8};
|
||||
uint8_t *par = BigBuf_malloc(MAX_PARITY_SIZE);
|
||||
uint8_t *buf = BigBuf_malloc(PM3_CMD_DATA_SIZE);
|
||||
uint8_t *uid = BigBuf_malloc(10);
|
||||
|
@ -2276,10 +2278,22 @@ void MifareCIdent(void) {
|
|||
|
||||
ReaderTransmit(rats, sizeof(rats), NULL);
|
||||
res = ReaderReceive(buf, par);
|
||||
// test for some MFC gen2
|
||||
if (memcmp(buf, "\x09\x78\x00\x91\x02\xDA\xBC\x19\x10\xF0\x05", 11) == 0) {
|
||||
|
||||
// super card ident
|
||||
uint8_t super[] = {0x0A, 0x00, 0x00, 0xA6, 0xB0, 0x00, 0x10, 0x14, 0x1D};
|
||||
ReaderTransmit(super, sizeof(super), NULL);
|
||||
res = ReaderReceive(buf, par);
|
||||
if (res == 22) {
|
||||
isGen = MAGIC_SUPER;
|
||||
goto OUT;
|
||||
}
|
||||
|
||||
isGen = MAGIC_GEN_2;
|
||||
goto OUT;
|
||||
}
|
||||
// test for some MFC 7b gen2
|
||||
if (memcmp(buf, "\x0D\x78\x00\x71\x02\x88\x49\xA1\x30\x20\x15\x06\x08\x56\x3D", 15) == 0) {
|
||||
isGen = MAGIC_GEN_2;
|
||||
}
|
||||
|
@ -2303,6 +2317,37 @@ void MifareCIdent(void) {
|
|||
isGen = MAGIC_GEN_2;
|
||||
goto OUT;
|
||||
}
|
||||
// test for NTAG213 magic gen2
|
||||
if (memcmp(buf, "\x85\x00\x00\xA0\x00\x00\x0A\xA5\x00\x04\x04\x02\x01\x00\x0F\x03\x79\x0C", 18) == 0) {
|
||||
isGen = MAGIC_GEN_2;
|
||||
goto OUT;
|
||||
}
|
||||
|
||||
// magic ntag test
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
SpinDelay(40);
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
|
||||
res = iso14443a_select_card(uid, NULL, &cuid, true, 0, true);
|
||||
if (res == 2) {
|
||||
ReaderTransmit(rdbl, sizeof(rdbl), NULL);
|
||||
res = ReaderReceive(buf, par);
|
||||
if (res == 18) {
|
||||
isGen = MAGIC_NTAG21X;
|
||||
}
|
||||
}
|
||||
|
||||
// magic MFC Gen3 test
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
SpinDelay(40);
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
|
||||
res = iso14443a_select_card(uid, NULL, &cuid, true, 0, true);
|
||||
if (res == 2) {
|
||||
ReaderTransmit(rdbl0, sizeof(rdbl0), NULL);
|
||||
res = ReaderReceive(buf, par);
|
||||
if (res == 18) {
|
||||
isGen = MAGIC_GEN_3;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
OUT:
|
||||
|
@ -2317,29 +2362,29 @@ OUT:
|
|||
void MifareHasStaticNonce(void) {
|
||||
|
||||
// variables
|
||||
int retval = PM3_SUCCESS, len;
|
||||
|
||||
uint32_t nt = 0 ;
|
||||
uint8_t rec[1] = {0x00};
|
||||
uint8_t recpar[1] = {0x00};
|
||||
int retval = PM3_SUCCESS;
|
||||
uint32_t nt = 0;
|
||||
uint8_t *uid = BigBuf_malloc(10);
|
||||
uint8_t data[1] = {0x00};
|
||||
|
||||
uint8_t data[1] = { NONCE_FAIL };
|
||||
struct Crypto1State mpcs = {0, 0};
|
||||
struct Crypto1State *pcs;
|
||||
pcs = &mpcs;
|
||||
iso14a_card_select_t card_info;
|
||||
|
||||
iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN);
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
uint8_t counter = 0;
|
||||
for (uint8_t i = 0; i < 3; i++) {
|
||||
|
||||
iso14a_card_select_t card_info;
|
||||
if (!iso14443a_select_card(uid, &card_info, NULL, true, 0, true)) {
|
||||
retval = PM3_ESOFT;
|
||||
goto OUT;
|
||||
}
|
||||
|
||||
uint8_t rec[1] = {0x00};
|
||||
uint8_t recpar[1] = {0x00};
|
||||
// Transmit MIFARE_CLASSIC_AUTH 0x60, block 0
|
||||
len = mifare_sendcmd_short(pcs, false, MIFARE_AUTH_KEYA, 0, rec, recpar, NULL);
|
||||
int len = mifare_sendcmd_short(pcs, false, MIFARE_AUTH_KEYA, 0, rec, recpar, NULL);
|
||||
if (len != 4) {
|
||||
retval = PM3_ESOFT;
|
||||
goto OUT;
|
||||
|
@ -2347,14 +2392,24 @@ void MifareHasStaticNonce(void) {
|
|||
|
||||
// Save the tag nonce (nt)
|
||||
if (nt == bytes_to_num(rec, 4)) {
|
||||
data[0]++;
|
||||
counter++;
|
||||
}
|
||||
|
||||
nt = bytes_to_num(rec, 4);
|
||||
|
||||
// some cards with static nonce need to be reset before next query
|
||||
FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF);
|
||||
LEDsoff();
|
||||
CHK_TIMEOUT();
|
||||
}
|
||||
|
||||
if (counter) {
|
||||
Dbprintf("%u static nonce %08x", data[0], nt);
|
||||
data[0] = NONCE_STATIC;
|
||||
} else {
|
||||
data[0] = NONCE_NORMAL;
|
||||
}
|
||||
|
||||
OUT:
|
||||
reply_ng(CMD_HF_MIFARE_STATIC_NONCE, retval, data, sizeof(data));
|
||||
// turns off
|
||||
|
|
|
@ -118,6 +118,7 @@ void MifareDesfireGetInformation(void) {
|
|||
struct p {
|
||||
uint8_t isOK;
|
||||
uint8_t uid[7];
|
||||
uint8_t uidlen;
|
||||
uint8_t versionHW[7];
|
||||
uint8_t versionSW[7];
|
||||
uint8_t details[14];
|
||||
|
@ -148,15 +149,9 @@ void MifareDesfireGetInformation(void) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (card.uidlen != 7) {
|
||||
if (DBGLEVEL >= DBG_ERROR) Dbprintf("Wrong UID size. Expected 7byte got %d", card.uidlen);
|
||||
payload.isOK = 2; // 2 == WRONG UID
|
||||
reply_ng(CMD_HF_DESFIRE_INFO, PM3_ESOFT, (uint8_t *)&payload, sizeof(payload));
|
||||
switch_off();
|
||||
return;
|
||||
}
|
||||
// add uid.
|
||||
memcpy(payload.uid, card.uid, sizeof(payload.uid));
|
||||
memcpy(payload.uid, card.uid, card.uidlen);
|
||||
payload.uidlen = card.uidlen;
|
||||
|
||||
LED_A_ON();
|
||||
uint8_t cmd[] = {0x90, MFDES_GET_VERSION, 0x00, 0x00, 0x00};
|
||||
|
|
|
@ -238,8 +238,10 @@ set (TARGET_SOURCES
|
|||
${PM3_ROOT}/client/src/cmdhfmfhard.c
|
||||
${PM3_ROOT}/client/src/cmdhfmfp.c
|
||||
${PM3_ROOT}/client/src/cmdhfmfu.c
|
||||
${PM3_ROOT}/client/src/cmdhfst.c
|
||||
${PM3_ROOT}/client/src/cmdhfthinfilm.c
|
||||
${PM3_ROOT}/client/src/cmdhftopaz.c
|
||||
${PM3_ROOT}/client/src/cmdhfwaveshare.c
|
||||
${PM3_ROOT}/client/src/cmdhw.c
|
||||
${PM3_ROOT}/client/src/cmdlf.c
|
||||
${PM3_ROOT}/client/src/cmdlfawid.c
|
||||
|
|
|
@ -432,8 +432,10 @@ SRCS = aidsearch.c \
|
|||
cmdhfmfhard.c \
|
||||
cmdhfmfu.c \
|
||||
cmdhfmfp.c \
|
||||
cmdhfst.c \
|
||||
cmdhfthinfilm.c \
|
||||
cmdhftopaz.c \
|
||||
cmdhfwaveshare.c \
|
||||
cmdhw.c \
|
||||
cmdlf.c \
|
||||
cmdlfawid.c \
|
||||
|
|
|
@ -117,8 +117,10 @@ add_library(pm3rrg_rdv4 SHARED
|
|||
${PM3_ROOT}/client/src/cmdhfmfhard.c
|
||||
${PM3_ROOT}/client/src/cmdhfmfp.c
|
||||
${PM3_ROOT}/client/src/cmdhfmfu.c
|
||||
${PM3_ROOT}/client/src/cmdhfst.c
|
||||
${PM3_ROOT}/client/src/cmdhfthinfilm.c
|
||||
${PM3_ROOT}/client/src/cmdhftopaz.c
|
||||
${PM3_ROOT}/client/src/cmdhfwaveshare.c
|
||||
${PM3_ROOT}/client/src/cmdhw.c
|
||||
${PM3_ROOT}/client/src/cmdlf.c
|
||||
${PM3_ROOT}/client/src/cmdlfawid.c
|
||||
|
|
|
@ -191,7 +191,7 @@ local function read_config()
|
|||
end
|
||||
|
||||
print('Magic NTAG 21* Configuration')
|
||||
print(' - Type ', typestr, '(geniune cardtype)')
|
||||
print(' - Type ', typestr, '(genuine cardtype)')
|
||||
print(' - Password', pwd)
|
||||
print(' - Pack ', pack)
|
||||
print(' - Version ', version)
|
||||
|
|
|
@ -35,6 +35,8 @@
|
|||
#include "cmdhfthinfilm.h" // Thinfilm
|
||||
#include "cmdhflto.h" // LTO-CM
|
||||
#include "cmdhfcryptorf.h" // CryptoRF
|
||||
#include "cmdhfst.h" // ST rothult
|
||||
#include "cmdhfwaveshare.h" // Waveshare
|
||||
#include "cmdtrace.h" // trace list
|
||||
#include "ui.h"
|
||||
#include "proxgui.h"
|
||||
|
@ -84,8 +86,6 @@ static int usage_hf_tune(void) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
#define PROMPT_CLEARLINE PrintAndLogEx(INPLACE, " \r")
|
||||
|
||||
int CmdHFSearch(const char *Cmd) {
|
||||
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
|
@ -365,8 +365,10 @@ static command_t CommandTable[] = {
|
|||
{"mfp", CmdHFMFP, AlwaysAvailable, "{ MIFARE Plus RFIDs... }"},
|
||||
{"mfu", CmdHFMFUltra, AlwaysAvailable, "{ MIFARE Ultralight RFIDs... }"},
|
||||
{"mfdes", CmdHFMFDes, AlwaysAvailable, "{ MIFARE Desfire RFIDs... }"},
|
||||
{"st", CmdHF_ST, AlwaysAvailable, "{ ST Rothult RFIDs... }"},
|
||||
{"thinfilm", CmdHFThinfilm, AlwaysAvailable, "{ Thinfilm RFIDs... }"},
|
||||
{"topaz", CmdHFTopaz, AlwaysAvailable, "{ TOPAZ (NFC Type 1) RFIDs... }"},
|
||||
{"waveshare", CmdHFWaveshare, AlwaysAvailable, "{ Waveshare NFC ePaper... }"},
|
||||
{"list", CmdTraceList, AlwaysAvailable, "List protocol data in trace buffer"},
|
||||
{"plot", CmdHFPlot, IfPm3Hfplot, "Plot signal"},
|
||||
{"tune", CmdHFTune, IfPm3Present, "Continuously measure HF antenna tuning"},
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
bool APDUInFramingEnable = true;
|
||||
|
||||
static int CmdHelp(const char *Cmd);
|
||||
static int waitCmd(uint8_t iSelect);
|
||||
static int waitCmd(uint8_t iSelect, uint32_t timeout);
|
||||
|
||||
static const manufactureName manufactureMapping[] = {
|
||||
// ID, "Vendor Country"
|
||||
|
@ -170,19 +170,40 @@ uint16_t atsFSC[] = {16, 24, 32, 40, 48, 64, 96, 128, 256};
|
|||
|
||||
static int usage_hf_14a_config(void) {
|
||||
PrintAndLogEx(NORMAL, "Usage: hf 14a config [a 0|1|2] [b 0|1|2] [2 0|1|2] [3 0|1|2]");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, "\nOptions:");
|
||||
PrintAndLogEx(NORMAL, " h This help");
|
||||
PrintAndLogEx(NORMAL, " a 0|1|2 ATQA<>anticollision: 0=follow standard 1=execute anticol 2=skip anticol");
|
||||
PrintAndLogEx(NORMAL, " b 0|1|2 BCC: 0=follow standard 1=use fixed BCC 2=use card BCC");
|
||||
PrintAndLogEx(NORMAL, " 2 0|1|2 SAK<>CL2: 0=follow standard 1=execute CL2 2=skip CL2");
|
||||
PrintAndLogEx(NORMAL, " 3 0|1|2 SAK<>CL3: 0=follow standard 1=execute CL3 2=skip CL3");
|
||||
PrintAndLogEx(NORMAL, " r 0|1|2 SAK<>ATS: 0=follow standard 1=execute RATS 2=skip RATS");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, "\nExamples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config ")" Print current configuration");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config a 1 ")" Force execution of anticollision");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config a 0 ")" Restore ATQA interpretation");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config b 1 ")" Force fix of bad BCC in anticollision");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config b 0 ")" Restore BCC check");
|
||||
PrintAndLogEx(NORMAL, "\nExamples to revive Gen2/DirectWrite magic cards failing at anticollision:");
|
||||
PrintAndLogEx(NORMAL, _CYAN_(" MFC 1k 4b UID")":");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config a 1 b 2 2 2 r 2"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf wrbl 0 A FFFFFFFFFFFF 11223344440804006263646566676869"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config a 0 b 0 2 0 r 0"));
|
||||
PrintAndLogEx(NORMAL, _CYAN_(" MFC 4k 4b UID")":");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config a 1 b 2 2 2 r 2"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf wrbl 0 A FFFFFFFFFFFF 11223344441802006263646566676869"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config a 0 b 0 2 0 r 0"));
|
||||
PrintAndLogEx(NORMAL, _CYAN_(" MFC 1k 7b UID")":");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config a 1 b 2 2 1 3 2 r 2"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf wrbl 0 A FFFFFFFFFFFF 04112233445566084400626364656667"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config a 0 b 0 2 0 3 0 r 0"));
|
||||
PrintAndLogEx(NORMAL, _CYAN_(" MFC 4k 7b UID")":");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config a 1 b 2 2 1 3 2 r 2"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf wrbl 0 A FFFFFFFFFFFF 04112233445566184200626364656667"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config a 0 b 0 2 0 3 0 r 0"));
|
||||
PrintAndLogEx(NORMAL, _CYAN_(" MFUL ")"/" _CYAN_(" MFUL EV1 ")"/" _CYAN_(" MFULC")":");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config a 1 b 2 2 1 3 2 r 2"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf mfu setuid 04112233445566"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf 14a config a 0 b 0 2 0 3 0 r 0"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -201,6 +222,7 @@ static int usage_hf_14a_sim(void) {
|
|||
PrintAndLogEx(NORMAL, " 7 = AMIIBO (NTAG 215), pack 0x8080");
|
||||
PrintAndLogEx(NORMAL, " 8 = MIFARE Classic 4k");
|
||||
PrintAndLogEx(NORMAL, " 9 = FM11RF005SH Shanghai Metro");
|
||||
PrintAndLogEx(NORMAL, " 10 = JCOP 31/41 Rothult");
|
||||
// PrintAndLogEx(NORMAL, " u : 4, 7 or 10 byte UID");
|
||||
PrintAndLogEx(NORMAL, " u : 4, 7 byte UID");
|
||||
PrintAndLogEx(NORMAL, " x : (Optional) Performs the 'reader attack', nr/ar attack against a reader");
|
||||
|
@ -1308,17 +1330,17 @@ static int CmdHF14ACmdRaw(const char *Cmd) {
|
|||
if (reply) {
|
||||
int res = 0;
|
||||
if (active_select)
|
||||
res = waitCmd(1);
|
||||
res = waitCmd(1, timeout);
|
||||
if (!res && datalen > 0)
|
||||
waitCmd(0);
|
||||
waitCmd(0, timeout);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int waitCmd(uint8_t iSelect) {
|
||||
static int waitCmd(uint8_t iSelect, uint32_t timeout) {
|
||||
PacketResponseNG resp;
|
||||
|
||||
if (WaitForResponseTimeout(CMD_ACK, &resp, 1500)) {
|
||||
if (WaitForResponseTimeout(CMD_ACK, &resp, timeout + 1500)) {
|
||||
uint16_t len = (resp.oldarg[0] & 0xFFFF);
|
||||
if (iSelect) {
|
||||
len = (resp.oldarg[1] & 0xFFFF);
|
||||
|
@ -1663,6 +1685,12 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
|||
}
|
||||
getTagLabel(card.uid[0], card.uid[1]);
|
||||
break;
|
||||
case 0x57: // Qualcomm
|
||||
if (memcmp(card.uid, "WSDZ10m", 7) == 0) {
|
||||
isMifareClassic = false;
|
||||
printTag("Waveshare NFC-Powered e-Paper");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
getTagLabel(card.uid[0], card.uid[1]);
|
||||
switch (card.sak) {
|
||||
|
@ -1955,23 +1983,28 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) {
|
|||
isMagic = detect_classic_magic();
|
||||
|
||||
if (isMifareClassic) {
|
||||
int res = detect_classic_prng();
|
||||
if (res == 1)
|
||||
PrintAndLogEx(SUCCESS, "Prng detection: " _GREEN_("weak"));
|
||||
else if (res == 0)
|
||||
PrintAndLogEx(SUCCESS, "Prng detection: " _YELLOW_("hard"));
|
||||
else
|
||||
PrintAndLogEx(FAILED, "Prng detection: " _RED_("fail"));
|
||||
|
||||
if (do_nack_test)
|
||||
detect_classic_nackbug(false);
|
||||
|
||||
res = detect_classic_static_nonce();
|
||||
if (res == 1)
|
||||
int res = detect_classic_static_nonce();
|
||||
if (res == NONCE_STATIC)
|
||||
PrintAndLogEx(SUCCESS, "Static nonce: " _YELLOW_("yes"));
|
||||
if (res == 2 && verbose)
|
||||
PrintAndLogEx(SUCCESS, "Static nonce: " _RED_("fail"));
|
||||
|
||||
if (res == NONCE_FAIL && verbose)
|
||||
PrintAndLogEx(SUCCESS, "Static nonce: " _RED_("read failed"));
|
||||
|
||||
if (res == NONCE_NORMAL) {
|
||||
|
||||
// not static
|
||||
res = detect_classic_prng();
|
||||
if (res == 1)
|
||||
PrintAndLogEx(SUCCESS, "Prng detection: " _GREEN_("weak"));
|
||||
else if (res == 0)
|
||||
PrintAndLogEx(SUCCESS, "Prng detection: " _YELLOW_("hard"));
|
||||
else
|
||||
PrintAndLogEx(FAILED, "Prng detection: " _RED_("fail"));
|
||||
|
||||
if (do_nack_test)
|
||||
detect_classic_nackbug(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -381,6 +381,7 @@ static int nxp_15693_print_signature(uint8_t *uid, uint8_t *signature) {
|
|||
{"NXP Ultralight Ev1", "0490933BDCD6E99B4E255E3DA55389A827564E11718E017292FAF23226A96614B8"},
|
||||
{"NXP NTAG21x (2013)", "04494E1A386D3D3CFE3DC10E5DE68A499B1C202DB5B132393E89ED19FE5BE8BC61"},
|
||||
{"MICRON Public key", "04f971eda742a4a80d32dcf6a814a707cc3dc396d35902f72929fdcd698b3468f2"},
|
||||
{"Spark1 Public key", "04d64bb732c0d214e7ec580736acf847284b502c25c0f7f2fa86aace1dada4387a"},
|
||||
};
|
||||
/*
|
||||
uint8_t nxp_15693_public_keys[][PUBLIC_ECDA_KEYLEN] = {
|
||||
|
|
|
@ -442,13 +442,19 @@ void annotateIso15693(char *exp, size_t size, uint8_t *cmd, uint8_t cmdsize) {
|
|||
uint8_t block = 0;
|
||||
if (cmdsize == 13)
|
||||
block = cmd[10];
|
||||
else if (cmdsize == 5)
|
||||
block = cmd[2];
|
||||
|
||||
snprintf(exp, size, "READBLOCK(%d)", block);
|
||||
return;
|
||||
}
|
||||
case ISO15693_WRITEBLOCK:
|
||||
snprintf(exp, size, "WRITEBLOCK");
|
||||
case ISO15693_WRITEBLOCK: {
|
||||
uint8_t block = 0;
|
||||
if (cmdsize == 9)
|
||||
block = cmd[2];
|
||||
snprintf(exp, size, "WRITEBLOCK(%d)", block);
|
||||
return;
|
||||
}
|
||||
case ISO15693_LOCKBLOCK:
|
||||
snprintf(exp, size, "LOCKBLOCK");
|
||||
return;
|
||||
|
|
|
@ -512,7 +512,7 @@ static int usage_hf14_gen3uid(void) {
|
|||
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf gen3uid 01020304050607"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_hf14_gen3blk(void) {
|
||||
static int usage_hf14_gen3block(void) {
|
||||
PrintAndLogEx(NORMAL, "Overwrite full manufacturer block for magic GEN 3 card");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf mf gen3blk [h] [block data (up to 32 hex symbols)]");
|
||||
|
@ -531,15 +531,15 @@ static int usage_hf14_gen3blk(void) {
|
|||
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf gen3blk"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_hf14_gen3freez(void) {
|
||||
PrintAndLogEx(NORMAL, "Lock further UID changes. No more UID changes available after operation completed");
|
||||
static int usage_hf14_gen3freeze(void) {
|
||||
PrintAndLogEx(NORMAL, "Perma lock further UID changes. No more UID changes available after operation completed");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf mf gen3freez [h] <Y>");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf mf gen3freeze [h] <y>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h this help");
|
||||
PrintAndLogEx(NORMAL, " <Y> confirm UID locks operation");
|
||||
PrintAndLogEx(NORMAL, " <y> confirm UID locks operation");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf gen3freez Y"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf mf gen3freeze y"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -996,6 +996,8 @@ static int CmdHF14AMfDump(const char *Cmd) {
|
|||
return PM3_EFILE;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Using `" _YELLOW_("%s") "`", keyFilename);
|
||||
|
||||
// Read keys A from file
|
||||
size_t bytes_read;
|
||||
for (sectorNo = 0; sectorNo < numSectors; sectorNo++) {
|
||||
|
@ -1026,6 +1028,7 @@ static int CmdHF14AMfDump(const char *Cmd) {
|
|||
for (sectorNo = 0; sectorNo < numSectors; sectorNo++) {
|
||||
for (tries = 0; tries < MIFARE_SECTOR_RETRY; tries++) {
|
||||
PrintAndLogEx(NORMAL, "." NOLF);
|
||||
fflush(stdout);
|
||||
|
||||
payload.blockno = FirstBlockOfSector(sectorNo) + NumBlocksPerSector(sectorNo) - 1;
|
||||
payload.keytype = 0;
|
||||
|
@ -1357,7 +1360,7 @@ static int CmdHF14AMfNested(const char *Cmd) {
|
|||
}
|
||||
|
||||
// check if tag doesn't have static nonce
|
||||
if (detect_classic_static_nonce() == 1) {
|
||||
if (detect_classic_static_nonce() == NONCE_STATIC) {
|
||||
PrintAndLogEx(WARNING, "Static nonce detected. Quitting...");
|
||||
PrintAndLogEx(INFO, "\t Try use " _YELLOW_("`hf mf staticnested`"));
|
||||
return PM3_EOPABORTED;
|
||||
|
@ -1607,8 +1610,8 @@ static int CmdHF14AMfNestedStatic(const char *Cmd) {
|
|||
}
|
||||
|
||||
// check if tag have static nonce
|
||||
if (detect_classic_static_nonce() == 0) {
|
||||
PrintAndLogEx(WARNING, "None static nonce detected. Quitting...");
|
||||
if (detect_classic_static_nonce() != NONCE_STATIC) {
|
||||
PrintAndLogEx(WARNING, "Normal nonce detected, or failed read of card. Quitting...");
|
||||
PrintAndLogEx(INFO, "\t Try use " _YELLOW_("`hf mf nested`"));
|
||||
return PM3_EOPABORTED;
|
||||
}
|
||||
|
@ -1921,7 +1924,7 @@ static int CmdHF14AMfNestedHard(const char *Cmd) {
|
|||
if (!know_target_key && nonce_file_read == false) {
|
||||
|
||||
// check if tag doesn't have static nonce
|
||||
if (detect_classic_static_nonce() == 1) {
|
||||
if (detect_classic_static_nonce() == NONCE_STATIC) {
|
||||
PrintAndLogEx(WARNING, "Static nonce detected. Quitting...");
|
||||
PrintAndLogEx(HINT, "\tTry use `" _YELLOW_("hf mf staticnested") "`");
|
||||
return PM3_EOPABORTED;
|
||||
|
@ -2002,7 +2005,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
|
|||
bool slow = false;
|
||||
bool legacy_mfchk = false;
|
||||
int prng_type = PM3_EUNDEF;
|
||||
int has_staticnonce = 2;
|
||||
int has_staticnonce;
|
||||
bool verbose = false;
|
||||
bool has_filename = false;
|
||||
bool errors = false;
|
||||
|
@ -2120,17 +2123,20 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
|
|||
// read uid to generate a filename for the key file
|
||||
char *fptr = GenerateFilename("hf-mf-", "-key.bin");
|
||||
|
||||
// card prng type (weak=1 / hard=0 / select/card comm error = negative value)
|
||||
prng_type = detect_classic_prng();
|
||||
if (prng_type < 0) {
|
||||
PrintAndLogEx(FAILED, "\nNo tag detected or other tag communication error");
|
||||
free(e_sector);
|
||||
return prng_type;
|
||||
}
|
||||
|
||||
// check if tag doesn't have static nonce
|
||||
has_staticnonce = detect_classic_static_nonce();
|
||||
|
||||
// card prng type (weak=1 / hard=0 / select/card comm error = negative value)
|
||||
if (has_staticnonce == NONCE_NORMAL) {
|
||||
prng_type = detect_classic_prng();
|
||||
if (prng_type < 0) {
|
||||
PrintAndLogEx(FAILED, "\nNo tag detected or other tag communication error");
|
||||
free(e_sector);
|
||||
return prng_type;
|
||||
}
|
||||
}
|
||||
|
||||
// print parameters
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "======================= " _YELLOW_("SETTINGS") " =======================");
|
||||
|
@ -2140,10 +2146,12 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
|
|||
PrintAndLogEx(INFO, " keytype ....... " _YELLOW_("%c"), keyType ? 'B' : 'A');
|
||||
PrintAndLogEx(INFO, " known key ..... " _YELLOW_("%s"), sprint_hex(key, sizeof(key)));
|
||||
|
||||
if (has_staticnonce)
|
||||
PrintAndLogEx(INFO, " card PRNG ..... " _YELLOW_("%s & STATIC"), prng_type ? "WEAK" : "HARD");
|
||||
else
|
||||
if (has_staticnonce == NONCE_STATIC)
|
||||
PrintAndLogEx(INFO, " card PRNG ..... " _YELLOW_("STATIC"));
|
||||
else if (has_staticnonce == NONCE_NORMAL)
|
||||
PrintAndLogEx(INFO, " card PRNG ..... " _YELLOW_("%s"), prng_type ? "WEAK" : "HARD");
|
||||
else
|
||||
PrintAndLogEx(INFO, " card PRNG ..... " _YELLOW_("Could not determine PRNG,") " " _RED_("read failed."));
|
||||
|
||||
PrintAndLogEx(INFO, " dictionary .... " _YELLOW_("%s"), strlen(filename) ? filename : "NONE");
|
||||
PrintAndLogEx(INFO, " legacy mode ... " _YELLOW_("%s"), legacy_mfchk ? "True" : "False");
|
||||
|
@ -2163,7 +2171,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
|
|||
}
|
||||
|
||||
if (mfCheckKeys(FirstBlockOfSector(blockNo), keyType, true, 1, key, &key64) == PM3_SUCCESS) {
|
||||
PrintAndLogEx(INFO, "target sector:%3u key type: %c -- using valid key [ " _YELLOW_("%s") "] (used for nested / hardnested attack)",
|
||||
PrintAndLogEx(INFO, "target sector:%3u key type: %c -- using valid key [ " _GREEN_("%s") "] (used for nested / hardnested attack)",
|
||||
blockNo,
|
||||
keyType ? 'B' : 'A',
|
||||
sprint_hex(key, sizeof(key))
|
||||
|
@ -2198,13 +2206,13 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
|
|||
know_target_key = true;
|
||||
blockNo = i;
|
||||
keyType = j;
|
||||
PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key ["_YELLOW_("%s") "] (used for nested / hardnested attack)",
|
||||
PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [ " _GREEN_("%s") "] (used for nested / hardnested attack)",
|
||||
i,
|
||||
j ? 'B' : 'A',
|
||||
sprint_hex(key, sizeof(key))
|
||||
);
|
||||
} else {
|
||||
PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key ["_YELLOW_("%s") "]",
|
||||
PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [ " _GREEN_("%s") "]",
|
||||
i,
|
||||
j ? 'B' : 'A',
|
||||
sprint_hex(key, sizeof(key))
|
||||
|
@ -2216,10 +2224,6 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
|
|||
}
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "======================= " _YELLOW_("STOP KNOWN KEY ATTACK") " =======================");
|
||||
}
|
||||
|
||||
if (num_found_keys == sectors_cnt * 2) {
|
||||
goto all_found;
|
||||
}
|
||||
|
@ -2263,6 +2267,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
|
|||
if (e_sector[i].foundKey[j] == 0) {
|
||||
for (uint32_t k = 0; k < key_cnt; k++) {
|
||||
PrintAndLogEx(NORMAL, "." NOLF);
|
||||
fflush(stdout);
|
||||
|
||||
if (mfCheckKeys(FirstBlockOfSector(i), j, true, 1, (keyBlock + (6 * k)), &key64) == PM3_SUCCESS) {
|
||||
e_sector[i].Key[j] = bytes_to_num((keyBlock + (6 * k)), 6);
|
||||
|
@ -2310,8 +2315,6 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
|
|||
lastChunk = false;
|
||||
} // end strategy
|
||||
}
|
||||
if (verbose) PrintAndLogEx(INFO, "======================= " _YELLOW_("STOP DICTIONARY ATTACK") " =======================");
|
||||
|
||||
|
||||
// Analyse the dictionary attack
|
||||
for (int i = 0; i < sectors_cnt; i++) {
|
||||
|
@ -2326,13 +2329,13 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
|
|||
know_target_key = true;
|
||||
blockNo = i;
|
||||
keyType = j;
|
||||
PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [ " _YELLOW_("%s") "] (used for nested / hardnested attack)",
|
||||
PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [ " _GREEN_("%s") "] (used for nested / hardnested attack)",
|
||||
i,
|
||||
j ? 'B' : 'A',
|
||||
sprint_hex(tmp_key, sizeof(tmp_key))
|
||||
);
|
||||
} else {
|
||||
PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [ " _YELLOW_("%s") "]",
|
||||
PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [ " _GREEN_("%s") "]",
|
||||
i,
|
||||
j ? 'B' : 'A',
|
||||
sprint_hex(tmp_key, sizeof(tmp_key))
|
||||
|
@ -2345,17 +2348,13 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
|
|||
// Check if at least one sector key was found
|
||||
if (know_target_key == false) {
|
||||
// Check if the darkside attack can be used
|
||||
if (prng_type && has_staticnonce == false) {
|
||||
if (prng_type && has_staticnonce != NONCE_STATIC) {
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "======================= " _YELLOW_("START DARKSIDE ATTACK") " =======================");
|
||||
}
|
||||
|
||||
isOK = mfDarkside(FirstBlockOfSector(blockNo), keyType, &key64);
|
||||
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "======================= " _YELLOW_("STOP DARKSIDE ATTACK") " =======================");
|
||||
}
|
||||
|
||||
switch (isOK) {
|
||||
case -1 :
|
||||
PrintAndLogEx(WARNING, "\nButton pressed. Aborted.");
|
||||
|
@ -2381,7 +2380,7 @@ static int CmdHF14AMfAutoPWN(const char *Cmd) {
|
|||
// Store the keys
|
||||
e_sector[blockNo].Key[keyType] = key64;
|
||||
e_sector[blockNo].foundKey[keyType] = 'S';
|
||||
PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [ " _YELLOW_("%s") "] (used for nested / hardnested attack)",
|
||||
PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [ " _GREEN_("%s") "] (used for nested / hardnested attack)",
|
||||
blockNo,
|
||||
keyType ? 'B' : 'A',
|
||||
sprint_hex(key, sizeof(key))
|
||||
|
@ -2421,7 +2420,7 @@ noValidKeyFound:
|
|||
if (mfCheckKeys(FirstBlockOfSector(i), j, true, 1, tmp_key, &key64) == PM3_SUCCESS) {
|
||||
e_sector[i].Key[j] = bytes_to_num(tmp_key, 6);
|
||||
e_sector[i].foundKey[j] = 'R';
|
||||
PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [ " _YELLOW_("%s") "]",
|
||||
PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [ " _GREEN_("%s") "]",
|
||||
i,
|
||||
j ? 'B' : 'A',
|
||||
sprint_hex(tmp_key, sizeof(tmp_key))
|
||||
|
@ -2463,7 +2462,7 @@ noValidKeyFound:
|
|||
e_sector[current_sector_i].foundKey[current_key_type_i] = 'A';
|
||||
e_sector[current_sector_i].Key[current_key_type_i] = key64;
|
||||
num_to_bytes(key64, 6, tmp_key);
|
||||
PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [ " _YELLOW_("%s") "]",
|
||||
PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [ " _GREEN_("%s") "]",
|
||||
current_sector_i,
|
||||
current_key_type_i ? 'B' : 'A',
|
||||
sprint_hex(tmp_key, sizeof(tmp_key))
|
||||
|
@ -2479,9 +2478,6 @@ noValidKeyFound:
|
|||
}
|
||||
|
||||
}
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "======================= " _YELLOW_("STOP READ B KEY ATTACK") " =======================");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2489,7 +2485,7 @@ noValidKeyFound:
|
|||
skipReadBKey:
|
||||
if (e_sector[current_sector_i].foundKey[current_key_type_i] == 0) {
|
||||
|
||||
if (has_staticnonce)
|
||||
if (has_staticnonce == NONCE_STATIC)
|
||||
goto tryStaticnested;
|
||||
|
||||
if (prng_type && (nested_failed == false)) {
|
||||
|
@ -2545,9 +2541,6 @@ tryNested:
|
|||
return PM3_ESOFT;
|
||||
}
|
||||
}
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "======================= " _YELLOW_("STOP NESTED ATTACK") " =======================");
|
||||
}
|
||||
|
||||
} else {
|
||||
tryHardnested: // If the nested attack fails then we try the hardnested attack
|
||||
|
@ -2583,13 +2576,9 @@ tryHardnested: // If the nested attack fails then we try the hardnested attack
|
|||
num_to_bytes(foundkey, 6, tmp_key);
|
||||
e_sector[current_sector_i].Key[current_key_type_i] = foundkey;
|
||||
e_sector[current_sector_i].foundKey[current_key_type_i] = 'H';
|
||||
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "======================= " _YELLOW_("STOP HARDNESTED ATTACK") " =======================");
|
||||
}
|
||||
}
|
||||
|
||||
if (has_staticnonce) {
|
||||
if (has_staticnonce == NONCE_STATIC) {
|
||||
tryStaticnested:
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "======================= " _YELLOW_("START STATIC NESTED ATTACK") " =======================");
|
||||
|
@ -2620,15 +2609,11 @@ tryStaticnested:
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (verbose) {
|
||||
PrintAndLogEx(INFO, "======================= " _YELLOW_("STOP STATIC NESTED ATTACK") " =======================");
|
||||
}
|
||||
}
|
||||
|
||||
// Check if the key was found
|
||||
if (e_sector[current_sector_i].foundKey[current_key_type_i]) {
|
||||
PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [" _YELLOW_("%s") "]",
|
||||
PrintAndLogEx(SUCCESS, "target sector:%3u key type: %c -- found valid key [ " _GREEN_("%s") "]",
|
||||
current_sector_i,
|
||||
current_key_type_i ? 'B' : 'A',
|
||||
sprint_hex(tmp_key, sizeof(tmp_key))
|
||||
|
@ -3183,6 +3168,7 @@ static int CmdHF14AMfChk(const char *Cmd) {
|
|||
for (uint16_t c = 0; c < keycnt; c += max_keys) {
|
||||
|
||||
PrintAndLogEx(NORMAL, "." NOLF);
|
||||
fflush(stdout);
|
||||
|
||||
if (kbd_enter_pressed()) {
|
||||
PrintAndLogEx(INFO, "\naborted via keyboard!\n");
|
||||
|
@ -3761,6 +3747,7 @@ int CmdHF14AMfELoad(const char *Cmd) {
|
|||
return PM3_ESOFT;
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "." NOLF);
|
||||
fflush(stdout);
|
||||
|
||||
blockNum++;
|
||||
counter += blockWidth;
|
||||
|
@ -4186,6 +4173,7 @@ static int CmdHF14AMfCLoad(const char *Cmd) {
|
|||
return PM3_ESOFT;
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "." NOLF);
|
||||
fflush(stdout);
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "\n");
|
||||
return PM3_SUCCESS;
|
||||
|
@ -4448,6 +4436,7 @@ static int CmdHF14AMfCSave(const char *Cmd) {
|
|||
PrintAndLogEx(WARNING, "Cant set emul block: %d", i);
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "." NOLF);
|
||||
fflush(stdout);
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "\n");
|
||||
PrintAndLogEx(SUCCESS, "uploaded %d bytes to emulator memory", bytes);
|
||||
|
@ -5170,18 +5159,18 @@ static int CmdHf14AGen3UID(const char *Cmd) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdHf14AGen3Blk(const char *Cmd) {
|
||||
static int CmdHf14AGen3Block(const char *Cmd) {
|
||||
uint8_t block[16] = {0x00};
|
||||
int blocklen = 0;
|
||||
uint8_t newBlock[16] = {0x00};
|
||||
|
||||
char ctmp = tolower(param_getchar(Cmd, 0));
|
||||
if (ctmp == 'h') return usage_hf14_gen3blk();
|
||||
if (ctmp == 'h') return usage_hf14_gen3block();
|
||||
|
||||
if (ctmp != '\0' && param_gethex_to_eol(Cmd, 0, block, sizeof(block), &blocklen))
|
||||
return usage_hf14_gen3blk();
|
||||
return usage_hf14_gen3block();
|
||||
|
||||
int res = mfGen3Blk(block, blocklen, newBlock);
|
||||
int res = mfGen3Block(block, blocklen, newBlock);
|
||||
if (res) {
|
||||
PrintAndLogEx(ERR, "Can't change manufacturer block data. Error=%d", res);
|
||||
return PM3_ESOFT;
|
||||
|
@ -5191,18 +5180,17 @@ static int CmdHf14AGen3Blk(const char *Cmd) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
static int CmdHf14AGen3Freez(const char *Cmd) {
|
||||
char ctmp = param_getchar(Cmd, 0);
|
||||
if (tolower(ctmp) == 'h') return usage_hf14_gen3freez();
|
||||
if (ctmp != 'Y') return usage_hf14_gen3freez();
|
||||
static int CmdHf14AGen3Freeze(const char *Cmd) {
|
||||
char ctmp = tolower(param_getchar(Cmd, 0));
|
||||
if (ctmp == 'h') return usage_hf14_gen3freeze();
|
||||
if (ctmp != 'y') return usage_hf14_gen3freeze();
|
||||
|
||||
int res = mfGen3Freez();
|
||||
int res = mfGen3Freeze();
|
||||
if (res) {
|
||||
PrintAndLogEx(ERR, "Can't lock UID changes. Error=%d", res);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Gen 3 UID locked");
|
||||
PrintAndLogEx(SUCCESS, "MFC Gen3 UID permalocked");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -5243,18 +5231,18 @@ static command_t CommandTable[] = {
|
|||
{"ecfill", CmdHF14AMfECFill, IfPm3Iso14443a, "Fill simulator memory with help of keys from simulator"},
|
||||
{"ekeyprn", CmdHF14AMfEKeyPrn, IfPm3Iso14443a, "Print keys from simulator memory"},
|
||||
{"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("magic") " -----------------------"},
|
||||
{"csetuid", CmdHF14AMfCSetUID, IfPm3Iso14443a, "Set UID (magic chinese card)"},
|
||||
{"csetuid", CmdHF14AMfCSetUID, IfPm3Iso14443a, "Set UID"},
|
||||
{"cwipe", CmdHF14AMfCWipe, IfPm3Iso14443a, "Wipe card to default UID/Sectors/Keys"},
|
||||
{"csetblk", CmdHF14AMfCSetBlk, IfPm3Iso14443a, "Write block (magic chinese card)"},
|
||||
{"cgetblk", CmdHF14AMfCGetBlk, IfPm3Iso14443a, "Read block (magic chinese card)"},
|
||||
{"cgetsc", CmdHF14AMfCGetSc, IfPm3Iso14443a, "Read sector (magic chinese card)"},
|
||||
{"cload", CmdHF14AMfCLoad, IfPm3Iso14443a, "Load dump (magic chinese card)"},
|
||||
{"csave", CmdHF14AMfCSave, IfPm3Iso14443a, "Save dump from magic chinese card into file or emulator"},
|
||||
{"csetblk", CmdHF14AMfCSetBlk, IfPm3Iso14443a, "Write block"},
|
||||
{"cgetblk", CmdHF14AMfCGetBlk, IfPm3Iso14443a, "Read block"},
|
||||
{"cgetsc", CmdHF14AMfCGetSc, IfPm3Iso14443a, "Read sector"},
|
||||
{"cload", CmdHF14AMfCLoad, IfPm3Iso14443a, "Load dump"},
|
||||
{"csave", CmdHF14AMfCSave, IfPm3Iso14443a, "Save dump from card into file or emulator"},
|
||||
{"cview", CmdHF14AMfCView, IfPm3Iso14443a, "view card"},
|
||||
{"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("magic gen3") " -----------------------"},
|
||||
{"gen3uid", CmdHf14AGen3UID, IfPm3Iso14443a, "Set UID without manufacturer block (magic gen3 card)"},
|
||||
{"gen3blk", CmdHf14AGen3Blk, IfPm3Iso14443a, "Overwrite full manufacturer block (magic gen 3 card)"},
|
||||
{"gen3freez", CmdHf14AGen3Freez, IfPm3Iso14443a, "Lock further UID changes (magic gen 3 card)"},
|
||||
{"gen3uid", CmdHf14AGen3UID, IfPm3Iso14443a, "Set UID without manufacturer block"},
|
||||
{"gen3blk", CmdHf14AGen3Block, IfPm3Iso14443a, "Overwrite full manufacturer block"},
|
||||
{"gen3freeze", CmdHf14AGen3Freeze, IfPm3Iso14443a, "Perma lock further UID changes"},
|
||||
|
||||
{"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("i") " -----------------------"},
|
||||
{"ice", CmdHF14AMfice, IfPm3Iso14443a, "collect MIFARE Classic nonces to file"},
|
||||
|
|
|
@ -1152,7 +1152,7 @@ static int mifare_desfire_change_key(uint8_t key_no, uint8_t *new_key, uint8_t n
|
|||
}
|
||||
|
||||
// --- GET SIGNATURE
|
||||
static int desfire_print_signature(uint8_t *uid, uint8_t *signature, size_t signature_len, nxp_cardtype_t card_type) {
|
||||
static int desfire_print_signature(uint8_t *uid, uint8_t uidlen, uint8_t *signature, size_t signature_len, nxp_cardtype_t card_type) {
|
||||
(void)card_type;
|
||||
|
||||
if (uid == NULL) {
|
||||
|
@ -1185,7 +1185,7 @@ static int desfire_print_signature(uint8_t *uid, uint8_t *signature, size_t sign
|
|||
uint8_t key[PUBLIC_DESFIRE_ECDA_KEYLEN];
|
||||
param_gethex_to_eol(nxp_desfire_public_keys[i].value, 0, key, PUBLIC_DESFIRE_ECDA_KEYLEN, &dl);
|
||||
|
||||
int res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP224R1, key, uid, 7, signature, signature_len, false);
|
||||
int res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP224R1, key, uid, uidlen, signature, signature_len, false);
|
||||
is_valid = (res == 0);
|
||||
if (is_valid)
|
||||
break;
|
||||
|
@ -3228,7 +3228,7 @@ static int CmdHF14ADesInfo(const char *Cmd) {
|
|||
SendCommandNG(CMD_HF_DESFIRE_INFO, NULL, 0);
|
||||
PacketResponseNG resp;
|
||||
|
||||
if (!WaitForResponseTimeout(CMD_HF_DESFIRE_INFO, &resp, 1500)) {
|
||||
if (WaitForResponseTimeout(CMD_HF_DESFIRE_INFO, &resp, 1500) == false) {
|
||||
PrintAndLogEx(WARNING, "Command execute timeout");
|
||||
DropField();
|
||||
return PM3_ETIMEOUT;
|
||||
|
@ -3237,6 +3237,7 @@ static int CmdHF14ADesInfo(const char *Cmd) {
|
|||
struct p {
|
||||
uint8_t isOK;
|
||||
uint8_t uid[7];
|
||||
uint8_t uidlen;
|
||||
uint8_t versionHW[7];
|
||||
uint8_t versionSW[7];
|
||||
uint8_t details[14];
|
||||
|
@ -3269,7 +3270,7 @@ static int CmdHF14ADesInfo(const char *Cmd) {
|
|||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Information") " ---------------------------");
|
||||
PrintAndLogEx(INFO, "-------------------------------------------------------------");
|
||||
PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(package->uid, sizeof(package->uid)));
|
||||
PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(package->uid, package->uidlen));
|
||||
PrintAndLogEx(SUCCESS, " Batch number: " _GREEN_("%s"), sprint_hex(package->details + 7, 5));
|
||||
PrintAndLogEx(SUCCESS, " Production date: week " _GREEN_("%02x") " / " _GREEN_("20%02x"), package->details[12], package->details[13]);
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
|
@ -3319,7 +3320,7 @@ static int CmdHF14ADesInfo(const char *Cmd) {
|
|||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature"));
|
||||
if (handler_desfire_signature(signature, &signature_len) == PM3_SUCCESS) {
|
||||
desfire_print_signature(package->uid, signature, signature_len, cardtype);
|
||||
desfire_print_signature(package->uid, package->uidlen, signature, signature_len, cardtype);
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, "--- Card doesn't support GetSignature cmd");
|
||||
}
|
||||
|
|
|
@ -2540,6 +2540,7 @@ static int CmdHF14AMfUCSetUid(const char *Cmd) {
|
|||
return PM3_EINVARG;
|
||||
}
|
||||
|
||||
PrintAndLogEx(INFO, "Please ignore possible transient BCC warnings");
|
||||
// read block2.
|
||||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_HF_MIFAREU_READBL, 2, 0, 0, NULL, 0);
|
||||
|
@ -2552,6 +2553,21 @@ static int CmdHF14AMfUCSetUid(const char *Cmd) {
|
|||
uint8_t oldblock2[4] = {0x00};
|
||||
memcpy(resp.data.asBytes, oldblock2, 4);
|
||||
|
||||
// Enforce bad BCC handling temporarily as BCC will be wrong between
|
||||
// block 1 write and block2 write
|
||||
hf14a_config config;
|
||||
SendCommandNG(CMD_HF_ISO14443A_GET_CONFIG, NULL, 0);
|
||||
if (!WaitForResponseTimeout(CMD_HF_ISO14443A_GET_CONFIG, &resp, 2000)) {
|
||||
PrintAndLogEx(WARNING, "command execution time out");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
memcpy(&config, resp.data.asBytes, sizeof(hf14a_config));
|
||||
int8_t oldconfig_bcc = config.forcebcc;
|
||||
if (oldconfig_bcc != 2) {
|
||||
config.forcebcc = 2;
|
||||
SendCommandNG(CMD_HF_ISO14443A_SET_CONFIG, (uint8_t *)&config, sizeof(hf14a_config));
|
||||
}
|
||||
|
||||
// block 0.
|
||||
uint8_t data[4];
|
||||
data[0] = uid[0];
|
||||
|
@ -2588,6 +2604,12 @@ static int CmdHF14AMfUCSetUid(const char *Cmd) {
|
|||
PrintAndLogEx(WARNING, "Command execute timeout");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
|
||||
// restore BCC config
|
||||
if (oldconfig_bcc != 2) {
|
||||
config.forcebcc = oldconfig_bcc;
|
||||
SendCommandNG(CMD_HF_ISO14443A_SET_CONFIG, (uint8_t *)&config, sizeof(hf14a_config));
|
||||
}
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
470
client/src/cmdhfst.c
Normal file
470
client/src/cmdhfst.c
Normal file
|
@ -0,0 +1,470 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2020 iceman1001
|
||||
//
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
// High frequency ISO14443A / ST commands
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#include "cmdhfst.h"
|
||||
#include <ctype.h>
|
||||
#include "fileutils.h"
|
||||
#include "cmdparser.h" // command_t
|
||||
#include "comms.h" // clearCommandBuffer
|
||||
#include "cmdtrace.h"
|
||||
#include "crc16.h"
|
||||
#include "cmdhf14a.h"
|
||||
#include "protocols.h" // definitions of ISO14A/7816 protocol
|
||||
#include "emv/apduinfo.h" // GetAPDUCodeDescription
|
||||
#include "mifare/ndef.h" // NDEFRecordsDecodeAndPrint
|
||||
|
||||
#define TIMEOUT 2000
|
||||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static int usage_hf_st_info(void) {
|
||||
PrintAndLogEx(NORMAL, "Usage: hf st info [h]");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h this help");
|
||||
PrintAndLogEx(NORMAL, "Example:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf st info"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_hf_st_sim(void) {
|
||||
PrintAndLogEx(NORMAL, "\n Emulating ST25TA512B tag with 7 byte UID\n");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf st sim [h] u <uid> ");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : This help");
|
||||
PrintAndLogEx(NORMAL, " u : 7 byte UID");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf st sim u 02E2007D0FCA4C"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_hf_st_ndef(void) {
|
||||
PrintAndLogEx(NORMAL, "\n Print NFC Data Exchange Format (NDEF)\n");
|
||||
PrintAndLogEx(NORMAL, "Usage: hf st ndef [h] p <pwd> ");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : This help");
|
||||
PrintAndLogEx(NORMAL, " p <pwd> : 16 byte password");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" hf st ndef p 82E80053D4CA5C0B656D852CC696C8A1"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
// get ST Microelectronics chip model (from UID)
|
||||
static char *get_st_chip_model(uint8_t pc) {
|
||||
static char model[40];
|
||||
char *s = model;
|
||||
memset(model, 0, sizeof(model));
|
||||
switch (pc) {
|
||||
case 0x0:
|
||||
sprintf(s, "SRIX4K (Special)");
|
||||
break;
|
||||
case 0x2:
|
||||
sprintf(s, "SR176");
|
||||
break;
|
||||
case 0x3:
|
||||
sprintf(s, "SRIX4K");
|
||||
break;
|
||||
case 0x4:
|
||||
sprintf(s, "SRIX512");
|
||||
break;
|
||||
case 0x6:
|
||||
sprintf(s, "SRI512");
|
||||
break;
|
||||
case 0x7:
|
||||
sprintf(s, "SRI4K");
|
||||
break;
|
||||
case 0xC:
|
||||
sprintf(s, "SRT512");
|
||||
break;
|
||||
case 0xC4:
|
||||
sprintf(s, "ST25TA64K");
|
||||
break;
|
||||
case 0xE2:
|
||||
sprintf(s, "ST25??? IKEA Rothult");
|
||||
break;
|
||||
case 0xE3:
|
||||
sprintf(s, "ST25TA02KB");
|
||||
break;
|
||||
case 0xE4:
|
||||
sprintf(s, "ST25TA512B");
|
||||
break;
|
||||
case 0xA3:
|
||||
sprintf(s, "ST25TA02KB-P");
|
||||
break;
|
||||
case 0xF3:
|
||||
sprintf(s, "ST25TA02KB-D");
|
||||
break;
|
||||
default :
|
||||
sprintf(s, "Unknown");
|
||||
break;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
/*
|
||||
// print UID info from SRx chips (ST Microelectronics)
|
||||
static void print_st_general_info(uint8_t *data, uint8_t len) {
|
||||
//uid = first 8 bytes in data
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(SwapEndian64(data, 8, 8), len));
|
||||
PrintAndLogEx(SUCCESS, " MFG: %02X, " _YELLOW_("%s"), data[6], getTagInfo(data[6]));
|
||||
PrintAndLogEx(SUCCESS, "Chip: %02X, " _YELLOW_("%s"), data[5] >> 2, get_st_chip_model(data[5] >> 2));
|
||||
}
|
||||
|
||||
*/
|
||||
static void print_st_cc_info(uint8_t *d, uint8_t n) {
|
||||
if (n < 0x0F) {
|
||||
PrintAndLogEx(WARNING, "Not enought bytes read from system file");
|
||||
return;
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(SUCCESS, "------------ " _CYAN_("Capability Container file") " ------------");
|
||||
PrintAndLogEx(SUCCESS, " len %u bytes (" _GREEN_("0x%02X") ")", d[1],d[1]);
|
||||
PrintAndLogEx(SUCCESS, " version %s (" _GREEN_("0x%02X") ")", (d[2] == 0x20) ? "v2.0" : "v1.0", d[2]);
|
||||
|
||||
uint16_t maxr = (d[3] << 8 | d[4]);
|
||||
PrintAndLogEx(SUCCESS, " max bytes read %u bytes ( 0x%04X )", maxr, maxr);
|
||||
uint16_t maxw = (d[5] << 8 | d[6]);
|
||||
PrintAndLogEx(SUCCESS, " max bytes write %u bytes ( 0x%04X )", maxw, maxw);
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(SUCCESS, " NDEF file control TLV {");
|
||||
PrintAndLogEx(SUCCESS, " (t) type of file ( %02X )", d[7]);
|
||||
PrintAndLogEx(SUCCESS, " (v) ( %02X )", d[8]);
|
||||
PrintAndLogEx(SUCCESS, " file id ( %02X%02X )", d[9], d[10]);
|
||||
|
||||
uint16_t maxndef = (d[11] << 8 | d[12]);
|
||||
PrintAndLogEx(SUCCESS, " max NDEF filesize %u bytes ( 0x%04X )", maxndef, maxndef);
|
||||
PrintAndLogEx(SUCCESS, " ----- " _CYAN_("access rights") " -------");
|
||||
PrintAndLogEx(SUCCESS, " read ( %02X )", d[13]);
|
||||
PrintAndLogEx(SUCCESS, " write ( %02X )", d[14]);
|
||||
PrintAndLogEx(SUCCESS, " }");
|
||||
PrintAndLogEx(SUCCESS, "----------------- " _CYAN_("raw") " -----------------");
|
||||
PrintAndLogEx(SUCCESS, "%s", sprint_hex_inrow(d, n));
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
}
|
||||
static void print_st_system_info(uint8_t *d, uint8_t n) {
|
||||
if (n < 0x12) {
|
||||
PrintAndLogEx(WARNING, "Not enought bytes read from system file");
|
||||
return;
|
||||
}
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(SUCCESS, "------------ " _CYAN_("ST System file") " ------------");
|
||||
|
||||
uint16_t len = (d[0] << 8 | d[1]);
|
||||
PrintAndLogEx(SUCCESS, " len %u bytes (" _GREEN_("0x%04X") ")", len, len);
|
||||
|
||||
if (d[2] == 0x80) {
|
||||
PrintAndLogEx(SUCCESS, " ST reserved ( 0x%02X )", d[2]);
|
||||
} else {
|
||||
PrintAndLogEx(SUCCESS, " GPO Config ( 0x%02X )", d[2]);
|
||||
PrintAndLogEx(SUCCESS, " config lock bit ( %s )", ((d[2] & 0x80) == 0x80) ? _RED_("locked") : _GREEN_("unlocked"));
|
||||
uint8_t conf = (d[2] & 0x70) >> 4;
|
||||
switch(conf) {
|
||||
case 0:
|
||||
PrintAndLogEx(SUCCESS, "");
|
||||
break;
|
||||
case 1:
|
||||
PrintAndLogEx(SUCCESS, "Session opened");
|
||||
break;
|
||||
case 2:
|
||||
PrintAndLogEx(SUCCESS, "WIP");
|
||||
break;
|
||||
case 3:
|
||||
PrintAndLogEx(SUCCESS, "MIP");
|
||||
break;
|
||||
case 4:
|
||||
PrintAndLogEx(SUCCESS, "Interrupt");
|
||||
break;
|
||||
case 5:
|
||||
PrintAndLogEx(SUCCESS, "State Control");
|
||||
break;
|
||||
case 6:
|
||||
PrintAndLogEx(SUCCESS, "RF Busy");
|
||||
break;
|
||||
case 7:
|
||||
PrintAndLogEx(SUCCESS, "Field Detect");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
PrintAndLogEx(SUCCESS, " Event counter config ( 0x%02X )", d[3]);
|
||||
PrintAndLogEx(SUCCESS, " config lock bit ( %s )", ((d[3] & 0x80) == 0x80) ? _RED_("locked") : _GREEN_("unlocked"));
|
||||
PrintAndLogEx(SUCCESS, " counter ( %s )", ((d[3] & 0x02) == 0x02) ? _RED_("enabled") : _GREEN_("disable"));
|
||||
PrintAndLogEx(SUCCESS, " counter increment on ( %s )", ((d[3] & 0x01) == 0x01) ? _YELLOW_("write") : _YELLOW_("read"));
|
||||
|
||||
uint32_t counter = (d[4] << 16 | d[5] << 8 | d[6]);
|
||||
PrintAndLogEx(SUCCESS, " 20bit counter ( 0x%05X )", counter & 0xFFFFF);
|
||||
|
||||
PrintAndLogEx(SUCCESS, " Product version ( 0x%02X )", d[7]);
|
||||
|
||||
PrintAndLogEx(SUCCESS, " UID " _GREEN_("%s"), sprint_hex_inrow(d + 8, 7));
|
||||
PrintAndLogEx(SUCCESS, " MFG 0x%02X, " _YELLOW_("%s"), d[8], getTagInfo(d[8]));
|
||||
PrintAndLogEx(SUCCESS, " Product Code 0x%02X, " _YELLOW_("%s"), d[9], get_st_chip_model(d[9]));
|
||||
PrintAndLogEx(SUCCESS, " Device# " _YELLOW_("%s"), sprint_hex_inrow(d + 10, 5));
|
||||
|
||||
uint16_t mem = (d[0xF] << 8 | d[0x10]);
|
||||
PrintAndLogEx(SUCCESS, " Memory Size - 1 %u bytes (" _GREEN_("0x%04X") ")", mem, mem);
|
||||
|
||||
PrintAndLogEx(SUCCESS, " IC Reference code %u ( 0x%02X )", d[0x12], d[0x12]);
|
||||
|
||||
PrintAndLogEx(SUCCESS, "----------------- " _CYAN_("raw") " -----------------");
|
||||
PrintAndLogEx(SUCCESS, "%s", sprint_hex_inrow(d, n));
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
|
||||
/*
|
||||
0012
|
||||
80000000001302E2007D0E8DCC
|
||||
*/
|
||||
}
|
||||
|
||||
static uint16_t get_sw(uint8_t *d, uint8_t n) {
|
||||
if (n < 2)
|
||||
return 0;
|
||||
|
||||
n -= 2;
|
||||
return d[n] * 0x0100 + d[n + 1];
|
||||
}
|
||||
|
||||
// ST rothult
|
||||
int infoHF_ST(void) {
|
||||
|
||||
bool activate_field = true;
|
||||
bool keep_field_on = true;
|
||||
uint8_t response[PM3_CMD_DATA_SIZE];
|
||||
int resplen = 0;
|
||||
|
||||
// --------------- Select NDEF Tag application ----------------
|
||||
uint8_t aSELECT_AID[80];
|
||||
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)
|
||||
return res;
|
||||
|
||||
if (resplen < 2)
|
||||
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));
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
activate_field = false;
|
||||
keep_field_on = true;
|
||||
// --------------- CC file reading ----------------
|
||||
|
||||
uint8_t aSELECT_FILE_CC[30];
|
||||
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)
|
||||
return res;
|
||||
|
||||
sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
PrintAndLogEx(ERR, "Selecting CC file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
uint8_t aREAD_CC[30];
|
||||
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)
|
||||
return res;
|
||||
|
||||
sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
PrintAndLogEx(ERR, "reading CC file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
print_st_cc_info(response, resplen - 2);
|
||||
|
||||
|
||||
// --------------- System file reading ----------------
|
||||
uint8_t aSELECT_FILE_SYS[30];
|
||||
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)
|
||||
return res;
|
||||
|
||||
sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
PrintAndLogEx(ERR, "Selecting system file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
keep_field_on = false;
|
||||
|
||||
uint8_t aREAD_SYS[30];
|
||||
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)
|
||||
return res;
|
||||
|
||||
sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
PrintAndLogEx(ERR, "reading system file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
print_st_system_info(response, resplen - 2);
|
||||
// PrintAndLogEx(NORMAL, "<<<< %s", sprint_hex(response, resplen));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
// menu command to get and print all info known about any known 14b tag
|
||||
static int cmd_hf_st_info(const char *Cmd) {
|
||||
char c = tolower(param_getchar(Cmd, 0));
|
||||
if (c == 'h') return usage_hf_st_info();
|
||||
return infoHF_ST();
|
||||
}
|
||||
|
||||
static int cmd_hf_st_sim(const char *Cmd) {
|
||||
char c = tolower(param_getchar(Cmd, 0));
|
||||
if (c == 'h' || c == 0x00) return usage_hf_st_sim();
|
||||
|
||||
int uidlen = 0;
|
||||
uint8_t cmdp = 0;
|
||||
uint8_t uid[7] = {0};
|
||||
if (c == 'u') {
|
||||
param_gethex_ex(Cmd, cmdp + 1, uid, &uidlen);
|
||||
uidlen >>= 1;
|
||||
if (uidlen != 7) {
|
||||
return usage_hf_st_sim();
|
||||
}
|
||||
}
|
||||
|
||||
char param[40];
|
||||
snprintf(param, sizeof(param), "t 10 u %s", sprint_hex_inrow(uid, uidlen));
|
||||
return CmdHF14ASim(param);
|
||||
}
|
||||
|
||||
static int cmd_hf_st_ndef(const char *Cmd) {
|
||||
char c = tolower(param_getchar(Cmd, 0));
|
||||
if (c == 'h' || c == 0x00) return usage_hf_st_ndef();
|
||||
|
||||
int pwdlen = 0;
|
||||
uint8_t cmdp = 0;
|
||||
uint8_t pwd[16] = {0};
|
||||
if (c == 'p') {
|
||||
param_gethex_ex(Cmd, cmdp + 1, pwd, &pwdlen);
|
||||
pwdlen >>= 1;
|
||||
if (pwdlen != 16) {
|
||||
return usage_hf_st_ndef();
|
||||
}
|
||||
}
|
||||
|
||||
bool activate_field = true;
|
||||
bool keep_field_on = true;
|
||||
uint8_t response[PM3_CMD_DATA_SIZE];
|
||||
int resplen = 0;
|
||||
|
||||
// --------------- Select NDEF Tag application ----------------
|
||||
uint8_t aSELECT_AID[80];
|
||||
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)
|
||||
return res;
|
||||
|
||||
if (resplen < 2)
|
||||
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));
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
activate_field = false;
|
||||
keep_field_on = true;
|
||||
|
||||
// --------------- NDEF file reading ----------------
|
||||
uint8_t aSELECT_FILE_NDEF[30];
|
||||
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)
|
||||
return res;
|
||||
|
||||
sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
PrintAndLogEx(ERR, "Selecting NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
// --------------- VERIFY ----------------
|
||||
uint8_t aVERIFY[30];
|
||||
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)
|
||||
return res;
|
||||
|
||||
sw = get_sw(response, resplen);
|
||||
if (sw == 0x6300) {
|
||||
// need to provide 16byte password
|
||||
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)
|
||||
return res;
|
||||
|
||||
sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
PrintAndLogEx(ERR, "Verify password failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
}
|
||||
|
||||
keep_field_on = false;
|
||||
uint8_t aREAD_NDEF[30];
|
||||
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)
|
||||
return res;
|
||||
|
||||
sw = get_sw(response, resplen);
|
||||
if (sw != 0x9000) {
|
||||
PrintAndLogEx(ERR, "reading NDEF file failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff));
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
NDEFRecordsDecodeAndPrint(response + 2, resplen - 4);
|
||||
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;
|
||||
}
|
||||
|
||||
static command_t CommandTable[] = {
|
||||
{"help", CmdHelp, AlwaysAvailable, "This help"},
|
||||
{"info", cmd_hf_st_info, IfPm3Iso14443a, "Tag information"},
|
||||
{"list", cmd_hf_st_list, AlwaysAvailable, "List ISO 14443A/7816 history"},
|
||||
{"ndef", cmd_hf_st_ndef, AlwaysAvailable, "read NDEF file on tag"},
|
||||
{"sim", cmd_hf_st_sim, IfPm3Iso14443a, "Fake ISO 14443A/ST 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 CmdHF_ST(const char *Cmd) {
|
||||
clearCommandBuffer();
|
||||
return CmdsParse(CommandTable, Cmd);
|
||||
}
|
19
client/src/cmdhfst.h
Normal file
19
client/src/cmdhfst.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Copyright (C) 2020 iceman1001
|
||||
//
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
// High frequency ISO14443A / ST commands
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef CMDHFST_H__
|
||||
#define CMDHFST_H__
|
||||
|
||||
#include "common.h"
|
||||
|
||||
int CmdHF_ST(const char *Cmd);
|
||||
|
||||
int infoHF_ST(void);
|
||||
#endif
|
1065
client/src/cmdhfwaveshare.c
Normal file
1065
client/src/cmdhfwaveshare.c
Normal file
File diff suppressed because it is too large
Load diff
10
client/src/cmdhfwaveshare.h
Normal file
10
client/src/cmdhfwaveshare.h
Normal file
|
@ -0,0 +1,10 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// Waveshare commands
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef CMDHFWAVESHARE_H__
|
||||
#define CMDHFWAVESHARE_H__
|
||||
|
||||
int CmdHFWaveshare(const char *Cmd);
|
||||
|
||||
#endif
|
|
@ -61,31 +61,43 @@ static bool g_lf_threshold_set = false;
|
|||
static int CmdHelp(const char *Cmd);
|
||||
|
||||
static int usage_lf_cmdread(void) {
|
||||
PrintAndLogEx(NORMAL, "Usage: lf cmdread d <delay period> z <zero period> o <one period> c <cmdbytes>");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf cmdread d <delay period> z <zero period> o <one period> c <cmdbytes> [q] [s #samples] [@]");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h This help");
|
||||
PrintAndLogEx(NORMAL, " d <delay> delay OFF period, (0 for bitbang mode) (decimal)");
|
||||
PrintAndLogEx(NORMAL, " z <zero> ZERO time period (decimal)");
|
||||
PrintAndLogEx(NORMAL, " o <one> ONE time period (decimal)");
|
||||
PrintAndLogEx(NORMAL, " c <cmd> Command bytes (in ones and zeros)");
|
||||
PrintAndLogEx(NORMAL, " q silent (optional)");
|
||||
PrintAndLogEx(NORMAL, " s #samples number of samples to collect (optional)");
|
||||
PrintAndLogEx(NORMAL, " @ run continuously until a key is pressed (optional)");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, " ************* " _YELLOW_("All periods in microseconds (us)"));
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " lf cmdread d 80 z 100 o 200 c 11000");
|
||||
PrintAndLogEx(NORMAL, "- probing for HT2:");
|
||||
PrintAndLogEx(NORMAL, " lf cmdread d 50 z 116 o 166 c 011000");
|
||||
PrintAndLogEx(NORMAL, "- probing for HT2, oscilloscope style:");
|
||||
PrintAndLogEx(NORMAL, " data plot");
|
||||
PrintAndLogEx(NORMAL, " lf cmdread d 50 z 116 o 166 c 011000 q s 2000 @");
|
||||
PrintAndLogEx(NORMAL, "Extras:");
|
||||
PrintAndLogEx(NORMAL, " use " _YELLOW_("'lf config'")" to set parameters.");
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
static int usage_lf_read(void) {
|
||||
PrintAndLogEx(NORMAL, "Usage: lf read [h] [s] [d numofsamples]");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf read [h] [q] [s #samples] [@]");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h This help");
|
||||
PrintAndLogEx(NORMAL, " d #samples # samples to collect (optional)");
|
||||
PrintAndLogEx(NORMAL, " s silent");
|
||||
PrintAndLogEx(NORMAL, " q silent (optional)");
|
||||
PrintAndLogEx(NORMAL, " s #samples number of samples to collect (optional)");
|
||||
PrintAndLogEx(NORMAL, " @ run continuously until a key is pressed (optional)");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, " lf read s d 12000 - collects 12000 samples silent");
|
||||
PrintAndLogEx(NORMAL, " lf read");
|
||||
PrintAndLogEx(NORMAL, " lf read");
|
||||
PrintAndLogEx(NORMAL, "- collecting quietly 12000 samples:");
|
||||
PrintAndLogEx(NORMAL, " lf read q s 12000 - ");
|
||||
PrintAndLogEx(NORMAL, "- oscilloscope style:");
|
||||
PrintAndLogEx(NORMAL, " data plot");
|
||||
PrintAndLogEx(NORMAL, " lf read q s 3000 @");
|
||||
PrintAndLogEx(NORMAL, "Extras:");
|
||||
PrintAndLogEx(NORMAL, " use " _YELLOW_("'lf config'")" to set parameters.");
|
||||
return PM3_SUCCESS;
|
||||
|
@ -307,14 +319,22 @@ int CmdLFCommandRead(const char *Cmd) {
|
|||
if (!session.pm3_present) return PM3_ENOTTY;
|
||||
|
||||
bool errors = false;
|
||||
bool verbose = true;
|
||||
bool continuous = false;
|
||||
uint32_t samples = 0;
|
||||
uint16_t datalen = 0;
|
||||
|
||||
uint8_t payload_header_size = 12;
|
||||
struct p {
|
||||
uint32_t delay;
|
||||
uint16_t ones;
|
||||
uint16_t zeros;
|
||||
uint8_t data[PM3_CMD_DATA_SIZE - 8];
|
||||
uint32_t samples : 31;
|
||||
bool verbose : 1;
|
||||
uint8_t data[PM3_CMD_DATA_SIZE - payload_header_size];
|
||||
} PACKED payload;
|
||||
payload.samples = samples;
|
||||
payload.verbose = verbose;
|
||||
|
||||
uint8_t cmdp = 0;
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
|
@ -337,6 +357,20 @@ int CmdLFCommandRead(const char *Cmd) {
|
|||
payload.ones = param_get32ex(Cmd, cmdp + 1, 0, 10) & 0xFFFF;
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 's':
|
||||
samples = param_get32ex(Cmd, cmdp + 1, 0, 10);
|
||||
payload.samples = samples;
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 'q':
|
||||
verbose = false;
|
||||
payload.verbose = verbose;
|
||||
cmdp++;
|
||||
break;
|
||||
case '@':
|
||||
continuous = true;
|
||||
cmdp++;
|
||||
break;
|
||||
default:
|
||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
|
@ -354,33 +388,51 @@ int CmdLFCommandRead(const char *Cmd) {
|
|||
|
||||
//Validations
|
||||
if (errors || cmdp == 0) return usage_lf_cmdread();
|
||||
|
||||
PrintAndLogEx(SUCCESS, "sending");
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_LF_MOD_THEN_ACQ_RAW_ADC, (uint8_t *)&payload, 8 + datalen);
|
||||
|
||||
PacketResponseNG resp;
|
||||
|
||||
uint8_t i = 10;
|
||||
// 20sec wait loop
|
||||
while (!WaitForResponseTimeout(CMD_LF_MOD_THEN_ACQ_RAW_ADC, &resp, 2000) && i != 0) {
|
||||
PrintAndLogEx(NORMAL, "." NOLF);
|
||||
i--;
|
||||
if (continuous) {
|
||||
PrintAndLogEx(INFO, "Press " _GREEN_("Enter") " to exit");
|
||||
}
|
||||
if (verbose) {
|
||||
PrintAndLogEx(SUCCESS, "Sending command...");
|
||||
}
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
|
||||
if (resp.status == PM3_SUCCESS) {
|
||||
if (i) {
|
||||
PrintAndLogEx(SUCCESS, "downloading response signal data");
|
||||
getSamples(0, false);
|
||||
return PM3_SUCCESS;
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
||||
return PM3_ETIMEOUT;
|
||||
int ret = PM3_SUCCESS;
|
||||
do {
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_LF_MOD_THEN_ACQ_RAW_ADC, (uint8_t *)&payload, payload_header_size + datalen);
|
||||
|
||||
PacketResponseNG resp;
|
||||
|
||||
uint8_t i = 10;
|
||||
// 20sec wait loop
|
||||
while (!WaitForResponseTimeout(CMD_LF_MOD_THEN_ACQ_RAW_ADC, &resp, 2000) && i != 0) {
|
||||
if (verbose) {
|
||||
PrintAndLogEx(NORMAL, "." NOLF);
|
||||
}
|
||||
i--;
|
||||
}
|
||||
}
|
||||
PrintAndLogEx(WARNING, "command failed.");
|
||||
return PM3_ESOFT;
|
||||
if (verbose) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
}
|
||||
if (resp.status == PM3_SUCCESS) {
|
||||
if (i) {
|
||||
if (verbose) {
|
||||
PrintAndLogEx(SUCCESS, "downloading response signal data");
|
||||
}
|
||||
getSamples(samples, false);
|
||||
ret = PM3_SUCCESS;
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, "timeout while waiting for reply.");
|
||||
return PM3_ETIMEOUT;
|
||||
}
|
||||
} else {
|
||||
PrintAndLogEx(WARNING, "command failed.");
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
if (kbd_enter_pressed()) {
|
||||
break;
|
||||
}
|
||||
} while (continuous);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int CmdFlexdemod(const char *Cmd) {
|
||||
|
@ -595,8 +647,8 @@ int lf_read(bool verbose, uint32_t samples) {
|
|||
if (!session.pm3_present) return PM3_ENOTTY;
|
||||
|
||||
struct p {
|
||||
bool verbose;
|
||||
uint32_t samples;
|
||||
uint32_t samples : 31;
|
||||
bool verbose : 1;
|
||||
} PACKED;
|
||||
|
||||
struct p payload;
|
||||
|
@ -627,20 +679,25 @@ int CmdLFRead(const char *Cmd) {
|
|||
|
||||
bool errors = false;
|
||||
bool verbose = true;
|
||||
bool continuous = false;
|
||||
uint32_t samples = 0;
|
||||
uint8_t cmdp = 0;
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
return usage_lf_read();
|
||||
case 'd':
|
||||
case 's':
|
||||
samples = param_get32ex(Cmd, cmdp + 1, 0, 10);
|
||||
cmdp += 2;
|
||||
break;
|
||||
case 's':
|
||||
case 'q':
|
||||
verbose = false;
|
||||
cmdp++;
|
||||
break;
|
||||
case '@':
|
||||
continuous = true;
|
||||
cmdp++;
|
||||
break;
|
||||
default:
|
||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
|
@ -650,8 +707,17 @@ int CmdLFRead(const char *Cmd) {
|
|||
|
||||
//Validations
|
||||
if (errors) return usage_lf_read();
|
||||
|
||||
return lf_read(verbose, samples);
|
||||
if (continuous) {
|
||||
PrintAndLogEx(INFO, "Press " _GREEN_("Enter") " to exit");
|
||||
}
|
||||
int ret = PM3_SUCCESS;
|
||||
do {
|
||||
ret = lf_read(verbose, samples);
|
||||
if (kbd_enter_pressed()) {
|
||||
break;
|
||||
}
|
||||
} while (continuous);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int CmdLFSniff(const char *Cmd) {
|
||||
|
@ -1200,6 +1266,7 @@ static bool CheckChipType(bool getDeviceData) {
|
|||
PrintAndLogEx(SUCCESS, "Chipset detection: " _GREEN_("T55xx"));
|
||||
PrintAndLogEx(HINT, "Hint: try " _YELLOW_("`lf t55xx`") " commands");
|
||||
retval = true;
|
||||
goto out;
|
||||
}
|
||||
|
||||
// check for em4x50 chips
|
||||
|
|
|
@ -50,19 +50,18 @@ static int CmdHelp(const char *Cmd);
|
|||
|
||||
static int usage_lf_fdx_clone(void) {
|
||||
PrintAndLogEx(NORMAL, "Clone a FDX-B animal tag to a T55x7 or Q5/T5555 tag.");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf fdx clone [h] <country id> <animal id> <extended> <Q5>");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf fdx clone [h] [c <country code>] [a <national code>] [e <extended>] <s> <Q5>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : This help");
|
||||
PrintAndLogEx(NORMAL, " <country id> : Country id");
|
||||
PrintAndLogEx(NORMAL, " <animal id> : Animal id");
|
||||
PrintAndLogEx(NORMAL, " <extended> : Extended data");
|
||||
//reserved/rfu
|
||||
//is animal tag
|
||||
PrintAndLogEx(NORMAL, " <Q5> : Specify writing to Q5/T5555 tag");
|
||||
PrintAndLogEx(NORMAL, " h : This help");
|
||||
PrintAndLogEx(NORMAL, " c <country> : (dec) Country code");
|
||||
PrintAndLogEx(NORMAL, " n <national> : (dec) National code");
|
||||
PrintAndLogEx(NORMAL, " e <extended> : (hex) Extended data");
|
||||
PrintAndLogEx(NORMAL, " s : Set animal bit");
|
||||
PrintAndLogEx(NORMAL, " <Q5> : Specify writing to Q5/T5555 tag");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf fdx clone 999 112233"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf fdx clone 999 112233 16a"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf fdx clone c 999 n 112233 s"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf fdx clone c 999 n 112233 e 16a"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -70,33 +69,37 @@ static int usage_lf_fdx_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] <country id> <animal id> <extended>");
|
||||
PrintAndLogEx(NORMAL, "Usage: lf fdx sim [h] [c <country code>] [n <national code>] [e <extended>] <s> <Q5>");
|
||||
PrintAndLogEx(NORMAL, "Options:");
|
||||
PrintAndLogEx(NORMAL, " h : This help");
|
||||
PrintAndLogEx(NORMAL, " <country id> : Country ID");
|
||||
PrintAndLogEx(NORMAL, " <animal id> : Animal ID");
|
||||
PrintAndLogEx(NORMAL, " <extended> : Extended data");
|
||||
PrintAndLogEx(NORMAL, " h : This help");
|
||||
PrintAndLogEx(NORMAL, " c <country> : (dec) Country code");
|
||||
PrintAndLogEx(NORMAL, " n <national> : (dec) National code");
|
||||
PrintAndLogEx(NORMAL, " e <extended> : (hex) Extended data");
|
||||
PrintAndLogEx(NORMAL, " s : Set animal bit");
|
||||
PrintAndLogEx(NORMAL, " <Q5> : Specify writing to Q5/T5555 tag");
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, "Examples:");
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf fdx sim 999 112233"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf fdx sim 999 112233 16a"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf fdx sim c 999 n 112233 s"));
|
||||
PrintAndLogEx(NORMAL, _YELLOW_(" lf fdx sim c 999 n 112233 e 16a"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
// clearing the topbit needed for the preambl detection.
|
||||
static void verify_values(uint64_t *animalid, uint32_t *countryid, uint32_t *extended) {
|
||||
static void verify_values(uint64_t *animalid, uint32_t *countryid, uint32_t *extended, uint8_t *is_animal) {
|
||||
if ((*animalid & 0x3FFFFFFFFF) != *animalid) {
|
||||
*animalid &= 0x3FFFFFFFFF;
|
||||
PrintAndLogEx(INFO, "Animal ID truncated to 38bits: " _YELLOW_("%"PRIx64), *animalid);
|
||||
}
|
||||
if ((*countryid & 0x3ff) != *countryid) {
|
||||
*countryid &= 0x3ff;
|
||||
if ((*countryid & 0x3FF) != *countryid) {
|
||||
*countryid &= 0x3FF;
|
||||
PrintAndLogEx(INFO, "Country ID truncated to 10bits:" _YELLOW_("%03d"), *countryid);
|
||||
}
|
||||
if ((*extended & 0xfff) != *extended) {
|
||||
*extended &= 0xfff;
|
||||
if ((*extended & 0xFFF) != *extended) {
|
||||
*extended &= 0xFFF;
|
||||
PrintAndLogEx(INFO, "Extended truncated to 24bits: " _YELLOW_("0x%03X"), *extended);
|
||||
}
|
||||
|
||||
*is_animal &= 0x01;
|
||||
}
|
||||
|
||||
static inline uint32_t bitcount(uint32_t a) {
|
||||
|
@ -228,6 +231,8 @@ int demodFDX(void) {
|
|||
// set and leave DemodBuffer intact
|
||||
setDemodBuff(DemodBuffer, 128, preambleIndex);
|
||||
setClockGrid(g_DemodClock, g_DemodStartIdx + (preambleIndex * g_DemodClock));
|
||||
|
||||
|
||||
// remove marker bits (1's every 9th digit after preamble) (pType = 2)
|
||||
size = removeParity(DemodBuffer, 11, 9, 2, 117);
|
||||
if (size != 104) {
|
||||
|
@ -236,29 +241,43 @@ int demodFDX(void) {
|
|||
}
|
||||
|
||||
//got a good demod
|
||||
uint8_t offset;
|
||||
uint64_t NationalCode = ((uint64_t)(bytebits_to_byteLSBF(DemodBuffer + 32, 6)) << 32) | bytebits_to_byteLSBF(DemodBuffer, 32);
|
||||
uint16_t countryCode = bytebits_to_byteLSBF(DemodBuffer + 38, 10);
|
||||
uint8_t dataBlockBit = DemodBuffer[48];
|
||||
uint32_t reservedCode = bytebits_to_byteLSBF(DemodBuffer + 49, 14);
|
||||
uint8_t animalBit = DemodBuffer[63];
|
||||
uint16_t crc = bytebits_to_byteLSBF(DemodBuffer + 64, 16);
|
||||
uint32_t extended = bytebits_to_byteLSBF(DemodBuffer + 80, 24);
|
||||
|
||||
offset = 38;
|
||||
uint16_t countryCode = bytebits_to_byteLSBF(DemodBuffer + offset, 10);
|
||||
|
||||
offset += 10;
|
||||
uint8_t dataBlockBit = DemodBuffer[offset];
|
||||
|
||||
offset++;
|
||||
uint32_t reservedCode = bytebits_to_byteLSBF(DemodBuffer + offset, 14);
|
||||
|
||||
offset += 14;
|
||||
uint8_t animalBit = DemodBuffer[offset];
|
||||
|
||||
offset++;
|
||||
uint16_t crc = bytebits_to_byteLSBF(DemodBuffer + offset, 16);
|
||||
|
||||
offset += 16;
|
||||
uint32_t extended = bytebits_to_byteLSBF(DemodBuffer + offset, 24);
|
||||
|
||||
uint64_t rawid = (uint64_t)(bytebits_to_byte(DemodBuffer, 32)) << 32 | bytebits_to_byte(DemodBuffer + 32, 32);
|
||||
uint8_t raw[8];
|
||||
num_to_bytes(rawid, 8, raw);
|
||||
|
||||
PrintAndLogEx(SUCCESS, "FDX-B / ISO 11784/5 Animal");
|
||||
PrintAndLogEx(SUCCESS, "Animal ID " _GREEN_("%04u-%012"PRIu64), countryCode, NationalCode);
|
||||
PrintAndLogEx(SUCCESS, "National Code " _GREEN_("%012" PRIu64) " (0x%" PRIx64 ")", NationalCode, NationalCode);
|
||||
PrintAndLogEx(SUCCESS, "Country Code %04u", countryCode);
|
||||
PrintAndLogEx(SUCCESS, "Reserved/RFU %u (0x04%X)", reservedCode, reservedCode);
|
||||
PrintAndLogEx(SUCCESS, "Animal Tag %s", animalBit ? _YELLOW_("True") : "False");
|
||||
PrintAndLogEx(SUCCESS, "Has extended data %s [0x%X]", dataBlockBit ? _YELLOW_("True") : "False", extended);
|
||||
PrintAndLogEx(SUCCESS, "National Code " _GREEN_("%012" PRIu64) " (0x%" PRIX64 ")", NationalCode, NationalCode);
|
||||
PrintAndLogEx(SUCCESS, "Country Code " _GREEN_("%04u"), 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);
|
||||
|
||||
uint8_t c[] = {0, 0};
|
||||
compute_crc(CRC_11784, raw, sizeof(raw), &c[0], &c[1]);
|
||||
PrintAndLogEx(SUCCESS, "CRC-16 0x%04X (%s) ", crc, (crc == (c[1] << 8 | c[0])) ? _GREEN_("ok") : _RED_("fail"));
|
||||
|
||||
PrintAndLogEx(SUCCESS, "CRC-16 0x%04X (%s)", crc, (crc == (c[1] << 8 | c[0])) ? _GREEN_("ok") : _RED_("fail"));
|
||||
// iceman: crc doesn't protect the extended data?
|
||||
PrintAndLogEx(SUCCESS, "Raw " _GREEN_("%s"), sprint_hex(raw, 8));
|
||||
|
||||
if (g_debugMode) {
|
||||
|
@ -327,21 +346,61 @@ static int CmdFdxRead(const char *Cmd) {
|
|||
|
||||
static int CmdFdxClone(const char *Cmd) {
|
||||
|
||||
uint32_t countryid = 0, extended = 0;
|
||||
uint64_t animalid = 0;
|
||||
uint32_t country_code = 0, extended = 0;
|
||||
uint64_t national_code = 0;
|
||||
uint8_t is_animal = 0, cmdp = 0;
|
||||
bool errors = false, has_extended = false, q5 = false;
|
||||
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_fdx_clone();
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
return usage_lf_fdx_clone();
|
||||
case 'c': {
|
||||
country_code = param_get32ex(Cmd, cmdp + 1, 0, 10);
|
||||
cmdp += 2;
|
||||
break;
|
||||
}
|
||||
case 'n': {
|
||||
national_code = param_get64ex(Cmd, cmdp + 1, 0, 10);
|
||||
cmdp += 2;
|
||||
break;
|
||||
}
|
||||
case 'e': {
|
||||
extended = param_get32ex(Cmd, cmdp + 1, 0, 16);
|
||||
has_extended = true;
|
||||
cmdp += 2;
|
||||
break;
|
||||
}
|
||||
case 's': {
|
||||
is_animal = 1;
|
||||
cmdp++;
|
||||
break;
|
||||
}
|
||||
case 'q': {
|
||||
q5 = true;
|
||||
cmdp++;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (errors || strlen(Cmd) == 0) return usage_lf_fdx_clone();
|
||||
|
||||
countryid = param_get32ex(Cmd, 0, 0, 10);
|
||||
animalid = param_get64ex(Cmd, 1, 0, 10);
|
||||
extended = param_get32ex(Cmd, 2, 0, 16);
|
||||
verify_values(&national_code, &country_code, &extended, &is_animal);
|
||||
|
||||
verify_values(&animalid, &countryid, &extended);
|
||||
PrintAndLogEx(INFO, " Country code %"PRIu32, country_code);
|
||||
PrintAndLogEx(INFO, " National code %"PRIu64, national_code);
|
||||
PrintAndLogEx(INFO, " Set animal bit %c", (is_animal) ? 'Y' : 'N');
|
||||
PrintAndLogEx(INFO, "Set data block bit %c", (has_extended) ? 'Y' : 'N');
|
||||
PrintAndLogEx(INFO, " Extended data 0x%"PRIX32, extended);
|
||||
PrintAndLogEx(INFO, " RFU 0");
|
||||
|
||||
uint8_t *bits = calloc(128, sizeof(uint8_t));
|
||||
|
||||
if (getFDXBits(animalid, countryid, 1, (extended > 0), extended, bits) != PM3_SUCCESS) {
|
||||
if (getFDXBits(national_code, country_code, is_animal, has_extended, extended, bits) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "Error with tag bitstream generation.");
|
||||
free(bits);
|
||||
return PM3_ESOFT;
|
||||
|
@ -350,7 +409,6 @@ static int CmdFdxClone(const char *Cmd) {
|
|||
uint32_t blocks[5] = {T55x7_MODULATION_DIPHASE | T55x7_BITRATE_RF_32 | 4 << T55x7_MAXBLOCK_SHIFT, 0, 0, 0, 0};
|
||||
|
||||
//Q5
|
||||
bool q5 = tolower(param_getchar(Cmd, 2)) == 'q';
|
||||
if (q5)
|
||||
blocks[0] = T5555_FIXED | T5555_MODULATION_BIPHASE | T5555_INVERT_OUTPUT | T5555_SET_BITRATE(32) | 4 << T5555_MAXBLOCK_SHIFT;
|
||||
|
||||
|
@ -362,7 +420,7 @@ static int CmdFdxClone(const char *Cmd) {
|
|||
|
||||
free(bits);
|
||||
|
||||
PrintAndLogEx(INFO, "Preparing to clone FDX-B to " _YELLOW_("%s") " with animal ID: " _GREEN_("%04u-%"PRIu64)" (extended 0x%X)", (q5) ? "Q5/T5555" : "T55x7", countryid, animalid, extended);
|
||||
PrintAndLogEx(INFO, "Preparing to clone FDX-B to " _YELLOW_("%s") " with animal ID: " _GREEN_("%04u-%"PRIu64), (q5) ? "Q5/T5555" : "T55x7", country_code, national_code);
|
||||
print_blocks(blocks, ARRAYLEN(blocks));
|
||||
|
||||
int res = clone_t55xx_tag(blocks, ARRAYLEN(blocks));
|
||||
|
@ -372,24 +430,59 @@ static int CmdFdxClone(const char *Cmd) {
|
|||
}
|
||||
|
||||
static int CmdFdxSim(const char *Cmd) {
|
||||
uint32_t countryid = 0, extended = 0;
|
||||
uint64_t animalid = 0;
|
||||
|
||||
char cmdp = tolower(param_getchar(Cmd, 0));
|
||||
if (strlen(Cmd) == 0 || cmdp == 'h') return usage_lf_fdx_sim();
|
||||
uint32_t country_code = 0, extended = 0;
|
||||
uint64_t national_code = 0;
|
||||
uint8_t is_animal = 0, cmdp = 0;
|
||||
bool errors = false, has_extended = false;
|
||||
|
||||
countryid = param_get32ex(Cmd, 0, 0, 10);
|
||||
animalid = param_get64ex(Cmd, 1, 0, 10);
|
||||
extended = param_get32ex(Cmd, 2, 0, 16);
|
||||
while (param_getchar(Cmd, cmdp) != 0x00 && !errors) {
|
||||
switch (tolower(param_getchar(Cmd, cmdp))) {
|
||||
case 'h':
|
||||
return usage_lf_fdx_sim();
|
||||
case 'c': {
|
||||
country_code = param_get32ex(Cmd, cmdp + 1, 0, 10);
|
||||
cmdp += 2;
|
||||
break;
|
||||
}
|
||||
case 'n': {
|
||||
national_code = param_get64ex(Cmd, cmdp + 1, 0, 10);
|
||||
cmdp += 2;
|
||||
break;
|
||||
}
|
||||
case 'e': {
|
||||
extended = param_get32ex(Cmd, cmdp + 1, 0, 10);
|
||||
has_extended = true;
|
||||
cmdp += 2;
|
||||
break;
|
||||
}
|
||||
case 's': {
|
||||
is_animal = 1;
|
||||
cmdp++;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp));
|
||||
errors = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (errors) return usage_lf_fdx_sim();
|
||||
|
||||
verify_values(&animalid, &countryid, &extended);
|
||||
verify_values(&national_code, &country_code, &extended, &is_animal);
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Simulating FDX-B animal ID: " _GREEN_("%04u-%"PRIu64)" (extended 0x%X)", countryid, animalid, extended);
|
||||
PrintAndLogEx(INFO, " Country code %"PRIu32, country_code);
|
||||
PrintAndLogEx(INFO, " National code %"PRIu64, national_code);
|
||||
PrintAndLogEx(INFO, " Set animal bit %c", (is_animal) ? 'Y' : 'N');
|
||||
PrintAndLogEx(INFO, "Set data block bit %c", (has_extended) ? 'Y' : 'N');
|
||||
PrintAndLogEx(INFO, " Extended data 0x%"PRIX32, extended);
|
||||
PrintAndLogEx(INFO, " RFU 0");
|
||||
|
||||
PrintAndLogEx(SUCCESS, "Simulating FDX-B animal ID: " _GREEN_("%04u-%"PRIu64), country_code, national_code);
|
||||
|
||||
//getFDXBits(uint64_t national_id, uint16_t country, uint8_t isanimal, uint8_t isextended, uint32_t extended, uint8_t *bits)
|
||||
uint8_t *bits = calloc(128, sizeof(uint8_t));
|
||||
|
||||
if (getFDXBits(animalid, countryid, 1, (extended > 0), extended, bits) != PM3_SUCCESS) {
|
||||
if (getFDXBits(national_code, country_code, is_animal, (extended > 0), extended, bits) != PM3_SUCCESS) {
|
||||
PrintAndLogEx(ERR, "Error with tag bitstream generation.");
|
||||
free(bits);
|
||||
return PM3_ESOFT;
|
||||
|
@ -453,7 +546,7 @@ int detectFDXB(uint8_t *dest, size_t *size) {
|
|||
return (int)startIdx;
|
||||
}
|
||||
|
||||
int getFDXBits(uint64_t national_id, uint16_t country, uint8_t is_animal, uint8_t is_extended, uint32_t extended, uint8_t *bits) {
|
||||
int getFDXBits(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);
|
||||
|
@ -471,21 +564,21 @@ int getFDXBits(uint64_t national_id, uint16_t country, uint8_t is_animal, uint8_
|
|||
num_to_bytebitsLSBF(0x00 >> 7, 7, bits + 74);
|
||||
|
||||
// add animal flag - OK
|
||||
bits[65] = is_animal;
|
||||
bits[81] = is_animal;
|
||||
|
||||
// add extended flag - OK
|
||||
bits[81] = is_extended;
|
||||
bits[65] = is_extended;
|
||||
|
||||
// add national code 40bits - OK
|
||||
num_to_bytebitsLSBF(national_id >> 0, 8, bits + 11);
|
||||
num_to_bytebitsLSBF(national_id >> 8, 8, bits + 20);
|
||||
num_to_bytebitsLSBF(national_id >> 16, 8, bits + 29);
|
||||
num_to_bytebitsLSBF(national_id >> 24, 8, bits + 38);
|
||||
num_to_bytebitsLSBF(national_id >> 32, 6, bits + 47);
|
||||
num_to_bytebitsLSBF(national_code >> 0, 8, bits + 11);
|
||||
num_to_bytebitsLSBF(national_code >> 8, 8, bits + 20);
|
||||
num_to_bytebitsLSBF(national_code >> 16, 8, bits + 29);
|
||||
num_to_bytebitsLSBF(national_code >> 24, 8, bits + 38);
|
||||
num_to_bytebitsLSBF(national_code >> 32, 6, bits + 47);
|
||||
|
||||
// add country code - OK
|
||||
num_to_bytebitsLSBF(country >> 0, 2, bits + 53);
|
||||
num_to_bytebitsLSBF(country >> 2, 8, bits + 56);
|
||||
num_to_bytebitsLSBF(country_code >> 0, 2, bits + 53);
|
||||
num_to_bytebitsLSBF(country_code >> 2, 8, bits + 56);
|
||||
|
||||
// add crc-16 - OK
|
||||
uint8_t raw[8];
|
||||
|
@ -501,6 +594,10 @@ int getFDXBits(uint64_t national_id, uint16_t country, uint8_t is_animal, uint8_
|
|||
num_to_bytebitsLSBF(extended >> 0, 8, bits + 101);
|
||||
num_to_bytebitsLSBF(extended >> 8, 8, bits + 110);
|
||||
num_to_bytebitsLSBF(extended >> 16, 8, bits + 119);
|
||||
|
||||
// 8 16 24 32 40 48 49
|
||||
// A8 28 0C 92 EA 6F 00 01
|
||||
// A8 28 0C 92 EA 6F 80 00
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
int CmdLFFdx(const char *Cmd);
|
||||
int detectFDXB(uint8_t *dest, size_t *size);
|
||||
int demodFDX(void);
|
||||
int getFDXBits(uint64_t national_id, uint16_t country, uint8_t is_animal, uint8_t is_extended, uint32_t extended, uint8_t *bits);
|
||||
int getFDXBits(uint64_t national_code, uint16_t country_code, uint8_t is_animal, uint8_t is_extended, uint32_t extended, uint8_t *bits);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -93,32 +93,35 @@ static int CmdGuardDemod(const char *Cmd) {
|
|||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
//got a good demod of 96 bits
|
||||
uint8_t ByteStream[8] = {0x00};
|
||||
// got a good demod of 96 bits
|
||||
|
||||
uint8_t plain[8] = {0x00};
|
||||
uint8_t xorKey = 0;
|
||||
size_t startIdx = preambleIndex + 6; //start after 6 bit preamble
|
||||
|
||||
uint8_t bits_no_spacer[90];
|
||||
//so as to not mess with raw DemodBuffer copy to a new sample array
|
||||
|
||||
// not mess with raw DemodBuffer copy to a new sample array
|
||||
memcpy(bits_no_spacer, DemodBuffer + startIdx, 90);
|
||||
|
||||
// remove the 18 (90/5=18) parity bits (down to 72 bits (96-6-18=72))
|
||||
size_t len = removeParity(bits_no_spacer, 0, 5, 3, 90); //source, startloc, paritylen, ptype, length_to_run
|
||||
if (len != 72) {
|
||||
PrintAndLogEx(DEBUG, "DEBUG: Error - gProxII spacer removal did not produce 72 bits: %zu, start: %zu", len, startIdx);
|
||||
return PM3_ESOFT;
|
||||
}
|
||||
|
||||
// get key and then get all 8 bytes of payload decoded
|
||||
xorKey = (uint8_t)bytebits_to_byteLSBF(bits_no_spacer, 8);
|
||||
for (size_t idx = 0; idx < 8; idx++) {
|
||||
ByteStream[idx] = ((uint8_t)bytebits_to_byteLSBF(bits_no_spacer + 8 + (idx * 8), 8)) ^ xorKey;
|
||||
PrintAndLogEx(DEBUG, "DEBUG: gProxII byte %zu after xor: %02x", idx, ByteStream[idx]);
|
||||
plain[idx] = ((uint8_t)bytebits_to_byteLSBF(bits_no_spacer + 8 + (idx * 8), 8)) ^ xorKey;
|
||||
PrintAndLogEx(DEBUG, "DEBUG: gProxII byte %zu after xor: %02x", idx, plain[idx]);
|
||||
}
|
||||
|
||||
setDemodBuff(DemodBuffer, 96, preambleIndex);
|
||||
setClockGrid(g_DemodClock, g_DemodStartIdx + (preambleIndex * g_DemodClock));
|
||||
|
||||
//ByteStream contains 8 Bytes (64 bits) of decrypted raw tag data
|
||||
uint8_t fmtLen = ByteStream[0] >> 2;
|
||||
//plain contains 8 Bytes (64 bits) of decrypted raw tag data
|
||||
uint8_t fmtLen = plain[0] >> 2;
|
||||
uint32_t FC = 0;
|
||||
uint32_t Card = 0;
|
||||
//get raw 96 bits to print
|
||||
|
@ -128,12 +131,12 @@ static int CmdGuardDemod(const char *Cmd) {
|
|||
bool unknown = false;
|
||||
switch (fmtLen) {
|
||||
case 36:
|
||||
FC = ((ByteStream[3] & 0x7F) << 7) | (ByteStream[4] >> 1);
|
||||
Card = ((ByteStream[4] & 1) << 19) | (ByteStream[5] << 11) | (ByteStream[6] << 3) | (ByteStream[7] >> 5);
|
||||
FC = ((plain[3] & 0x7F) << 7) | (plain[4] >> 1);
|
||||
Card = ((plain[4] & 1) << 19) | (plain[5] << 11) | (plain[6] << 3) | ((plain[7] & 0xE0) >> 5);
|
||||
break;
|
||||
case 26:
|
||||
FC = ((ByteStream[3] & 0x7F) << 1) | (ByteStream[4] >> 7);
|
||||
Card = ((ByteStream[4] & 0x7F) << 9) | (ByteStream[5] << 1) | (ByteStream[6] >> 7);
|
||||
FC = ((plain[3] & 0x7F) << 1) | (plain[4] >> 7);
|
||||
Card = ((plain[4] & 0x7F) << 9) | (plain[5] << 1) | (plain[6] >> 7);
|
||||
break;
|
||||
default :
|
||||
unknown = true;
|
||||
|
@ -309,14 +312,12 @@ int getGuardBits(uint8_t fmtlen, uint32_t fc, uint32_t cn, uint8_t *guardBits) {
|
|||
break;
|
||||
}
|
||||
case 36: {
|
||||
// FC = ((ByteStream[3] & 0x7F)<<7) | (ByteStream[4]>>1);
|
||||
// Card = ((ByteStream[4]&1)<<19) | (ByteStream[5]<<11) | (ByteStream[6]<<3) | (ByteStream[7]>>5);
|
||||
rawbytes[1] = (36 << 2);
|
||||
// Get 26 wiegand from FacilityCode, CardNumber
|
||||
uint8_t wiegand[34];
|
||||
// Get wiegand from FacilityCode 14bits, CardNumber 20bits
|
||||
uint8_t wiegand[36];
|
||||
memset(wiegand, 0x00, sizeof(wiegand));
|
||||
num_to_bytebits(fc, 8, wiegand);
|
||||
num_to_bytebits(cn, 26, wiegand + 8);
|
||||
num_to_bytebits(fc, 14, wiegand);
|
||||
num_to_bytebits(cn, 20, wiegand + 14);
|
||||
|
||||
// add wiegand parity bits (dest, source, len)
|
||||
wiegand_add_parity(pre, wiegand, 34);
|
||||
|
@ -351,28 +352,27 @@ int getGuardBits(uint8_t fmtlen, uint32_t fc, uint32_t cn, uint8_t *guardBits) {
|
|||
rawbytes[3] = 0;
|
||||
|
||||
// add wiegand to rawbytes
|
||||
for (i = 0; i < 4; ++i)
|
||||
for (i = 0; i < 5; ++i)
|
||||
rawbytes[i + 4] = bytebits_to_byte(pre + (i * 8), 8);
|
||||
|
||||
PrintAndLogEx(DEBUG, " WIE | %s\n", sprint_hex(rawbytes, sizeof(rawbytes)));
|
||||
|
||||
PrintAndLogEx(DEBUG, " WIE | %s", sprint_hex(rawbytes, sizeof(rawbytes)));
|
||||
|
||||
// XOR (only works on wiegand stuff)
|
||||
for (i = 1; i < 12; ++i)
|
||||
for (i = 1; i < sizeof(rawbytes); ++i)
|
||||
rawbytes[i] ^= xorKey ;
|
||||
|
||||
PrintAndLogEx(DEBUG, " XOR | %s \n", sprint_hex(rawbytes, sizeof(rawbytes)));
|
||||
PrintAndLogEx(DEBUG, " XOR | %s", sprint_hex(rawbytes, sizeof(rawbytes)));
|
||||
|
||||
// convert rawbytes to bits in pre
|
||||
for (i = 0; i < 12; ++i)
|
||||
for (i = 0; i < sizeof(rawbytes); ++i)
|
||||
num_to_bytebitsLSBF(rawbytes[i], 8, pre + (i * 8));
|
||||
|
||||
PrintAndLogEx(DEBUG, "\n Raw | %s \n", sprint_hex(rawbytes, sizeof(rawbytes)));
|
||||
PrintAndLogEx(DEBUG, " Raw | %s\n", sprint_bin(pre, 64));
|
||||
PrintAndLogEx(DEBUG, " Raw | %s", sprint_hex(rawbytes, sizeof(rawbytes)));
|
||||
PrintAndLogEx(DEBUG, " Raw | %s", sprint_bin(pre, 96));
|
||||
|
||||
// add spacer bit 0 every 4 bits, starting with index 0,
|
||||
// 12 bytes, 24 nibbles. 24+1 extra bites. 3bytes. ie 9bytes | 1byte xorkey, 8bytes rawdata (64bits, should be enough for a 40bit wiegand)
|
||||
addParity(pre, guardBits + 6, 64, 5, 3);
|
||||
// 12 bytes, 24 nibbles. 24+1 extra bites. 3bytes. ie 9bytes | 1byte xorkey, 8bytes rawdata (72bits, should be enough for a 40bit wiegand)
|
||||
addParity(pre, guardBits + 6, 72, 5, 3);
|
||||
|
||||
// preamble
|
||||
guardBits[0] = 1;
|
||||
|
|
|
@ -829,7 +829,7 @@ static int CmdT55xxSetConfig(const char *Cmd) {
|
|||
return printConfiguration(config);
|
||||
}
|
||||
int T55xxReadBlock(uint8_t block, bool page1, bool usepwd, uint8_t override, uint32_t password, uint8_t downlink_mode) {
|
||||
return T55xxReadBlockEx(block, page1, usepwd, override, password, downlink_mode, false);
|
||||
return T55xxReadBlockEx(block, page1, usepwd, override, password, downlink_mode, true);
|
||||
}
|
||||
|
||||
int T55xxReadBlockEx(uint8_t block, bool page1, bool usepwd, uint8_t override, uint32_t password, uint8_t downlink_mode, bool verbose) {
|
||||
|
|
|
@ -187,6 +187,12 @@ int CmdsParse(const command_t Commands[], const char *Cmd) {
|
|||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
if (strcmp(Cmd, "coffee") == 0) {
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(NORMAL, " ((\n ))\n" _YELLOW_(" .______.\n | |]\n \\ /\n `----´\n\n"));
|
||||
return PM3_SUCCESS;
|
||||
}
|
||||
|
||||
char cmd_name[128];
|
||||
memset(cmd_name, 0, sizeof(cmd_name));
|
||||
|
||||
|
|
|
@ -372,7 +372,7 @@ int ecdsa_signature_verify(mbedtls_ecp_group_id curveid, uint8_t *key_xy, uint8_
|
|||
return res;
|
||||
}
|
||||
|
||||
|
||||
// take signature bytes, converts to ASN1 signature and tries to verify
|
||||
int ecdsa_signature_r_s_verify(mbedtls_ecp_group_id curveid, uint8_t *key_xy, uint8_t *input, int length, uint8_t *r_s, size_t r_s_len, bool hash) {
|
||||
int res;
|
||||
uint8_t signature[MBEDTLS_ECDSA_MAX_LEN];
|
||||
|
@ -391,10 +391,8 @@ int ecdsa_signature_r_s_verify(mbedtls_ecp_group_id curveid, uint8_t *key_xy, ui
|
|||
}
|
||||
|
||||
res = ecdsa_signature_verify(curveid, key_xy, input, length, signature, signature_len, hash);
|
||||
|
||||
mbedtls_mpi_free(&r);
|
||||
mbedtls_mpi_free(&s);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
|
@ -1482,6 +1482,7 @@ static int filelist(const char *path, const char *ext, uint8_t last, bool tentat
|
|||
|
||||
char tmp_fullpath[1024] = {0};
|
||||
strncat(tmp_fullpath, path, sizeof(tmp_fullpath) - 1);
|
||||
tmp_fullpath[1023] = 0x00;
|
||||
strncat(tmp_fullpath, namelist[i]->d_name, strlen(tmp_fullpath) - 1);
|
||||
|
||||
if (is_directory(tmp_fullpath)) {
|
||||
|
|
|
@ -535,7 +535,7 @@ int mfnested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBlockNo,
|
|||
free(statelists[1].head.slhead);
|
||||
num_to_bytes(key64, 6, resultKey);
|
||||
|
||||
PrintAndLogEx(SUCCESS, "\ntarget block:%3u key type: %c -- found valid key [" _YELLOW_("%s") "]",
|
||||
PrintAndLogEx(SUCCESS, "\ntarget block:%3u key type: %c -- found valid key [ " _GREEN_("%s") "]",
|
||||
package->block,
|
||||
package->keytype ? 'B' : 'A',
|
||||
sprint_hex(resultKey, 6)
|
||||
|
@ -714,7 +714,7 @@ int mfStaticNested(uint8_t blockNo, uint8_t keyType, uint8_t *key, uint8_t trgBl
|
|||
num_to_bytes(key64, 6, resultKey);
|
||||
|
||||
PrintAndLogEx(NORMAL, "");
|
||||
PrintAndLogEx(SUCCESS, "target block:%3u key type: %c -- found valid key [" _YELLOW_("%s") "]",
|
||||
PrintAndLogEx(SUCCESS, "target block:%3u key type: %c -- found valid key [ " _GREEN_("%s") "]",
|
||||
package->block,
|
||||
package->keytype ? 'B' : 'A',
|
||||
sprint_hex(resultKey, 6)
|
||||
|
@ -959,7 +959,7 @@ int mfGen3UID(uint8_t *uid, uint8_t uidlen, uint8_t *oldUid) {
|
|||
}
|
||||
}
|
||||
|
||||
int mfGen3Blk(uint8_t *block, int blockLen, uint8_t *newBlock) {
|
||||
int mfGen3Block(uint8_t *block, int blockLen, uint8_t *newBlock) {
|
||||
clearCommandBuffer();
|
||||
SendCommandMIX(CMD_HF_MIFARE_GEN3BLK, blockLen, 0, 0, block, 16);
|
||||
PacketResponseNG resp;
|
||||
|
@ -974,7 +974,7 @@ int mfGen3Blk(uint8_t *block, int blockLen, uint8_t *newBlock) {
|
|||
}
|
||||
}
|
||||
|
||||
int mfGen3Freez(void) {
|
||||
int mfGen3Freeze(void) {
|
||||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_HF_MIFARE_GEN3FREEZ, NULL, 0);
|
||||
PacketResponseNG resp;
|
||||
|
@ -1144,19 +1144,14 @@ int detect_classic_static_nonce(void) {
|
|||
clearCommandBuffer();
|
||||
SendCommandNG(CMD_HF_MIFARE_STATIC_NONCE, NULL, 0);
|
||||
PacketResponseNG resp;
|
||||
|
||||
if (WaitForResponseTimeout(CMD_HF_MIFARE_STATIC_NONCE, &resp, 500)) {
|
||||
if (WaitForResponseTimeout(CMD_HF_MIFARE_STATIC_NONCE, &resp, 1000)) {
|
||||
|
||||
if (resp.status == PM3_ESOFT)
|
||||
return 2;
|
||||
return NONCE_FAIL;
|
||||
|
||||
if (resp.data.asBytes[0] == 0)
|
||||
return 0;
|
||||
|
||||
if (resp.data.asBytes[0] != 0)
|
||||
return 1;
|
||||
return resp.data.asBytes[0];
|
||||
}
|
||||
return 2;
|
||||
return NONCE_FAIL;
|
||||
}
|
||||
|
||||
/* try to see if card responses to "chinese magic backdoor" commands. */
|
||||
|
@ -1179,11 +1174,20 @@ int detect_classic_magic(void) {
|
|||
PrintAndLogEx(SUCCESS, "Magic capabilities : " _GREEN_("Gen 1b"));
|
||||
break;
|
||||
case MAGIC_GEN_2:
|
||||
PrintAndLogEx(SUCCESS, "Magic capabilities : " _GREEN_("Gen 2 / CUID"));
|
||||
PrintAndLogEx(SUCCESS, "Magic capabilities : " _GREEN_("Gen 2 / CUID"));
|
||||
break;
|
||||
case MAGIC_GEN_3:
|
||||
PrintAndLogEx(SUCCESS, "Magic capabilities : " _GREEN_("Gen 3 / APDU"));
|
||||
break;
|
||||
case MAGIC_GEN_UNFUSED:
|
||||
PrintAndLogEx(SUCCESS, "Magic capabilities : " _GREEN_("Write Once / FUID"));
|
||||
break;
|
||||
case MAGIC_SUPER:
|
||||
PrintAndLogEx(SUCCESS, "Magic capabilities : " _GREEN_("super card"));
|
||||
break;
|
||||
case MAGIC_NTAG21X:
|
||||
PrintAndLogEx(SUCCESS, "Magic capabilities : " _GREEN_("NTAG21x"));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -81,8 +81,8 @@ int mfCSetBlock(uint8_t blockNo, uint8_t *data, uint8_t *uid, uint8_t params);
|
|||
int mfCGetBlock(uint8_t blockNo, uint8_t *data, uint8_t params);
|
||||
|
||||
int mfGen3UID(uint8_t *uid, uint8_t uidlen, uint8_t *oldUid);
|
||||
int mfGen3Blk(uint8_t *block, int blockLen, uint8_t *newBlock);
|
||||
int mfGen3Freez(void);
|
||||
int mfGen3Block(uint8_t *block, int blockLen, uint8_t *newBlock);
|
||||
int mfGen3Freeze(void);
|
||||
|
||||
int tryDecryptWord(uint32_t nt, uint32_t ar_enc, uint32_t at_enc, uint8_t *data, int len);
|
||||
|
||||
|
|
|
@ -53,6 +53,7 @@ extern bool showDemod;
|
|||
#endif
|
||||
#define MAX_PRINT_BUFFER 2048
|
||||
|
||||
#define PROMPT_CLEARLINE PrintAndLogEx(INPLACE, " \r")
|
||||
void PrintAndLogOptions(const char *str[][2], size_t size, size_t space);
|
||||
void PrintAndLogEx(logLevel_t level, const char *fmt, ...);
|
||||
void SetFlushAfterWrite(bool value);
|
||||
|
|
|
@ -591,7 +591,7 @@ static const cardformat_t FormatTable[] = {
|
|||
{"H10306", Pack_H10306, Unpack_H10306, "HID H10306 34-bit", {1, 1, 0, 0, 1}}, // imported from old pack/unpack
|
||||
{"N10002", Pack_N10002, Unpack_N10002, "HID N10002 34-bit", {1, 1, 0, 0, 1}}, // from cardinfo.barkweb.com.au
|
||||
{"C1k35s", Pack_C1k35s, Unpack_C1k35s, "HID Corporate 1000 35-bit standard layout", {1, 1, 0, 0, 1}}, // imported from old pack/unpack
|
||||
{"C15001", Pack_C15001, Unpack_C15001, "HID KeySpan 36-bit", {1, 1, 0, 1, 1}}, // from Proxmark forums
|
||||
{"C15001", Pack_C15001, Unpack_C15001, "HID KeyScan 36-bit", {1, 1, 0, 1, 1}}, // from Proxmark forums
|
||||
{"S12906", Pack_S12906, Unpack_S12906, "HID Simplex 36-bit", {1, 1, 1, 0, 1}}, // from cardinfo.barkweb.com.au
|
||||
{"Sie36", Pack_Sie36, Unpack_Sie36, "HID 36-bit Siemens", {1, 1, 0, 0, 1}}, // from cardinfo.barkweb.com.au
|
||||
{"H10320", Pack_H10320, Unpack_H10320, "HID H10320 36-bit BCD", {1, 0, 0, 0, 1}}, // from Proxmark forums
|
||||
|
|
63
doc/cloner_notes.md
Normal file
63
doc/cloner_notes.md
Normal file
|
@ -0,0 +1,63 @@
|
|||
# Notes on Cloner gunes
|
||||
|
||||
This document is based mostly on information posted on http://www.proxmark.org/forum/viewtopic.php?pid=39903#p39903
|
||||
|
||||
- [Blue and black cloners](#blue-and-black-cloners)
|
||||
- [White cloner (pre 2015)](#white-cloner-pre-2015)
|
||||
- [White cloner (after 2016)](#white-cloner-after-2016)
|
||||
- [White cloner (after 2016 D Quality)](#white-cloner-after-2016-d-quality)
|
||||
- [restore page1 data](#restore-page1-data)
|
||||
|
||||
|
||||
# Blue and black cloners
|
||||
|
||||
3 variants:
|
||||
1. EM cloner
|
||||
2. HID cloner
|
||||
3. EM/HID cloner
|
||||
|
||||
Quality varies my manufacturer (Quality A (Good) until D (Bad))
|
||||
They set a password on block 7 of the chip and set the password enable bit in block 0
|
||||
```
|
||||
Standard password is normally: 51243648
|
||||
```
|
||||
**Be sure to purchase the EM/HID version**
|
||||
|
||||
# White cloner (pre 2015)
|
||||
|
||||
Multifrequency
|
||||
Buttons light up BLUE
|
||||
Reads data correctly
|
||||
Coil performance acceptable
|
||||
```
|
||||
Standard password is normally (for T55xx): AA55BBBB
|
||||
Standard password 13,56mHz: individual per white cloner
|
||||
```
|
||||
|
||||
|
||||
# White cloner (after 2016)
|
||||
Multifrequency
|
||||
Buttons light up WHITE
|
||||
Data scrambled (variable per individual cloner, possibly due to prevent legal issues)
|
||||
Coil performance good
|
||||
```
|
||||
Standard password is normally (for T55xx): AA55BBBB
|
||||
Standard password 13,56mHz: individual per white cloner
|
||||
```
|
||||
|
||||
|
||||
# White cloner (after 2016 D Quality)
|
||||
Multifrequency (it says so but it doesn't)
|
||||
Only works for EM/HID card (125kHz)
|
||||
High frequency not working
|
||||
```
|
||||
Standard password is normally (for T55xx): AA55BBBB
|
||||
```
|
||||
**Note: Sets the HID card in TEST MODE**
|
||||
|
||||
|
||||
# Restore page1 data
|
||||
```
|
||||
lf t55xx write b 1 d E0150A48 1
|
||||
If t55xx write b 2 d 2D782308 1
|
||||
```
|
844
doc/magic_cards_notes.md
Normal file
844
doc/magic_cards_notes.md
Normal file
|
@ -0,0 +1,844 @@
|
|||
# Notes on Magic Cards, aka UID changeable
|
||||
This document is based mostly on information posted on http://www.proxmark.org/forum/viewtopic.php?pid=35372#p35372
|
||||
|
||||
Useful docs:
|
||||
* [AN10833 MIFARE Type Identification Procedure](https://www.nxp.com/docs/en/application-note/AN10833.pdf)
|
||||
|
||||
- [ISO14443A](#iso14443a)
|
||||
* [Identifying broken ISO14443A magic](#identifying-broken-iso14443a-magic)
|
||||
- [MIFARE Classic](#mifare-classic)
|
||||
* [MIFARE Classic block0](#mifare-classic-block0)
|
||||
* [MIFARE Classic Gen1A aka UID](#mifare-classic-gen1a-aka-uid)
|
||||
* [MIFARE Classic Gen1B](#mifare-classic-gen1b)
|
||||
* [MIFARE Classic DirectWrite aka Gen2 aka CUID](#mifare-classic-directwrite-aka-gen2-aka-cuid)
|
||||
* [MIFARE Classic DirectWrite, FUID version aka 1-write](#mifare-classic-directwrite-fuid-version-aka-1-write)
|
||||
* [MIFARE Classic DirectWrite, UFUID version](#mifare-classic-directwrite-ufuid-version)
|
||||
* [MIFARE Classic, other versions](#mifare-classic-other-versions)
|
||||
* [MIFARE Classic APDU aka Gen3](#mifare-classic-apdu-aka-gen3)
|
||||
* [MIFARE Classic Super](#mifare-classic-super)
|
||||
- [MIFARE Ultralight](#mifare-ultralight)
|
||||
* [MIFARE Ultralight blocks 0..2](#mifare-ultralight-blocks-02)
|
||||
* [MIFARE Ultralight Gen1A](#mifare-ultralight-gen1a)
|
||||
* [MIFARE Ultralight DirectWrite](#mifare-ultralight-directwrite)
|
||||
* [MIFARE Ultralight EV1 DirectWrite](#mifare-ultralight-ev1-directwrite)
|
||||
* [MIFARE Ultralight C Gen1A](#mifare-ultralight-c-gen1a)
|
||||
* [MIFARE Ultralight C DirectWrite](#mifare-ultralight-c-directwrite)
|
||||
- [NTAG](#ntag)
|
||||
* [NTAG213 DirectWrite](#ntag213-directwrite)
|
||||
* [NTAG21x](#ntag21x)
|
||||
- [DESFire](#desfire)
|
||||
* ["DESFire" APDU, 7b UID](#desfire-apdu-7b-uid)
|
||||
* ["DESFire" APDU, 4b UID](#desfire-apdu-4b-uid)
|
||||
- [ISO14443B](#iso14443b)
|
||||
* [ISO14443B magic](#iso14443b-magic)
|
||||
- [ISO15693](#iso15693)
|
||||
* [ISO15693 magic](#iso15693-magic)
|
||||
|
||||
|
||||
# ISO14443A
|
||||
|
||||
## Identifying broken ISO14443A magic
|
||||
|
||||
When a magic card configuration is really messed up and the card is not labeled, it may be hard to find out which type of card it is.
|
||||
|
||||
Here are some tips if the card doesn't react or gives error on a simple `hf 14a reader`:
|
||||
|
||||
Let's force a 4b UID anticollision and see what happens:
|
||||
```
|
||||
hf 14a config a 1 b 2 2 2 r 2
|
||||
hf 14a reader
|
||||
```
|
||||
It it responds, we know it's a TypeA card. But maybe it's a 7b UID, so let's force a 7b UID anticollision:
|
||||
```
|
||||
hf 14a config a 1 b 2 2 1 3 2 r 2
|
||||
hf 14a reader
|
||||
```
|
||||
At this stage, you know if it's a TypeA 4b or 7b card and you can check further on this page how to reconfigure different types of cards.
|
||||
|
||||
To restore anticollision config of the Proxmark3:
|
||||
|
||||
```
|
||||
hf 14a config a 0 b 0 2 0 3 0 r 0
|
||||
```
|
||||
# MIFARE Classic
|
||||
|
||||
Referred as M1, S50 (1k), S70 (4k)
|
||||
|
||||
## MIFARE Classic block0
|
||||
|
||||
UID 4b: (actually NUID as there are no more "unique" IDs on 4b)
|
||||
|
||||
```
|
||||
11223344440804006263646566676869
|
||||
^^^^^^^^ UID
|
||||
^^ BCC
|
||||
^^ SAK(*)
|
||||
^^^^ ATQA
|
||||
^^^^^^^^^^^^^^^^ Manufacturer data
|
||||
(*) some cards have a different SAK in their anticollision and in block0: +0x80 in the block0 (e.g. 08->88, 18->98)
|
||||
```
|
||||
|
||||
|
||||
Computing BCC on UID 11223344: `hf analyse lcr 11223344` = `44`
|
||||
|
||||
UID 7b:
|
||||
|
||||
```
|
||||
04112233445566884400c82000000000
|
||||
^^ Manufacturer byte
|
||||
^^^^^^^^^^^^^^ UID
|
||||
^^ SAK(*)
|
||||
^^^^ ATQA
|
||||
^^^^^^^^^^^^ Manufacturer data
|
||||
(*) all? cards have a different SAK in their anticollision and in block0: +0x80 in the block0 (e.g. 08->88, 18->98)
|
||||
```
|
||||
|
||||
## MIFARE Classic Gen1A aka UID
|
||||
|
||||
### Identify
|
||||
|
||||
```
|
||||
hf 14a info
|
||||
...
|
||||
[+] Magic capabilities : Gen 1a
|
||||
```
|
||||
|
||||
### Magic commands
|
||||
|
||||
* Wipe: `40(7)`, `41` (use 2000ms timeout)
|
||||
* Read: `40(7)`, `43`, `30xx`+crc
|
||||
* Write: `40(7)`, `43`, `A0xx`+crc, `xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`+crc
|
||||
|
||||
### Characteristics
|
||||
|
||||
* UID: Only 4b versions
|
||||
* ATQA:
|
||||
* all cards play blindly the block0 ATQA bytes, beware!
|
||||
* SAK:
|
||||
* some cards play blindly the block0 SAK byte, beware!
|
||||
* some cards use a fix "08" in anticollision, no matter the block0
|
||||
* some cards use a fix "08" in anticollision, unless SAK in block0 has most significant bit "80" set, in which case SAK="88"
|
||||
* BCC:
|
||||
* all cards play blindly the block0 BCC byte, beware!
|
||||
* ATS:
|
||||
* no card with ATS
|
||||
|
||||
#### MIFARE Classic Gen1A flavour 1
|
||||
|
||||
* SAK: play blindly the block0 SAK byte, beware!
|
||||
* PRNG: static 01200145
|
||||
* Wipe: filled with 0xFF
|
||||
|
||||
#### MIFARE Classic Gen1A flavour 2
|
||||
|
||||
* SAK: play blindly the block0 SAK byte, beware!
|
||||
* PRNG: static 01200145
|
||||
* Wipe: filled with 0x00
|
||||
|
||||
#### MIFARE Classic Gen1A flavour 3
|
||||
|
||||
* SAK: 08
|
||||
* PRNG: static 01200145
|
||||
* Wipe: filled with 0xFF
|
||||
|
||||
#### MIFARE Classic Gen1A flavour 4
|
||||
|
||||
* SAK: 08
|
||||
* PRNG: weak
|
||||
* Wipe: timeout, no wipe
|
||||
|
||||
#### MIFARE Classic Gen1A flavour 5
|
||||
|
||||
* SAK: 08
|
||||
* PRNG: weak
|
||||
* Wipe: reply ok but no wipe performed
|
||||
|
||||
#### MIFARE Classic Gen1A flavour 6
|
||||
|
||||
* SAK: 08 or 88 if block0_SAK most significant bit is set
|
||||
* PRNG: weak
|
||||
* Wipe: timeout, no wipe
|
||||
|
||||
#### MIFARE Classic Gen1A flavour 7
|
||||
|
||||
* SAK: 08 or 88 if block0_SAK most significant bit is set
|
||||
* PRNG: weak
|
||||
* Wipe: filled with 0x00
|
||||
|
||||
### Proxmark3 commands
|
||||
|
||||
```
|
||||
hf mf csetuid
|
||||
hf mf cwipe
|
||||
hf mf csetblk
|
||||
hf mf cgetblk
|
||||
hf mf cgetsc
|
||||
hf mf cload
|
||||
hf mf csave
|
||||
hf mf cview
|
||||
```
|
||||
|
||||
When "soft-bricked" (by writing invalid data in block0), these ones may help:
|
||||
|
||||
```
|
||||
# MFC Gen1A 1k:
|
||||
hf mf cwipe -u 11223344 -a 0004 -s 08
|
||||
# MFC Gen1A 4k:
|
||||
hf mf cwipe -u 11223344 -a 0044 -s 18
|
||||
```
|
||||
or just fixing block0:
|
||||
```
|
||||
# MFC Gen1A 1k:
|
||||
hf mf csetuid 11223344 0004 08
|
||||
# MFC Gen1A 4k:
|
||||
hf mf csetuid 11223344 0044 18
|
||||
```
|
||||
|
||||
```
|
||||
script run remagic
|
||||
```
|
||||
|
||||
To execute commands manually:
|
||||
```
|
||||
hf 14a raw -a -p -b 7 40
|
||||
hf 14a raw -p 43
|
||||
hf 14a raw -p -c A000
|
||||
hf 14a raw -c -t 1000 11223344440804006263646566676869
|
||||
```
|
||||
wipe:
|
||||
```
|
||||
hf 14a raw -a -p -b 7 40
|
||||
hf 14a raw -t 1000 41
|
||||
```
|
||||
|
||||
### libnfc commands
|
||||
|
||||
```
|
||||
nfc-mfsetuid
|
||||
nfc-mfclassic R a u mydump
|
||||
nfc-mfclassic W a u mydump
|
||||
```
|
||||
|
||||
## MIFARE Classic Gen1B
|
||||
|
||||
Similar to Gen1A, but supports directly read/write after command 40
|
||||
|
||||
### Identify
|
||||
|
||||
```
|
||||
hf 14a info
|
||||
...
|
||||
[+] Magic capabilities : Gen 1b
|
||||
```
|
||||
|
||||
### Magic commands
|
||||
|
||||
* Read: `40(7)`, `30xx`
|
||||
* Write: `40(7)`, `A0xx`+crc, `xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx`+crc
|
||||
|
||||
## MIFARE Classic DirectWrite aka Gen2 aka CUID
|
||||
|
||||
### Identify
|
||||
|
||||
```
|
||||
hf 14a info
|
||||
...
|
||||
[+] Magic capabilities : Gen 2 / CUID
|
||||
```
|
||||
|
||||
Not all Gen2 cards can be identified with `hf 14a info`, only those replying to RATS.
|
||||
|
||||
To identify the other ones, you've to try to write to block0 and see if it works...
|
||||
|
||||
### Magic commands
|
||||
|
||||
Android compatible
|
||||
|
||||
* issue regular write to block0
|
||||
|
||||
### Characteristics
|
||||
|
||||
* UID: 4b and 7b versions
|
||||
* ATQA:
|
||||
* some cards play blindly the block0 ATQA bytes, beware!
|
||||
* some cards use a fix ATQA in anticollision, no matter the block0. Including all 7b.
|
||||
* SAK:
|
||||
* some cards play blindly the block0 SAK byte, beware!
|
||||
* some cards use a fix "08" or "18" in anticollision, no matter the block0. Including all 7b.
|
||||
* BCC:
|
||||
* some cards play blindly the block0 BCC byte, beware!
|
||||
* some cards compute a proper BCC in anticollision. Including all 7b comuting their BCC0 and BCC1.
|
||||
* ATS:
|
||||
* some cards don't reply to RATS
|
||||
* some reply with an ATS
|
||||
|
||||
#### MIFARE Classic DirectWrite flavour 1
|
||||
|
||||
* UID 4b
|
||||
* ATQA: play blindly the block0 ATQA bytes, beware!
|
||||
* SAK: play blindly the block0 SAK byte, beware!
|
||||
* BCC: play blindly the block0 BCC byte, beware!
|
||||
* ATS: no
|
||||
* PRNG: weak
|
||||
|
||||
#### MIFARE Classic DirectWrite flavour 2
|
||||
|
||||
* UID 4b
|
||||
* ATQA: fixed
|
||||
* SAK: fixed
|
||||
* BCC: computed
|
||||
* ATS: 0978009102DABC1910F005
|
||||
* PRNG: weak
|
||||
|
||||
#### MIFARE Classic DirectWrite flavour 3
|
||||
|
||||
* UID 4b
|
||||
* ATQA: play blindly the block0 ATQA bytes, beware!
|
||||
* SAK: fixed
|
||||
* BCC: play blindly the block0 BCC byte, beware!
|
||||
* ATS: no
|
||||
* PRNG: weak
|
||||
|
||||
#### MIFARE Classic DirectWrite flavour 4
|
||||
|
||||
* UID 7b
|
||||
* ATQA: fixed
|
||||
* SAK: fixed
|
||||
* BCC: computed
|
||||
* ATS: 0978009102DABC1910F005
|
||||
* PRNG: static 00000000
|
||||
|
||||
#### MIFARE Classic DirectWrite flavour 5
|
||||
|
||||
* UID 4b
|
||||
* ATQA: fixed
|
||||
* SAK: play blindly the block0 SAK byte, beware!
|
||||
* BCC: computed
|
||||
* ATS: no
|
||||
* PRNG: weak
|
||||
|
||||
#### MIFARE Classic DirectWrite flavour 6
|
||||
|
||||
**TODO** need more info
|
||||
|
||||
* UID 7b
|
||||
* ATS: 0D780071028849A13020150608563D
|
||||
|
||||
### Proxmark3 commands
|
||||
|
||||
```
|
||||
hf mf wrbl 0 A FFFFFFFFFFFF 11223344440804006263646566676869
|
||||
```
|
||||
|
||||
When "soft-bricked" (by writing invalid data in block0), these ones may help:
|
||||
|
||||
```
|
||||
hf 14a config h
|
||||
```
|
||||
|
||||
e.g. for 4b UID:
|
||||
|
||||
```
|
||||
hf 14a config a 1 b 2 2 2 r 2
|
||||
hf mf wrbl 0 A FFFFFFFFFFFF 11223344440804006263646566676869 # for 1k
|
||||
hf mf wrbl 0 A FFFFFFFFFFFF 11223344441802006263646566676869 # for 4k
|
||||
hf 14a config a 0 b 0 2 0 r 0
|
||||
hf 14a reader
|
||||
```
|
||||
|
||||
e.g. for 7b UID:
|
||||
|
||||
```
|
||||
hf 14a config a 1 b 2 2 1 3 2 r 2
|
||||
hf mf wrbl 0 A FFFFFFFFFFFF 04112233445566084400626364656667 # for 1k
|
||||
hf mf wrbl 0 A FFFFFFFFFFFF 04112233445566184200626364656667 # for 4k
|
||||
hf 14a config a 0 b 0 2 0 3 0 r 0
|
||||
hf 14a reader
|
||||
```
|
||||
## MIFARE Classic DirectWrite, FUID version aka 1-write
|
||||
|
||||
Same as MIFARE Classic DirectWrite, but block0 can be written only once.
|
||||
|
||||
Initial UID is AA55C396
|
||||
|
||||
### Identify
|
||||
|
||||
Only possible before personalisation.
|
||||
|
||||
```
|
||||
hf 14a info
|
||||
...
|
||||
[+] Magic capabilities : Write Once / FUID
|
||||
```
|
||||
|
||||
## MIFARE Classic DirectWrite, UFUID version
|
||||
|
||||
Same as MIFARE Classic DirectWrite, but block0 can be locked with special command.
|
||||
|
||||
### Identify
|
||||
|
||||
**TODO**
|
||||
|
||||
### Proxmark3 commands
|
||||
|
||||
To lock definitively block0:
|
||||
```
|
||||
hf 14a raw -a -p -b 7 40
|
||||
hf 14a raw -p 43
|
||||
hf 14a raw -p -c e000
|
||||
hf 14a raw -c 85000000000000000000000000000008
|
||||
```
|
||||
|
||||
## MIFARE Classic, other versions
|
||||
|
||||
**TODO**
|
||||
|
||||
* ZXUID, EUID, ICUID ?
|
||||
* Some cards exhibit a specific SAK=28 ??
|
||||
|
||||
## MIFARE Classic APDU aka Gen3
|
||||
|
||||
### Identify
|
||||
|
||||
```
|
||||
hf 14a info
|
||||
...
|
||||
[+] Magic capabilities : Gen 3 / APDU
|
||||
```
|
||||
|
||||
### Magic commands
|
||||
|
||||
Android compatible
|
||||
|
||||
* issue special APDUs
|
||||
|
||||
```
|
||||
cla ins p1 p2 len
|
||||
90 F0 CC CC 10 <block0> - write block 0
|
||||
90 FB CC CC 07 <uid> - change uid (independently of block0 data)
|
||||
90 FD 11 11 00 - lock permanently
|
||||
```
|
||||
It seems the length byte gets ignored anyway.
|
||||
|
||||
Note: it seems some cards only accept the "change UID" command.
|
||||
|
||||
It accepts direct read of block0 (and only block0) without prior auth.
|
||||
|
||||
### Characteristics
|
||||
|
||||
* UID: 4b and 7b versions
|
||||
* ATQA/SAK: fixed
|
||||
* BCC: auto
|
||||
* ATS: none
|
||||
|
||||
### Proxmark3 commands
|
||||
|
||||
```
|
||||
# change just UID:
|
||||
hf mf gen3uid
|
||||
# write block0:
|
||||
hf mf gen3blk
|
||||
# lock (uid/block0?) forever:
|
||||
hf mf gen3freeze
|
||||
```
|
||||
See also
|
||||
```
|
||||
script run mfc_gen3_writer -h
|
||||
```
|
||||
|
||||
Equivalent:
|
||||
```
|
||||
# change just UID:
|
||||
hf 14a raw -s -c -t 2000 90FBCCCC07 11223344556677
|
||||
# write block0:
|
||||
hf 14a raw -s -c -t 2000 90F0CCCC10 041219c3219316984200e32000000000
|
||||
# lock (uid/block0?) forever:
|
||||
hf 14a raw -s -c 90FD111100
|
||||
```
|
||||
|
||||
## MIFARE Classic Super
|
||||
|
||||
It behaves like DirectWrite but records reader auth attempts.
|
||||
|
||||
To change UID: same commands as for MFC DirectWrite
|
||||
|
||||
To do reader-only attack: at least two versions exist.
|
||||
|
||||
* type 1: https://github.com/nfc-tools/nfc-supercard for card with ATS: 0978009102DABC1910F005
|
||||
* type 2: https://github.com/netscylla/super-card/blob/master/libnfc-1.7.1/utils/nfc-super.c for ??
|
||||
|
||||
### Identify
|
||||
|
||||
Only type 1 at the moment:
|
||||
|
||||
```
|
||||
hf 14a info
|
||||
...
|
||||
[+] Magic capabilities : super card
|
||||
```
|
||||
|
||||
# MIFARE Ultralight
|
||||
|
||||
## MIFARE Ultralight blocks 0..2
|
||||
|
||||
```
|
||||
SN0 SN1 SN2 BCC0
|
||||
SN3 SN4 SN5 SN6
|
||||
BCC1 Int LCK0 LCK1
|
||||
```
|
||||
|
||||
UID is made of SN0..SN6 bytes
|
||||
|
||||
Computing BCC0 on UID 04112233445566: `analyse lcr 88041122` = `bf`
|
||||
|
||||
Computing BCC1 on UID 04112233445566: `analyse lcr 33445566` = `44`
|
||||
|
||||
Int is internal, typically 0x48
|
||||
|
||||
## MIFARE Ultralight Gen1A
|
||||
|
||||
### Identify
|
||||
|
||||
**TODO**
|
||||
|
||||
### Characteristics
|
||||
|
||||
#### Magic commands
|
||||
|
||||
**TODO**
|
||||
|
||||
#### UID
|
||||
|
||||
Only 7b versions
|
||||
|
||||
#### SAK, ATQA, BCC, ATS
|
||||
|
||||
**TODO** need more tests
|
||||
|
||||
### Proxmark3 commands
|
||||
|
||||
```
|
||||
script run ul_uid -h
|
||||
```
|
||||
|
||||
When "soft-bricked" (by writing invalid data in block0), these ones may help:
|
||||
|
||||
```
|
||||
hf 14a config h
|
||||
script run remagic -u
|
||||
```
|
||||
|
||||
## MIFARE Ultralight DirectWrite
|
||||
|
||||
### Identify
|
||||
|
||||
```
|
||||
hf 14a info
|
||||
...
|
||||
[+] Magic capabilities : Gen 2 / CUID
|
||||
```
|
||||
|
||||
It seems so far that all MFUL DW have an ATS.
|
||||
|
||||
### Magic commands
|
||||
|
||||
Issue three regular MFU write commands in a row to write first three blocks.
|
||||
|
||||
### Characteristics
|
||||
|
||||
* UID: Only 7b versions
|
||||
* ATQA:
|
||||
* all cards play fix ATQA
|
||||
* SAK:
|
||||
* all cards play fix SAK
|
||||
* BCC:
|
||||
* some cards play blindly the block0 BCC0 and block2 BCC1 bytes, beware!
|
||||
* some cards compute proper BCC0 and BCC1 in anticollision
|
||||
* ATS:
|
||||
* all cards reply with an ATS
|
||||
|
||||
#### MIFARE Ultralight DirectWrite flavour 1
|
||||
|
||||
* BCC: computed
|
||||
* ATS: 0A78008102DBA0C119402AB5
|
||||
|
||||
#### MIFARE Ultralight DirectWrite flavour 2
|
||||
|
||||
* BCC: play blindly the block0 BCC0 and block2 BCC1 bytes, beware!
|
||||
* ATS: 850000A00A000AB00000000000000000184D
|
||||
|
||||
### Proxmark3 commands
|
||||
|
||||
```
|
||||
hf mfu setuid
|
||||
```
|
||||
|
||||
Equivalent: don't use `hf mfu wrbl` as you need to write three blocks in a row, but do, with proper BCCx:
|
||||
|
||||
```
|
||||
hf 14a raw -s -c -p a2 00 041122bf
|
||||
hf 14a raw -c -p a2 01 33445566
|
||||
hf 14a raw -c a2 02 44480000
|
||||
```
|
||||
|
||||
When "soft-bricked" (by writing invalid data in block0), these ones may help:
|
||||
|
||||
```
|
||||
hf 14a config h
|
||||
```
|
||||
|
||||
E.g.:
|
||||
```
|
||||
hf 14a config a 1 b 2 2 1 3 2 r 2
|
||||
hf mfu setuid 04112233445566
|
||||
hf 14a config a 0 b 0 2 0 3 0 r 0
|
||||
hf 14a reader
|
||||
```
|
||||
|
||||
### libnfc commands
|
||||
|
||||
```
|
||||
nfc-mfultralight -h
|
||||
```
|
||||
See `--uid` and `--full`
|
||||
|
||||
### Android
|
||||
|
||||
* MIFARE++ Ultralight
|
||||
|
||||
## MIFARE Ultralight EV1 DirectWrite
|
||||
|
||||
Similar to MFUL DirectWrite
|
||||
|
||||
### Identify
|
||||
|
||||
```
|
||||
hf 14a info
|
||||
...
|
||||
[+] Magic capabilities : Gen 2 / CUID
|
||||
```
|
||||
|
||||
### Characteristics
|
||||
|
||||
* UID: Only 7b versions
|
||||
* ATQA:
|
||||
* all cards play fix ATQA
|
||||
* SAK:
|
||||
* all cards play fix SAK
|
||||
* BCC:
|
||||
* cards play blindly the block0 BCC0 and block2 BCC1 bytes, beware!
|
||||
* ATS:
|
||||
* all cards reply with an ATS
|
||||
|
||||
#### MIFARE Ultralight EV1 DirectWrite flavour 1
|
||||
|
||||
* BCC: play blindly the block0 BCC0 and block2 BCC1 bytes, beware!
|
||||
* ATS: 850000A000000AC30004030101000B0341DF
|
||||
|
||||
#### MIFARE Ultralight EV1 DirectWrite flavour 2
|
||||
|
||||
* BCC: play blindly the block0 BCC0 and block2 BCC1 bytes, beware!
|
||||
* ATS: 850000A00A000AC30004030101000B0316D7
|
||||
|
||||
## MIFARE Ultralight C Gen1A
|
||||
|
||||
Similar to MFUL Gen1A
|
||||
|
||||
## MIFARE Ultralight C DirectWrite
|
||||
|
||||
Similar to MFUL DirectWrite
|
||||
|
||||
### Identify
|
||||
|
||||
```
|
||||
hf 14a info
|
||||
...
|
||||
[+] Magic capabilities : Gen 2 / CUID
|
||||
```
|
||||
|
||||
### Characteristics
|
||||
|
||||
* UID: Only 7b versions
|
||||
* ATQA:
|
||||
* all cards play fix ATQA
|
||||
* SAK:
|
||||
* all cards play fix SAK
|
||||
* BCC:
|
||||
* cards compute proper BCC0 and BCC1 in anticollision
|
||||
* ATS:
|
||||
* all cards reply with an ATS
|
||||
|
||||
#### MIFARE Ultralight C DirectWrite flavour 1
|
||||
|
||||
* BCC: computed
|
||||
* ATS: 0A78008102DBA0C119402AB5
|
||||
|
||||
# NTAG
|
||||
|
||||
## NTAG213 DirectWrite
|
||||
|
||||
Similar to MFUL DirectWrite
|
||||
|
||||
### Identify
|
||||
|
||||
```
|
||||
hf 14a info
|
||||
...
|
||||
[+] Magic capabilities : Gen 2 / CUID
|
||||
```
|
||||
|
||||
### Characteristics
|
||||
|
||||
* UID: Only 7b versions
|
||||
* ATQA:
|
||||
* all cards play fix ATQA
|
||||
* SAK:
|
||||
* all cards play fix SAK
|
||||
* BCC:
|
||||
* cards play blindly the block0 BCC0 and block2 BCC1 bytes, beware!
|
||||
* ATS:
|
||||
* all cards reply with an ATS
|
||||
|
||||
#### NTAG213 DirectWrite flavour 1
|
||||
|
||||
* BCC: play blindly the block0 BCC0 and block2 BCC1 bytes, beware!
|
||||
* ATS: 0A78008102DBA0C119402AB5
|
||||
|
||||
## NTAG21x
|
||||
|
||||
### Identify
|
||||
|
||||
```
|
||||
hf 14a info
|
||||
...
|
||||
[+] Magic capabilities : NTAG21x
|
||||
```
|
||||
|
||||
### Characteristics
|
||||
|
||||
Emulates fully NTAG213, 213F, 215, 216, 216F
|
||||
|
||||
Emulates partially UL EV1 48k/128k, NTAG210, NTAG212, NTAGI2C 1K/2K, NTAGI2C 1K/2K PLUS
|
||||
|
||||
### Proxmark3 commands
|
||||
|
||||
```
|
||||
script run mfu_magic -h
|
||||
```
|
||||
|
||||
# DESFire
|
||||
|
||||
## "DESFire" APDU, 7b UID
|
||||
|
||||
### Identify
|
||||
|
||||
**TODO**
|
||||
|
||||
### Magic commands
|
||||
|
||||
Android compatible
|
||||
|
||||
* issue special APDUs
|
||||
|
||||
### Characteristics
|
||||
|
||||
* ATQA: 0344
|
||||
* SAK: 20
|
||||
* ATS: 0675338102005110 or 06757781028002F0
|
||||
|
||||
Only mimics DESFire anticollision (but wrong ATS), no further DESFire support
|
||||
|
||||
### Proxmark commands
|
||||
|
||||
UID 04112233445566
|
||||
```
|
||||
hf 14a raw -s -c 0200ab00000704112233445566
|
||||
```
|
||||
or equivalently
|
||||
```
|
||||
hf 14a apdu -s 00ab00000704112233445566
|
||||
```
|
||||
|
||||
### libnfc commands
|
||||
|
||||
```
|
||||
pn53x-tamashell
|
||||
4a0100
|
||||
420200ab00000704112233445566
|
||||
```
|
||||
## "DESFire" APDU, 4b UID
|
||||
|
||||
### Magic commands
|
||||
|
||||
Android compatible
|
||||
|
||||
* issue special APDUs
|
||||
|
||||
### Characteristics
|
||||
|
||||
* ATQA: 0008 ??? This is not DESFire, 0008/20 doesn't match anything
|
||||
* SAK: 20
|
||||
* ATS: 0675338102005110 or 06757781028002F0
|
||||
|
||||
Only mimics DESFire anticollision (but wrong ATS), no further DESFire support
|
||||
|
||||
### Proxmark commands
|
||||
|
||||
UID 04112233445566
|
||||
```
|
||||
hf 14a raw -s -c 0200ab00000411223344
|
||||
```
|
||||
or equivalently
|
||||
```
|
||||
hf 14a apdu -s 00ab00000411223344
|
||||
```
|
||||
|
||||
It accepts longer UID but that doesn't affect BCC/ATQA/SAK
|
||||
|
||||
### pn53x-tamashell commands
|
||||
```
|
||||
4a0100
|
||||
420200ab00000411223344
|
||||
```
|
||||
|
||||
### Remarks
|
||||
|
||||
The same effect (with better ATQA!) can be obtained with a MFC Gen1A that uses SAK defined in block0:
|
||||
|
||||
```
|
||||
hf mf csetblk 0 1122334444204403A1A2A3A4A5A6A7A8
|
||||
hf 14a info
|
||||
[+] UID: 11 22 33 44
|
||||
[+] ATQA: 03 44
|
||||
[+] SAK: 20 [1]
|
||||
[+] Possible types:
|
||||
[+] MIFARE DESFire MF3ICD40
|
||||
```
|
||||
|
||||
# ISO14443B
|
||||
|
||||
## ISO14443B magic
|
||||
|
||||
No such card is available.
|
||||
|
||||
Some vendor allow to specify an ID (PUPI) when ordering a card.
|
||||
|
||||
# ISO15693
|
||||
|
||||
## ISO15693 magic
|
||||
|
||||
### Identify
|
||||
|
||||
**TODO**
|
||||
|
||||
### Proxmark3 commands
|
||||
|
||||
Always set a UID starting with `E0`.
|
||||
|
||||
```
|
||||
hf 15 csetuid E011223344556677
|
||||
```
|
||||
or (ignore errors):
|
||||
```
|
||||
script run iso15_magic -u E004013344556677
|
||||
```
|
|
@ -17,12 +17,10 @@ There are two ways to install, build and use Proxmark3 on Windows:
|
|||
Install required drivers for your Windows installation. You may need admin privileges to do this.
|
||||
Step by step guides are online such as [RyscCorps](https://store.ryscc.com/blogs/news/how-to-install-a-proxmark3-driver-on-windows-10).
|
||||
|
||||
## Download / clone ProxSpace repo
|
||||
## Download ProxSpace repo
|
||||
|
||||
Download the Gator96100 ProxSpace package from https://github.com/Gator96100/ProxSpace/releases
|
||||
|
||||
If you prefer, you can clone it, provided that you installed Github for Windows https://desktop.github.com/.
|
||||
|
||||
Extract 'ProxSpace' to a location path without spaces.
|
||||
For example D:\OneDrive\Documents\GitHub is ok whereas C:\My Documents\My Projects\proxspace is not.
|
||||
|
||||
|
@ -30,7 +28,7 @@ If you're running Windows in a Virtualbox guest, make sure not to install ProxSp
|
|||
|
||||
## Launch ProxSpace
|
||||
|
||||
Run `runme.bat` or `runme64.bat` depending on your Windows architecture.
|
||||
Run `runme64.bat`.
|
||||
|
||||
You'll get a Bash prompt and your home directory should become the ProxSpace `pm3` sub-directory.
|
||||
|
||||
|
@ -76,8 +74,15 @@ If you want to run the graphical components of the Proxmark3 client, you need to
|
|||
|
||||
Enter WSL prompt (`wsl`) and from there, follow the [Linux Installation Instructions](/doc/md/Installation_Instructions/Linux-Installation-Instructions.md) for Ubuntu, summarized here below:
|
||||
|
||||
Make sure your WSL guest OS is up-to-date first
|
||||
```sh
|
||||
sudo apt-get update
|
||||
sudo apt-get upgrade -y
|
||||
sudo apt-get auto-remove -y
|
||||
```
|
||||
|
||||
Install dependencies
|
||||
```sh
|
||||
sudo apt-get install --no-install-recommends git ca-certificates build-essential pkg-config \
|
||||
libreadline-dev gcc-arm-none-eabi libnewlib-dev libbz2-dev qtbase5-dev
|
||||
```
|
||||
|
|
|
@ -24,6 +24,13 @@ git pull
|
|||
make clean && make all
|
||||
```
|
||||
|
||||
### if you got an error
|
||||
Read the [troubleshooting guide](/doc/md/Installation_Instructions/Troubleshooting.md),
|
||||
|
||||
For instance, on WSl-1 you usually get the _libQt5Core.so.5 not found_ message
|
||||
[solution](/doc/md/Installation_Instructions/Troubleshooting.md#libQt5Coreso5-not-found)
|
||||
|
||||
|
||||
## Install
|
||||
|
||||
This is an optional step. If you do
|
||||
|
|
|
@ -710,6 +710,11 @@ typedef struct {
|
|||
#define MODE_EXIT_AFTER_MAC 1
|
||||
#define MODE_FULLSIM 2
|
||||
|
||||
// Static Nonce detection
|
||||
#define NONCE_FAIL 0x01
|
||||
#define NONCE_NORMAL 0x02
|
||||
#define NONCE_STATIC 0x03
|
||||
|
||||
// Dbprintf flags
|
||||
#define FLAG_RAWPRINT 0x00
|
||||
#define FLAG_LOG 0x01
|
||||
|
|
|
@ -215,10 +215,13 @@ ISO 7816-4 Basic interindustry commands. For command APDU's.
|
|||
#define MAGIC_SINGLE (MAGIC_WUPC | MAGIC_HALT | MAGIC_INIT | MAGIC_OFF) //0x1E
|
||||
|
||||
// by CMD_HF_MIFARE_CIDENT
|
||||
#define MAGIC_GEN_1A 1
|
||||
#define MAGIC_GEN_1B 2
|
||||
#define MAGIC_GEN_2 4
|
||||
#define MAGIC_GEN_UNFUSED 5
|
||||
#define MAGIC_GEN_1A 1
|
||||
#define MAGIC_GEN_1B 2
|
||||
#define MAGIC_GEN_2 4
|
||||
#define MAGIC_GEN_UNFUSED 5
|
||||
#define MAGIC_SUPER 6
|
||||
#define MAGIC_NTAG21X 7
|
||||
#define MAGIC_GEN_3 8
|
||||
/**
|
||||
06 00 = INITIATE
|
||||
0E xx = SELECT ID (xx = Chip-ID)
|
||||
|
|
|
@ -348,7 +348,9 @@ while true; do
|
|||
if ! CheckExecute "lf VIKING test" "$CLIENTBIN -c 'data load traces/Transit999-best.pm3;lf search 1'" "Viking ID found"; then break; fi
|
||||
if ! CheckExecute "lf FDX-B test" "$CLIENTBIN -c 'data load traces/homeagain1600.pm3;lf search 1'" "FDX-B ID found"; then break; fi
|
||||
if ! CheckExecute "lf INDALA test" "$CLIENTBIN -c 'data load traces/indala-504278295.pm3;lf search 1'" "Indala ID found"; then break; fi
|
||||
if ! CheckExecute "lf FDX/BioThermo test" "$CLIENTBIN -c 'data load traces/lf_fdx_biothermo.pm3; lf fdx demo'" "95.2 F / 35.1 C"; then break; fi
|
||||
if ! CheckExecute "lf FDX/BioThermo test" "$CLIENTBIN -c 'data load traces/lf_fdx_biothermo.pm3; lf fdx demod'" "95.2 F / 35.1 C"; then break; fi
|
||||
if ! CheckExecute "lf GPROXII test" "$CLIENTBIN -c 'data load traces/lf_gprox_36_30_14489.pm3; lf search 1'" "Guardall G-Prox II ID found"; then break; fi
|
||||
if ! CheckExecute "lf IDTECK test" "$CLIENTBIN -c 'data load traces/lf_idteck_4944544BAC40E069.pm3; lf search 1'" "Idteck ID found"; then break; fi
|
||||
|
||||
echo -e "\n${C_BLUE}Testing HF:${C_NC}"
|
||||
if ! CheckExecute "hf mf offline text" "$CLIENTBIN -c 'hf mf'" "at_enc"; then break; fi
|
||||
|
|
|
@ -13,6 +13,8 @@ indala-504278295.pm3: PSK 26 bit indala
|
|||
homeagain.pm3: HomeAgain animal (cat) tag - ID 985121004515220
|
||||
homeagain1600.pm3: HomeAgain animal (cat) tag - ID 985121004515220
|
||||
keri.pm3: Keri PSK-3 Key Ring tag (back of tag: 1460 3411)
|
||||
lf_gprox_36_30_14489.pm3: G-Prox-II FC: 30 Card: 3949, Format 36b ASK/BIPHASE
|
||||
lf_idteck_4944544BAC40E069.pm3: IDTECK raw 4944544BAC40E069 , PSK
|
||||
Transit999-best.pm3: Transit 999 format (UID 99531670)
|
||||
ATA5577-HIDemu-FC1-C9.pm3: ata5577 in hid prox 26 bit emulation facility code:1 card#:9
|
||||
AWID-15-259.pm3: AWID FSK RF/50 FC: 15 Card: 259
|
||||
|
|
39999
traces/lf_gprox_36_30_14489.pm3
Normal file
39999
traces/lf_gprox_36_30_14489.pm3
Normal file
File diff suppressed because it is too large
Load diff
30000
traces/lf_idteck_4944544BAC40E069.pm3
Normal file
30000
traces/lf_idteck_4944544BAC40E069.pm3
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue