diff --git a/.gitignore b/.gitignore index db6ff9138..081c0f8e8 100644 --- a/.gitignore +++ b/.gitignore @@ -32,6 +32,7 @@ version.c *.swp *.json.bak *.pyc +*.bmp # new build file for add-ons. Makefile.platform diff --git a/CHANGELOG.md b/CHANGELOG.md index d95130493..b07ce95dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,8 @@ 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 options to `lf read` and `lf cmdread` (@doegox) + - Add lf t55xx sniff to allow extracting commands and passwords used be cloners. (@mwalker33) + - Add options to `lf read`, `lf cmdread`, `lf sniff` for repeated acquisitions (@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) diff --git a/README.md b/README.md index 287648038..3155f8093 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,9 @@ -| Releases | Linux & OSX CI | Windows CI | Coverity | -| ------------------- |:-------------------:| -------------------:| -------------------:| -| [![Latest release](https://img.shields.io/github/v/release/rfidresearchgroup/proxmark3)](https://github.com/RfidResearchGroup/proxmark3/releases/latest) | [![Build status](https://api.travis-ci.org/RfidResearchGroup/proxmark3.svg?branch=master)](https://travis-ci.org/RfidResearchGroup/proxmark3) | [![Build status](https://ci.appveyor.com/api/projects/status/b4gwrhq3nc876cuu/branch/master?svg=true)](https://ci.appveyor.com/project/RfidResearchGroup/proxmark3/branch/master) | [![Coverity Status](https://scan.coverity.com/projects/19334/badge.svg)](https://scan.coverity.com/projects/proxmark3-rrg-iceman-repo)| +| Releases | Linux & OSX CI | Windows CI | Coverity | Contributors | +| ------------------- |:-------------------:| -------------------:| -------------------:| -------------------:| +| [![Latest release](https://img.shields.io/github/v/release/rfidresearchgroup/proxmark3)](https://github.com/RfidResearchGroup/proxmark3/releases/latest) | [![Build status](https://api.travis-ci.org/RfidResearchGroup/proxmark3.svg?branch=master)](https://travis-ci.org/RfidResearchGroup/proxmark3) | [![Build status](https://ci.appveyor.com/api/projects/status/b4gwrhq3nc876cuu/branch/master?svg=true)](https://ci.appveyor.com/project/RfidResearchGroup/proxmark3/branch/master) | [![Coverity Status](https://scan.coverity.com/projects/19334/badge.svg)](https://scan.coverity.com/projects/proxmark3-rrg-iceman-repo)| ![GitHub contributors](https://img.shields.io/github/contributors/rfidresearchgroup/proxmark3) | @@ -57,14 +57,14 @@ On the software side: quite a lot, see the [Changelog file](CHANGELOG.md). This repo compiles nicely on - Proxspace v3.x - - [latest release v3.5](https://github.com/Gator96100/ProxSpace/releases) + - [latest release v3.6](https://github.com/Gator96100/ProxSpace/releases) - Windows/mingw environment with Qt5.6.1 & GCC 4.9 - - Ubuntu 1604 -> 2004 + - Ubuntu 16.04 -> 20.04 - ParrotOS, Gentoo, Pentoo, Kali, Nethunter, Archlinux, Fedora, Debian - Rasbian - Android / Termux - Mac OS X / Homebrew - - WSL, WSL2 (Windows subsystem linux) on Windows 10 + - WSL1 (Windows subsystem linux) on Windows 10 - Docker container - [ RRG / Iceman repo based ubuntu 18.04 container ](https://hub.docker.com/r/secopsconsult/proxmark3) - [ Iceman fork based container v1.7 ](https://hub.docker.com/r/iceman1001/proxmark3/) @@ -73,7 +73,7 @@ Hardware to run client on - PC - Android - Raspberry Pi & Raspberry Pi Zero - - Jetson Nano + - Nvidia Jetson Nano ## Precompiled binaries We don't maintain any precompiled binaries in this repo. There is community effort over at the Proxmark3 forum where @gator96100 has set up a google drive with many mingw binaries which is up-to-date. We link to these files here as to make it easier for users. @@ -81,14 +81,15 @@ If you are having troubles with these files, contact the package maintainer @gat Ref: - +For Proxmark3 RDV4 - [Precompiled builds for RDV40 dedicated x86](https://drive.google.com/open?id=13zUs-aiQkYaSl5KWrBtuW5IWCoHJPsue) - [Precompiled builds for RDV40 dedicated x64](https://drive.google.com/open?id=1SyPB8t5Vo8O0Lh7PjNm3Kv-mO4BNbxjX) +For Proxmark3 RDV4 with blueshark addon - [Precompiled builds for RDV40 dedicated with Bluetooth addon x86](https://drive.google.com/open?id=1TqWYctkRvkLshQ1ZRBHPLDzYHR-asuMO) - [Precompiled builds for RDV40 dedicated with Bluetooth addon x64](https://drive.google.com/open?id=17ful7u2QyYmMQzQzc5fAf8nJvyoDJfSL) -Generice Proxmark3 devices (non RDV4) +Generice Proxmark3 devices (non RDV4), for Proxmark3 Easy, RDV1, RDV2, RDV3, etc etc - [Precompiled builds for RRG / Iceman repository x86](https://drive.google.com/open?id=1PI3Xr1mussPBPnYGu4ZjWzGPARK4N7JR) - [Precompiled builds for RRG / Iceman repository x64](https://drive.google.com/open?id=1uX9RtYGinuFrpHybu4xq_BE3HrobI20e) @@ -101,11 +102,12 @@ We usually merge your contributions fast since we do like the idea of getting a ## Issues & Troubleshooting -Please search the [issues](https://github.com/rfidresearchgroup/proxmark3/issues) page here and see if your issue is listed in the first instance. Next place to visit is the [Proxmark Forum](http://www.proxmark.org/forum/index.php). Learn to search it well and finally Google / duckduckgo is your friend :) You will find many blogposts, youtube videos, tweets, reddit - +Please search the [issues](https://github.com/rfidresearchgroup/proxmark3/issues) page here and see if your issue is listed in the first instance. Read the [Troubleshooting](/doc/md/Installation_Instructions/Troubleshooting.md) guide to weed out most known problems. -Offical channels +Next place to visit is the [Proxmark Forum](http://www.proxmark.org/forum/index.php). Learn to search it well and finally Google / duckduckgo is your friend :) You will find many blogposts, youtube videos, tweets, reddit + +### Offical channels - [Proxmark3 IRC channel](http://webchat.freenode.net/?channels=#proxmark3) - [Proxmark3 sub reddit](https://www.reddit.com/r/proxmark3/) - [Twitter](https://twitter.com/proxmark3/) @@ -131,7 +133,7 @@ The separation from official Proxmark3 repo gives us a lot of freedom to create ## Proxmark3 GUI The official PM3-GUI from Gaucho will not work. -The new universal GUI will work. [Proxmark3 Universal GUI](https://github.com/burma69/PM3UniversalGUI) Almost, change needed in order to show helptext when client isn't connected to a device. +The new [Proxmark3 Universal GUI](https://github.com/burma69/PM3UniversalGUI) will work more or less. Change is needed in order to show helptext when client isn't connected to a device. We don't know how active the maintainers. ## The end diff --git a/appveyor.yml b/appveyor.yml index 328796653..d5ef4ac7f 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,6 +7,7 @@ environment: proxspace_zip_folder_name: ProxSpace-* proxspace_path: \ProxSpace proxspace_home_path: \ProxSpace\pm3 + wsl_git_path: C:\proxmark init: - ps: >- @@ -34,14 +35,15 @@ 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""""" + Write-Host "$Text" + Start-Process "cmd.exe" "/c ""cd /D $env:proxspace_path && runme64.bat -c ""exit""""" $StartTime=[System.Environment]::TickCount Start-Sleep -s 10 while($true) { $cmdprocess = Get-Process "cmd" -ErrorAction SilentlyContinue if (!$cmdprocess -Or $cmdprocess.HasExited) { + Write-Host "$Text" -NoNewLine Write-Host "[ OK ]" -ForegroundColor Green break } @@ -51,30 +53,67 @@ clone_script: $tmp = $cmdprocess.CloseMainWindow() Start-Sleep -s 5 Stop-Process -Name "cmd" -Force -ErrorAction SilentlyContinue + Write-Host "$Text" -NoNewLine Write-Host "Exit by pacman.conf" -ForegroundColor Green break } if ([System.Environment]::TickCount-$StartTime -gt 1000000) { + Write-Host "$Text" -NoNewLine Write-host "Exit by timeout" -ForegroundColor Yellow break } - Start-Sleep -s 1 + Start-Sleep -s 5 + Receive-Job -Job $WSLjob } } - Write-Host "Removing ProxSpace..." -NoNewLine + $WSLjob = Start-Job -Name WSLInstall -ScriptBlock { + Function WSLExec($Text, $Cmd) { + Write-Host "$Text" + wsl -- bash -c $Cmd + Write-Host "$Text" -NoNewLine + Write-Host "[ OK ]" -ForegroundColor Green + } - $CloneTime=[System.Environment]::TickCount + $WSLInstallTime=[System.Environment]::TickCount + WSLExec "WSL update..." "sudo apt-get update 1>/dev/null" + WSLExec "WSL upgrade..." "sudo apt-get upgrade -y 1>/dev/null" + WSLExec "WSL cleanup..." "sudo apt-get auto-remove -y 1>/dev/null" + WSLExec "WSL install..." "sudo apt-get -y install --reinstall --no-install-recommends git ca-certificates build-essential pkg-config libreadline-dev gcc-arm-none-eabi libnewlib-dev libbz2-dev qtbase5-dev cmake 1>/dev/null" + WSLExec "WSL QT fix..." "sudo strip --remove-section=.note.ABI-tag /usr/lib/x86_64-linux-gnu/libQt5Core.so.5" + Add-AppveyorMessage -Message "WSL setup took $(([System.Environment]::TickCount-$WSLInstallTime) / 1000) sec" -Category Information + } + + Function GitClone($Text, $Folder) { + Write-Host "$Text" -NoNewLine + if(-not $env:appveyor_pull_request_number) { + git clone -q --branch=$env:appveyor_repo_branch https://github.com/$env:appveyor_repo_name.git $Folder + cd $Folder + git checkout -qf $env:appveyor_repo_commit + } else { + git clone -q https://github.com/$env:appveyor_repo_name.git $Folder + cd $Folder + git fetch -q origin +refs/pull/$env:appveyor_pull_request_number/merge: + git checkout -qf FETCH_HEAD + } + Write-Host "[ OK ]" -ForegroundColor Green + } + + Write-Host "ProxSpace: Removing folder..." -NoNewLine + + $PSInstallTime=[System.Environment]::TickCount cd \ Remove-Item -Recurse -Force -Path $env:proxspace_path Write-Host "[ OK ]" -ForegroundColor Green + + Receive-Job -Job $WSLjob - Write-Host "Download ProxSpace..." -NoNewLine + Write-Host "ProxSpace: downloading..." -NoNewLine [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 @@ -82,7 +121,9 @@ clone_script: Write-Host "[ OK ]" -ForegroundColor Green - Write-Host "Extracting ProxSpace..." -NoNewLine + Receive-Job -Job $WSLjob + + Write-Host "ProxSpace: extracting..." -NoNewLine Expand-Archive -LiteralPath "$env:proxspace_zip_file" -DestinationPath "\" @@ -90,37 +131,30 @@ clone_script: Write-Host "[ OK ]" -ForegroundColor Green - Write-Host "Renaming ProxSpace folder..." -NoNewLine + Receive-Job -Job $WSLjob + + Write-Host "ProxSpace: renaming folder..." -NoNewLine Get-ChildItem -Path "\$env:proxspace_zip_folder_name" | Rename-Item -NewName (Split-Path $env:proxspace_path -Leaf) Write-Host "[ OK ]" -ForegroundColor Gree - ExecUpdate "Initial msys2 startup..." $true + ExecUpdate "ProxSpace: initial msys2 startup..." $true - ExecUpdate "Installing required packages..." $false + ExecUpdate "ProxSpace: installing required packages..." $false $psversion = (Select-String -Pattern 'PSVERSION=' -SimpleMatch -Path "$env:proxspace_path\msys2\ps\09-proxspace_setup.post").Line.Split("""")[1] Write-Host "ProxSpace version: $psversion" -ForegroundColor Yellow - Write-Host "Cloning repository <$env:appveyor_repo_name> to $env:appveyor_build_folder ..." -NoNewLine - - if(-not $env:appveyor_pull_request_number) { - git clone -q --branch=$env:appveyor_repo_branch https://github.com/$env:appveyor_repo_name.git $env:appveyor_build_folder - cd $env:appveyor_build_folder - git checkout -qf $env:appveyor_repo_commit - } else { - git clone -q https://github.com/$env:appveyor_repo_name.git $env:appveyor_build_folder - cd $env:appveyor_build_folder - git fetch -q origin +refs/pull/$env:appveyor_pull_request_number/merge: - git checkout -qf FETCH_HEAD - } + Add-AppveyorMessage -Message "ProxSpace download and update took $(([System.Environment]::TickCount-$PSInstallTime) / 1000) sec" -Category Information - Write-Host "[ OK ]" -ForegroundColor Green + GitClone "ProxSpace: Cloning repository <$env:appveyor_repo_name> to $env:appveyor_build_folder ..." $env:appveyor_build_folder - Add-AppveyorMessage -Message "ProxSpace download and update took $(([System.Environment]::TickCount-$CloneTime) / 1000) sec" -Category Information + Receive-Job -Wait -Job $WSLjob + + GitClone "WSL: Cloning repository <$env:appveyor_repo_name> to $env:wsl_git_path ..." $env:wsl_git_path install: @@ -131,90 +165,119 @@ build_script: Function ExecMinGWCmd($Cmd) { cd $env:proxspace_path - msys2\msys2_shell.cmd -mingw64 -defterm -no-start -c "cd $pmfolder && $Cmd" + ./runme64.bat -c "cd $pmfolder && $Cmd" } - - Write-Host "---------- make ----------" -ForegroundColor Yellow + Function ExecCheck($Name) { + $testspass = ($LASTEXITCODE -eq 0) + + $global:TestsPassed=$testspass + + if ($testspass) { + Add-AppveyorTest -Name $Name -Framework NUnit -Filename $Name -Outcome Passed -Duration "$([System.Environment]::TickCount-$TestTime)" + Write-Host "$Name [ OK ]" -ForegroundColor Green + } else { + Add-AppveyorTest -Name $Name -Framework NUnit -Filename $Name -Outcome Failed -Duration "$([System.Environment]::TickCount-$TestTime)" + Write-Host "$Name [ ERROR ]" -ForegroundColor Red + throw "Tests error." + } + } + + $WSLjob = Start-Job -Name WSLCompile -ScriptBlock { + Function ExecWSLCmd($Cmd) { + wsl -- bash -c $Cmd + } + + Function ExecCheck($Name) { + $testspass = ($LASTEXITCODE -eq 0) + + $global:TestsPassed=$testspass + + if ($testspass) { + Add-AppveyorTest -Name $Name -Framework NUnit -Filename $Name -Outcome Passed -Duration "$([System.Environment]::TickCount-$TestTime)" + Write-Host "$Name [ OK ]" -ForegroundColor Green + } else { + Add-AppveyorTest -Name $Name -Framework NUnit -Filename $Name -Outcome Failed -Duration "$([System.Environment]::TickCount-$TestTime)" + Write-Host "$Name [ ERROR ]" -ForegroundColor Red + throw "Tests error." + } + } + + #Windows Subsystem for Linux (WSL) + Write-Host "---------- WSL make ----------" -ForegroundColor Yellow + cd $env:wsl_git_path + $TestTime=[System.Environment]::TickCount + ExecWSLCmd "make clean;make V=1" + #some checks + if(!(Test-Path "$env:wsl_git_path\client\proxmark3")){ + throw "Main file proxmark3 not exists." + } + + ExecWSLCmd "make check" + ExecCheck "WSL make Tests" + Start-Sleep -s 2 + Write-Host "---------- WSL btaddon ----------" -ForegroundColor Yellow + $TestTime=[System.Environment]::TickCount + ExecWSLCmd "make clean;make V=1 PLATFORM_EXTRAS=BTADDON" + ExecWSLCmd "make check" + ExecCheck "WSL BTaddon Tests" + Start-Sleep -s 2 + Write-Host "---------- WSL make clean ----------" -ForegroundColor Yellow + ExecWSLCmd 'make clean' + Write-Host "---------- WSL cmake ----------" -ForegroundColor Yellow + $TestTime=[System.Environment]::TickCount + ExecWSLCmd 'mkdir -p client/build; cd client/build; cmake ..; make VERBOSE=1;' + Write-Host "---------- WSL cmake tests ----------" -ForegroundColor Yellow + ExecWSLCmd './tools/pm3_tests.sh --clientbin client/build/proxmark3 client' + ExecCheck "WSL cmake Tests" + } + + #ProxSpace + + Write-Host "---------- PS make ----------" -ForegroundColor Yellow $TestTime=[System.Environment]::TickCount - #make - - cd $env:proxspace_path - - msys2\ps\setup.cmd - ExecMinGWCmd "make clean;make V=1" - #some checks - if(!(Test-Path "$env:proxspace_home_path\$pmfolder\client\proxmark3.exe")){ - throw "Main file proxmark3.exe not exists." + throw "Main file proxmark3.exe not exists." } ExecMinGWCmd 'make check' - $testspass = ($LASTEXITCODE -eq 0) + ExecCheck "PS make Tests" - $global:TestsPassed=$testspass - - if ($testspass) { - Add-AppveyorTest -Name "make Tests" -Framework NUnit -Filename "make check" -Outcome Passed -Duration "$([System.Environment]::TickCount-$TestTime)" - Write-Host "make Tests [ OK ]" -ForegroundColor Green - } else { - Add-AppveyorTest -Name "make Tests" -Framework NUnit -Filename "make check" -Outcome Failed -Duration "$([System.Environment]::TickCount-$TestTime)" - Write-Host "make Tests [ ERROR ]" -ForegroundColor Red - throw "Tests error." - } - - Write-Host "---------- btaddon ----------" -ForegroundColor Yellow + Write-Host "---------- PS btaddon ----------" -ForegroundColor Yellow $TestTime=[System.Environment]::TickCount ExecMinGWCmd 'make clean;make V=1 PLATFORM_EXTRAS=BTADDON' ExecMinGWCmd 'make check' - - $testspass = ($LASTEXITCODE -eq 0) - - $global:TestsPassed=(($global:TestsPassed) -and ($testspass)) - if ($testspass) { - Add-AppveyorTest -Name "BTaddon Tests" -Framework NUnit -Filename "make check" -Outcome Passed -Duration "$([System.Environment]::TickCount-$TestTime)" - Write-Host "BTaddon Tests [ OK ]" -ForegroundColor Green - } else { - Add-AppveyorTest -Name "BTaddon Tests" -Framework NUnit -Filename "make check" -Outcome Failed -Duration "$([System.Environment]::TickCount-$TestTime)" - Write-Host "BTaddon Tests [ ERROR ]" -ForegroundColor Red - } + ExecCheck "PS BTaddon Tests" - Write-Host "---------- make clean ----------" -ForegroundColor Yellow + Write-Host "---------- PS make clean ----------" -ForegroundColor Yellow ExecMinGWCmd 'make clean' - Write-Host "---------- cmake ----------" -ForegroundColor Yellow + Write-Host "---------- PS cmake ----------" -ForegroundColor Yellow $TestTime=[System.Environment]::TickCount ExecMinGWCmd 'mkdir -p client/build; cd client/build; cmake -G""MSYS Makefiles"" ..; make VERBOSE=1;' - Write-Host "---------- cmake tests ----------" -ForegroundColor Yellow + Write-Host "---------- PS cmake tests ----------" -ForegroundColor Yellow ExecMinGWCmd './tools/pm3_tests.sh --clientbin client/build/proxmark3.exe client' - $testspass = ($LASTEXITCODE -eq 0) - - $global:TestsPassed=(($global:TestsPassed) -and ($testspass)) + ExecCheck "PS cmake Tests" - if ($testspass) { - Add-AppveyorTest -Name "cmake Tests" -Framework NUnit -Filename "make client/check" -Outcome Passed -Duration "$([System.Environment]::TickCount-$TestTime)" - Write-Host "cmake Tests [ OK ]" -ForegroundColor Green - } else { - Add-AppveyorTest -Name "cmake Tests" -Framework NUnit -Filename "make client/check" -Outcome Failed -Duration "$([System.Environment]::TickCount-$TestTime)" - Write-Host "cmake Tests [ ERROR ]" -ForegroundColor Red - } + Receive-Job -Wait -Job $WSLjob + test_script: - ps: >- diff --git a/armsrc/Standalone/hf_aveful.c b/armsrc/Standalone/hf_aveful.c index a619459f5..9a56be82c 100644 --- a/armsrc/Standalone/hf_aveful.c +++ b/armsrc/Standalone/hf_aveful.c @@ -11,8 +11,15 @@ // Several parts of this code is based on code by Craig Young from HF_YOUNG // This code does not: -// - Account for cards with authentication (MFU EV1 etc) -// - Determine if cards have block count that's not the same as the BLOCKS def +// - Account for cards with non-default keys on authentication (MFU EV1 etc) + +// This code is designed to work with: +// - MIFARE Ultralight +// - MIFARE Ultralight EV1 (default keys) +// - MIFARE Ultralight Nano (untested, but should work) +// - Infineon My-d Move (without password set) +// - Infineon My-d Move Lean +// - Any other Ultralight clones that have no auth and MAX_DEFAULT_BLOCKS (16) blocks #include "standalone.h" // standalone definitions #include "proxmark3_arm.h" @@ -22,10 +29,11 @@ #include "dbprint.h" #include "ticks.h" // SpinDelay +#include "protocols.h" // MIFARE_ULEV1_VERSION, MIFARE_ULEV1_READSIG, MIFARE_ULEV1_READ_CNT, MIFARE_ULEV1_CHECKTEAR +#include // memcmp #include "mifareutil.h" #include "iso14443a.h" -#define BLOCKS 16 #define SAK 0x00 #define ATQA0 0x44 #define ATQA1 0x00 @@ -34,6 +42,15 @@ #define STATE_READ 1 #define STATE_EMUL 2 +// Taken from cmdhfmfu.c, increased by 01h to be 1 indexed +#define MAX_UL_BLOCKS 0x10 +#define MAX_UL_NANO_40 0x0B +#define MAX_ULEV1a_BLOCKS 0x14 +#define MAX_ULEV1b_BLOCKS 0x29 +#define MAX_MY_D_MOVE 0x26 +#define MAX_MY_D_MOVE_LEAN 0x10 +#define MAX_DEFAULT_BLOCKS 0x10 + typedef struct { uint8_t uid[10]; uint8_t uidlen; @@ -41,6 +58,70 @@ typedef struct { uint8_t sak; } PACKED card_clone_t; +int get_block_count(iso14a_card_select_t card, uint8_t version[], uint16_t version_len); +uint16_t get_ev1_version(iso14a_card_select_t card, uint8_t *version); +uint16_t get_ev1_signature(iso14a_card_select_t card, uint8_t *signature); +uint16_t get_ev1_counter(iso14a_card_select_t card, uint8_t counter, uint8_t *response); +uint16_t get_ev1_tearing(iso14a_card_select_t card, uint8_t counter, uint8_t *response); + +uint16_t get_ev1_version(iso14a_card_select_t card, uint8_t *version) { + return mifare_sendcmd(MIFARE_ULEV1_VERSION, NULL, 0, version, NULL, NULL); +} + +uint16_t get_ev1_signature(iso14a_card_select_t card, uint8_t *response) { + uint8_t cmd[4] = {MIFARE_ULEV1_READSIG, 0x00, 0x00, 0x00}; + AddCrc14A(cmd, 2); + ReaderTransmit(cmd, sizeof(cmd), NULL); + return ReaderReceive(response, NULL); +} + +uint16_t get_ev1_counter(iso14a_card_select_t card, uint8_t counter, uint8_t *response) { + uint8_t cmd[4] = {MIFARE_ULEV1_READ_CNT, counter, 0x00, 0x00}; + AddCrc14A(cmd, 2); + ReaderTransmit(cmd, sizeof(cmd), NULL); + return ReaderReceive(response, NULL); +} + +uint16_t get_ev1_tearing(iso14a_card_select_t card, uint8_t counter, uint8_t *response) { + uint8_t cmd[4] = {MIFARE_ULEV1_CHECKTEAR, counter, 0x00, 0x00}; + AddCrc14A(cmd, 2); + ReaderTransmit(cmd, sizeof(cmd), NULL); + return ReaderReceive(response, NULL); +} + +int get_block_count(iso14a_card_select_t card, uint8_t version[], uint16_t version_len) { + // Default to MAX_DEFAULT_BLOCKS blocks + int block_count = MAX_DEFAULT_BLOCKS; + // Most of this code is from cmdhfmfu.c + // Infineon manufacturer ID + if (card.uid[0] == 0x05) { + // Infinition MY-D tests Exam high nibble + uint8_t nib = (card.uid[1] & 0xf0) >> 4; + switch (nib) { + case 3: + block_count = MAX_MY_D_MOVE; + break; // or SLE 66R01P // 38 pages of 4 bytes + case 7: + block_count = MAX_MY_D_MOVE_LEAN; + break; // or SLE 66R01L // 16 pages of 4 bytes + } + } else { + // Moved this from case to if as I only care about non-ultralight ev0. + if (version_len == 0x0A) { + if (memcmp(version, "\x00\x04\x03\x01\x01\x00\x0B", 7) == 0) { block_count = MAX_ULEV1a_BLOCKS; } + else if (memcmp(version, "\x00\x04\x03\x01\x02\x00\x0B", 7) == 0) { block_count = MAX_UL_NANO_40; } + else if (memcmp(version, "\x00\x04\x03\x02\x01\x00\x0B", 7) == 0) { block_count = MAX_ULEV1a_BLOCKS; } + else if (memcmp(version, "\x00\x04\x03\x01\x01\x00\x0E", 7) == 0) { block_count = MAX_ULEV1b_BLOCKS; } + else if (memcmp(version, "\x00\x04\x03\x02\x01\x00\x0E", 7) == 0) { block_count = MAX_ULEV1b_BLOCKS; } + else if (memcmp(version, "\x00\x34\x21\x01\x01\x00\x0E", 7) == 0) { block_count = MAX_ULEV1b_BLOCKS; } // Mikron JSC Russia EV1 41 pages tag + else if (memcmp(version, "\x00\x34\x21\x01\x01\x00\x0E", 7) == 0) { block_count = MAX_UL_BLOCKS; } + else if (version[2] == 0x03) { block_count = MAX_ULEV1a_BLOCKS; } + } + } + + return block_count; +} + void ModInfo(void) { DbpString(" HF Mifare Ultralight read/simulation by Ave Ozkal"); } @@ -88,33 +169,77 @@ void RunMod(void) { iso14443a_setup(FPGA_HF_ISO14443A_READER_LISTEN); iso14443a_select_card(NULL, NULL, NULL, true, 0, true); bool read_successful = true; + + // Get version and re-select card as UL EV0s like to shut off after a 0x60 + uint8_t version[10] = {0x00}; + uint16_t version_len = 0; + version_len = get_ev1_version(card, version); + iso14443a_select_card(NULL, NULL, NULL, true, 0, true); + + int block_count = get_block_count(card, version, version_len); + Dbprintf("Card was determined as having %d blocks.", block_count); Dbprintf("Contents:"); - for (int i = 0; i < BLOCKS; i++) { - uint8_t dataout[4] = {0x00}; + for (int i = 0; i < block_count; i++) { + uint8_t dataout[16] = {0x00}; if (mifare_ultra_readblock(i, dataout)) { // If there's an error reading, go back to search state read_successful = false; break; } - // We're skipping 14 blocks (56 bytes) here, as that "[...] has version/signature/counter data here" according to comments on dumptoemul-mfu + // We're skipping 14 blocks (56 bytes) here, as that "[...] has version/signature/counter data here" according to comments on hf_mfu_dumptoemulator // When converting a bin, it's almost all 0 other than one 0x0F byte, and functionality seems to be unaffected if that byte is set to 0x00. emlSetMem_xt(dataout, 14 + i, 1, 4); Dbhexdump(4, dataout, 0); } + // It's not the best way to determine this, + // but with what I'm trying to support It Should Be Okay + bool is_ev1 = (version_len != 0) && (block_count != 16); + if (read_successful) { + uint8_t signature[34] = {0x00}; + if (is_ev1) { + get_ev1_signature(card, signature); + } + Dbprintf("Preparing emulator memory with:"); + // Fill first 14 blocks with 0x00 (see comment above) + for (int i = 0; i < 14; i++) { + uint8_t dataout[4] = {0x00, 0x00, 0x00, 0x00}; + + if (is_ev1 && (i == 0 || i == 1)) { + // On block 0 and 1, set version on EV1 + memcpy(dataout, version + (i * 4), 4); + } else if (i == 2) { + // On block 2, set last byte to the card's block count + dataout[3] = block_count; + } else if (is_ev1 && ((i > 2 && i < 11))) { + // On 3-10 add signature on EV1 + memcpy(dataout, signature + ((i - 3) * 4), 4); + } else if (is_ev1 && (i > 10)) { + // On 11-14 read and set counter and tearing on EV1 + uint8_t counter[5]; + uint8_t tearing[3]; + get_ev1_counter(card, i - 11, counter); + get_ev1_tearing(card, i - 11, tearing); + memcpy(dataout, counter, 3); + memcpy(dataout + 3, tearing, 1); + } + + Dbhexdump(4, dataout, 0); + emlSetMem_xt(dataout, i, 1, 4); + } Dbprintf("Successfully loaded into emulator memory..."); state = STATE_EMUL; } else { Dbprintf("Read failure, going back to search state."); state = STATE_SEARCH; } - } else if (state == 2) { + } else if (state == STATE_EMUL) { uint8_t flags = FLAG_7B_UID_IN_DATA; Dbprintf("Starting simulation, press pm3-button to stop and go back to search state."); - SimulateIso14443aTag(2, flags, card.uid); + SimulateIso14443aTag(7, flags, card.uid); // Go back to search state if user presses pm3-button state = STATE_SEARCH; diff --git a/armsrc/Standalone/hf_bog.c b/armsrc/Standalone/hf_bog.c index 50e1d824f..1d766aa52 100644 --- a/armsrc/Standalone/hf_bog.c +++ b/armsrc/Standalone/hf_bog.c @@ -15,7 +15,7 @@ The retrieved sniffing session can be acquired by connecting the device to a client that supports the reconnect capability and issue 'hf 14a list'. In order to view the grabbed authentication attempts in the flash mem, -you can simply run 'script run read_pwd_mem' or just 'mem dump p l 256' +you can simply run 'script run mem_readpwd' or just 'mem dump p l 256' from the client to view the stored quadlets. */ @@ -249,5 +249,5 @@ void RunMod(void) { LEDsoff(); SpinDelay(300); Dbprintf("- [ End ] -> You can take shell back ..."); - Dbprintf("- [ ! ] -> use 'script run read_pwd_mem_spiffs' to print passwords"); + Dbprintf("- [ ! ] -> use 'script run data_read_pwd_mem_spiffs' to print passwords"); } diff --git a/armsrc/appmain.c b/armsrc/appmain.c index 0fc9dd63d..42161d738 100644 --- a/armsrc/appmain.c +++ b/armsrc/appmain.c @@ -770,18 +770,29 @@ static void PacketReceived(PacketCommandNG *packet) { case CMD_LF_MOD_THEN_ACQ_RAW_ADC: { struct p { uint32_t delay; - uint16_t ones; - uint16_t zeros; + uint16_t period_0; + uint16_t period_1; + uint8_t symbol_extra[LF_CMDREAD_MAX_EXTRA_SYMBOLS]; + uint16_t period_extra[LF_CMDREAD_MAX_EXTRA_SYMBOLS]; 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 + sizeof(struct p), payload->verbose, payload->samples); + uint8_t symbol_extra[LF_CMDREAD_MAX_EXTRA_SYMBOLS]; + uint16_t period_extra[LF_CMDREAD_MAX_EXTRA_SYMBOLS]; + memcpy(symbol_extra, payload->symbol_extra, sizeof(symbol_extra)); + memcpy(period_extra, payload->period_extra, sizeof(period_extra)); + ModThenAcquireRawAdcSamples125k(payload->delay, payload->period_0, payload->period_1, symbol_extra, period_extra, packet->data.asBytes + sizeof(struct p), payload->verbose, payload->samples); break; } case CMD_LF_SNIFF_RAW_ADC: { - uint32_t bits = SniffLF(); - reply_mix(CMD_ACK, bits, 0, 0, 0, 0); + struct p { + uint32_t samples : 31; + bool verbose : 1; + } PACKED; + struct p *payload = (struct p *)packet->data.asBytes; + uint32_t bits = SniffLF(payload->verbose, payload->samples); + reply_ng(CMD_LF_SNIFF_RAW_ADC, PM3_SUCCESS, (uint8_t *)&bits, sizeof(bits)); break; } case CMD_LF_HID_WATCH: { @@ -1344,7 +1355,8 @@ static void PacketReceived(PacketCommandNG *packet) { break; } case CMD_HF_MIFARE_CIDENT: { - MifareCIdent(); + bool is_mfc = packet->data.asBytes[0]; + MifareCIdent(is_mfc); break; } // Gen 3 magic cards diff --git a/armsrc/hitag2.c b/armsrc/hitag2.c index eab276bad..a35fade72 100644 --- a/armsrc/hitag2.c +++ b/armsrc/hitag2.c @@ -130,6 +130,8 @@ static int hitag2_init(void) { #define HITAG_T_WAIT_2_MIN 90 /* T_wait2 should be at least 90 */ #define HITAG_T_WAIT_MAX 300 /* bit more than HITAG_T_WAIT_1 + HITAG_T_WAIT_2 */ #define HITAG_T_PROG 614 +#define HITAG_T_WAIT_POWERUP 313 /* transponder internal powerup time is 312.5 */ +#define HITAG_T_WAIT_START_AUTH_MAX 232 /* transponder waiting time to receive the START_AUTH command is 232.5, then it enters public mode */ #define HITAG_T_TAG_ONE_HALF_PERIOD 10 #define HITAG_T_TAG_TWO_HALF_PERIOD 25 @@ -1431,13 +1433,14 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) { // init as reader lf_init(true, false); + FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); uint8_t tag_modulation; size_t max_nrzs = (8 * HITAG_FRAME_LEN + 5) * 2; // up to 2 nrzs per bit uint8_t nrz_samples[max_nrzs]; + bool turn_on = true; size_t nrzs = 0; int16_t checked = 0; - uint32_t signal_size = 10000; while (bStop == false && BUTTON_PRESS() == false) { @@ -1487,6 +1490,7 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) { } case RHT2F_UID_ONLY: { bStop = !hitag2_read_uid(rx, rxlen, tx, &txlen); + if (bSuccessful) bStop = true; attempt_count++; //attempt 3 times to get uid then quit if (!bStop && attempt_count == 3) bStop = true; @@ -1498,11 +1502,20 @@ void ReaderHitag(hitag_function htf, hitag_data *htd) { goto out; } } - - // Wait for t_wait_2 carrier periods after the last tag bit before transmitting, - lf_wait_periods(t_wait_2); - command_start += t_wait_2; - + if (bStop) break; + if (turn_on) { + // Wait 50ms with field off to be sure the transponder gets reset + SpinDelay(50); + FpgaWriteConfWord(FPGA_MAJOR_MODE_LF_ADC | FPGA_LF_ADC_READER_FIELD); + turn_on = false; + // Wait with field on to be in "Wait for START_AUTH" timeframe + lf_wait_periods(HITAG_T_WAIT_POWERUP + HITAG_T_WAIT_START_AUTH_MAX / 4); + command_start += HITAG_T_WAIT_POWERUP + HITAG_T_WAIT_START_AUTH_MAX / 4; + } else { + // Wait for t_wait_2 carrier periods after the last tag bit before transmitting, + lf_wait_periods(t_wait_2); + command_start += t_wait_2; + } // Transmit the reader frame command_duration = hitag_reader_send_frame(tx, txlen); response_start = command_start + command_duration; diff --git a/armsrc/lfops.c b/armsrc/lfops.c index 8c4b1e454..324f8ae0e 100644 --- a/armsrc/lfops.c +++ b/armsrc/lfops.c @@ -383,13 +383,15 @@ 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, bool verbose, uint32_t samples) { +void ModThenAcquireRawAdcSamples125k(uint32_t delay_off, uint16_t period_0, uint16_t period_1, uint8_t *symbol_extra, uint16_t *period_extra, uint8_t *command, bool verbose, uint32_t samples) { FpgaDownloadAndGo(FPGA_BITSTREAM_LF); // use lf config settings sample_config *sc = getSamplingConfig(); + LFSetupFPGAForADC(sc->divisor, true); + // this causes the field to turn on for uncontrolled amount of time, so we'll turn it off // Make sure the tag is reset FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); @@ -402,15 +404,14 @@ void ModThenAcquireRawAdcSamples125k(uint32_t delay_off, uint32_t period_0, uint // clear read buffer BigBuf_Clear_keep_EM(); - LFSetupFPGAForADC(sc->divisor, true); - - // little more time for the tag to fully power up - WaitMS(20); - // if delay_off = 0 then just bitbang 1 = antenna on 0 = off for respective periods. bool bitbang = (delay_off == 0); // now modulate the reader field + + // Some tags need to be interrogated very soon after activation else they enter their emulation mode + // Therefore it's up to the caller to add an initial symbol of adequate duration, except for bitbang mode. if (bitbang) { + TurnReadLFOn(20000); // HACK it appears the loop and if statements take up about 7us so adjust waits accordingly... uint8_t hack_cnt = 7; if (period_0 < hack_cnt || period_1 < hack_cnt) { @@ -459,11 +460,19 @@ void ModThenAcquireRawAdcSamples125k(uint32_t delay_off, uint32_t period_0, uint } else { // old mode of cmd read using delay as off period while (*command != '\0' && *command != ' ') { LED_D_ON(); - if (*(command++) == '0') + if (*command == '0') { TurnReadLFOn(period_0); - else + } else if (*command == '1') { TurnReadLFOn(period_1); - + } else { + for (uint8_t i=0; i < LF_CMDREAD_MAX_EXTRA_SYMBOLS; i++) { + if (*command == symbol_extra[i]) { + TurnReadLFOn(period_extra[i]); + break; + } + } + } + command++; LED_D_OFF(); FpgaWriteConfWord(FPGA_MAJOR_MODE_OFF); WaitUS(delay_off); diff --git a/armsrc/lfops.h b/armsrc/lfops.h index 17c79ef61..0ac8066af 100644 --- a/armsrc/lfops.h +++ b/armsrc/lfops.h @@ -15,7 +15,7 @@ #include "pm3_cmd.h" // struct -void ModThenAcquireRawAdcSamples125k(uint32_t delay_off, uint32_t period_0, uint32_t period_1, uint8_t *command, bool verbose, uint32_t samples); +void ModThenAcquireRawAdcSamples125k(uint32_t delay_off, uint16_t period_0, uint16_t period_1, uint8_t *symbol_extra, uint16_t *period_extra, uint8_t *command, bool verbose, uint32_t samples); void ReadTItag(void); void WriteTItag(uint32_t idhi, uint32_t idlo, uint16_t crc); diff --git a/armsrc/lfsampling.c b/armsrc/lfsampling.c index 91bde7569..7b38bd346 100644 --- a/armsrc/lfsampling.c +++ b/armsrc/lfsampling.c @@ -243,8 +243,11 @@ void LFSetupFPGAForADC(int divisor, bool reader_field) { StartTicks(); // 50ms for the resonant antenna to settle. - if (reader_field) + if (reader_field) { WaitMS(50); + } else { + WaitMS(1); + } } /** @@ -397,9 +400,9 @@ uint32_t SampleLF(bool verbose, uint32_t sample_size) { * Initializes the FPGA for sniffer-mode (field off), and acquires the samples. * @return number of bits sampled **/ -uint32_t SniffLF(void) { +uint32_t SniffLF(bool verbose, uint32_t sample_size) { BigBuf_Clear_ext(false); - return ReadLF(false, true, 0); + return ReadLF(false, verbose, sample_size); } /** diff --git a/armsrc/lfsampling.h b/armsrc/lfsampling.h index f60324d70..d10f8279e 100644 --- a/armsrc/lfsampling.h +++ b/armsrc/lfsampling.h @@ -40,7 +40,7 @@ uint32_t SampleLF(bool verbose, uint32_t sample_size); * Initializes the FPGA for sniff-mode (field off), and acquires the samples. * @return number of bits sampled **/ -uint32_t SniffLF(void); +uint32_t SniffLF(bool verbose, uint32_t sample_size); uint32_t DoAcquisition(uint8_t decimation, uint8_t bits_per_sample, bool avg, int16_t trigger_threshold, bool verbose, uint32_t sample_size, uint32_t cancel_after, int32_t samples_to_skip); diff --git a/armsrc/mifarecmd.c b/armsrc/mifarecmd.c index 53e33ff38..76cbea5c1 100644 --- a/armsrc/mifarecmd.c +++ b/armsrc/mifarecmd.c @@ -1978,15 +1978,15 @@ int MifareECardLoad(uint8_t sectorcnt, uint8_t keytype) { uint64_t ui64Key = emlGetKey(sectorNo, keytype); if (sectorNo == 0) { if (mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keytype, ui64Key, AUTH_FIRST)) { - retval = PM3_ESOFT; + retval = PM3_EPARTIAL; if (DBGLEVEL > DBG_ERROR) Dbprintf("Sector[%2d]. Auth error", sectorNo); - goto out; + continue; } } else { if (mifare_classic_auth(pcs, cuid, FirstBlockOfSector(sectorNo), keytype, ui64Key, AUTH_NESTED)) { - retval = PM3_ESOFT; + retval = PM3_EPARTIAL; if (DBGLEVEL > DBG_ERROR) Dbprintf("Sector[%2d]. Auth nested error", sectorNo); - goto out; + continue; } } @@ -2236,14 +2236,14 @@ void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint8_t *datain) { OnSuccessMagic(); } -void MifareCIdent(void) { +void MifareCIdent(bool is_mfc) { // variables uint8_t isGen = 0; 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 rdblf0[4] = { ISO14443A_CMD_READBLOCK, 0xF0, 0x8D, 0x5f}; + uint8_t rdbl00[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); @@ -2323,29 +2323,32 @@ void MifareCIdent(void) { 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; + if (! is_mfc) { + // 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(rdblf0, sizeof(rdblf0), 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; + if (is_mfc) { + // 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(rdbl00, sizeof(rdbl00), NULL); + res = ReaderReceive(buf, par); + if (res == 18) { + isGen = MAGIC_GEN_3; + } } } }; diff --git a/armsrc/mifarecmd.h b/armsrc/mifarecmd.h index b024d2d1b..58cec9b49 100644 --- a/armsrc/mifarecmd.h +++ b/armsrc/mifarecmd.h @@ -41,7 +41,7 @@ int MifareECardLoadExt(uint8_t sectorcnt, uint8_t keytype); void MifareCSetBlock(uint32_t arg0, uint32_t arg1, uint8_t *datain); // Work with "magic Chinese" card void MifareCGetBlock(uint32_t arg0, uint32_t arg1, uint8_t *datain); -void MifareCIdent(void); // is "magic chinese" card? +void MifareCIdent(bool is_mfc); // is "magic chinese" card? void MifareHasStaticNonce(void); // Has the tag a static nonce? int DoGen3Cmd(uint8_t *cmd, uint8_t cmd_len); diff --git a/armsrc/usart.h b/armsrc/usart.h index 5a7dea38f..abe495692 100644 --- a/armsrc/usart.h +++ b/armsrc/usart.h @@ -4,9 +4,6 @@ #include "common.h" #include "usart_defs.h" -#define USART_BUFFLEN 512 -#define USART_FIFOLEN (2*USART_BUFFLEN) - // Higher baudrates are pointless, only increasing overflow risk extern uint32_t g_usart_baudrate; diff --git a/client/Makefile b/client/Makefile index ebf07c4b4..f3569e037 100644 --- a/client/Makefile +++ b/client/Makefile @@ -326,9 +326,9 @@ ifeq ($(SKIPQT),1) else ifeq ($(QT_FOUND),1) ifeq ($(QT5_FOUND),1) - $(info GUI support: QT5 found, enabled) + $(info GUI support: QT5 found, enabled ($(shell QT_SELECT=5 qmake -v 2>/dev/null|grep -o 'Qt version.*'))) else - $(info GUI support: QT4 found, enabled) + $(info GUI support: QT4 found, enabled ($(shell QT_SELECT=4 qmake -v 2>/dev/null|grep -o 'Qt version.*'))) endif else $(info GUI support: QT not found, disabled) diff --git a/client/dictionaries/mfc_default_keys.dic b/client/dictionaries/mfc_default_keys.dic index d19c572e9..d0318737c 100644 --- a/client/dictionaries/mfc_default_keys.dic +++ b/client/dictionaries/mfc_default_keys.dic @@ -1133,3 +1133,70 @@ c67beb41ffbf c67beb41ffbf b84d52971107 52b0d3f6116e +# +# Data from https://pastebin.com/cLSQQ9xN +ca3a24669d45 +4087c6a75a96 +160a91d29a9c +b7bf0c13066e +403f09848b87 +d73438698eea +5f31f6fcd3a0 +a0974382c4c5 +a82045a10949 +# +# Data from https://pastebin.com/2iV8h93h +# +# funnivarium +# forum ankara +# +2602FFFFFFFF +# +# macera adasi +# ankara kentpark +# INACTIVE +# +0A4600FF00FF +DFF293979FA7 +4D6F62692E45 +4118D7EF0902 +# +# petrol ofisi +# positive card +# ode-gec +# +0406080A0C0E +# +# konya elkart +# +988ACDECDFB0 +120D00FFFFFF +# +# bowlingo +# serdivan avym +# +4AE23A562A80 +# +# kart54 +# +2AFFD6F88B97 +A9F3F289B70C +DB6819558A25 +6130DFA578A0 +B16B2E573235 +42EF7BF572AB +274E6101FC5E +# +# crazy park +# kizilay avm +# +00DD300F4F10 +# +# kartsistem B +# +FEE2A3FBC5B6 +# +# toru ent +# taurus avm +# +005078565703 \ No newline at end of file diff --git a/client/dictionaries/mfdes_default_keys.dic b/client/dictionaries/mfdes_default_keys.dic index dac73fa04..4c863c3f5 100644 --- a/client/dictionaries/mfdes_default_keys.dic +++ b/client/dictionaries/mfdes_default_keys.dic @@ -42,3 +42,5 @@ eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee 100f0e0d0c0b0a090807060504030201 404142434445464748494a4b4c4d4e4f 303132333435363738393a3b3c3d3e3f +9CABF398358405AE2F0E2B3D31C99A8A # Default key +605F5E5D5C5B5A59605F5E5D5C5B5A59 # access control \ No newline at end of file diff --git a/client/dictionaries/mfp_default_keys.dic b/client/dictionaries/mfp_default_keys.dic index e492e2686..a063e34ad 100644 --- a/client/dictionaries/mfp_default_keys.dic +++ b/client/dictionaries/mfp_default_keys.dic @@ -27,4 +27,4 @@ eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee 100f0e0d0c0b0a090807060504030201 404142434445464748494a4b4c4d4e4f 303132333435363738393a3b3c3d3e3f - +605F5E5D5C5B5A59605F5E5D5C5B5A59 diff --git a/client/luascripts/e.lua b/client/luascripts/data_hex_crc.lua similarity index 94% rename from client/luascripts/e.lua rename to client/luascripts/data_hex_crc.lua index 43e0ab407..a970eaf93 100644 --- a/client/luascripts/e.lua +++ b/client/luascripts/data_hex_crc.lua @@ -9,11 +9,11 @@ desc = [[ This script calculates many checksums (CRC) over the provided hex input. ]] example = [[ - script run e -b 010203040506070809 - script run e -b 010203040506070809 -w 16 + script run data_hex_crc -b 010203040506070809 + script run data_hex_crc -b 010203040506070809 -w 16 ]] usage = [[ -script run e [-b ] +script run data_hex_crc [-b ] ]] arguments = [[ -b data in hex diff --git a/client/luascripts/mifare_access.lua b/client/luascripts/data_mf_accessdecode.lua similarity index 97% rename from client/luascripts/mifare_access.lua rename to client/luascripts/data_mf_accessdecode.lua index 4c416e8d6..551080b5d 100644 --- a/client/luascripts/mifare_access.lua +++ b/client/luascripts/data_mf_accessdecode.lua @@ -8,10 +8,10 @@ desc = [[ This script tries to decode Mifare Classic Access bytes ]] example = [[ - 1. script run mifare_access -a 7F0F0869 + 1. script run data_mf_accessdecode -a 7F0F0869 ]] usage = [[ -script run mifare_access [-h] [-a ] +script run data_mf_accessdecode [-h] [-a ] ]] arguments = [[ -h : this help diff --git a/client/luascripts/dumptoemul.lua b/client/luascripts/data_mf_bin2eml.lua similarity index 97% rename from client/luascripts/dumptoemul.lua rename to client/luascripts/data_mf_bin2eml.lua index 88121f86d..ef48ead16 100644 --- a/client/luascripts/dumptoemul.lua +++ b/client/luascripts/data_mf_bin2eml.lua @@ -12,10 +12,10 @@ This script takes a dumpfile from 'hf mf dump' and converts it to a format that by the emulator ]] example = [[ - script run dumptoemul -i dumpdata-foobar.bin + script run data_mf_bin2eml -i dumpdata-foobar.bin ]] usage = [[ -script run dumptoemul [-i ] [-o ] +script run data_mf_bin2eml [-i ] [-o ] ]] arguments = [[ -h This help diff --git a/client/luascripts/htmldump.lua b/client/luascripts/data_mf_bin2html.lua similarity index 95% rename from client/luascripts/htmldump.lua rename to client/luascripts/data_mf_bin2html.lua index 2853d343b..c33b4782b 100644 --- a/client/luascripts/htmldump.lua +++ b/client/luascripts/data_mf_bin2html.lua @@ -13,10 +13,10 @@ This script takes a dumpfile and produces a html based dump, which is a bit more easily analyzed. ]] example = [[ - script run htmldump -o mifarecard_foo.html + script run data_mf_bin2html -o mifarecard_foo.html ]] usage = [[ -script run htmldump [-i ] [-o ] +script run data_mf_bin2html [-i ] [-o ] ]] arguments = [[ -h This help diff --git a/client/luascripts/emul2dump.lua b/client/luascripts/data_mf_eml2bin.lua similarity index 91% rename from client/luascripts/emul2dump.lua rename to client/luascripts/data_mf_eml2bin.lua index e0286e625..d31b58418 100644 --- a/client/luascripts/emul2dump.lua +++ b/client/luascripts/data_mf_eml2bin.lua @@ -10,12 +10,12 @@ desc =[[ This script takes an dumpfile in EML (ASCII) format and converts it to the PM3 dumpbin file to be used with `hf mf restore` ]] example =[[ - 1. script run emul2dump - 2. script run emul2dump -i myfile.eml - 3. script run emul2dump -i myfile.eml -o myfile.bin + 1. script run data_mf_eml2bin + 2. script run data_mf_eml2bin -i myfile.eml + 3. script run data_mf_eml2bin -i myfile.eml -o myfile.bin ]] usage = [[ -script run emul2dump [-i ] [-o ] +script run data_mf_eml2bin [-i ] [-o ] ]] arguments = [[ -h This help diff --git a/client/luascripts/emul2html.lua b/client/luascripts/data_mf_eml2html.lua similarity index 95% rename from client/luascripts/emul2html.lua rename to client/luascripts/data_mf_eml2html.lua index 533637669..9b2edbe87 100644 --- a/client/luascripts/emul2html.lua +++ b/client/luascripts/data_mf_eml2html.lua @@ -13,10 +13,10 @@ This script takes a dumpfile on EML (ASCII) format and produces a html based dum bit more easily analyzed. ]] example = [[ - script run emul2html -o dumpdata.eml + script run data_mf_eml2html -o dumpdata.eml ]] usage = [[ -script run htmldump [-i ] [-o ] +script run data_mf_eml2html [-i ] [-o ] ]] arguments = [[ -h This help diff --git a/client/luascripts/cmdline.lua b/client/luascripts/examples/example_cmdline.lua similarity index 100% rename from client/luascripts/cmdline.lua rename to client/luascripts/examples/example_cmdline.lua diff --git a/client/luascripts/parameters.lua b/client/luascripts/examples/example_parameters.lua similarity index 88% rename from client/luascripts/parameters.lua rename to client/luascripts/examples/example_parameters.lua index dce215eb7..0925f7d2c 100644 --- a/client/luascripts/parameters.lua +++ b/client/luascripts/examples/example_parameters.lua @@ -4,7 +4,7 @@ local getopt = require('getopt') local ansicolors = require('ansicolors') copyright = '' -usage = 'script run parameters.lua -a 1 -blala -c -de' +usage = 'script run example_parameters.lua -a 1 -blala -c -de' author = 'Martin Holst Swende' version = 'v1.0.2' desc = [[ @@ -12,10 +12,10 @@ This is an example script to demonstrate handle parameters in scripts. For more info, check the comments in the code ]] example = [[ - 1. script run parameters -a mytestparam_input -c + 1. script run example_parameters -a mytestparam_input -c ]] usage = [[ -script run parameters [-h] [-a ] [-b ] [-c] [-d] [-e] +script run example_parameters [-h] [-a ] [-b ] [-c] [-d] [-e] ]] arguments = [[ -h This help @@ -52,7 +52,7 @@ local function main(args) 5 parameters; two with values and three flags. The following should be valid: - script run parameters.lua -a 1 -blala -c -de + script run example_parameters.lua -a 1 -blala -c -de Notice two things: 1. 'blala' works just like 'b lala', both set 'b' to 'lala' diff --git a/client/luascripts/ufodump.lua b/client/luascripts/hf_14a_aztek.lua similarity index 98% rename from client/luascripts/ufodump.lua rename to client/luascripts/hf_14a_aztek.lua index d9a8faa68..c63a9f85c 100644 --- a/client/luascripts/ufodump.lua +++ b/client/luascripts/hf_14a_aztek.lua @@ -14,13 +14,13 @@ xor: the first three block (0,1,2) is not XORED. The rest seems to be xored. ]] example = [[ -- default - script run ufodump + script run hf_14a_aztek -- stop at block 10 - script run ufodump -b 10 + script run hf_14a_aztek -b 10 ]] usage = [[ -script run ufudump [-h] [-b] +script run hf_14a_aztek [-h] [-b] ]] arguments = [[ -h This help diff --git a/client/luascripts/14araw.lua b/client/luascripts/hf_14a_raw.lua similarity index 95% rename from client/luascripts/14araw.lua rename to client/luascripts/hf_14a_raw.lua index e6a180bfb..35d2cff87 100644 --- a/client/luascripts/14araw.lua +++ b/client/luascripts/hf_14a_raw.lua @@ -7,23 +7,23 @@ copyright = '' author = "Martin Holst Swende" version = 'v1.0.2' desc = [[ -This is a script to allow raw 1444a commands to be sent and received. +This is a script to allow raw 14443a commands to be sent and received. ]] example = [[ # 1. Connect and don't disconnect - script run 14araw -p + script run hf_14a_raw -p # 2. Send mf auth, read response (nonce) - script run 14araw -o -x 6000F57b -p + script run hf_14a_raw -o -x 6000F57b -p # 3. disconnect - script run 14araw -o + script run hf_14a_raw -o # All three steps in one go: - script run 14araw -x 6000F57b + script run hf_14a_raw -x 6000F57b ]] usage = [[ -script run 14araw -x 6000F57b +script run hf_14a_raw -x 6000F57b ]] arguments = [[ -o do not connect - use this only if you previously used -p to stay connected diff --git a/client/luascripts/lto_dump.lua b/client/luascripts/hf_14a_read-ltocm.lua similarity index 97% rename from client/luascripts/lto_dump.lua rename to client/luascripts/hf_14a_read-ltocm.lua index d2dd87762..f88cd2c67 100644 --- a/client/luascripts/lto_dump.lua +++ b/client/luascripts/hf_14a_read-ltocm.lua @@ -13,13 +13,13 @@ It starts from block 0 and ends at default block 254. ]] example = [[ -- default - script run lto_dump + script run hf_14a_read-ltocm -- stop at block 10 - script run lto_dump -e 10 + script run hf_14a_read-ltocm -e 10 ]] usage = [[ -script run lto_dump -h -s -e +script run hf_14a_read-ltocm -h -s -e ]] arguments = [[ h this helptext diff --git a/client/luascripts/calypso.lua b/client/luascripts/hf_14b_calypso.lua similarity index 98% rename from client/luascripts/calypso.lua rename to client/luascripts/hf_14b_calypso.lua index de72f41c6..0439ac800 100644 --- a/client/luascripts/calypso.lua +++ b/client/luascripts/hf_14b_calypso.lua @@ -12,11 +12,11 @@ desc = [[ This is a script to communicate with a CALYSPO / 14443b tag using the '14b raw' commands ]] example = [[ - script run calypso -b 11223344 + script run hf_14b_calypso -b 11223344 ]] usage = [[ -script run calypso -h -b +script run hf_14b_calypso -h -b ]] arguments = [[ h this helptext diff --git a/client/luascripts/iso15_magic.lua b/client/luascripts/hf_15_magic.lua similarity index 95% rename from client/luascripts/iso15_magic.lua rename to client/luascripts/hf_15_magic.lua index 94f1d8f97..173cf1ee7 100644 --- a/client/luascripts/iso15_magic.lua +++ b/client/luascripts/hf_15_magic.lua @@ -15,12 +15,12 @@ example = [[ -- ISO15693 slix magic tag - script run iso15_magic -u E004013344556677 + script run hf_15_magic -u E004013344556677 - script run iso15_magic -u E004013344556677 -a + script run hf_15_magic -u E004013344556677 -a ]] usage = [[ -script run iso15_magic -h -u +script run hf_15_magic -h -u ]] arguments = [[ -h : this help diff --git a/client/luascripts/legic.lua b/client/luascripts/hf_legic.lua similarity index 99% rename from client/luascripts/legic.lua rename to client/luascripts/hf_legic.lua index 393cc9e52..1715bf400 100644 --- a/client/luascripts/legic.lua +++ b/client/luascripts/hf_legic.lua @@ -96,7 +96,7 @@ Known issues; needs to be fixed: * last byte in last segment is handled incorrectly when it is the last bytes on the card itself (MIM256: => byte 256) --]] -example = "script run legic" +example = "script run hf_legic" author = "Mosci, uhei" version = "1.0.4" diff --git a/client/luascripts/legic_buffer2card.lua b/client/luascripts/hf_legic_buffer2card.lua similarity index 95% rename from client/luascripts/legic_buffer2card.lua rename to client/luascripts/hf_legic_buffer2card.lua index d0a018d83..eac8f1ed2 100644 --- a/client/luascripts/legic_buffer2card.lua +++ b/client/luascripts/hf_legic_buffer2card.lua @@ -11,10 +11,10 @@ desc = This is a script which writes value 0x01 to bytes from position 0x07 until 0xFF on a Legic Prime Tag (MIM256 or MIM1024) -- (created with 'hf legic save my_dump.hex') -- ]] example = [[ - script run legic_buffer2card + script run hf_legic_buffer2card ]] usage = [[ -script run legic_buffer2card -h +script run hf_legic_buffer2card -h ]] arguments = [[ -h - Help text diff --git a/client/luascripts/legic_clone.lua b/client/luascripts/hf_legic_clone.lua similarity index 98% rename from client/luascripts/legic_clone.lua rename to client/luascripts/hf_legic_clone.lua index 0f03157e5..28a95bca7 100644 --- a/client/luascripts/legic_clone.lua +++ b/client/luascripts/hf_legic_clone.lua @@ -18,7 +18,7 @@ local ansicolors = require('ansicolors') simplest usage: Dump a legic tag with 'hf legic dump' place your 'empty' tag on the reader and run - 'script run legic_clone -i orig.bin -w' + 'script run hf_legic_clone -i orig.bin -w' you will see some output like: @@ -95,11 +95,11 @@ This is a script which creates a clone-dump of a dump from a LEGIC Prime Tag (MI Create a dump by running `hf legic dump`. ]] example = [[ - script run legic_clone -i my_dump.bin -o my_clone.bin -c f8 - script run legic_clone -i my_dump.bin -d -s + script run hf_legic_clone -i my_dump.bin -o my_clone.bin -c f8 + script run hf_legic_clone -i my_dump.bin -d -s ]] usage = [[ -script run legic_clone [-h] [-i ] [-o ] [-c ] [-d] [-s] [-w] +script run hf_legic_clone [-h] [-i ] [-o ] [-c ] [-d] [-s] [-w] ]] arguments = [[ required : diff --git a/client/luascripts/mifare_autopwn.lua b/client/luascripts/hf_mf_autopwn.lua similarity index 97% rename from client/luascripts/mifare_autopwn.lua rename to client/luascripts/hf_mf_autopwn.lua index 6ff40a70d..f7ea2a832 100644 --- a/client/luascripts/mifare_autopwn.lua +++ b/client/luascripts/hf_mf_autopwn.lua @@ -13,10 +13,10 @@ This is a script which automates cracking and dumping mifare classic cards. It s place by the device. ]] example = [[ - 1. script run mifare_autopwn + 1. script run hf_mf_autopwn ]] usage = [[ -script run mifare_autopwn [-h] [-d] [-k ] +script run hf_mf_autopwn [-h] [-d] [-k ] ]] arguments = [[ -h this help @@ -128,10 +128,10 @@ local function dump_tag(uid, numsectors) -- Save the global args, those are *our* arguments local myargs = args - -- Set the arguments for htmldump script + -- Set the arguments for data_mf_bin2html script args =('-i %s.bin -o %s.html'):format(dumpfile, dumpfile) -- call it - require('htmldump') + require('data_mf_bin2html') -- Set back args. Not that it's used, just for the karma... args = myargs diff --git a/client/luascripts/luxeodump.lua b/client/luascripts/hf_mf_dump-luxeo.lua similarity index 98% rename from client/luascripts/luxeodump.lua rename to client/luascripts/hf_mf_dump-luxeo.lua index 3efc8e7c0..3ee86ecbc 100644 --- a/client/luascripts/luxeodump.lua +++ b/client/luascripts/hf_mf_dump-luxeo.lua @@ -1,7 +1,7 @@ --- -- This Lua script is designed to run with Iceman/RRG Proxmark3 fork --- Just copy luxeodump.lua to client/luascripts/ --- and run "script run luxeodump" +-- Just copy hf_mf_dump-luxeo.lua to client/luascripts/ +-- and run "script run hf_mf_dump-luxeo" -- requirements local cmds = require('commands') @@ -17,10 +17,10 @@ desc = [[ This is a script that tries to dump and decrypt the data of a specific type of Mifare laundromat token. OBS! Tag must be on the antenna. ]] example = [[ - script run luxeodump + script run hf_mf_dump-luxeo ]] usage = [[ -script run luxeodump +script run hf_mf_dump-luxeo ]] arguments = [[ -h This help diff --git a/client/luascripts/formatMifare.lua b/client/luascripts/hf_mf_format.lua similarity index 97% rename from client/luascripts/formatMifare.lua rename to client/luascripts/hf_mf_format.lua index 30ab20535..d949c25f2 100644 --- a/client/luascripts/formatMifare.lua +++ b/client/luascripts/hf_mf_format.lua @@ -20,16 +20,16 @@ The script will skip the manufactoring block 0. ]] example = [[ -- generate commands - 1. script run formatMifare + 1. script run hf_mf_format -- generate command, replacing key with new key. - 2. script run formatMifare -k aabbccddeeff -n 112233445566 -a FF0780 + 2. script run hf_mf_format -k aabbccddeeff -n 112233445566 -a FF0780 -- generate commands and execute them against card. - 3. script run formatMifare -x + 3. script run hf_mf_format -x ]] usage = [[ -script run formatMifare -k -n -a -x +script run hf_mf_format -k -n -a -x ]] arguments = [[ -h - this help diff --git a/client/luascripts/mfc_gen3_writer.lua b/client/luascripts/hf_mf_gen3_writer.lua similarity index 98% rename from client/luascripts/mfc_gen3_writer.lua rename to client/luascripts/hf_mf_gen3_writer.lua index 9e78b2aee..7795ac26c 100644 --- a/client/luascripts/mfc_gen3_writer.lua +++ b/client/luascripts/hf_mf_gen3_writer.lua @@ -12,8 +12,7 @@ local read14a = require('read14a') --[[ ---Suggestions of improvement: --- Add support another types of dumps: BIN, JSON ---- Maybe it will be not only as `mfc_gen3_writer`, like a universal dump manager. ---- Add undependence from the operation system. At the moment code not working in Linux. +--- Maybe it will be not only as `hf_mf_gen3_writer`, like a universal dump manager. --- Hide system messages when you writing a dumps, replace it to some of like [#####----------] 40% -- iceman notes: diff --git a/client/luascripts/mfckeys.lua b/client/luascripts/hf_mf_keycheck.lua similarity index 97% rename from client/luascripts/mfckeys.lua rename to client/luascripts/hf_mf_keycheck.lua index bf0cccb45..59680cbe4 100644 --- a/client/luascripts/mfckeys.lua +++ b/client/luascripts/hf_mf_keycheck.lua @@ -22,10 +22,10 @@ desc = ("This script implements Mifare check keys.\ It utilises a large list of default keys (currently %d keys).\ If you want to add more, just put them inside /lualibs/mfc_default_keys.lua\n"):format(#keylist) example = [[ - 1. script run mfckeys + 1. script run hf_mf_keycheck ]] usage = [[ -script run mfckeys [-p] +script run hf_mf_keycheck [-p] ]] arguments = [[ -h : this help @@ -60,7 +60,7 @@ end -- waits for answer from pm3 device local function checkCommand(response) if not response then - print("Timeout while waiting for response. Increase TIMEOUT in mfckeys.lua to wait longer") + print("Timeout while waiting for response. Increase TIMEOUT in hf_mf_keycheck.lua to wait longer") return nil, "Timeout while waiting for device to respond" end @@ -237,7 +237,7 @@ local function perform_check(uid, numsectors) local end_time = os.time() print('') - print('[+] mfckeys - Checkkey execution time: '..os.difftime(end_time, start_time)..' sec') + print('[+] hf_mf_keycheck - Checkkey execution time: '..os.difftime(end_time, start_time)..' sec') core.fast_push_mode(false) diff --git a/client/luascripts/remagic.lua b/client/luascripts/hf_mf_magicrevive.lua similarity index 94% rename from client/luascripts/remagic.lua rename to client/luascripts/hf_mf_magicrevive.lua index 51aa0be40..abbb45576 100644 --- a/client/luascripts/remagic.lua +++ b/client/luascripts/hf_mf_magicrevive.lua @@ -11,15 +11,15 @@ or mifare Ultralight magic card which answers to chinese backdoor commands ]] example = [[ -- target a Ultralight based card - 1. script run remagic -u + 1. script run hf_mf_magicrevive -u ]] usage = [[ -script run remagic [-h] [-u] +script run hf_mf_magicrevive [-h] [-u] ]] arguments = [[ -h this help - -u remagic a Ultralight tag w 7 bytes UID. + -u try to revive a bricked magic Ultralight tag w 7 bytes UID. ]] --- -- A debug printout-function diff --git a/client/luascripts/didump.lua b/client/luascripts/hf_mf_mini_dumpdecrypt.lua similarity index 98% rename from client/luascripts/didump.lua rename to client/luascripts/hf_mf_mini_dumpdecrypt.lua index 39207151e..ec6006ed2 100644 --- a/client/luascripts/didump.lua +++ b/client/luascripts/hf_mf_mini_dumpdecrypt.lua @@ -16,19 +16,19 @@ This is a script to dump and decrypt the data of a specific type of Mifare Mini The dump is decrypted. If a raw dump is wanted, use the -r parameter ]] example = [[ - script run didump + script run hf_mf_mini_dumpdecrypt -- selftest - script run didump -t + script run hf_mf_mini_dumpdecrypt -t -- Generate raw dump, into json. - script run didump -r + script run hf_mf_mini_dumpdecrypt -r -- load file - script run didump -i dumpdata.json + script run hf_mf_mini_dumpdecrypt -i dumpdata.json ]] usage = [[ -script run didump -h -t -r -d -e -v -i dumpdata.json +script run hf_mf_mini_dumpdecrypt -h -t -r -d -e -v -i dumpdata.json ]] arguments = [[ h this helptext diff --git a/client/luascripts/tnp3clone.lua b/client/luascripts/hf_mf_tnp3_clone.lua similarity index 94% rename from client/luascripts/tnp3clone.lua rename to client/luascripts/hf_mf_tnp3_clone.lua index 056e7021b..490c49242 100644 --- a/client/luascripts/tnp3clone.lua +++ b/client/luascripts/hf_mf_tnp3_clone.lua @@ -15,17 +15,17 @@ copyright = '' author = "Iceman" version = 'v1.0.2' desc = [[ -This script will try making a barebone clone of a tnp3 tag on to a magic generation1 card. +This script will try to make a barebones clone of a tnp3 tag on to a magic generation1 card. ]] example = [[ - script run tnp3clone - script run tnp3clone -h - script run tnp3clone -l - script run tnp3clone -t aa00 -s 0030 + script run hf_mf_tnp3_clone + script run hf_mf_tnp3_clone -h + script run hf_mf_tnp3_clone -l + script run hf_mf_tnp3_clone -t aa00 -s 0030 ]] usage = [[ -script run tnp3clone [-h] [-t ] [-s ] +script run hf_mf_tnp3_clone [-h] [-t ] [-s ] ]] arguments = [[ -h : this help diff --git a/client/luascripts/tnp3dump.lua b/client/luascripts/hf_mf_tnp3_dump.lua similarity index 94% rename from client/luascripts/tnp3dump.lua rename to client/luascripts/hf_mf_tnp3_dump.lua index 0dea0a01a..ee59046eb 100644 --- a/client/luascripts/tnp3dump.lua +++ b/client/luascripts/hf_mf_tnp3_dump.lua @@ -16,18 +16,18 @@ This script will try to dump the contents of a Mifare TNP3xxx card. It will need a valid KeyA in order to find the other keys and decode the card. ]] example = [[ - script run tnp3dump - script run tnp3dump -n - script run tnp3dump -p - script run tnp3dump -k aabbccddeeff - script run tnp3dump -k aabbccddeeff -n - script run tnp3dump -o myfile - script run tnp3dump -n -o myfile - script run tnp3dump -p -o myfile - script run tnp3dump -k aabbccddeeff -n -o myfile + script run hf_mf_tnp3_dump + script run hf_mf_tnp3_dump -n + script run hf_mf_tnp3_dump -p + script run hf_mf_tnp3_dump -k aabbccddeeff + script run hf_mf_tnp3_dump -k aabbccddeeff -n + script run hf_mf_tnp3_dump -o myfile + script run hf_mf_tnp3_dump -n -o myfile + script run hf_mf_tnp3_dump -p -o myfile + script run hf_mf_tnp3_dump -k aabbccddeeff -n -o myfile ]] usage = [[ -script run tnp3dump [-h] [-k ] [-n] [-p] [-o ] +script run hf_mf_tnp3_dump [-h] [-k ] [-n] [-p] [-o ] ]] arguments = [[ -h : this help diff --git a/client/luascripts/tnp3sim.lua b/client/luascripts/hf_mf_tnp3_sim.lua similarity index 98% rename from client/luascripts/tnp3sim.lua rename to client/luascripts/hf_mf_tnp3_sim.lua index 069bbfe08..dded9327a 100644 --- a/client/luascripts/tnp3sim.lua +++ b/client/luascripts/hf_mf_tnp3_sim.lua @@ -13,17 +13,17 @@ author = 'Iceman' version = 'v1.0.2' desc = [[ This script will try to load a binary datadump of a Mifare TNP3xxx card. -It vill try to validate all checksums and view some information stored in the dump +It will try to validate all checksums and view some information stored in the dump For an experimental mode, it tries to manipulate some data. At last it sends all data to the PM3 device memory where it can be used in the command "hf mf sim" ]] example = [[ - 1. script run tnp3sim - 2. script run tnp3sim -m - 3. script run tnp3sim -m -i myfile + 1. script run hf_mf_tnp3_sim + 2. script run hf_mf_tnp3_sim -m + 3. script run hf_mf_tnp3_sim -m -i myfile ]] usage = [[ -script run tnp3sim [-h] [-m] [-i ] +script run hf_mf_tnp3_sim [-h] [-m] [-i ] ]] arguments = [[ -h : this help diff --git a/client/luascripts/hf_bruteforce.lua b/client/luascripts/hf_mf_uidbruteforce.lua similarity index 88% rename from client/luascripts/hf_bruteforce.lua rename to client/luascripts/hf_mf_uidbruteforce.lua index 1d3b00777..461e8aad3 100644 --- a/client/luascripts/hf_bruteforce.lua +++ b/client/luascripts/hf_mf_uidbruteforce.lua @@ -1,5 +1,5 @@ --- Run me like this (connected via USB): ./pm3 -l hf_bruteforce.lua --- Run me like this (connected via Blueshark addon): ./client/proxmark3 /dev/rfcomm0 -l ./hf_bruteforce.lua +-- Run me like this (connected via USB): ./pm3 -l hf_mf_uidbruteforce.lua +-- Run me like this (connected via Blueshark addon): ./client/proxmark3 /dev/rfcomm0 -l ./hf_mf_uidbruteforce.lua local getopt = require('getopt') local ansicolors = require('ansicolors') @@ -13,14 +13,14 @@ This script bruteforces 4 or 7 byte UID Mifare classic card numbers. example =[[ Bruteforce a 4 byte UID Mifare classic card number, starting at 11223344, ending at 11223346. - script run hf_bruteforce -s 0x11223344 -e 0x11223346 -t 1000 -x mfc + script run hf_mf_uidbruteforce -s 0x11223344 -e 0x11223346 -t 1000 -x mfc Bruteforce a 7 byte UID Mifare Ultralight card number, starting at 11223344556677, ending at 11223344556679. - script run hf_bruteforce -s 0x11223344556677 -e 0x11223344556679 -t 1000 -x mfu + script run hf_mf_uidbruteforce -s 0x11223344556677 -e 0x11223344556679 -t 1000 -x mfu ]] usage = [[ -script run hf_bruteforce [-s ] [-e ] [-t ] [-x ] +script run hf_mf_uidbruteforce [-s ] [-e ] [-t ] [-x ] ]] arguments = [[ -h this help diff --git a/client/luascripts/calc_mizip.lua b/client/luascripts/hf_mf_uidkeycalc-mizip.lua similarity index 97% rename from client/luascripts/calc_mizip.lua rename to client/luascripts/hf_mf_uidkeycalc-mizip.lua index 79fbae75f..902aeeda8 100644 --- a/client/luascripts/calc_mizip.lua +++ b/client/luascripts/hf_mf_uidkeycalc-mizip.lua @@ -13,13 +13,13 @@ Algo not found by me. ]] example = [[ -- if called without, it reads tag uid - script run calc_mizip + script run hf_mf_uidkeycalc-mizip -- - script run calc_mizip -u 11223344 + script run hf_mf_uidkeycalc-mizip -u 11223344 ]] usage = [[ -script run calc_mizip -h -u +script run hf_mf_uidkeycalc-mizip -h -u ]] arguments = [[ -h : this help diff --git a/client/luascripts/calc_di.lua b/client/luascripts/hf_mf_uidkeycalc.lua similarity index 97% rename from client/luascripts/calc_di.lua rename to client/luascripts/hf_mf_uidkeycalc.lua index 737d993af..88330ae85 100644 --- a/client/luascripts/calc_di.lua +++ b/client/luascripts/hf_mf_uidkeycalc.lua @@ -13,13 +13,13 @@ Algo not found by me. ]] example = [[ -- if called without, it reads tag uid - script run calc_di + script run hf_mf_uidkeycalc -- - script run calc_di -u 11223344556677 + script run hf_mf_uidkeycalc -u 11223344556677 ]] usage = [[ -script run calc_di -h -u +script run hf_mf_uidkeycalc -h -u ]] arguments = [[ -h : this help diff --git a/client/luascripts/mifareplus.lua b/client/luascripts/hf_mfp_raw.lua similarity index 99% rename from client/luascripts/mifareplus.lua rename to client/luascripts/hf_mfp_raw.lua index a30f24f8b..e28c274a8 100644 --- a/client/luascripts/mifareplus.lua +++ b/client/luascripts/hf_mfp_raw.lua @@ -15,10 +15,10 @@ Please read the NXP manual before running this script to prevent making irrevers Small changes can be to made this script to communicate with the Mifare Plus S, X, or SE. ]] example = [[ - 1. script run mifareplus + 1. script run hf_mfp_raw ]] usage = [[ -script run mifareplus [-h] +script run hf_mfp_raw [-h] ]] arguments = [[ -h : this help diff --git a/client/luascripts/dumptoemul-mfu.lua b/client/luascripts/hf_mfu_dumptoemulator.lua similarity index 97% rename from client/luascripts/dumptoemul-mfu.lua rename to client/luascripts/hf_mfu_dumptoemulator.lua index 0bd11e297..47f52e135 100644 --- a/client/luascripts/dumptoemul-mfu.lua +++ b/client/luascripts/hf_mfu_dumptoemulator.lua @@ -12,10 +12,10 @@ This script takes a dumpfile from 'hf mfu dump' and converts it to a format that by the emulator ]] example = [[ - script run dumptoemul-mfu -i dumpdata-foobar.bin + script run hf_mfu_dumptoemulator -i dumpdata-foobar.bin ]] usage = [[ -script run dumptoemul-mfu [-i ] [-o ] +script run hf_mfu_dumptoemulator [-i ] [-o ] ]] arguments = [[ -h This help diff --git a/client/luascripts/mfu_magic.lua b/client/luascripts/hf_mfu_magicwrite.lua similarity index 97% rename from client/luascripts/mfu_magic.lua rename to client/luascripts/hf_mfu_magicwrite.lua index 5b817fe93..e29296f45 100644 --- a/client/luascripts/mfu_magic.lua +++ b/client/luascripts/hf_mfu_magicwrite.lua @@ -16,28 +16,28 @@ version = 'v1.1.3' desc = 'This script enables easy programming of a MAGIC NTAG 21* card' example = [[ -- wipe tag - script run mfu_magic -w + script run hf_mfu_magicwrite -w -- wipe a locked down tag by giving the password - script run mfu_magic -k ffffffff -w + script run hf_mfu_magicwrite -k ffffffff -w --read magic tag configuration - script run mfu_magic -c + script run hf_mfu_magicwrite -c -- set uid - script run mfu_magic -u 04112233445566 + script run hf_mfu_magicwrite -u 04112233445566 -- set pwd / pack - script run mfu_magic -p 11223344 -a 8080 + script run hf_mfu_magicwrite -p 11223344 -a 8080 -- set version to NTAG213 - script run mfu_magic -v 0004040201000f03 + script run hf_mfu_magicwrite -v 0004040201000f03 -- set signature - script run mfu_magic -s 1122334455667788990011223344556677889900112233445566778899001122 + script run hf_mfu_magicwrite -s 1122334455667788990011223344556677889900112233445566778899001122 ]] usage = [[ -script run mfu_magic -h -k -c -w -u -t -p -a -s -o -v +script run hf_mfu_easywrite -h -k -c -w -u -t -p -a -s -o -v ]] arguments = [[ -h this help diff --git a/client/luascripts/ul_uid.lua b/client/luascripts/hf_mfu_setuid.lua similarity index 96% rename from client/luascripts/ul_uid.lua rename to client/luascripts/hf_mfu_setuid.lua index ece368ce5..6b161b054 100644 --- a/client/luascripts/ul_uid.lua +++ b/client/luascripts/hf_mfu_setuid.lua @@ -12,13 +12,13 @@ This script tries to set UID on a mifare Ultralight magic card which either ]] example = [[ -- backdoor magic tag - script run ul_uid -u 11223344556677 + script run hf_mfu_setuid -u 11223344556677 -- brickable magic tag - script run ul_uid -b -u 11223344556677 + script run hf_mfu_setuid -b -u 11223344556677 ]] usage = [[ -script run ul_uid [-h] [-b] [-u ] +script run hf_mfu_setuid [-h] [-b] [-u ] ]] arguments = [[ -h : this help diff --git a/client/luascripts/calc_ev1_it.lua b/client/luascripts/hf_mfu_uidkeycalc-italy.lua similarity index 96% rename from client/luascripts/calc_ev1_it.lua rename to client/luascripts/hf_mfu_uidkeycalc-italy.lua index 2e333d147..4777a186d 100644 --- a/client/luascripts/calc_ev1_it.lua +++ b/client/luascripts/hf_mfu_uidkeycalc-italy.lua @@ -13,13 +13,13 @@ Algo not found by me. ]] example =[[ -- if called without, it reads tag uid - script run calc_ev1_it + script run hf_mfu_uidkeycalc-italy -- - script run calc_ev1_it -u 11223344556677 + script run hf_mfu_uidkeycalc-italy -u 11223344556677 ]] usage = [[ -script run calc_ev1_it -h -u " +script run hf_mfu_uidkeycalc-italy -h -u " ]] arguments = [[ -h : this help diff --git a/client/luascripts/ndef_dump.lua b/client/luascripts/hf_ndef_dump.lua similarity index 99% rename from client/luascripts/ndef_dump.lua rename to client/luascripts/hf_ndef_dump.lua index 672beda1c..b2c282cf8 100644 --- a/client/luascripts/ndef_dump.lua +++ b/client/luascripts/hf_ndef_dump.lua @@ -21,10 +21,10 @@ Therefore, the .eml is better to use file when saving dumps.) ]] example = [[ - 1. script run ndef_dump + 1. script run hf_ndef_dump ]] usage = [[ -script run ndef_dump [-h] [-d] [-v] +script run hf_ndef_dump [-h] [-d] [-v] ]] arguments = [[ -h this help diff --git a/client/luascripts/ntag_3d.lua b/client/luascripts/hf_ntag-3d.lua similarity index 95% rename from client/luascripts/ntag_3d.lua rename to client/luascripts/hf_ntag-3d.lua index d986923ba..e46705bd1 100644 --- a/client/luascripts/ntag_3d.lua +++ b/client/luascripts/hf_ntag-3d.lua @@ -13,16 +13,16 @@ Thanks to @jack for his invaluable input on some of the configuration. ]] example =[[ -- This will generate GOLD, PLA, TH, EU, 200m, tagbased uid. - script run ntag_3d -c 46 -m 50 -p 5448 -s 4555 -l 200 + script run hf_ntag-3d -c 46 -m 50 -p 5448 -s 4555 -l 200 -- This will generate GOLD, PLA, TH, EU, 200m, userbased uid. - script run ntag_3d -u 11223344556677 -c 46 -m 50 -p 5448 -s 4555 -l 200 + script run hf_ntag-3d -u 11223344556677 -c 46 -m 50 -p 5448 -s 4555 -l 200 -- This will generate GOLD, PLA, TH, EU, 200m, userbased uid. and configure a MAGIC NTAG. - script run ntag_3d -u 11223344556677 -c 46 -m 50 -p 5448 -s 4555 -l 200 -1 + script run hf_ntag-3d -u 11223344556677 -c 46 -m 50 -p 5448 -s 4555 -l 200 -1 ]] usage = [[ -script run ntag_3d [-h] [-t] [-u ] [-c ] [-m ] [-p ] [-s ] [-l ] +script run hf_ntag-3d [-h] [-t] [-u ] [-c ] [-m ] [-p ] [-s ] [-l ] ]] arguments = [[ -h : this help @@ -221,13 +221,13 @@ local function configure_magic_ntag(uid) local pwd, pack = core.keygen_algo_d(uid) - -- Set the arguments for mfu_magic script v1.0.8 + -- Set the arguments for hf_mfu_magicwrite script v1.0.8 -- -t 12 == configure NTAG213F -- -u == set UID -- -p == set pwd -- -a == set pack args =('-t 12 -u %s -p %08X -a %04X'):format(uid, pwd, pack) - require('mfu_magic') + require('hf_mfu_magicwrite') -- Set back args. Not that it's used, just for the karma... args = myargs diff --git a/client/luascripts/lf_bulk.lua b/client/luascripts/lf_hid_bulkclone.lua similarity index 96% rename from client/luascripts/lf_bulk.lua rename to client/luascripts/lf_hid_bulkclone.lua index 709c992a4..dae59a53c 100644 --- a/client/luascripts/lf_bulk.lua +++ b/client/luascripts/lf_hid_bulkclone.lua @@ -1,5 +1,5 @@ -- --- lf_bulk.lua - A tool to clone a large number of tags at once. +-- lf_hid_bulkclone.lua - A tool to clone a large number of tags at once. -- Updated 2017-04-18 -- Updated 2018-02-20 iceman local getopt = require('getopt') @@ -14,10 +14,10 @@ For more info, check the comments in the code ]] example = [[ -- - script run lf_bulk.lua -f 1 -b 1000 -c 10 + script run lf_hid_bulkclone.lua -f 1 -b 1000 -c 10 ]] usage = [[ -script run lf_bulk.lua -f facility -b base_id_num -c count +script run lf_hid_bulkclone.lua -f facility -b base_id_num -c count ]] arguments = [[ -h : this help diff --git a/client/luascripts/read_pwd_mem.lua b/client/luascripts/mem_readpwd.lua similarity index 91% rename from client/luascripts/read_pwd_mem.lua rename to client/luascripts/mem_readpwd.lua index 0c786f6f9..82343b943 100644 --- a/client/luascripts/read_pwd_mem.lua +++ b/client/luascripts/mem_readpwd.lua @@ -9,31 +9,31 @@ desc = [[ This script will read the flash memory of RDV4 and print the stored passwords/keys. It was meant to be used as a help tool after using the BogRun standalone mode before SPIFFS. -You should now use read_pwd_mem_spiffs instead after the updated BogRun standalone mode. +You should now use data_read_pwd_mem_spiffs instead after the updated BogRun standalone mode. (Iceman) script adapted to read and print keys in the default dictionary flashmemory sections. ]] example = [[ -- This will scan the first 256 bytes of flash memory for stored passwords - script run read_pwd_mem + script run mem_readpwd -- This will scan 256 bytes of flash memory at offset 64 for stored passwords - script run read_pwd_mem -o 64 + script run mem_readpwd -o 64 -- This will scan 32 bytes of flash memory at offset 64 for stored passwords - script run read_pwd_mem -o 64 -l 32 + script run mem_readpwd -o 64 -l 32 -- This will print the stored Mifare dictionary keys - script run read_pwd_mem -m + script run mem_readpwd -m -- This will print the stored t55xx dictionary passwords - script run read_pwd_mem -t + script run mem_readpwd -t -- This will print the stored iClass dictionary keys - script run read_pwd_mem -i + script run mem_readpwd -i ]] usage = [[ - script run read_pwd_mem [-h] [-o ] [-l ] [-k ] [-m] [-t] [-i] + script run mem_readpwd [-h] [-o ] [-l ] [-k ] [-m] [-t] [-i] ]] arguments = [[ -h : this help diff --git a/client/luascripts/read_pwd_mem_spiffs.lua b/client/luascripts/mem_spiffs_readpwd.lua similarity index 93% rename from client/luascripts/read_pwd_mem_spiffs.lua rename to client/luascripts/mem_spiffs_readpwd.lua index ae2f0ba99..b4995e406 100644 --- a/client/luascripts/read_pwd_mem_spiffs.lua +++ b/client/luascripts/mem_spiffs_readpwd.lua @@ -11,16 +11,16 @@ It was meant to be used as a help tool after using the BogRun standalone mode. ]] example = [[ -- This will read the hf_bog.log file in SPIFFS and print the stored passwords - script run read_pwd_mem_spiffs + script run mem_spiffs_readpwd -- This will read the other.log file in SPIFFS and print the stored passwords - script run read_pwd_mem_spiffs -f other.log + script run mem_spiffs_readpwd -f other.log -- This will delete the hf_bog.log file from SPIFFS - script run read_pwd_mem_spiffs -r + script run mem_spiffs_readpwd -r ]] usage = [[ - script run read_pwd_mem_spiffs [-h] [-f ] [-r] + script run mem_spiffs_readpwd [-h] [-f ] [-r] ]] arguments = [[ -h : this help diff --git a/client/luascripts/brutesim.lua b/client/luascripts/multi_bruteforce.lua similarity index 96% rename from client/luascripts/brutesim.lua rename to client/luascripts/multi_bruteforce.lua index 4d8ba7d57..ef1edc697 100644 --- a/client/luascripts/brutesim.lua +++ b/client/luascripts/multi_bruteforce.lua @@ -26,16 +26,16 @@ It uses both LF and HF simulations. -- Author note -- I wrote this as i was doing a PACS audit. This is far from complete, but is easily expandable. -- The idea was based on proxbrute, but i needed more options, and support for different readers. - -- I dont know LUA, so I used Brian Redbeards lf_bulk_program.lua script as a starting point, sorry if its kludgy. + -- I dont know LUA, so I used Brian Redbeards lf_hid_bulkclone.lua script as a starting point, sorry if its kludgy. ]] example = [[ -- (the above example would bruteforce pyramid tags, starting at 10:1000, ending at 10:991, and waiting 1 second between each card) - script run brutesim -r pyramid -f 10 -b 1000 -c 10 -t 1 -d down + script run multi_bruteforce -r pyramid -f 10 -b 1000 -c 10 -t 1 -d down ]] usage = [[ -script run brutesim -r rfid_tag -f facility_code -b base_card_number -c count -t timeout -d direction +script run multi_bruteforce -r rfid_tag -f facility_code -b base_card_number -c count -t timeout -d direction ]] arguments = [[ -h this help @@ -110,7 +110,7 @@ local function isempty(s) return s == nil or s == '' end --- The code below was blatantly stolen from Brian Redbeard's lf_bulk_program.lua script +-- The code below was blatantly stolen from Brian Redbeard's lf_hid_bulkclone.lua script local function toBits(num, bits) bits = bits or math.max(1, select(2, math.frexp(num))) local t = {} diff --git a/client/luascripts/tracetest.lua b/client/luascripts/tests/data_tracetest.lua similarity index 97% rename from client/luascripts/tracetest.lua rename to client/luascripts/tests/data_tracetest.lua index b7e931b99..2ce83116c 100644 --- a/client/luascripts/tracetest.lua +++ b/client/luascripts/tests/data_tracetest.lua @@ -18,10 +18,10 @@ The following tracefiles will be loaded: modulation*.pm3 ]] example = [[ - 1. script run tracetest + 1. script run data_tracetest ]] usage = [[ -script run tracetest [-h] +script run data_tracetest [-h] ]] arguments = [[ -h : this help diff --git a/client/luascripts/hf_read.lua b/client/luascripts/tests/hf_read.lua similarity index 100% rename from client/luascripts/hf_read.lua rename to client/luascripts/tests/hf_read.lua diff --git a/client/luascripts/test_t55x7_ask.lua b/client/luascripts/tests/lf_t55xx_defaultask.lua similarity index 96% rename from client/luascripts/test_t55x7_ask.lua rename to client/luascripts/tests/lf_t55xx_defaultask.lua index adfaf1eeb..efb6ce8fe 100644 --- a/client/luascripts/test_t55x7_ask.lua +++ b/client/luascripts/tests/lf_t55xx_defaultask.lua @@ -36,13 +36,13 @@ Loop: -xx 1C xxxx = RF/128 -testsuit for the ASK/MANCHESTER demod +testsuite for the ASK/MANCHESTER demod ]] example =[[ - 1. script run test_t55x7_ask + 1. script run lf_t55xx_defaultask ]] usage = [[ -script run test_t55x7_ask [-h] +script run lf_t55xx_defaultask [-h] ]] arguments = [[ -h : this help diff --git a/client/luascripts/test_t55x7_bi.lua b/client/luascripts/tests/lf_t55xx_defaultbi.lua similarity index 97% rename from client/luascripts/test_t55x7_bi.lua rename to client/luascripts/tests/lf_t55xx_defaultbi.lua index 4b897b367..495faef02 100644 --- a/client/luascripts/test_t55x7_bi.lua +++ b/client/luascripts/tests/lf_t55xx_defaultbi.lua @@ -33,10 +33,10 @@ Loop: testsuit for the BIPHASE demod ]] example = [[ - 1. script run test_t55x7_bi + 1. script run lf_t55xx_defaultbi ]] usage = [[ -script run test_t55x7_bi [-h] +script run lf_t55xx_defaultbi [-h] ]] arguments = [[ -h : this help diff --git a/client/luascripts/test_t55x7_fsk.lua b/client/luascripts/tests/lf_t55xx_defaultfsk.lua similarity index 97% rename from client/luascripts/test_t55x7_fsk.lua rename to client/luascripts/tests/lf_t55xx_defaultfsk.lua index 7a8d724a0..2a5c272c4 100644 --- a/client/luascripts/test_t55x7_fsk.lua +++ b/client/luascripts/tests/lf_t55xx_defaultfsk.lua @@ -35,10 +35,10 @@ Loop: testsuit for the ASK/MANCHESTER demod ]] example = [[ - 1. script run test_t55x7_fsk + 1. script run lf_t55xx_defaultfsk ]] usage = [[ -script run test_t55x7_fsk [-h] +script run lf_t55xx_defaultfsk [-h] ]] arguments = [[ -h : this help diff --git a/client/luascripts/test_t55x7_psk.lua b/client/luascripts/tests/lf_t55xx_defaultpsk.lua similarity index 98% rename from client/luascripts/test_t55x7_psk.lua rename to client/luascripts/tests/lf_t55xx_defaultpsk.lua index 361b231c4..8b4f0447a 100644 --- a/client/luascripts/test_t55x7_psk.lua +++ b/client/luascripts/tests/lf_t55xx_defaultpsk.lua @@ -30,10 +30,10 @@ Loop OUTER: In all 12 individual test for the PSK demod ]] example = [[ - 1. script run test_t55x7_psk + 1. script run lf_t55xx_defaultpsk ]] usage = [[ -script run test_t55x7_psk [-h] +script run lf_t55xx_defaultpsk [-h] ]] arguments = [[ -h : this help diff --git a/client/luascripts/test_t55x7.lua b/client/luascripts/tests/lf_t55xx_writetest.lua similarity index 98% rename from client/luascripts/test_t55x7.lua rename to client/luascripts/tests/lf_t55xx_writetest.lua index 3c4b83441..cfe46d565 100644 --- a/client/luascripts/test_t55x7.lua +++ b/client/luascripts/tests/lf_t55xx_writetest.lua @@ -30,12 +30,12 @@ testsuit for T55XX commands demodulation ]] example = [[ - 1. script run test_t55x7 - 2. script run test_t55x7 -t FSK2A - 3. script run test_t55x7 -t PSK1 + 1. script run lf_t55xx_writetest + 2. script run lf_t55xx_writetest -t FSK2A + 3. script run lf_t55xx_writetest -t PSK1 ]] usage = [[ -script run test_t55x7 [-h] [-t +script run lf_t55xx_writetest [-h] [-t ]] arguments = [[ -h this help diff --git a/client/src/cmdhf14a.c b/client/src/cmdhf14a.c index fbd9fc618..cc6a7caab 100644 --- a/client/src/cmdhf14a.c +++ b/client/src/cmdhf14a.c @@ -1979,32 +1979,33 @@ int infoHF14A(bool verbose, bool do_nack_test, bool do_aid_search) { } int isMagic = 0; - if (isMifareClassic || isMifareUltralight) { - isMagic = detect_classic_magic(); + if (isMifareClassic) { + isMagic = detect_mf_magic(true); + } + if (isMifareUltralight) { + isMagic = detect_mf_magic(false); + } + if (isMifareClassic) { + int res = detect_classic_static_nonce(); + if (res == NONCE_STATIC) + PrintAndLogEx(SUCCESS, "Static nonce: " _YELLOW_("yes")); - if (isMifareClassic) { + if (res == NONCE_FAIL && verbose) + PrintAndLogEx(SUCCESS, "Static nonce: " _RED_("read failed")); - int res = detect_classic_static_nonce(); - if (res == NONCE_STATIC) - PrintAndLogEx(SUCCESS, "Static nonce: " _YELLOW_("yes")); + if (res == NONCE_NORMAL) { - if (res == NONCE_FAIL && verbose) - PrintAndLogEx(SUCCESS, "Static nonce: " _RED_("read failed")); + // 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 (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); - } + if (do_nack_test) + detect_classic_nackbug(false); } } diff --git a/client/src/cmdhf14b.c b/client/src/cmdhf14b.c index b0ce49f50..811fcb195 100644 --- a/client/src/cmdhf14b.c +++ b/client/src/cmdhf14b.c @@ -105,10 +105,10 @@ static int usage_hf_14b_write_srx(void) { static int usage_hf_14b_dump(void) { PrintAndLogEx(NORMAL, "This command dumps the contents of a ISO-14443-B tag and save it to file\n" "\n" - "Usage: hf 14b dump [h] [card memory] \n" + "Usage: hf 14b dump [h] [card memory] \n" "Options:\n" "\th this help\n" - "\t[card memory] 1 = SRIX4K (default), 2 = SRI512" + "\t[card memory] 1 = SRIX4K (default), 2 = SRI512\n" "\tf filename, if no UID will be used as filename\n" "\n" "Example:\n" @@ -835,6 +835,8 @@ static int CmdHF14BDump(const char *Cmd) { uint8_t blocks = 0; iso14b_card_select_t card; + if (strlen(Cmd) < 1) return usage_hf_14b_dump(); + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { switch (tolower(param_getchar(Cmd, cmdp))) { case 'h': diff --git a/client/src/cmdhf15.c b/client/src/cmdhf15.c index 421e7488f..76500668d 100644 --- a/client/src/cmdhf15.c +++ b/client/src/cmdhf15.c @@ -380,7 +380,7 @@ static int nxp_15693_print_signature(uint8_t *uid, uint8_t *signature) { {"NXP Public key", "04A748B6A632FBEE2C0897702B33BEA1C074998E17B84ACA04FF267E5D2C91F6DC"}, {"NXP Ultralight Ev1", "0490933BDCD6E99B4E255E3DA55389A827564E11718E017292FAF23226A96614B8"}, {"NXP NTAG21x (2013)", "04494E1A386D3D3CFE3DC10E5DE68A499B1C202DB5B132393E89ED19FE5BE8BC61"}, - {"MICRON Public key", "04f971eda742a4a80d32dcf6a814a707cc3dc396d35902f72929fdcd698b3468f2"}, + {"MIKRON Public key", "04f971eda742a4a80d32dcf6a814a707cc3dc396d35902f72929fdcd698b3468f2"}, {"Spark1 Public key", "04d64bb732c0d214e7ec580736acf847284b502c25c0f7f2fa86aace1dada4387a"}, }; /* @@ -423,6 +423,16 @@ static int nxp_15693_print_signature(uint8_t *uid, uint8_t *signature) { }; */ uint8_t i; + uint8_t revuid[8]; + for (i = 0; i < sizeof(revuid); i++) { + revuid[i] = uid[7 - i]; + } + uint8_t revsign[32]; + for (i = 0; i < sizeof(revsign); i++) { + revsign[i] = signature[31 - i]; + } + + int reason = 0; bool is_valid = false; for (i = 0; i < ARRAYLEN(nxp_15693_public_keys); i++) { @@ -432,22 +442,65 @@ static int nxp_15693_print_signature(uint8_t *uid, uint8_t *signature) { int res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP128R1, key, uid, 8, signature, 32, false); is_valid = (res == 0); - if (is_valid) + if (is_valid) { + reason = 1; break; + } + + // try with sha256 + res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP128R1, key, uid, 8, signature, 32, true); + is_valid = (res == 0); + if (is_valid) { + reason = 2; + break; + } + + // try with reversed uid / signature + res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP128R1, key, revuid, sizeof(revuid), revsign, sizeof(revsign), false); + is_valid = (res == 0); + if (is_valid) { + reason = 3; + break; + } + + + // try with sha256 + res = ecdsa_signature_r_s_verify(MBEDTLS_ECP_DP_SECP128R1, key, revuid, sizeof(revuid), revsign, sizeof(revsign), true); + is_valid = (res == 0); + if (is_valid) { + reason = 4; + break; + } } PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature")); if (is_valid == false || i == ARRAYLEN(nxp_15693_public_keys)) { - PrintAndLogEx(SUCCESS, "Signature verification " _RED_("failed")); + PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp128r1"); + PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, 32)); + PrintAndLogEx(SUCCESS, " Signature verification: " _RED_("failed")); return PM3_ESOFT; } - PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature")); PrintAndLogEx(INFO, " IC signature public key name: %s", nxp_15693_public_keys[i].desc); PrintAndLogEx(INFO, "IC signature public key value: %s", nxp_15693_public_keys[i].value); PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp128r1"); - PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex(signature, 32)); - PrintAndLogEx(SUCCESS, " Signature verified: " _GREEN_("successful")); + PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, 32)); + PrintAndLogEx(SUCCESS, " Signature verification: " _GREEN_("successful")); + switch(reason) { + case 1: + PrintAndLogEx(INFO, " Params used: UID and signature, plain"); + break; + case 2: + PrintAndLogEx(INFO, " Params used: UID and signature, SHA256"); + break; + case 3: + PrintAndLogEx(INFO, " Params used: reversed UID and signature, plain"); + break; + case 4: + PrintAndLogEx(INFO, " Params used: reversed UID and signature, SHA256"); + break; + } return PM3_SUCCESS; } diff --git a/client/src/cmdhfmf.c b/client/src/cmdhfmf.c index 0220a026d..df9d07c54 100644 --- a/client/src/cmdhfmf.c +++ b/client/src/cmdhfmf.c @@ -317,10 +317,23 @@ static int usage_hf14_decryptbytes(void) { return PM3_SUCCESS; } -static int usage_hf14_eget(void) { - PrintAndLogEx(NORMAL, "Usage: hf mf eget "); +static int usage_hf14_egetblk(void) { + PrintAndLogEx(NORMAL, "Usage: hf mf egetblk "); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h this help"); + PrintAndLogEx(NORMAL, " block number"); PrintAndLogEx(NORMAL, "Examples:"); - PrintAndLogEx(NORMAL, _YELLOW_(" hf mf eget 0")); + PrintAndLogEx(NORMAL, _YELLOW_(" hf mf egetblk 0")); + return PM3_SUCCESS; +} +static int usage_hf14_egetsc(void) { + PrintAndLogEx(NORMAL, "Get sector data from emulator memory.\n"); + PrintAndLogEx(NORMAL, "Usage: hf mf egetsc [h] "); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h this help"); + PrintAndLogEx(NORMAL, " sector number"); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, _YELLOW_(" hf mf egetsc 0")); return PM3_SUCCESS; } static int usage_hf14_eclr(void) { @@ -909,7 +922,7 @@ static int FastDumpWithEcFill(uint8_t numsectors) { clearCommandBuffer(); SendCommandNG(CMD_HF_MIFARE_EML_LOAD, (uint8_t *)&payload, sizeof(payload)); - bool res = WaitForResponseTimeout(CMD_HF_MIFARE_EML_LOAD, &resp, 2000); + bool res = WaitForResponseTimeout(CMD_HF_MIFARE_EML_LOAD, &resp, 2500); if (res == false) { PrintAndLogEx(WARNING, "Command execute timeout"); return PM3_ETIMEOUT; @@ -923,7 +936,7 @@ static int FastDumpWithEcFill(uint8_t numsectors) { clearCommandBuffer(); SendCommandNG(CMD_HF_MIFARE_EML_LOAD, (uint8_t *)&payload, sizeof(payload)); - res = WaitForResponseTimeout(CMD_HF_MIFARE_EML_LOAD, &resp, 2000); + res = WaitForResponseTimeout(CMD_HF_MIFARE_EML_LOAD, &resp, 2500); if (res == false) { PrintAndLogEx(WARNING, "Command execute timeout"); return PM3_ETIMEOUT; @@ -3607,9 +3620,9 @@ void printKeyTableEx(uint8_t sectorscnt, sector_t *e_sector, uint8_t start_secto // EMULATOR COMMANDS -static int CmdHF14AMfEGet(const char *Cmd) { +static int CmdHF14AMfEGetBlk(const char *Cmd) { char c = tolower(param_getchar(Cmd, 0)); - if (strlen(Cmd) < 1 || c == 'h') return usage_hf14_eget(); + if (strlen(Cmd) < 1 || c == 'h') return usage_hf14_egetblk(); uint8_t data[16] = {0x00}; uint8_t blockNo = param_get8(Cmd, 0); @@ -3620,6 +3633,44 @@ static int CmdHF14AMfEGet(const char *Cmd) { } return PM3_SUCCESS; } +static int CmdHF14AMfEGetSc(const char *Cmd) { + uint8_t data[16] = {0}; + + char ctmp = tolower(param_getchar(Cmd, 0)); + if (strlen(Cmd) < 1 || ctmp == 'h') return usage_hf14_egetsc(); + + uint8_t sector = param_get8(Cmd, 0); + if (sector > 39) { + PrintAndLogEx(WARNING, "Sector number must be less then 40"); + return PM3_ESOFT; + } + + PrintAndLogEx(NORMAL, "\n # | data - sector %02d / 0x%02X ", sector, sector); + PrintAndLogEx(NORMAL, "----+------------------------------------------------"); + uint8_t blocks = 4; + uint8_t start = sector * 4; + if (sector > 32) { + blocks = 16; + start = 128 + (sector - 32) * 16; + } + + for (int i = 0; i < blocks; i++) { + + int res = mfEmlGetMem(data, start + i, 1); + if (res == PM3_SUCCESS) { + if (start + i == 0) { + PrintAndLogEx(INFO, "%03d | " _RED_("%s"), start + i, sprint_hex_ascii(data, sizeof(data))); + } else if (mfIsSectorTrailer(i)) { + PrintAndLogEx(INFO, "%03d | " _YELLOW_("%s"), start + i, sprint_hex_ascii(data, sizeof(data))); + } else { + PrintAndLogEx(INFO, "%03d | %s ", start + i, sprint_hex_ascii(data, sizeof(data))); + } + } + } + decode_print_st(start + blocks - 1, data); + return PM3_SUCCESS; +} + static int CmdHF14AMfEClear(const char *Cmd) { char c = tolower(param_getchar(Cmd, 0)); @@ -5222,23 +5273,24 @@ static command_t CommandTable[] = { // {"sniff", CmdHF14AMfSniff, 0, "Sniff card-reader communication"}, {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("simulation") " -----------------------"}, {"sim", CmdHF14AMfSim, IfPm3Iso14443a, "Simulate MIFARE card"}, + {"ecfill", CmdHF14AMfECFill, IfPm3Iso14443a, "Fill simulator memory with help of keys from simulator"}, {"eclr", CmdHF14AMfEClear, IfPm3Iso14443a, "Clear simulator memory"}, - {"eget", CmdHF14AMfEGet, IfPm3Iso14443a, "Get simulator memory block"}, - {"eset", CmdHF14AMfESet, IfPm3Iso14443a, "Set simulator memory block"}, + {"egetblk", CmdHF14AMfEGetBlk, IfPm3Iso14443a, "Get simulator memory block"}, + {"egetsc", CmdHF14AMfEGetSc, IfPm3Iso14443a, "Get simulator memory sector"}, + {"ekeyprn", CmdHF14AMfEKeyPrn, IfPm3Iso14443a, "Print keys from simulator memory"}, {"eload", CmdHF14AMfELoad, IfPm3Iso14443a, "Load from file emul dump"}, {"esave", CmdHF14AMfESave, IfPm3Iso14443a, "Save to file emul dump"}, + {"eset", CmdHF14AMfESet, IfPm3Iso14443a, "Set simulator memory block"}, {"eview", CmdHF14AMfEView, IfPm3Iso14443a, "View emul memory"}, - {"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"}, - {"cwipe", CmdHF14AMfCWipe, IfPm3Iso14443a, "Wipe card to default UID/Sectors/Keys"}, - {"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"}, + {"csetblk", CmdHF14AMfCSetBlk, IfPm3Iso14443a, "Write block"}, + {"csetuid", CmdHF14AMfCSetUID, IfPm3Iso14443a, "Set UID"}, {"cview", CmdHF14AMfCView, IfPm3Iso14443a, "view card"}, + {"cwipe", CmdHF14AMfCWipe, IfPm3Iso14443a, "Wipe card to default UID/Sectors/Keys"}, {"-----------", CmdHelp, IfPm3Iso14443a, "----------------------- " _CYAN_("magic gen3") " -----------------------"}, {"gen3uid", CmdHf14AGen3UID, IfPm3Iso14443a, "Set UID without manufacturer block"}, {"gen3blk", CmdHf14AGen3Block, IfPm3Iso14443a, "Overwrite full manufacturer block"}, diff --git a/client/src/cmdhfmfdes.c b/client/src/cmdhfmfdes.c index e48e54958..3b36e033d 100644 --- a/client/src/cmdhfmfdes.c +++ b/client/src/cmdhfmfdes.c @@ -321,6 +321,7 @@ typedef enum { DESFIRE_EV3, DESFIRE_LIGHT, PLUS_EV1, + NTAG413DNA, } nxp_cardtype_t; typedef struct { @@ -347,9 +348,9 @@ static char *getCardSizeStr(uint8_t fsize) { // is LSB set? if (fsize & 1) - snprintf(retStr, sizeof(buf), "0x%02X (" _YELLOW_("%d - %d bytes") ")", fsize, usize, lsize); + snprintf(retStr, sizeof(buf), "0x%02X (" _GREEN_("%d - %d bytes") ")", fsize, usize, lsize); else - snprintf(retStr, sizeof(buf), "0x%02X (" _YELLOW_("%d bytes") ")", fsize, lsize); + snprintf(retStr, sizeof(buf), "0x%02X (" _GREEN_("%d bytes") ")", fsize, lsize); return buf; } @@ -377,18 +378,22 @@ static char *getVersionStr(uint8_t major, uint8_t minor) { char *retStr = buf; if (major == 0x00) - snprintf(retStr, sizeof(buf), "%x.%x (" _YELLOW_("DESFire MF3ICD40") ")", major, minor); + snprintf(retStr, sizeof(buf), "%x.%x (" _GREEN_("DESFire MF3ICD40") ")", major, minor); else if (major == 0x01 && minor == 0x00) - snprintf(retStr, sizeof(buf), "%x.%x (" _YELLOW_("DESFire EV1") ")", major, minor); + snprintf(retStr, sizeof(buf), "%x.%x (" _GREEN_("DESFire EV1") ")", major, minor); else if (major == 0x12 && minor == 0x00) - snprintf(retStr, sizeof(buf), "%x.%x (" _YELLOW_("DESFire EV2") ")", major, minor); + snprintf(retStr, sizeof(buf), "%x.%x (" _GREEN_("DESFire EV2") ")", major, minor); else if (major == 0x33 && minor == 0x00) - snprintf(retStr, sizeof(buf), "%x.%x (" _YELLOW_("DESFire EV3") ")", major, minor); + snprintf(retStr, sizeof(buf), "%x.%x (" _GREEN_("DESFire EV3") ")", major, minor); else if (major == 0x30 && minor == 0x00) - snprintf(retStr, sizeof(buf), "%x.%x (" _YELLOW_("DESFire Light") ")", major, minor); + snprintf(retStr, sizeof(buf), "%x.%x (" _GREEN_("DESFire Light") ")", major, minor); + else if (major == 0x10 && minor == 0x00) + snprintf(retStr, sizeof(buf), "%x.%x (" _GREEN_("NTAG413DNA") ")", major, minor); else snprintf(retStr, sizeof(buf), "%x.%x (" _YELLOW_("Unknown") ")", major, minor); return buf; + +//04 01 01 01 00 1A 05 } static int DESFIRESendApdu(bool activate_field, bool leavefield_on, sAPDU apdu, uint8_t *result, uint32_t max_result_len, uint32_t *result_len, uint16_t *sw) { @@ -648,9 +653,10 @@ static nxp_cardtype_t getCardType(uint8_t major, uint8_t minor) { return DESFIRE_EV3; if (major == 0x30 && minor == 0x00) return DESFIRE_LIGHT; - if (major == 0x11 && minor == 0x00) + if (major == 0x11 && minor == 0x00) return PLUS_EV1; - + if (major == 0x10 && minor == 0x00) + return NTAG413DNA; return DESFIRE_UNKNOWN; } @@ -1176,6 +1182,7 @@ static int desfire_print_signature(uint8_t *uid, uint8_t uidlen, uint8_t *signat {"Mifare Plus EV1", "044409ADC42F91A8394066BA83D872FB1D16803734E911170412DDF8BAD1A4DADFD0416291AFE1C748253925DA39A5F39A1C557FFACD34C62E"} }; + uint32_t i; bool is_valid = false; @@ -1190,24 +1197,29 @@ static int desfire_print_signature(uint8_t *uid, uint8_t uidlen, uint8_t *signat if (is_valid) break; } +// PrintAndLogEx(NORMAL, ""); +// PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature")); if (is_valid == false || i == ARRAYLEN(nxp_desfire_public_keys)) { - PrintAndLogEx(SUCCESS, "Signature verification " _RED_("failed")); + PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp224r1"); + PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, 16)); + PrintAndLogEx(INFO, " : %s", sprint_hex_inrow(signature + 16, 16)); + PrintAndLogEx(INFO, " : %s", sprint_hex_inrow(signature + 32, 16)); + PrintAndLogEx(INFO, " : %s", sprint_hex_inrow(signature + 48, signature_len - 48)); + PrintAndLogEx(SUCCESS, " Signature verification: " _RED_("failed")); return PM3_ESOFT; } -// PrintAndLogEx(NORMAL, ""); -// PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature")); PrintAndLogEx(INFO, " IC signature public key name: " _GREEN_("%s"), nxp_desfire_public_keys[i].desc); PrintAndLogEx(INFO, "IC signature public key value: %.32s", nxp_desfire_public_keys[i].value); - PrintAndLogEx(INFO, " : %.32s", nxp_desfire_public_keys[i].value + 16); PrintAndLogEx(INFO, " : %.32s", nxp_desfire_public_keys[i].value + 32); - PrintAndLogEx(INFO, " : %.32s", nxp_desfire_public_keys[i].value + 48); + PrintAndLogEx(INFO, " : %.32s", nxp_desfire_public_keys[i].value + 64); + PrintAndLogEx(INFO, " : %.32s", nxp_desfire_public_keys[i].value + 96); PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp224r1"); PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, 16)); PrintAndLogEx(INFO, " : %s", sprint_hex_inrow(signature + 16, 16)); PrintAndLogEx(INFO, " : %s", sprint_hex_inrow(signature + 32, 16)); PrintAndLogEx(INFO, " : %s", sprint_hex_inrow(signature + 48, signature_len - 48)); - PrintAndLogEx(SUCCESS, " Signature verified: " _GREEN_("successful")); + PrintAndLogEx(SUCCESS, " Signature verification: " _GREEN_("successful")); return PM3_SUCCESS; } @@ -3312,7 +3324,10 @@ static int CmdHF14ADesInfo(const char *Cmd) { if (major == 0 && minor == 2) PrintAndLogEx(INFO, "\t0.2 - DESFire Light, Originality check, "); - if (cardtype == DESFIRE_EV2 || cardtype == DESFIRE_LIGHT || cardtype == DESFIRE_EV3) { + if (cardtype == DESFIRE_EV2 || + cardtype == DESFIRE_LIGHT || + cardtype == DESFIRE_EV3 || + cardtype == NTAG413DNA) { // Signature originality check uint8_t signature[56] = {0}; size_t signature_len = 0; diff --git a/client/src/cmdhfmfp.c b/client/src/cmdhfmfp.c index 4ee04e781..f7d7d2142 100644 --- a/client/src/cmdhfmfp.c +++ b/client/src/cmdhfmfp.c @@ -58,9 +58,9 @@ static char *getCardSizeStr(uint8_t fsize) { // is LSB set? if (fsize & 1) - snprintf(retStr, sizeof(buf), "0x%02X (" _YELLOW_("%d - %d bytes") ")", fsize, usize, lsize); + snprintf(retStr, sizeof(buf), "0x%02X (" _GREEN_("%d - %d bytes") ")", fsize, usize, lsize); else - snprintf(retStr, sizeof(buf), "0x%02X (" _YELLOW_("%d bytes") ")", fsize, lsize); + snprintf(retStr, sizeof(buf), "0x%02X (" _GREEN_("%d bytes") ")", fsize, lsize); return buf; } @@ -88,18 +88,17 @@ static char *getVersionStr(uint8_t major, uint8_t minor) { char *retStr = buf; if (major == 0x00) - snprintf(retStr, sizeof(buf), "%x.%x (" _YELLOW_("DESFire MF3ICD40") ")", major, minor); + snprintf(retStr, sizeof(buf), "%x.%x (" _GREEN_("DESFire MF3ICD40") ")", major, minor); else if (major == 0x01 && minor == 0x00) - snprintf(retStr, sizeof(buf), "%x.%x (" _YELLOW_("DESFire EV1") ")", major, minor); + snprintf(retStr, sizeof(buf), "%x.%x (" _GREEN_("DESFire EV1") ")", major, minor); else if (major == 0x12 && minor == 0x00) - snprintf(retStr, sizeof(buf), "%x.%x (" _YELLOW_("DESFire EV2") ")", major, minor); + snprintf(retStr, sizeof(buf), "%x.%x (" _GREEN_("DESFire EV2") ")", major, minor); else if (major == 0x33 && minor == 0x00) - snprintf(retStr, sizeof(buf), "%x.%x (" _YELLOW_("DESFire EV3") ")", major, minor); + snprintf(retStr, sizeof(buf), "%x.%x (" _GREEN_("DESFire EV3") ")", major, minor); else if (major == 0x30 && minor == 0x00) - snprintf(retStr, sizeof(buf), "%x.%x (" _YELLOW_("DESFire Light") ")", major, minor); - + snprintf(retStr, sizeof(buf), "%x.%x (" _GREEN_("DESFire Light") ")", major, minor); else if (major == 0x11 && minor == 0x00) - snprintf(retStr, sizeof(buf), "%x.%x (" _YELLOW_("Plus EV1") ")", major, minor); + snprintf(retStr, sizeof(buf), "%x.%x (" _GREEN_("Plus EV1") ")", major, minor); else snprintf(retStr, sizeof(buf), "%x.%x (" _YELLOW_("Unknown") ")", major, minor); return buf; @@ -186,21 +185,26 @@ static int plus_print_signature(uint8_t *uid, uint8_t uidlen, uint8_t *signature PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature")); if (is_valid == false || i == ARRAYLEN(nxp_plus_public_keys)) { - PrintAndLogEx(SUCCESS, "Signature verification " _RED_("failed")); + PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp224r1"); + PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, 16)); + PrintAndLogEx(INFO, " : %s", sprint_hex_inrow(signature + 16, 16)); + PrintAndLogEx(INFO, " : %s", sprint_hex_inrow(signature + 32, 16)); + PrintAndLogEx(INFO, " : %s", sprint_hex_inrow(signature + 48, signature_len - 48)); + PrintAndLogEx(SUCCESS, " Signature verification: " _RED_("failed")); return PM3_ESOFT; } PrintAndLogEx(INFO, " IC signature public key name: " _GREEN_("%s"), nxp_plus_public_keys[i].desc); PrintAndLogEx(INFO, "IC signature public key value: %.32s", nxp_plus_public_keys[i].value); - PrintAndLogEx(INFO, " : %.32s", nxp_plus_public_keys[i].value + 16); PrintAndLogEx(INFO, " : %.32s", nxp_plus_public_keys[i].value + 32); - PrintAndLogEx(INFO, " : %.32s", nxp_plus_public_keys[i].value + 48); + PrintAndLogEx(INFO, " : %.32s", nxp_plus_public_keys[i].value + 64); + PrintAndLogEx(INFO, " : %.32s", nxp_plus_public_keys[i].value + 96); PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp224r1"); PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, 16)); PrintAndLogEx(INFO, " : %s", sprint_hex_inrow(signature + 16, 16)); PrintAndLogEx(INFO, " : %s", sprint_hex_inrow(signature + 32, 16)); PrintAndLogEx(INFO, " : %s", sprint_hex_inrow(signature + 48, signature_len - 48)); - PrintAndLogEx(SUCCESS, " Signature verified: " _GREEN_("successful")); + PrintAndLogEx(SUCCESS, " Signature verification: " _GREEN_("successful")); return PM3_SUCCESS; } @@ -356,10 +360,8 @@ static int CmdHFMFPInfo(const char *Cmd) { } if (card.sak == 0x20) { - PrintAndLogEx(INFO, " SAK: " _GREEN_("MIFARE Plus SL0/SL3") " or " _GREEN_("MIFARE DESFire")); - if (card.ats_len > 0) { - + PrintAndLogEx(INFO, " SAK: " _GREEN_("MIFARE Plus SL0/SL3") " or " _GREEN_("MIFARE DESFire")); SLmode = 3; // check SL0 uint8_t data[250] = {0}; @@ -368,15 +370,22 @@ static int CmdHFMFPInfo(const char *Cmd) { uint8_t cmd[3 + 16] = {0xa8, 0x90, 0x90, 0x00}; int res = ExchangeRAW14a(cmd, sizeof(cmd), true, false, data, sizeof(data), &datalen, false); - // DESFire answers 0x1C + // DESFire answers 0x1C or 67 00 // Plus answers 0x0B, 0x09 - PrintAndLogEx(INFO, "ICEE: %s", sprint_hex(data, datalen)); - - if (memcmp(data, "\x67\x00", 2) == 0) { - PrintAndLogEx(INFO, "\tMost likely a MIFARE DESFire tag"); + if ( data[0] != 0x0b && data[0] != 0x09 && data[0] != 0x1C && data[0] != 0x67) { + PrintAndLogEx(INFO, _RED_("Send copy to iceman of this command output!")); + PrintAndLogEx(INFO, "data: %s", sprint_hex(data, datalen)); + } + + if ((memcmp(data, "\x67\x00", 2) == 0) || + (memcmp(data, "\x1C\x83\x0C", 3) == 0) + ) { + PrintAndLogEx(INFO, " result: " _RED_("MIFARE DESFire")); PrintAndLogEx(HINT, "Hint: Try " _YELLOW_("`hf mfdes info`")); DropField(); return PM3_SUCCESS; + } else { + PrintAndLogEx(INFO, " result: " _GREEN_("MIFARE Plus SL0/SL3")); } if (!res && datalen > 1 && data[0] == 0x09) { diff --git a/client/src/cmdhfmfu.c b/client/src/cmdhfmfu.c index a9b03cb46..0fcbe1796 100644 --- a/client/src/cmdhfmfu.c +++ b/client/src/cmdhfmfu.c @@ -136,7 +136,7 @@ static int usage_hf_mfu_wrbl(void) { static int usage_hf_mfu_eload(void) { PrintAndLogEx(NORMAL, "It loads emul dump from the file " _YELLOW_("`filename.eml`")); - PrintAndLogEx(NORMAL, "Hint: See " _YELLOW_("`script run dumptoemul-mfu`") " to convert the .bin to the eml"); + PrintAndLogEx(NORMAL, "Hint: See " _YELLOW_("`script run hf_mfu_dumptoemulator`") " to convert the .bin to the eml"); PrintAndLogEx(NORMAL, "Usage: hf mfu eload u [numblocks]"); PrintAndLogEx(NORMAL, " Options:"); PrintAndLogEx(NORMAL, " h : this help"); @@ -272,14 +272,14 @@ uint32_t UL_TYPES_ARRAY[] = { UNKNOWN, UL, UL_C, UL_EV1_48, UL_EV1_128, NTAG, NTAG_203, NTAG_210, NTAG_212, NTAG_213, NTAG_215, NTAG_216, MY_D, MY_D_NFC, MY_D_MOVE, MY_D_MOVE_NFC, MY_D_MOVE_LEAN, FUDAN_UL, - UL_EV1, NTAG_213_F, NTAG_216_F, UL_NANO_40, NTAG_I2C_1K + UL_EV1, NTAG_213_F, NTAG_216_F, UL_NANO_40, NTAG_I2C_1K, NTAG_213_TT }; uint8_t UL_MEMORY_ARRAY[ARRAYLEN(UL_TYPES_ARRAY)] = { MAX_UL_BLOCKS, MAX_UL_BLOCKS, MAX_ULC_BLOCKS, MAX_ULEV1a_BLOCKS, MAX_ULEV1b_BLOCKS, MAX_NTAG_203, MAX_NTAG_203, MAX_NTAG_210, MAX_NTAG_212, MAX_NTAG_213, MAX_NTAG_215, MAX_NTAG_216, MAX_UL_BLOCKS, MAX_MY_D_NFC, MAX_MY_D_MOVE, MAX_MY_D_MOVE, MAX_MY_D_MOVE_LEAN, MAX_UL_BLOCKS, - MAX_ULEV1a_BLOCKS, MAX_NTAG_213, MAX_NTAG_216, MAX_UL_NANO_40, MAX_NTAG_I2C_1K + MAX_ULEV1a_BLOCKS, MAX_NTAG_213, MAX_NTAG_216, MAX_UL_NANO_40, MAX_NTAG_I2C_1K, MAX_NTAG_213 }; //------------------------------------ @@ -493,7 +493,7 @@ static int ul_fudan_check(void) { return (!resp.data.asBytes[0]) ? FUDAN_UL : UL; //if response == 0x00 then Fudan, else Genuine NXP } -static int ul_print_default(uint8_t *data) { +static int ul_print_default(uint8_t *data, uint8_t *real_uid) { uint8_t uid[7]; uid[0] = data[0]; @@ -503,10 +503,14 @@ static int ul_print_default(uint8_t *data) { uid[4] = data[5]; uid[5] = data[6]; uid[6] = data[7]; + bool mful_uid_layout = true; - PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(uid, 7)); - PrintAndLogEx(SUCCESS, " UID[0]: %02X, %s", uid[0], getTagInfo(uid[0])); - if (uid[0] == 0x05 && ((uid[1] & 0xf0) >> 4) == 2) { // is infineon and 66RxxP + if (memcmp(uid, real_uid, 7) != 0) { + mful_uid_layout = false; + } + PrintAndLogEx(SUCCESS, " UID: " _GREEN_("%s"), sprint_hex(real_uid, 7)); + PrintAndLogEx(SUCCESS, " UID[0]: %02X, %s", real_uid[0], getTagInfo(real_uid[0])); + if (real_uid[0] == 0x05 && ((real_uid[1] & 0xf0) >> 4) == 2) { // is infineon and 66RxxP uint8_t chip = (data[8] & 0xC7); // 11000111 mask, bit 3,4,5 RFU switch (chip) { case 0xC2: @@ -520,20 +524,23 @@ static int ul_print_default(uint8_t *data) { break; //512 pages /2 sectors } } - // CT (cascade tag byte) 0x88 xor SN0 xor SN1 xor SN2 - int crc0 = 0x88 ^ uid[0] ^ uid[1] ^ uid[2]; - if (data[3] == crc0) - PrintAndLogEx(SUCCESS, " BCC0: %02X (" _GREEN_("ok") ")", data[3]); - else - PrintAndLogEx(NORMAL, " BCC0: %02X, crc should be %02X", data[3], crc0); + if (mful_uid_layout) { + // CT (cascade tag byte) 0x88 xor SN0 xor SN1 xor SN2 + int crc0 = 0x88 ^ uid[0] ^ uid[1] ^ uid[2]; + if (data[3] == crc0) + PrintAndLogEx(SUCCESS, " BCC0: %02X (" _GREEN_("ok") ")", data[3]); + else + PrintAndLogEx(NORMAL, " BCC0: %02X, crc should be %02X", data[3], crc0); - int crc1 = uid[3] ^ uid[4] ^ uid[5] ^ uid[6]; - if (data[8] == crc1) - PrintAndLogEx(SUCCESS, " BCC1: %02X (" _GREEN_("ok") ")", data[8]); - else - PrintAndLogEx(NORMAL, " BCC1: %02X, crc should be %02X", data[8], crc1); - - PrintAndLogEx(SUCCESS, " Internal: %02X (%s)", data[9], (data[9] == 0x48) ? _GREEN_("default") : _RED_("not default")); + int crc1 = uid[3] ^ uid[4] ^ uid[5] ^ uid[6]; + if (data[8] == crc1) + PrintAndLogEx(SUCCESS, " BCC1: %02X (" _GREEN_("ok") ")", data[8]); + else + PrintAndLogEx(NORMAL, " BCC1: %02X, crc should be %02X", data[8], crc1); + PrintAndLogEx(SUCCESS, " Internal: %02X (%s)", data[9], (data[9] == 0x48) ? _GREEN_("default") : _RED_("not default")); + } else { + PrintAndLogEx(SUCCESS, "Blocks 0-2: %s", sprint_hex(data + 0, 12)); + } PrintAndLogEx(SUCCESS, " Lock: %s - %s", sprint_hex(data + 10, 2), @@ -678,6 +685,8 @@ int ul_print_type(uint32_t tagtype, uint8_t spaces) { PrintAndLogEx(SUCCESS, "%*sTYPE: " _YELLOW_("NTAG 213 144bytes (NT2H1311G0DU)"), spaces, ""); else if (tagtype & NTAG_213_F) PrintAndLogEx(SUCCESS, "%*sTYPE: " _YELLOW_("NTAG 213F 144bytes (NT2H1311F0DTL)"), spaces, ""); + else if (tagtype & NTAG_213_TT) + PrintAndLogEx(SUCCESS, "%*sTYPE: " _YELLOW_("NTAG 213TT 144bytes (NT2H1311TTDU)"), spaces, ""); else if (tagtype & NTAG_215) PrintAndLogEx(SUCCESS, "%*sTYPE: " _YELLOW_("NTAG 215 504bytes (NT2H1511G0DU)"), spaces, ""); else if (tagtype & NTAG_216) @@ -758,7 +767,7 @@ static int ulev1_print_configuration(uint32_t tagtype, uint8_t *data, uint8_t st PrintAndLogEx(INFO, " cfg0 [%u/0x%02X]: %s", startPage, startPage, sprint_hex(data, 4)); - if ((tagtype & (NTAG_213_F | NTAG_216_F))) { + if ((tagtype & (NTAG_213_F | NTAG_213_TT | NTAG_216_F))) { uint8_t mirror_conf = (data[0] & 0xC0); uint8_t mirror_byte = (data[0] & 0x30); bool sleep_en = (data[0] & 0x08); @@ -801,7 +810,7 @@ static int ulev1_print_configuration(uint32_t tagtype, uint8_t *data, uint8_t st break; } // valid mirror start page and byte position within start page. - if (tagtype & NTAG_213_F) { + if ((tagtype & NTAG_213_F)||(tagtype & NTAG_213_TT)) { switch (mirror_conf) { case 1: { PrintAndLogEx(INFO, " mirror start block %02X | byte pos %02X - %s", data[2], mirror_byte, (data[2] >= 0x4 && data[2] <= 0x24) ? "OK" : "Invalid value"); break;} @@ -880,7 +889,7 @@ static int ulev1_print_signature(TagTypeUL_t tagtype, uint8_t *uid, uint8_t *sig {"NXP Public key", "04A748B6A632FBEE2C0897702B33BEA1C074998E17B84ACA04FF267E5D2C91F6DC"}, {"NXP Ultralight Ev1", "0490933BDCD6E99B4E255E3DA55389A827564E11718E017292FAF23226A96614B8"}, {"NXP NTAG21x (2013)", "04494E1A386D3D3CFE3DC10E5DE68A499B1C202DB5B132393E89ED19FE5BE8BC61"}, - {"MICRON Public key", "04f971eda742a4a80d32dcf6a814a707cc3dc396d35902f72929fdcd698b3468f2"}, + {"MIKRON Public key", "04f971eda742a4a80d32dcf6a814a707cc3dc396d35902f72929fdcd698b3468f2"}, }; /* @@ -945,17 +954,19 @@ static int ulev1_print_signature(TagTypeUL_t tagtype, uint8_t *uid, uint8_t *sig } PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature")); if (is_valid == false || i == ARRAYLEN(nxp_mfu_public_keys)) { - PrintAndLogEx(SUCCESS, "Signature verification " _RED_("failed")); + PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp128r1"); + PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, signature_len)); + PrintAndLogEx(SUCCESS, " Signature verification: " _RED_("failed")); return PM3_ESOFT; } - PrintAndLogEx(INFO, "--- " _CYAN_("Tag Signature")); PrintAndLogEx(INFO, " IC signature public key name: %s", nxp_mfu_public_keys[i].desc); PrintAndLogEx(INFO, "IC signature public key value: %s", nxp_mfu_public_keys[i].value); PrintAndLogEx(INFO, " Elliptic curve parameters: NID_secp128r1"); PrintAndLogEx(INFO, " TAG IC Signature: %s", sprint_hex_inrow(signature, signature_len)); - PrintAndLogEx(SUCCESS, " Signature verified: " _GREEN_("successful")); + PrintAndLogEx(SUCCESS, " Signature verification: " _GREEN_("successful")); return PM3_SUCCESS; } @@ -1088,6 +1099,7 @@ uint32_t GetHF14AMfU_Type(void) { MF0UNH1001DUx 0004030203000B03 NT2L1001G0DUx 0004040102000B03 NT2H1001G0DUx 0004040202000B03 + NT2H1311TTDUx 0004040203000F03 Micron UL 0034210101000E03 */ @@ -1104,6 +1116,7 @@ uint32_t GetHF14AMfU_Type(void) { else if (memcmp(version, "\x00\x04\x04\x02\x01\x00\x13", 7) == 0) { tagtype = NTAG_216; break; } else if (memcmp(version, "\x00\x04\x04\x04\x01\x00\x0F", 7) == 0) { tagtype = NTAG_213_F; break; } else if (memcmp(version, "\x00\x04\x04\x04\x01\x00\x13", 7) == 0) { tagtype = NTAG_216_F; break; } + else if (memcmp(version, "\x00\x04\x04\x02\x03\x00\x0F", 7) == 0) { tagtype = NTAG_213_TT; break; } else if (memcmp(version, "\x00\x04\x04\x05\x02\x01\x13", 7) == 0) { tagtype = NTAG_I2C_1K; break; } else if (memcmp(version, "\x00\x04\x04\x05\x02\x01\x15", 7) == 0) { tagtype = NTAG_I2C_2K; break; } else if (memcmp(version, "\x00\x04\x04\x05\x02\x02\x13", 7) == 0) { tagtype = NTAG_I2C_1K_PLUS; break; } @@ -1208,7 +1221,6 @@ static int CmdHF14AMfUInfo(const char *Cmd) { uint8_t *key = pwd; uint8_t pack[4] = {0, 0, 0, 0}; int len; - uint8_t uid[7]; char tempStr[50]; @@ -1261,9 +1273,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) { PrintAndLogEx(ERR, "Error: tag didn't answer to READ"); return PM3_ESOFT; } else if (status == 16) { - memcpy(uid, data, 3); - memcpy(uid + 3, data + 4, 4); - ul_print_default(data); + ul_print_default(data, card.uid); ndef_print_CC(data + 12); } else { locked = true; @@ -1328,7 +1338,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) { } // NTAG counters? - if ((tagtype & (NTAG_213 | NTAG_213_F | NTAG_215 | NTAG_216))) { + if ((tagtype & (NTAG_213 | NTAG_213_F | NTAG_213_TT | NTAG_215 | NTAG_216))) { if (ntag_print_counter()) { // failed - re-select if (ul_auth_select(&card, tagtype, hasAuthKey, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) return PM3_ESOFT; @@ -1336,7 +1346,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) { } // Read signature - if ((tagtype & (UL_EV1_48 | UL_EV1_128 | UL_EV1 | UL_NANO_40 | NTAG_213 | NTAG_213_F | NTAG_215 | NTAG_216 | NTAG_216_F | NTAG_I2C_1K | NTAG_I2C_2K | NTAG_I2C_1K_PLUS | NTAG_I2C_2K_PLUS))) { + if ((tagtype & (UL_EV1_48 | UL_EV1_128 | UL_EV1 | UL_NANO_40 | NTAG_213 | NTAG_213_F | NTAG_213_TT | NTAG_215 | NTAG_216 | NTAG_216_F | NTAG_I2C_1K | NTAG_I2C_2K | NTAG_I2C_1K_PLUS | NTAG_I2C_2K_PLUS))) { uint8_t ulev1_signature[32] = {0x00}; status = ulev1_readSignature(ulev1_signature, sizeof(ulev1_signature)); if (status == -1) { @@ -1345,7 +1355,7 @@ static int CmdHF14AMfUInfo(const char *Cmd) { return PM3_ESOFT; } if (status == 32) { - ulev1_print_signature(tagtype, uid, ulev1_signature, sizeof(ulev1_signature)); + ulev1_print_signature(tagtype, card.uid, ulev1_signature, sizeof(ulev1_signature)); } else { // re-select if (ul_auth_select(&card, tagtype, hasAuthKey, authkeyptr, pack, sizeof(pack)) == PM3_ESOFT) return PM3_ESOFT; @@ -1984,6 +1994,7 @@ static int CmdHF14AMfUDump(const char *Cmd) { iso14a_card_select_t card; mfu_dump_t dump_file_data; + memset(&dump_file_data, 0, sizeof(dump_file_data)); uint8_t get_version[] = {0, 0, 0, 0, 0, 0, 0, 0}; uint8_t get_counter_tearing[][4] = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}; uint8_t get_signature[32]; @@ -2021,7 +2032,7 @@ static int CmdHF14AMfUDump(const char *Cmd) { uint8_t n = 0; // NTAG has 1 counter, at 0x02 - if ((tagtype & (NTAG_213 | NTAG_213_F | NTAG_215 | NTAG_216))) { + if ((tagtype & (NTAG_213 | NTAG_213_F | NTAG_213_TT | NTAG_215 | NTAG_216))) { n = 2; } diff --git a/client/src/cmdhfmfu.h b/client/src/cmdhfmfu.h index 67e405677..210783874 100644 --- a/client/src/cmdhfmfu.h +++ b/client/src/cmdhfmfu.h @@ -57,6 +57,7 @@ typedef enum TAGTYPE_UL { NTAG_216_F = 0x800000, UL_EV1 = 0x1000000, UL_NANO_40 = 0x2000000, + NTAG_213_TT = 0x4000000, UL_MAGIC = UL | MAGIC, UL_C_MAGIC = UL_C | MAGIC, UL_ERROR = 0xFFFFFF, diff --git a/client/src/cmdhfst.c b/client/src/cmdhfst.c index e16b513e4..acb6ee361 100644 --- a/client/src/cmdhfst.c +++ b/client/src/cmdhfst.c @@ -52,6 +52,34 @@ static int usage_hf_st_ndef(void) { return PM3_SUCCESS; } +static int usage_hf_st_protect(void) { + PrintAndLogEx(NORMAL, "\n Change R/W protection for NFC Data Exchange Format (NDEF)\n"); + PrintAndLogEx(NORMAL, "Usage: hf st protect [h] p r|w [0|1]"); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h : This help"); + PrintAndLogEx(NORMAL, " p : 16 byte write password"); + PrintAndLogEx(NORMAL, " r|w : Change (r)ead or (w)rite protection"); + PrintAndLogEx(NORMAL, " [0|1] : Enable / Disable protection"); + PrintAndLogEx(NORMAL, " 0 = Disable (default)"); + PrintAndLogEx(NORMAL, " 1 = Enable"); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, _YELLOW_(" hf st protect p 82E80053D4CA5C0B656D852CC696C8A1 r 0")); + return PM3_SUCCESS; +} + +static int usage_hf_st_pwd(void) { + PrintAndLogEx(NORMAL, "\n Change R/W password for NFC Data Exchange Format (NDEF)\n"); + PrintAndLogEx(NORMAL, "Usage: hf st pwd [h] p r|w n "); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h : This help"); + PrintAndLogEx(NORMAL, " p : 16 byte write password"); + PrintAndLogEx(NORMAL, " r|w : Change (r)ead or (w)rite password"); + PrintAndLogEx(NORMAL, " n : New 16 byte password"); + PrintAndLogEx(NORMAL, "Examples:"); + PrintAndLogEx(NORMAL, _YELLOW_(" hf st pwd p 82E80053D4CA5C0B656D852CC696C8A1 r n 00000000000000000000000000000000")); + return PM3_SUCCESS; +} + // get ST Microelectronics chip model (from UID) static char *get_st_chip_model(uint8_t pc) { static char model[40]; @@ -138,8 +166,8 @@ static void print_st_cc_info(uint8_t *d, uint8_t n) { 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, " read ( %02X ) protection: %s", d[13], ((d[13] & 0x80) == 0x80) ? _RED_("enabled") : _GREEN_("disabled")); + PrintAndLogEx(SUCCESS, " write ( %02X ) protection: %s", d[14], ((d[14] & 0x80) == 0x80) ? _RED_("enabled") : _GREEN_("disabled")); PrintAndLogEx(SUCCESS, " }"); PrintAndLogEx(SUCCESS, "----------------- " _CYAN_("raw") " -----------------"); PrintAndLogEx(SUCCESS, "%s", sprint_hex_inrow(d, n)); @@ -443,6 +471,273 @@ static int cmd_hf_st_ndef(const char *Cmd) { return PM3_SUCCESS; } +static int cmd_hf_st_protect(const char *Cmd) { + + uint8_t cmdp = 0; + bool errors = false; + int pwdlen = 0; + uint8_t pwd[16] = {0}; + int statelen = 3; + uint8_t state[3] = {0x26, 0, 0}; + + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h': + return usage_hf_st_protect(); + case '0': + state[0] = 0x26; //Disable protection + cmdp++; + break; + case '1': + state[0] = 0x28; //Enable protection + cmdp++; + break; + case 'r': + state[2] = 0x01; + cmdp++; + break; + case 'w': + state[2] = 0x02; + cmdp++; + break; + case 'p': + param_gethex_ex(Cmd, cmdp + 1, pwd, &pwdlen); + pwdlen >>= 1; + cmdp += 2; + break; + default: + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + + //Validations + + if (state[2] == 0x00) { + PrintAndLogEx(WARNING, "Missing action (r)ead or (w)rite"); + errors = true; + } + if (pwdlen != 16) { + PrintAndLogEx(WARNING, "Missing 16 byte password"); + errors = true; + } + + if (errors || cmdp == 0) return usage_hf_st_protect(); + + 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; + + // --------------- Select NDEF file ---------------- + 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; + // need to provide 16byte password + param_gethex_to_eol("0020000210", 0, aVERIFY, sizeof(aVERIFY), &aVERIFY_n); + memcpy(aVERIFY + aVERIFY_n, pwd, pwdlen); + res = ExchangeAPDU14a(aVERIFY, aVERIFY_n + pwdlen, activate_field, keep_field_on, response, sizeof(response), &resplen); + if (res) + 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; + } + + // --------------- Change protection ---------------- + keep_field_on = false; + uint8_t aPROTECT[30]; + int aPROTECT_n = 0; + param_gethex_to_eol("00", 0, aPROTECT, sizeof(aPROTECT), &aPROTECT_n); + memcpy(aPROTECT + aPROTECT_n, state, statelen); + res = ExchangeAPDU14a(aPROTECT, aPROTECT_n + statelen, activate_field, keep_field_on, response, sizeof(response), &resplen); + if (res) + return res; + + sw = get_sw(response, resplen); + if (sw != 0x9000) { + PrintAndLogEx(ERR, "changing protection failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + return PM3_ESOFT; + } + + PrintAndLogEx(SUCCESS, " %s protection ( %s )", ((state[2] & 0x01) == 0x01) ? _YELLOW_("read") : _YELLOW_("write"), + ((state[0] & 0x28) == 0x28) ? _RED_("enabled") : _GREEN_("disabled")); + + return PM3_SUCCESS; +} + +static int cmd_hf_st_pwd(const char *Cmd) { + char c = tolower(param_getchar(Cmd, 0)); + if (c == 'h' || c == 0x00) return usage_hf_st_pwd(); + + uint8_t cmdp = 0; + bool errors = false; + int pwdlen = 0; + uint8_t pwd[16] = {0}; + int newpwdlen = 0; + uint8_t newpwd[16] = {0}; + int changePwdlen = 4; + uint8_t changePwd[4] = {0x24, 0x00, 0x00, 0x10}; + + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h': + return usage_hf_st_pwd(); + case 'r': + changePwd[2] = 0x01; + cmdp++; + break; + case 'w': + changePwd[2] = 0x02; + cmdp++; + break; + case 'p': + param_gethex_ex(Cmd, cmdp + 1, pwd, &pwdlen); + pwdlen >>= 1; + cmdp += 2; + break; + case 'n': + param_gethex_ex(Cmd, cmdp + 1, newpwd, &newpwdlen); + newpwdlen >>= 1; + cmdp += 2; + break; + default: + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + + //Validations + + if (changePwd[2] == 0x00) { + PrintAndLogEx(WARNING, "Missing password specification: (r)ead or (w)rite"); + errors = true; + } + if (pwdlen != 16) { + PrintAndLogEx(WARNING, "Missing original 16 byte password"); + errors = true; + } + if (newpwdlen != 16) { + PrintAndLogEx(WARNING, "Missing new 16 byte password"); + errors = true; + } + if (errors || cmdp == 0) return usage_hf_st_pwd(); + + 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; + + // --------------- Select NDEF file ---------------- + 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; + // need to provide 16byte password + param_gethex_to_eol("0020000210", 0, aVERIFY, sizeof(aVERIFY), &aVERIFY_n); + memcpy(aVERIFY + aVERIFY_n, pwd, pwdlen); + res = ExchangeAPDU14a(aVERIFY, aVERIFY_n + pwdlen, activate_field, keep_field_on, response, sizeof(response), &resplen); + if (res) + 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; + } + + // --------------- Change password ---------------- + + keep_field_on = false; + uint8_t aCHG_PWD[30]; + int aCHG_PWD_n = 0; + param_gethex_to_eol("00", 0, aCHG_PWD, sizeof(aCHG_PWD), &aCHG_PWD_n); + memcpy(aCHG_PWD + aCHG_PWD_n, changePwd, changePwdlen); + memcpy(aCHG_PWD + aCHG_PWD_n + changePwdlen, newpwd, newpwdlen); + res = ExchangeAPDU14a(aCHG_PWD, aCHG_PWD_n + changePwdlen + newpwdlen, activate_field, keep_field_on, response, sizeof(response), &resplen); + if (res) + return res; + + sw = get_sw(response, resplen); + if (sw != 0x9000) { + PrintAndLogEx(ERR, "password change failed (%04x - %s).", sw, GetAPDUCodeDescription(sw >> 8, sw & 0xff)); + return PM3_ESOFT; + } + PrintAndLogEx(SUCCESS, " %s password changed", ((changePwd[2] & 0x01) == 0x01) ? _YELLOW_("read") : _YELLOW_("write")); + + return PM3_SUCCESS; + +} + static int cmd_hf_st_list(const char *Cmd) { (void)Cmd; // Cmd is not used so far CmdTraceList("7816"); @@ -450,11 +745,13 @@ static int cmd_hf_st_list(const char *Cmd) { } 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"}, + {"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"}, + {"protect", cmd_hf_st_protect, IfPm3Iso14443a, "change protection on tag"}, + {"pwd", cmd_hf_st_pwd, IfPm3Iso14443a, "change password on tag"}, + {"sim", cmd_hf_st_sim, IfPm3Iso14443a, "Fake ISO 14443A/ST tag"}, {NULL, NULL, NULL, NULL} }; diff --git a/client/src/cmdhfwaveshare.c b/client/src/cmdhfwaveshare.c index bbcee4e18..b41ecefea 100644 --- a/client/src/cmdhfwaveshare.c +++ b/client/src/cmdhfwaveshare.c @@ -364,31 +364,36 @@ static int read_bmp_rgb(uint8_t *bmp, const size_t bmpsize, uint8_t model_nr, ui if (pbmpheader->bpp != 24) { return PM3_ESOFT; } + if (pbmpheader->B == 'M' || pbmpheader->M == 'B') { //0x4d42 PrintAndLogEx(WARNING, "The file is not a BMP!"); return PM3_ESOFT; } + PrintAndLogEx(DEBUG, "file size = %d", pbmpheader->fsize); PrintAndLogEx(DEBUG, "file offset = %d", pbmpheader->offset); if (pbmpheader->fsize > bmpsize) { PrintAndLogEx(WARNING, "The file is truncated!"); return PM3_ESOFT; } + // Get BMP file data pointer uint32_t offset = pbmpheader->offset; uint16_t width = pbmpheader->BMP_Width; uint16_t height = pbmpheader->BMP_Height; - int16_t *chanR = calloc(width*height, sizeof(int16_t)); + int16_t *chanR = calloc(width * height, sizeof(int16_t)); if (chanR == NULL) { return PM3_EMALLOC; } - int16_t *chanG = calloc(width*height, sizeof(int16_t)); + + int16_t *chanG = calloc(width * height, sizeof(int16_t)); if (chanG == NULL) { free(chanR); return PM3_EMALLOC; } - int16_t *chanB = calloc(width*height, sizeof(int16_t)); + + int16_t *chanB = calloc(width * height, sizeof(int16_t)); if (chanB == NULL) { free(chanR); free(chanG); @@ -396,26 +401,26 @@ static int read_bmp_rgb(uint8_t *bmp, const size_t bmpsize, uint8_t model_nr, ui } // Extracting BMP chans - for (uint16_t Y=0; Yoffset; - for (uint16_t Y=0; Yoffset; - for (uint16_t Y=0; Y rxBufLen) { - PrintAndLogEx(WARNING, "Received % bytes, rxBuf too small (%)", resp.oldarg[0], rxBufLen); + PrintAndLogEx(WARNING, "Received %u bytes, rxBuf too small (%u)", resp.oldarg[0], rxBufLen); memcpy(rxBuf, resp.data.asBytes, rxBufLen); *actLen = rxBufLen; return PM3_ESOFT; @@ -565,6 +573,7 @@ static int transceive_blocking( uint8_t* txBuf, uint16_t txBufLen, uint8_t* rxBu memcpy(rxBuf, resp.data.asBytes, resp.oldarg[0]); *actLen = resp.oldarg[0]; } + if ((retransmit) && (rxBuf[0] != 0 || rxBuf[1] != 0)) { fail_num++; if (fail_num > 10) { diff --git a/client/src/cmdhw.c b/client/src/cmdhw.c index 4c93210eb..7c24bb342 100644 --- a/client/src/cmdhw.c +++ b/client/src/cmdhw.c @@ -715,18 +715,20 @@ void pm3_version(bool verbose, bool oneliner) { PrintAndLogEx(NORMAL, "%s", temp); PrintAndLogEx(NORMAL, " compiled with " PM3CLIENTCOMPILER __VERSION__ PM3HOSTOS PM3HOSTARCH); - if (IfPm3Flash() == false && IfPm3Smartcard() == false && IfPm3FpcUsartHost() == false) { - PrintAndLogEx(NORMAL, "\n [ " _YELLOW_("PROXMARK3") " ]"); - } else { - PrintAndLogEx(NORMAL, "\n [ " _YELLOW_("PROXMARK3 RDV4") " ]"); - PrintAndLogEx(NORMAL, " external flash: %s", IfPm3Flash() ? _GREEN_("present") : _YELLOW_("absent")); - PrintAndLogEx(NORMAL, " smartcard reader: %s", IfPm3Smartcard() ? _GREEN_("present") : _YELLOW_("absent")); - PrintAndLogEx(NORMAL, "\n [ " _YELLOW_("PROXMARK3 RDV4 Extras") " ]"); - PrintAndLogEx(NORMAL, " FPC USART for BT add-on support: %s", IfPm3FpcUsartHost() ? _GREEN_("present") : _YELLOW_("absent")); - - if (IfPm3FpcUsartDevFromUsb()) { - PrintAndLogEx(NORMAL, " FPC USART for developer support: %s", _GREEN_("present")); + PrintAndLogEx(NORMAL, "\n [ " _YELLOW_("PROXMARK3") " ]"); + if (IfPm3Rdv4Fw() == false ){ + PrintAndLogEx(NORMAL, " firmware.........................%s", _GREEN_("PM3OTHER")); + if (IfPm3FpcUsartHost()) { + PrintAndLogEx(NORMAL, " FPC USART for BT add-on..........%s", _GREEN_("present")); } + } else { + PrintAndLogEx(NORMAL, " firmware.........................%s", _GREEN_("PM3RDV4")); + PrintAndLogEx(NORMAL, " external flash...................%s", IfPm3Flash() ? _GREEN_("present") : _YELLOW_("absent")); + PrintAndLogEx(NORMAL, " smartcard reader.................%s", IfPm3Smartcard() ? _GREEN_("present") : _YELLOW_("absent")); + PrintAndLogEx(NORMAL, " FPC USART for BT add-on..........%s", IfPm3FpcUsartHost() ? _GREEN_("present") : _YELLOW_("absent")); + } + if (IfPm3FpcUsartDevFromUsb()) { + PrintAndLogEx(NORMAL, " FPC USART for developer..........%s", _GREEN_("present")); } PrintAndLogEx(NORMAL, ""); diff --git a/client/src/cmdlf.c b/client/src/cmdlf.c index f7ffab795..74821b449 100644 --- a/client/src/cmdlf.c +++ b/client/src/cmdlf.c @@ -56,29 +56,36 @@ #include "cmdlfmotorola.h" // for Motorola menu #include "cmdlfgallagher.h" // for GALLAGHER menu +#define LF_CMDREAD_MAX_EXTRA_SYMBOLS 4 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 z o c [q] [s #samples] [@]"); + PrintAndLogEx(NORMAL, "Usage: lf cmdread d z o [e ] c [q] [s #samples] [@]"); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h This help"); - PrintAndLogEx(NORMAL, " d delay OFF period, (0 for bitbang mode) (decimal)"); - PrintAndLogEx(NORMAL, " z ZERO time period (decimal)"); - PrintAndLogEx(NORMAL, " o ONE time period (decimal)"); - PrintAndLogEx(NORMAL, " c 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, " d delay OFF period, (0 for bitbang mode)"); + PrintAndLogEx(NORMAL, " z ZERO time period"); + PrintAndLogEx(NORMAL, " o ONE time period"); + PrintAndLogEx(NORMAL, " e Extra symbol definition and duration (up to %i)", LF_CMDREAD_MAX_EXTRA_SYMBOLS); + PrintAndLogEx(NORMAL, " b B period"); + PrintAndLogEx(NORMAL, " c Command symbols (0/1/...)"); + 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, " ************* " _YELLOW_("All periods in decimal and in microseconds (us)")); PrintAndLogEx(NORMAL, "Examples:"); - 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, "- probing for Hitag 1/Hitag S:"); + PrintAndLogEx(NORMAL, _YELLOW_(" lf cmdread d 50 z 116 o 166 e W 3000 c W00110")); + PrintAndLogEx(NORMAL, "- probing for Hitag 2:"); + PrintAndLogEx(NORMAL, _YELLOW_(" lf cmdread d 50 z 116 o 166 e W 3000 c W11000")); + PrintAndLogEx(NORMAL, "- probing for Hitag 2, oscilloscope style:"); + PrintAndLogEx(NORMAL, _YELLOW_(" data plot")); + PrintAndLogEx(NORMAL, _YELLOW_(" lf cmdread d 50 z 116 o 166 e W 3000 c W11000 q s 2000 @")); + PrintAndLogEx(NORMAL, "- probing for Hitag (us):"); + PrintAndLogEx(NORMAL, _YELLOW_(" lf cmdread d 48 z 112 o 176 e W 3000 e S 240 e E 336 c W0S00000010000E")); PrintAndLogEx(NORMAL, "Extras:"); PrintAndLogEx(NORMAL, " use " _YELLOW_("'lf config'")" to set parameters."); return PM3_SUCCESS; @@ -117,12 +124,19 @@ static int usage_lf_sim(void) { } static int usage_lf_sniff(void) { PrintAndLogEx(NORMAL, "Sniff low frequence signal."); - PrintAndLogEx(NORMAL, "Usage: lf sniff [h]"); + PrintAndLogEx(NORMAL, "Usage: lf sniff [h] [q] [s #samples] [@]"); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " h This help"); + 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, "Examples:"); + PrintAndLogEx(NORMAL, " lf sniff"); + PrintAndLogEx(NORMAL, "- oscilloscope style:"); + PrintAndLogEx(NORMAL, " data plot"); + PrintAndLogEx(NORMAL, " lf sniff q s 3000 @"); PrintAndLogEx(NORMAL, "Extras:"); PrintAndLogEx(NORMAL, " use " _YELLOW_("'lf config'")" to set parameters."); - PrintAndLogEx(NORMAL, " use " _YELLOW_("'data samples'")" command to download from device"); PrintAndLogEx(NORMAL, " use " _YELLOW_("'data plot'")" to look at it"); return PM3_SUCCESS; } @@ -324,17 +338,20 @@ int CmdLFCommandRead(const char *Cmd) { uint32_t samples = 0; uint16_t datalen = 0; - const uint8_t payload_header_size = 12; + const uint8_t payload_header_size = 12 + (3 * LF_CMDREAD_MAX_EXTRA_SYMBOLS); struct p { uint32_t delay; - uint16_t ones; - uint16_t zeros; + uint16_t period_0; + uint16_t period_1; + uint8_t symbol_extra[LF_CMDREAD_MAX_EXTRA_SYMBOLS]; + uint16_t period_extra[LF_CMDREAD_MAX_EXTRA_SYMBOLS]; 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 index_extra = 0; uint8_t cmdp = 0; while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { @@ -350,13 +367,24 @@ int CmdLFCommandRead(const char *Cmd) { cmdp += 2; break; case 'z': // zero - payload.zeros = param_get32ex(Cmd, cmdp + 1, 0, 10) & 0xFFFF; + payload.period_0 = param_get32ex(Cmd, cmdp + 1, 0, 10) & 0xFFFF; cmdp += 2; break; case 'o': // ones - payload.ones = param_get32ex(Cmd, cmdp + 1, 0, 10) & 0xFFFF; + payload.period_1 = param_get32ex(Cmd, cmdp + 1, 0, 10) & 0xFFFF; cmdp += 2; break; + case 'e': // extra symbol definition + if (index_extra < LF_CMDREAD_MAX_EXTRA_SYMBOLS - 1) { + payload.symbol_extra[index_extra] = param_getchar(Cmd, cmdp + 1); + payload.period_extra[index_extra] = param_get32ex(Cmd, cmdp + 2, 0, 10) & 0xFFFF; + index_extra++; + cmdp += 3; + } else { + PrintAndLogEx(WARNING, "Too many extra symbols, please define up to %i symbols", LF_CMDREAD_MAX_EXTRA_SYMBOLS); + errors = true; + } + break; case 's': samples = param_get32ex(Cmd, cmdp + 1, 0, 10); payload.samples = samples; @@ -380,7 +408,7 @@ int CmdLFCommandRead(const char *Cmd) { // bitbang mode if (payload.delay == 0) { - if (payload.zeros < 7 || payload.ones < 7) { + if (payload.period_0 < 7 || payload.period_1 < 7) { PrintAndLogEx(WARNING, "warning periods cannot be less than 7us in bit bang mode"); return PM3_EINVARG; } @@ -720,18 +748,81 @@ int CmdLFRead(const char *Cmd) { return ret; } +int lf_sniff(bool verbose, uint32_t samples) { + if (!session.pm3_present) return PM3_ENOTTY; + + struct p { + uint32_t samples : 31; + bool verbose : 1; + } PACKED; + + struct p payload; + payload.verbose = verbose; + payload.samples = samples; + + clearCommandBuffer(); + SendCommandNG(CMD_LF_SNIFF_RAW_ADC, (uint8_t *)&payload, sizeof(payload)); + PacketResponseNG resp; + if (g_lf_threshold_set) { + WaitForResponse(CMD_LF_SNIFF_RAW_ADC, &resp); + } else { + if (!WaitForResponseTimeout(CMD_LF_SNIFF_RAW_ADC, &resp, 2500)) { + PrintAndLogEx(WARNING, "(lf_read) command execution time out"); + return PM3_ETIMEOUT; + } + } + + // response is number of bits read + uint32_t size = (resp.data.asDwords[0] / 8); + getSamples(size, verbose); + return PM3_SUCCESS; +} + int CmdLFSniff(const char *Cmd) { if (!session.pm3_present) return PM3_ENOTTY; - uint8_t cmdp = tolower(param_getchar(Cmd, 0)); - if (cmdp == 'h') return usage_lf_sniff(); + 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_sniff(); + case 's': + samples = param_get32ex(Cmd, cmdp + 1, 0, 10); + cmdp += 2; + break; + case 'q': + verbose = false; + cmdp++; + break; + case '@': + continuous = true; + cmdp++; + break; + default: + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } - clearCommandBuffer(); - SendCommandNG(CMD_LF_SNIFF_RAW_ADC, NULL, 0); - WaitForResponse(CMD_ACK, NULL); - getSamples(0, true); - return PM3_SUCCESS; + //Validations + if (errors) return usage_lf_sniff(); + if (continuous) { + PrintAndLogEx(INFO, "Press " _GREEN_("Enter") " to exit"); + } + int ret = PM3_SUCCESS; + do { + ret = lf_sniff(verbose, samples); + if (kbd_enter_pressed()) { + break; + } + } while (continuous); + return ret; } static void ChkBitstream(void) { @@ -1362,7 +1453,7 @@ int CmdLFfind(const char *Cmd) { if (demodNexWatch() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("NexWatch ID") " found!"); goto out;} if (demodIndala() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Indala ID") " found!"); goto out;} if (demodEM410x() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("EM410x ID") " found!"); goto out;} - if (demodFDX() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("FDX-B ID") " found!"); goto out;} + if (demodFDX(true) == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("FDX-B ID") " found!"); goto out;} if (demodGuard() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Guardall G-Prox II ID") " found!"); goto out; } if (demodIdteck() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Idteck ID") " found!"); goto out;} if (demodJablotron() == PM3_SUCCESS) { PrintAndLogEx(SUCCESS, "\nValid " _GREEN_("Jablotron ID") " found!"); goto out;} @@ -1431,7 +1522,7 @@ out: } static command_t CommandTable[] = { - {"help", CmdHelp, AlwaysAvailable, "This help"}, + {"-----------", CmdHelp, AlwaysAvailable, "-------------- " _CYAN_("Direct") " --------------"}, {"awid", CmdLFAWID, AlwaysAvailable, "{ AWID RFIDs... }"}, {"cotag", CmdLFCOTAG, AlwaysAvailable, "{ COTAG CHIPs... }"}, {"em", CmdLFEM4X, AlwaysAvailable, "{ EM4X CHIPs & RFIDs... }"}, @@ -1458,16 +1549,17 @@ static command_t CommandTable[] = { {"t55xx", CmdLFT55XX, AlwaysAvailable, "{ T55xx CHIPs... }"}, {"viking", CmdLFViking, AlwaysAvailable, "{ Viking RFIDs... }"}, {"visa2000", CmdLFVisa2k, AlwaysAvailable, "{ Visa2000 RFIDs... }"}, - {"", CmdHelp, AlwaysAvailable, ""}, + {"-----------", CmdHelp, AlwaysAvailable, "--------------------- " _CYAN_("General") " ---------------------"}, + {"help", CmdHelp, AlwaysAvailable, "This help"}, {"config", CmdLFConfig, IfPm3Lf, "Get/Set config for LF sampling, bit/sample, decimation, frequency"}, {"cmdread", CmdLFCommandRead, IfPm3Lf, "Modulate LF reader field to send command before read (all periods in microseconds)"}, {"read", CmdLFRead, IfPm3Lf, "Read LF tag"}, {"search", CmdLFfind, AlwaysAvailable, "Read and Search for valid known tag (in offline mode it you can load first then search)"}, {"sim", CmdLFSim, IfPm3Lf, "Simulate LF tag from buffer with optional GAP (in microseconds)"}, - {"simask", CmdLFaskSim, IfPm3Lf, "Simulate LF ASK tag from demodbuffer or input"}, - {"simfsk", CmdLFfskSim, IfPm3Lf, "Simulate LF FSK tag from demodbuffer or input"}, - {"simpsk", CmdLFpskSim, IfPm3Lf, "Simulate LF PSK tag from demodbuffer or input"}, -// {"simpsk", CmdLFnrzSim, IfPm3Lf, "Simulate LF NRZ tag from demodbuffer or input"}, + {"simask", CmdLFaskSim, IfPm3Lf, "Simulate " _YELLOW_("LF ASK tag") " from demodbuffer or input"}, + {"simfsk", CmdLFfskSim, IfPm3Lf, "Simulate " _YELLOW_("LF FSK tag") " from demodbuffer or input"}, + {"simpsk", CmdLFpskSim, IfPm3Lf, "Simulate " _YELLOW_("LF PSK tag") " from demodbuffer or input"}, +// {"simpsk", CmdLFnrzSim, IfPm3Lf, "Simulate " _YELLOW_("LF NRZ tag") " from demodbuffer or input"}, {"simbidir", CmdLFSimBidir, IfPm3Lf, "Simulate LF tag (with bidirectional data transmission between reader and tag)"}, {"sniff", CmdLFSniff, IfPm3Lf, "Sniff LF traffic between reader and tag"}, {"tune", CmdLFTune, IfPm3Lf, "Continuously measure LF antenna tuning"}, diff --git a/client/src/cmdlf.h b/client/src/cmdlf.h index bb0628609..bcc695764 100644 --- a/client/src/cmdlf.h +++ b/client/src/cmdlf.h @@ -33,6 +33,7 @@ int CmdVchDemod(const char *Cmd); int CmdLFfind(const char *Cmd); int lf_read(bool verbose, uint32_t samples); +int lf_sniff(bool verbose, uint32_t samples); int lf_config(sample_config *config); int lf_getconfig(sample_config *config); diff --git a/client/src/cmdlffdx.c b/client/src/cmdlffdx.c index af4f316ae..431ec8216 100644 --- a/client/src/cmdlffdx.c +++ b/client/src/cmdlffdx.c @@ -65,6 +65,17 @@ static int usage_lf_fdx_clone(void) { return PM3_SUCCESS; } +static int usage_lf_fdx_read(void) { + PrintAndLogEx(NORMAL, "Read FDX-B animal tag"); + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(NORMAL, "Usage: lf fdx read [h] [@]"); + PrintAndLogEx(NORMAL, "Options:"); + PrintAndLogEx(NORMAL, " h : This help"); + PrintAndLogEx(NORMAL, " @ : run continuously until a key is pressed (optional)"); + PrintAndLogEx(NORMAL, "Note that the continuous mode is less verbose"); + return PM3_SUCCESS; +} + 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."); @@ -206,7 +217,7 @@ static int CmdFDXBdemodBI(const char *Cmd) { //see ASKDemod for what args are accepted //almost the same demod as cmddata.c/CmdFDXBdemodBI -int demodFDX(void) { +int demodFDX(bool verbose) { //Differential Biphase / di-phase (inverted biphase) //get binary from ask wave if (ASKbiphaseDemod("0 32 1 100", false) != PM3_SUCCESS) { @@ -266,6 +277,11 @@ int demodFDX(void) { uint8_t raw[8]; num_to_bytes(rawid, 8, raw); + if (!verbose) { + PROMPT_CLEARLINE; + PrintAndLogEx(SUCCESS, "Animal ID " _GREEN_("%04u-%012"PRIu64), countryCode, NationalCode); + return PM3_SUCCESS; + } 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); @@ -307,7 +323,7 @@ int demodFDX(void) { static int CmdFdxDemod(const char *Cmd) { (void)Cmd; // Cmd is not used so far - return demodFDX(); + return demodFDX(true); } static int CmdFdxRead(const char *Cmd) { @@ -318,6 +334,27 @@ static int CmdFdxRead(const char *Cmd) { PrintAndLogEx(ERR, "failed to get current device LF config"); return retval; } + + bool errors = false; + bool continuous = false; + uint8_t cmdp = 0; + while (param_getchar(Cmd, cmdp) != 0x00 && !errors) { + switch (tolower(param_getchar(Cmd, cmdp))) { + case 'h': + return usage_lf_fdx_read(); + case '@': + continuous = true; + cmdp++; + break; + default: + PrintAndLogEx(WARNING, "Unknown parameter '%c'", param_getchar(Cmd, cmdp)); + errors = true; + break; + } + } + + //Validations + if (errors) return usage_lf_fdx_read(); int16_t tmp_div = config.divisor; if (tmp_div != LF_DIVISOR_134) { config.divisor = LF_DIVISOR_134; @@ -328,11 +365,22 @@ static int CmdFdxRead(const char *Cmd) { return retval; } } - retval = lf_read(false, 10000); - if (retval != PM3_SUCCESS) { - PrintAndLogEx(ERR, "failed to get LF read from device"); - return retval; + if (continuous) { + PrintAndLogEx(INFO, "Press " _GREEN_("Enter") " to exit"); } + int ret = PM3_SUCCESS; + do { + retval = lf_read(false, 10000); + if (retval != PM3_SUCCESS) { + PrintAndLogEx(ERR, "failed to get LF read from device"); + return retval; + } + ret = demodFDX(!continuous); // be verbose only if not in continuous mode + if (kbd_enter_pressed()) { + break; + } + PrintAndLogEx(INPLACE, ""); + } while (continuous); if (tmp_div != LF_DIVISOR_134) { config.divisor = tmp_div; retval = lf_config(&config); @@ -341,7 +389,7 @@ static int CmdFdxRead(const char *Cmd) { return retval; } } - return CmdFdxDemod(Cmd); + return ret; } static int CmdFdxClone(const char *Cmd) { diff --git a/client/src/cmdlffdx.h b/client/src/cmdlffdx.h index faf1f2aa7..637a2d5c7 100644 --- a/client/src/cmdlffdx.h +++ b/client/src/cmdlffdx.h @@ -13,7 +13,7 @@ int CmdLFFdx(const char *Cmd); int detectFDXB(uint8_t *dest, size_t *size); -int demodFDX(void); +int demodFDX(bool verbose); int getFDXBits(uint64_t national_code, uint16_t country_code, uint8_t is_animal, uint8_t is_extended, uint32_t extended, uint8_t *bits); #endif diff --git a/client/src/cmdlft55xx.c b/client/src/cmdlft55xx.c index 9cc15168b..92c78dfa6 100644 --- a/client/src/cmdlft55xx.c +++ b/client/src/cmdlft55xx.c @@ -401,17 +401,18 @@ static int usage_t55xx_clonehelp(void) { return PM3_SUCCESS; } static int usage_t55xx_sniff(void) { - PrintAndLogEx(NORMAL, "Usage: lf t55xx sniff [w ] [l ] [b] [h]"); + PrintAndLogEx(NORMAL, "Usage: lf t55xx sniff [w ] [l ] [s ] [t ] [1] [h]"); PrintAndLogEx(NORMAL, "Options:"); PrintAndLogEx(NORMAL, " w <0> <1> - Set samples width for 0 and 1 matching (default auto detect)"); - PrintAndLogEx(NORMAL, " l - Set minimum signal level (default 20)"); - PrintAndLogEx(NORMAL, " b - Extract from current sample buffer (default will get new samples)"); + // PrintAndLogEx(NORMAL, " s - Set minimum signal level (default 20)"); + PrintAndLogEx(NORMAL, " t - Set tolerance level (default 5). lower means tighter"); + PrintAndLogEx(NORMAL, " 1 - Extract from current sample buffer (default will get new samples)"); PrintAndLogEx(NORMAL, " h - This help"); PrintAndLogEx(NORMAL, ""); PrintAndLogEx(NORMAL, "Examples:"); PrintAndLogEx(NORMAL, _YELLOW_(" lf t55xx sniff")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf t55xx sniff b")); - PrintAndLogEx(NORMAL, _YELLOW_(" lf t55xx sniff w 7 14 b")); + PrintAndLogEx(NORMAL, _YELLOW_(" lf t55xx sniff 1 t 2")); + PrintAndLogEx(NORMAL, _YELLOW_(" lf t55xx sniff w 7 14 1")); PrintAndLogEx(NORMAL, ""); return PM3_SUCCESS; } @@ -3724,27 +3725,62 @@ static int CmdT55xxProtect(const char *Cmd) { return PM3_SUCCESS; } +// if the difference bettwen a and b is less then or eq to d i.e. does a = b +/- d +#define approxEq(a,b,d) ((abs(a-b) <= d) ? true : false) + +static uint8_t t55sniffGetPacket(int *pulseBuffer, char *data, uint8_t width0, uint8_t width1, uint8_t tolerance) { + int i = 0; + bool ok = true; + uint8_t dataLen = 0; + + while (ok && (i < 73)) { // 70 bits max Fixed bit packet + if (approxEq(width0, pulseBuffer[i], tolerance)) { + data[dataLen++] = '0'; + i++; + continue; + } + if (approxEq(width1, pulseBuffer[i], tolerance)) { + data[dataLen++] = '1'; + i++; + continue; + } + + ok = false; + } + data[dataLen] = 0x00; + + return dataLen; +} + +static uint8_t t55sniffTrimSamples(int *pulseBuffer, int *pulseIdx, uint8_t len) { + for (uint8_t ii = 0; ii < (80 - len); ii++) { + pulseBuffer[ii] = pulseBuffer[ii + len]; + } + + *pulseIdx -= len; + return PM3_SUCCESS; +} + static int CmdT55xxSniff(const char *Cmd) { - uint8_t cmdp = 0; + bool sampleData = true; - uint8_t width0 = 0; - uint8_t width1 = 0; - uint8_t minLevel = 20; - int pulseSamples = 0; - bool eop; - uint8_t page; - uint32_t usedPassword; - uint32_t blockData; - uint8_t blockAddr; - char data[100]; // Max should be 80. + bool haveData = false; + uint8_t cmdp = 0; + uint8_t width0 = 0, width1 = 0; + uint8_t tolerance = 5, page, blockAddr; uint16_t dataLen = 0; size_t idx = 0; - size_t start; - int minWidth; - int maxWidth; + uint32_t usedPassword, blockData; + int pulseSamples = 0; + int pulseIdx = 0; + int minWidth = 1000; + int maxWidth = 0; char modeText [100]; char pwdText [100]; - bool haveData = false; + char dataText [100]; + int pulseBuffer[80] = { 0 }; // max should be 73 +/- - Holds Pulse widths + char data[80]; // linked to pulseBuffer. - Holds 0/1 from pulse widths + /* Notes: @@ -3770,14 +3806,12 @@ static int CmdT55xxSniff(const char *Cmd) { | 1 | 48 - 64 | 41 - 72 | 21 - 96 | tbc | ---------------------------------------------------- 00 01 10 11 - - */ while (param_getchar(Cmd, cmdp) != 0x00) { switch (tolower(param_getchar(Cmd, cmdp))) { case 'h': return usage_t55xx_sniff(); - case 'b': + case '1': sampleData = false; cmdp ++; break; @@ -3785,7 +3819,7 @@ static int CmdT55xxSniff(const char *Cmd) { width0 = param_get8ex(Cmd, cmdp + 1, 0, 10); width1 = param_get8ex(Cmd, cmdp + 2, 0, 10); cmdp += 3; - + if (width0 == 0) PrintAndLogEx (ERR,"need both sample widths! "_RED_("Missing sample width for 0")); if (width1 == 0) PrintAndLogEx (ERR,"need both sample widths! "_RED_("Missing sample width for 1")); if ((width0 == 0) || (width1 == 0)) { @@ -3793,229 +3827,245 @@ static int CmdT55xxSniff(const char *Cmd) { return usage_t55xx_sniff(); } break; - case 'l': - minLevel = param_get8ex(Cmd, cmdp + 1, 0, 10); + case 't': + tolerance = param_get8ex(Cmd, cmdp + 1, 0, 10); cmdp += 2; break; default: - cmdp++; - PrintAndLogEx (ERR,"Invalid options supplied!"); - return usage_t55xx_sniff(); + cmdp++; + PrintAndLogEx (ERR,"Invalid options supplied!"); + return usage_t55xx_sniff(); } } - // setup and sample data from Proxmark (if not directed to existing sample/graphbuffer + // setup and sample data from Proxmark + // if not directed to existing sample/graphbuffer if (sampleData) { - // get samples - CmdLFSniff (""); + CmdLFSniff (""); } + // Headings + PrintAndLogEx(NORMAL, ""); + PrintAndLogEx(INFO,_CYAN_("T55xx command detection")); + PrintAndLogEx(SUCCESS, "Downlink mode | password | Data | blk | page | 0 | 1 | raw"); + PrintAndLogEx(SUCCESS, "----------------------+----------+----------+-----+------+-----+-----+-------------------------------------------------------------------------------"); + idx = 0; + // loop though sample buffer + while (idx < GraphTraceLen) { - PrintAndLogEx(NORMAL, ""); - PrintAndLogEx(INFO,_CYAN_("T55xx write Detection")); - PrintAndLogEx(INFO,"Minimum signal level : "_GREEN_("%d"),minLevel); - PrintAndLogEx(SUCCESS, "Downlink mode | password | Data | blk | page | 0 | 1 | raw"); - PrintAndLogEx(SUCCESS, "-----------------+----------+----------+-----+------+-----+-----+-------------------------------------------------------------------------------"); - - while (idx < GraphTraceLen) - { - start = idx; minWidth = 1000; maxWidth = 0; + dataLen = 0; + data[0] = 0; + haveData = false; + sprintf(modeText, "Default"); + sprintf(pwdText, " "); + sprintf(dataText, " "); - // Auto detect bit widths - if ((width0 == 0) && (width1 == 0)) { - // Skip till we get to a "non modulated section" - while ((idx < GraphTraceLen) && ((GraphBuffer[idx] < -5) || (GraphBuffer[idx] > 5))) - idx++; + if (pulseSamples == 0) { + idx++; + } - while ((idx < GraphTraceLen) && ((GraphBuffer[idx] > (-1 * minLevel)) && (GraphBuffer[idx] < minLevel))) - idx++; + // find high + while ((idx < GraphTraceLen) && (GraphBuffer[idx] < 0)) { + idx++; + } - eop = false; - pulseSamples = 0; + // count high samples + pulseSamples = 0; + while ((idx < GraphTraceLen) && (GraphBuffer[idx] > 0)) { // last bit seems to be high to zero, but can vary in width.. + pulseSamples++; + idx++; + } - // Skip until start of next signal - Should be a positive rise above 0 - while ((idx < GraphTraceLen) && (GraphBuffer[idx] < 10)) idx++; + if (pulseSamples > 0) { + pulseBuffer[pulseIdx++] = pulseSamples; + if (pulseIdx > 79) { // make room for next sample - if not used by now, it wont be. + t55sniffTrimSamples (pulseBuffer, &pulseIdx, 1); + } - while ((idx < GraphTraceLen) && !eop) { - - if ((GraphBuffer[idx-1] <= 0) && (GraphBuffer[idx] > 0)) - pulseSamples = 0; - - if ((GraphBuffer[idx-1] > 0) && (GraphBuffer[idx] <= 0)) { - if (pulseSamples > 0) { - - if (pulseSamples < minWidth) - minWidth = pulseSamples; - - if (pulseSamples > maxWidth) - maxWidth = pulseSamples; - - pulseSamples = 0; - } - } - - if ((GraphBuffer[idx-1] > 0) && (GraphBuffer[idx] <= 0) ) { - // End of Packet will have a High to zero drop and stay around 0, so if it drags on or does not keep going down - if (((GraphBuffer[idx+5] + 10) > GraphBuffer[idx]) || (pulseSamples > 50)) { // very high chance of being noise - eop = true; + // Check Samples for valid packets; + // We should find (outside of leading bits) we have a packet of "1" and "0" at same widths. + if (pulseIdx >= 6) {// min size for a read - ignoring 1of4 10 0 + + // We auto find widths + if ((width0 == 0) && (width1 == 0)) { + // We ignore bit 0 for the moment as it may be a ref. pulse, so check last + uint8_t ii = 2; + minWidth = pulseBuffer[1]; + maxWidth = pulseBuffer[1]; + bool done = false; + + while ((!done) && (ii < pulseIdx) && ((maxWidth <= minWidth) || (approxEq(minWidth,maxWidth,tolerance)))) { // min should be 8, 16-32 more normal + if (pulseBuffer[ii]+3 < minWidth) { + minWidth = pulseBuffer[ii]; + done = true; + } + if (pulseBuffer[ii]-1 > maxWidth) { + maxWidth = pulseBuffer[ii]; + done = true; + } + ii++; } } else { - pulseSamples++; + minWidth = width0; + maxWidth = width1; } - idx++; } - maxWidth = minWidth * 1.75;// + ((25 * MinWidth) / 100); - // minWidth = MinWidth;// - ((15 * MinWidth) / 100); - } else { - maxWidth = width1; - minWidth = width0; - } - - // ===================================================== - // go back and find first packet.... - idx = start; - haveData = false; - - // Skip till we get to a "non modulated section" - ie skip if sample is in mid packet - while ((idx < GraphTraceLen) && ((GraphBuffer[idx] < -5) || (GraphBuffer[idx] > 5))) - idx++; - while ((idx < GraphTraceLen) && ((GraphBuffer[idx] > (-1 * minLevel)) && (GraphBuffer[idx] < minLevel))) - idx++; - - dataLen = 0; - eop = false; - pulseSamples = 0; - - // Skip until start of next signal - Should be a positive rise above 0 - while ((idx < GraphTraceLen) && (GraphBuffer[idx] < 10)) idx++; - - while ((idx < GraphTraceLen) && !eop) { - if ((GraphBuffer[idx-1] <= 0) && (GraphBuffer[idx] > 0)) { - pulseSamples = 0; + // out of bounds... min max far enough appart and minWidth is large enough + if (((maxWidth - minWidth) < 6) || (minWidth < 6)) // min 8 +/- + continue; + + // At this point we should have + // - a min of 6 samples + // - the 0 and 1 sample widths + // - min 0 and min seperations (worst case) + // No max checks done (yet) as have seen samples > then specs in use. + + // Check first bit. + + // Long leading 0 + if (haveData == false && (approxEq(pulseBuffer[0],136+minWidth,tolerance) && approxEq(pulseBuffer[1],maxWidth,tolerance))) { + printf ("Long Leading 0 - not yet hanled | have 1 Fisrt bit | Min : %-3d - Max : %-3d : diff : %d\n",minWidth,maxWidth, maxWidth-minWidth); + continue; } - // a return to 0 makes end of needed data. it should cross to negataive before rising to next bit - if ((GraphBuffer[idx-1] > 0) && (GraphBuffer[idx] <= 0) ) { - // End of Packet will have a High to zero drop and stay around 0, so if it drags on or does not keep going down - // - if (((GraphBuffer[idx+5] + 10) > GraphBuffer[idx]) || (pulseSamples > 50)) { // very high chance of being noise - eop = true; - } else { // if we have way too many samples, wont be a valid bit. - if (pulseSamples >= maxWidth) //16) // 30 ?? - data[dataLen++] = '1'; - else { - if (pulseSamples >= minWidth) // Since we found Min Width this should be hit - data[dataLen++] = '0'; - else { - eop = true; // Too short, not a bit - Something went wrong, as we found min width + + // Fixed bit - Default + if (haveData == false && (approxEq(pulseBuffer[0], maxWidth, tolerance))) { + dataLen = t55sniffGetPacket (pulseBuffer, data, minWidth, maxWidth, tolerance); + + // if ((dataLen == 39) ) + // printf ("Fixed | Data end of 80 samples | offset : %llu - datalen %-2d - data : %s --- - Bit 0 width : %d\n",idx,dataLen,data,pulseBuffer[0]); + + if (data[0] == '0') { // should never get here.. + dataLen = 0; + data[0] = 0; + } else { + + // Default Read + if (dataLen == 6) { + t55sniffTrimSamples (pulseBuffer, &pulseIdx,4); // left 1 or 2 samples seemed to help + + page = data[1] - '0'; + blockAddr = 0; + for (uint8_t i = 3; i < 6; i++) { + blockAddr <<= 1; + if (data[i] == '1') + blockAddr |= 1; } + blockData = 0; + haveData = true; + sprintf(modeText, "Default Read"); + } + + // Password Write + if (dataLen == 70) { + t55sniffTrimSamples (pulseBuffer, &pulseIdx,70); + + page = data[1] - '0'; + usedPassword = 0; + for (uint8_t i = 2; i <= 33; i++) { + usedPassword <<= 1; + if (data[i] == '1') + usedPassword |= 1; + } + // Lock bit 34 + blockData = 0; + for (uint8_t i = 35; i <= 66; i++) { + blockData <<= 1; + if (data[i] == '1') + blockData |= 1; + } + blockAddr = 0; + for (uint8_t i = 67; i <= 69; i++) { + blockAddr <<= 1; + if (data[i] == '1') + blockAddr |= 1; + } + haveData = true; + sprintf(modeText, "Default pwd write"); + sprintf(pwdText, "%08X", usedPassword); + sprintf(dataText, "%08X",blockData ); + } + + // Default Write (or password read ??) + if (dataLen == 38) { + t55sniffTrimSamples (pulseBuffer, &pulseIdx,38); + + page = data[1] - '0'; + usedPassword = 0; + blockData = 0; + for (uint8_t i = 3; i <= 34; i++) { + blockData <<= 1; + if (data[i] == '1') + blockData |= 1; + } + blockAddr = 0; + for (uint8_t i = 35; i <= 37; i++) { + blockAddr <<= 1; + if (data[i] == '1') + blockAddr |= 1; + } + haveData = true; + sprintf(modeText, "Default write"); + sprintf(dataText, "%08X",blockData ); } } } - else - pulseSamples++; - if (dataLen > 80) // to long for t55xx packets - eop = true; - idx++; - } - data[dataLen] = 0x00; - // printf ("%d : %s\n",dataLen,data); - - sprintf(modeText, "Default"); - sprintf(pwdText, " "); + // Leading 0 + if (haveData == false && (approxEq(pulseBuffer[0], minWidth, tolerance))) { + // leading 0 (should = 0 width) + // 1 of 4 (leads with 00) + dataLen = t55sniffGetPacket (pulseBuffer,data,minWidth,maxWidth,tolerance); + // **** Should check to 0 to be actual 0 as well i.e. 01 .... data .... + if ((data[0] == '0') && (data[1] == '1')) { + if (dataLen == 73) { + t55sniffTrimSamples (pulseBuffer, &pulseIdx, 73); - if (dataLen == 73) { // Potential leading 0 password write. - if ((memcmp (data, "01100", 5) == 0) || (memcmp (data, "01000", 5) == 0)) { // Still looking good Page 1 or 0 - - page = data[2] - '0'; - usedPassword = 0; - for (uint8_t i = 5; i < 32+5; i++) { - usedPassword <<= 1; - if (data[i] == '1') - usedPassword |= 1; + page = data[2] - '0'; + usedPassword = 0; + for (uint8_t i = 5; i <= 36; i++) { + usedPassword <<= 1; + if (data[i] == '1') + usedPassword |= 1; + } + blockData = 0; + for (uint8_t i = 38; i <= 69; i++) { + blockData <<= 1; + if (data[i] == '1') + blockData |= 1; + } + blockAddr = 0; + for (uint8_t i = 70; i <= 72; i++) { + blockAddr <<= 1; + if (data[i] == '1') + blockAddr |= 1; + } + haveData = true; + sprintf(modeText, "Leading 0 pwd write"); + sprintf(pwdText, "%08X", usedPassword); + sprintf(dataText, "%08X",blockData ); + } } - blockData = 0; - for (uint8_t i = 38; i < 38+32; i++) { - blockData <<= 1; - if (data[i] == '1') - blockData |= 1; - } - blockAddr = 0; - for (uint8_t i = 70; i < 70+3; i++) { - blockAddr <<= 1; - if (data[i] == '1') - blockAddr |= 1; - } - haveData = true; - sprintf(modeText, "leading 0"); - sprintf(pwdText,"%08X", usedPassword); - } - } - - if (dataLen == 70) { // Potential default password write. - - if ((memcmp (data, "10", 2) == 0) || (memcmp (data, "11", 2) == 0)) { // Still looking good Page 1 or 0 - - page = data[1] - '0'; - usedPassword = 0; - for (uint8_t i = 2; i < 34; i++) { - usedPassword <<= 1; - if (data[i] == '1') - usedPassword |= 1; - } - blockData = 0; - for (uint8_t i = 35; i < 67; i++) { - blockData <<= 1; - if (data[i] == '1') - blockData |= 1; - } - blockAddr = 0; - for (uint8_t i = 67; i < 70; i++) { - blockAddr <<= 1; - if (data[i] == '1') - blockAddr |= 1; - } - haveData = true; - sprintf(pwdText, "%08X", usedPassword); } } - - if (dataLen == 38) { // Potential defaukt write (no password). - - if ((memcmp (data, "10", 2) == 0) || (memcmp (data, "11", 2) == 0)) { // Still looking good Page 1 or 0 - - page = data[1] - '0'; - blockData = 0; - for (uint8_t i = 3; i < 35; i++) { - blockData <<= 1; - if (data[i] == '1') - blockData |= 1; - } - blockAddr = 0; - for (uint8_t i = 35; i < 38; i++) { - blockAddr <<= 1; - if (data[i] == '1') - blockAddr |= 1; - } - haveData = true; - } - } - - if ((haveData) && (minWidth > 1) && (maxWidth > minWidth)){ + // Print results + if (haveData) { //&& (minWidth > 1) && (maxWidth > minWidth)){ if (blockAddr == 7) - PrintAndLogEx (SUCCESS, "%-15s | "_GREEN_("%s")" | "_YELLOW_("%08X")" | "_YELLOW_("%d")" | "_GREEN_("%d")" | %3d | %3d | %s", modeText, pwdText, blockData, blockAddr, page, minWidth, maxWidth, data); + PrintAndLogEx (SUCCESS, "%-20s | "_GREEN_("%8s")" | "_YELLOW_("%8s")" | "_YELLOW_("%d")" | "_GREEN_("%d")" | %3d | %3d | %s", modeText, pwdText, dataText, blockAddr, page, minWidth, maxWidth, data); else - PrintAndLogEx (SUCCESS, "%-15s | "_GREEN_("%s")" | "_GREEN_("%08X")" | "_GREEN_("%d")" | "_GREEN_("%d")" | %3d | %3d | %s", modeText, pwdText, blockData, blockAddr, page, minWidth, maxWidth, data); + PrintAndLogEx (SUCCESS, "%-20s | "_GREEN_("%8s")" | "_GREEN_("%8s")" | "_GREEN_("%d")" | "_GREEN_("%d")" | %3d | %3d | %s", modeText, pwdText, dataText, blockAddr, page, minWidth, maxWidth, data); } } - PrintAndLogEx (SUCCESS, "------------------------------------------------------------------------------------------------------------------------------------------------"); - PrintAndLogEx (NORMAL, ""); + // footer + PrintAndLogEx (SUCCESS, "-----------------------------------------------------------------------------------------------------------------------------------------------------"); + PrintAndLogEx (NORMAL, ""); + return PM3_SUCCESS; } diff --git a/client/src/cmdparser.c b/client/src/cmdparser.c index 837c13fed..590dee87d 100644 --- a/client/src/cmdparser.c +++ b/client/src/cmdparser.c @@ -26,6 +26,12 @@ bool IfPm3Present(void) { return session.pm3_present; } +bool IfPm3Rdv4Fw(void) { + if (!IfPm3Present()) + return false; + return (pm3_capabilities.compiled_with_flash) || (pm3_capabilities.compiled_with_smartcard); +} + bool IfPm3Flash(void) { if (!IfPm3Present()) return false; @@ -168,7 +174,11 @@ void CmdsHelp(const command_t Commands[]) { while (Commands[i].Name) { if (Commands[i].IsAvailable()) { g_printAndLog = PRINTANDLOG_PRINT; - PrintAndLogEx(NORMAL, _GREEN_("%-16s")" %s", Commands[i].Name, Commands[i].Help); + if (Commands[i].Name[0] == '-' || Commands[i].Name[0] == ' ') { + PrintAndLogEx(NORMAL, "%-16s %s", Commands[i].Name, Commands[i].Help); + } else { + PrintAndLogEx(NORMAL, _GREEN_("%-16s")" %s", Commands[i].Name, Commands[i].Help); + } g_printAndLog = PRINTANDLOG_PRINT | PRINTANDLOG_LOG; } ++i; diff --git a/client/src/cmdparser.h b/client/src/cmdparser.h index baade0bcb..4e1e37a77 100644 --- a/client/src/cmdparser.h +++ b/client/src/cmdparser.h @@ -24,6 +24,7 @@ typedef struct command_s { // helpers for command_t IsAvailable bool AlwaysAvailable(void); bool IfPm3Present(void); +bool IfPm3Rdv4Fw(void); bool IfPm3Flash(void); bool IfPm3Smartcard(void); bool IfPm3FpcUsart(void); diff --git a/client/src/mifare/mifarehost.c b/client/src/mifare/mifarehost.c index 032c9eccf..78fca3487 100644 --- a/client/src/mifare/mifarehost.c +++ b/client/src/mifare/mifarehost.c @@ -1154,13 +1154,14 @@ int detect_classic_static_nonce(void) { return NONCE_FAIL; } -/* try to see if card responses to "chinese magic backdoor" commands. */ -int detect_classic_magic(void) { +/* try to see if card responses to "Chinese magic backdoor" commands. */ +int detect_mf_magic(bool is_mfc) { uint8_t isGeneration = 0; PacketResponseNG resp; clearCommandBuffer(); - SendCommandNG(CMD_HF_MIFARE_CIDENT, NULL, 0); + uint8_t payload[] = { is_mfc }; + SendCommandNG(CMD_HF_MIFARE_CIDENT, payload, sizeof(payload)); if (WaitForResponseTimeout(CMD_HF_MIFARE_CIDENT, &resp, 1500)) { if (resp.status == PM3_SUCCESS) isGeneration = resp.data.asBytes[0]; diff --git a/client/src/mifare/mifarehost.h b/client/src/mifare/mifarehost.h index f6a840550..7a3535257 100644 --- a/client/src/mifare/mifarehost.h +++ b/client/src/mifare/mifarehost.h @@ -54,7 +54,7 @@ typedef struct { //uint8_t foundKey[2]; } icesector_t; -#define KEYS_IN_BLOCK ((PM3_CMD_DATA_SIZE - 4) / 6) +#define KEYS_IN_BLOCK ((PM3_CMD_DATA_SIZE - 5) / 6) #define KEYBLOCK_SIZE (KEYS_IN_BLOCK * 6) #define CANDIDATE_SIZE (0xFFFF * 6) @@ -88,7 +88,7 @@ int tryDecryptWord(uint32_t nt, uint32_t ar_enc, uint32_t at_enc, uint8_t *data, int detect_classic_prng(void); int detect_classic_nackbug(bool verbose); -int detect_classic_magic(void); +int detect_mf_magic(bool is_mfc); int detect_classic_static_nonce(void); void mf_crypto1_decrypt(struct Crypto1State *pcs, uint8_t *data, int len, bool isEncrypted); #endif diff --git a/client/src/proxguiqt.cpp b/client/src/proxguiqt.cpp index 149018b9f..2d988fc9e 100644 --- a/client/src/proxguiqt.cpp +++ b/client/src/proxguiqt.cpp @@ -637,6 +637,80 @@ void Plot::closeEvent(QCloseEvent *event) { g_useOverlays = false; } +void Plot::Zoom(float factor, int refX) { + if (factor >=1) { // Zoom in + if (GraphPixelsPerPoint <= 25 * factor) { + GraphPixelsPerPoint *= factor; + GraphStart += (refX - GraphStart) - ((refX - GraphStart) / factor); + } + } else { // Zoom out + if (GraphPixelsPerPoint >= 0.01 / factor) { + GraphPixelsPerPoint *= factor; + if (GraphStart >= ((refX - GraphStart) / factor) - (refX - GraphStart)) { + GraphStart -= ((refX - GraphStart) / factor) - (refX - GraphStart); + } else { + GraphStart = 0; + } + } + } +} + +void Plot::Move(int offset) { + if (offset > 0) { // Move right + if (GraphPixelsPerPoint < 20) { + GraphStart += offset; + } else { + GraphStart++; + } + } else { // Move left + if (GraphPixelsPerPoint < 20) { + if (GraphStart >= (uint)-offset) { + GraphStart += offset; + } else { + GraphStart = 0; + } + } else { + if (GraphStart > 0) { + GraphStart--; + } + } + } +} + +void Plot::wheelEvent(QWheelEvent *event) { + // event->delta() + // 120 => shift right 5% + // -120 => shift left 5% + const float move_offset = 0.05; + // -120+shift => zoom in 10% + // 120+shift => zoom out 10% + const float zoom_offset = 0.1; + if (event->modifiers() & Qt::ShiftModifier) { +// event->position doesn't exist in QT5.12.8, both exist in 5.14.2 and event->x doesn't exist in 5.15.0 +#if QT_VERSION >= 0x050d00 + int x = event->position().x(); +#else + int x = event->x(); +#endif + x -= WIDTH_AXES; + x = (int)(x / GraphPixelsPerPoint); + x += GraphStart; +// event->angleDelta doesn't exist in QT4, both exist in 5.12.8 and 5.14.2 and event->delta doesn't exist in 5.15.0 +#if QT_VERSION >= 0x050d00 + Zoom(1.0-(float)event->angleDelta().y()/(120/zoom_offset), x); +#else + Zoom(1.0-(float)event->delta()/(120/zoom_offset), x); +#endif + } else { +#if QT_VERSION >= 0x050d00 + Move(PageWidth*(-(float)event->angleDelta().y()/(120/move_offset))); +#else + Move(PageWidth*(-(float)event->delta()/(120/move_offset))); +#endif + } + this->update(); +} + void Plot::mouseMoveEvent(QMouseEvent *event) { int x = event->x(); x -= WIDTH_AXES; @@ -667,37 +741,27 @@ void Plot::keyPressEvent(QKeyEvent *event) { switch (event->key()) { case Qt::Key_Down: - if (GraphPixelsPerPoint <= 50) { - GraphPixelsPerPoint *= 2; + if (event->modifiers() & Qt::ShiftModifier) { + Zoom(2, CursorBPos); + } else { + Zoom(2, CursorAPos); } break; case Qt::Key_Up: - if (GraphPixelsPerPoint >= 0.02) { - GraphPixelsPerPoint /= 2; + if (event->modifiers() & Qt::ShiftModifier) { + Zoom(0.5, CursorBPos); + } else { + Zoom(0.5, CursorAPos); } break; case Qt::Key_Right: - if (GraphPixelsPerPoint < 20) { - GraphStart += offset; - } else { - GraphStart++; - } + Move(offset); break; case Qt::Key_Left: - if (GraphPixelsPerPoint < 20) { - if (GraphStart >= offset) { - GraphStart -= offset; - } else { - GraphStart = 0; - } - } else { - if (GraphStart > 0) { - GraphStart--; - } - } + Move(-offset); break; case Qt::Key_G: @@ -720,8 +784,12 @@ void Plot::keyPressEvent(QKeyEvent *event) { puts("PLOT window keystrokes"); puts("\tKey Action"); puts("-----------------------------------------------------------------------"); - puts("\tUP Zoom out"); - puts("\tDOWN Zoom in"); + puts("\tUP Zoom out around yellow cursor"); + puts("\t UP Zoom out around purple cursor"); + puts("\t WHEEL MOUSE UP Zoom out around mouse cursor"); + puts("\tDOWN Zoom in around yellow cursor"); + puts("\t DOWN Zoom in around purple cursor"); + puts("\t WHEEL MOUSE DOWN Zoom in around mouse cursor"); puts("\tG Toggle grid display"); puts("\tH Show help"); puts("\tL Toggle lock grid relative to samples"); @@ -731,12 +799,14 @@ void Plot::keyPressEvent(QKeyEvent *event) { puts("\tPGUP Page left"); puts("\tPGDOWN Page right"); puts("\tLEFT Move left"); - puts("\t LEFT Move left 1 sample"); - puts("\t LEFT Page left"); - puts("\tLEFT MOUSE CLICK Set yellow cursor"); puts("\tRIGHT Move right"); + puts("\tWHEEL MOUSE UP Move left"); + puts("\tWHEEL MOUSE DOWN Move right"); + puts("\t LEFT Move left 1 sample"); puts("\t RIGHT Move right 1 sample"); + puts("\t LEFT Page left"); puts("\t RIGHT Page right"); + puts("\tLEFT MOUSE CLICK Set yellow cursor"); puts("\tRIGHT MOUSE CLICK Set purple cursor"); puts("-----------------------------------------------------------------------"); break; diff --git a/client/src/proxguiqt.h b/client/src/proxguiqt.h index 7f9a82126..3264a2919 100644 --- a/client/src/proxguiqt.h +++ b/client/src/proxguiqt.h @@ -50,6 +50,9 @@ class Plot: public QWidget { protected: void paintEvent(QPaintEvent *event); void closeEvent(QCloseEvent *event); + void Zoom(float factor, int refX); + void Move(int offset); + void wheelEvent(QWheelEvent *event); void mouseMoveEvent(QMouseEvent *event); void mousePressEvent(QMouseEvent *event) { mouseMoveEvent(event); } void keyPressEvent(QKeyEvent *event); diff --git a/client/src/proxmark3.c b/client/src/proxmark3.c index 1358137bf..1b074d9fe 100644 --- a/client/src/proxmark3.c +++ b/client/src/proxmark3.c @@ -34,8 +34,8 @@ #include "flash.h" #include "preferences.h" -#define BANNERMSG1 "" -#define BANNERMSG2 " :snowflake: bleeding edge :coffee:" +#define BANNERMSG1 " Iceman :coffee:" +#define BANNERMSG2 " :snowflake: bleeding edge" #define BANNERMSG3 " https://github.com/rfidresearchgroup/proxmark3/" typedef enum LogoMode { UTF8, ANSI, ASCII } LogoMode; diff --git a/client/src/scripting.c b/client/src/scripting.c index 64dd0f84a..fed896970 100644 --- a/client/src/scripting.c +++ b/client/src/scripting.c @@ -55,7 +55,7 @@ static int l_clearCommandBuffer(lua_State *L) { } /** - * Enable / Disable fast push mode for lua scripts like mfckeys + * Enable / Disable fast push mode for lua scripts like hf_mf_keycheck * The following params expected: * *@brief l_fast_push_mode diff --git a/common/commonutil.c b/common/commonutil.c index 6b7444045..9be805f31 100644 --- a/common/commonutil.c +++ b/common/commonutil.c @@ -142,3 +142,15 @@ void htole24(uint32_t val, uint8_t data[3]) { data[2] = (uint8_t)(val >> 16); } + +// ROL on u32 +uint32_t rotl(uint32_t a, uint8_t n) { + n &= 31; + return (a << n) | (a >> (32 - n)); +} + +// ROR on u32 +uint32_t rotr(uint32_t a, uint8_t n) { + n &= 31; + return (a >> n) | (a << (32 - n)); +} \ No newline at end of file diff --git a/common/commonutil.h b/common/commonutil.h index fdd2ac065..6bf330e7c 100644 --- a/common/commonutil.h +++ b/common/commonutil.h @@ -51,9 +51,13 @@ uint16_t reflect16(uint16_t b); // dedicated 16bit reversal void num_to_bytes(uint64_t n, size_t len, uint8_t *dest); uint64_t bytes_to_num(uint8_t *src, size_t len); +// rotate left byte array void rol(uint8_t *data, const size_t len); void lsl(uint8_t *data, size_t len); uint32_t le24toh(uint8_t data[3]); void htole24(uint32_t val, uint8_t data[3]); +// rol on a u32 +uint32_t rotl(uint32_t a, uint8_t n); +uint32_t rotr(uint32_t a, uint8_t n); #endif diff --git a/common/generator.c b/common/generator.c index f189d09e3..37a1aa4f7 100644 --- a/common/generator.c +++ b/common/generator.c @@ -414,12 +414,21 @@ int mfc_algo_sky_all(uint8_t *uid, uint8_t *keys) { return PM3_SUCCESS; } +// LF T55x7 White gun cloner algo +uint32_t lf_t55xx_white_pwdgen(uint32_t id) { + uint32_t r1 = rotl(id & 0x000000ec, 8); + uint32_t r2 = rotl(id & 0x86000000, 16); + uint32_t pwd = 0x10303; + pwd += ((id & 0x86ee00ec) ^ r1 ^ r2 ); + return pwd; +} + //------------------------------------ // Self tests //------------------------------------ int generator_selftest(void) { -#define NUM_OF_TEST 5 +#define NUM_OF_TEST 6 PrintAndLogEx(INFO, "PWD / KEY generator selftest"); PrintAndLogEx(INFO, "----------------------------"); @@ -468,6 +477,13 @@ int generator_selftest(void) { testresult++; PrintAndLogEx(success ? SUCCESS : WARNING, "UID | %s | %"PRIx64" - %s", sprint_hex(uid6, 4), key6, success ? "OK" : "->82C7E64BC565<--"); + + uint32_t lf_id = lf_t55xx_white_pwdgen(0x00000080); + success = (lf_id = 0x00018383); + if (success) + testresult++; + PrintAndLogEx(success ? SUCCESS : WARNING, "ID | 0x00000080 | %08"PRIx32 " - %s", lf_id, success ? "OK" : "->00018383<--"); + PrintAndLogEx(SUCCESS, "------------------- Selftest %s", (testresult == NUM_OF_TEST) ? "OK" : "fail"); return PM3_SUCCESS; } diff --git a/common/generator.h b/common/generator.h index c90fe483a..b1c3c82d0 100644 --- a/common/generator.h +++ b/common/generator.h @@ -41,5 +41,7 @@ int mfc_algo_di_all(uint8_t *uid, uint8_t *keys); int mfc_algo_sky_one(uint8_t *uid, uint8_t sector, uint8_t keytype, uint64_t *key); int mfc_algo_sky_all(uint8_t *uid, uint8_t *keys); +uint32_t lf_t55xx_white_pwdgen(uint32_t id); + int generator_selftest(void); #endif diff --git a/doc/cheatsheet.md b/doc/cheatsheet.md index a032d620d..7da56cbcd 100644 --- a/doc/cheatsheet.md +++ b/doc/cheatsheet.md @@ -233,7 +233,7 @@ Options --- i : Specifies the dump-file (input). If omitted, 'dumpdata.bin' is used -pm3 --> script run dumptoemul -i dumpdata.bin +pm3 --> script run data_mf_bin2eml -i dumpdata.bin ``` Write to MIFARE block @@ -285,7 +285,7 @@ Simulate MIFARE Sequence ``` pm3 --> hf mf chk *1 ? d mfc_default_keys pm3 --> hf mf dump 1 -pm3 --> script run dumptoemul -i dumpdata.bin +pm3 --> script run data_mf_bin2eml -i dumpdata.bin pm3 --> hf mf eload 353C2AA6 pm3 --> hf mf sim u 353c2aa6 ``` @@ -305,19 +305,19 @@ pm3 --> hf mfu info Clone MIFARE Ultralight EV1 Sequence ``` pm3 --> hf mfu dump k FFFFFFFF -pm3 --> script run dumptoemul-mfu -i hf-mfu-XXXX-dump.bin -o hf-mfu-XXXX-dump.eml +pm3 --> script run hf_mfu_dumptoemulator -i hf-mfu-XXXX-dump.bin -o hf-mfu-XXXX-dump.eml pm3 --> hf mfu eload u hf-mfu-XXXX-dump.eml pm3 --> hf mfu sim t 7 u hf-mfu-XXXX-dump.eml ``` Bruteforce MIFARE Classic card numbers from 11223344 to 11223346 ``` -pm3 --> script run hf_bruteforce -s 0x11223344 -e 0x11223346 -t 1000 -x mfc +pm3 --> script run hf_mf_uidbruteforce -s 0x11223344 -e 0x11223346 -t 1000 -x mfc ``` Bruteforce MIFARE Ultralight EV1 card numbers from 11223344556677 to 11223344556679 ``` -pm3 --> script run hf_bruteforce -s 0x11223344556677 -e 0x11223344556679 -t 1000 -x mfu +pm3 --> script run hf_mf_uidbruteforce -s 0x11223344556677 -e 0x11223344556679 -t 1000 -x mfu ``` ## Wiegand manipulation @@ -563,7 +563,7 @@ Options -i Specifies the dump-file (input). If omitted, 'dumpdata.bin' is used -o Specifies the output file. If omitted, .eml is used -pm3 --> script run dumptoemul -i xxxxxxxxxxxxxx.bin +pm3 --> script run data_mf_bin2eml -i xxxxxxxxxxxxxx.bin ``` Convert .eml to .bin @@ -573,7 +573,7 @@ Options -i Specifies the dump-file (input). If omitted, 'dumpdata.eml' is used -o Specifies the output file. If omitted, .bin is used -pm3 --> script run emul2dump -i myfile.eml -o myfile.bin +pm3 --> script run data_mf_eml2bin -i myfile.eml -o myfile.bin ``` Format Mifare card @@ -585,7 +585,7 @@ Options -a The new access bytes that will be written to the card -x Execute the commands aswell -pm3 --> script run formatMifare -k FFFFFFFFFFFF -n FFFFFFFFFFFF -x +pm3 --> script run hf_mf_format -k FFFFFFFFFFFF -n FFFFFFFFFFFF -x ``` ## Memory diff --git a/doc/cloner_notes.md b/doc/cloner_notes.md index f0d3df87f..11d2b07b5 100644 --- a/doc/cloner_notes.md +++ b/doc/cloner_notes.md @@ -67,12 +67,13 @@ If t55xx write b 2 d 2D782308 1 The T55x7 protocol uses a pwm based protocol for writing to tags. In order to make decoding easier try the new command as seen below instead. It will try to extract the data written. ``` -lf config s +-- after threshold limit 20 is triggred, skip 10000 samples before collecting samples. +lf config s 10000 t 20 lf t55xx sniff -- if you have a save trace from before, try data load xxxxxxx.pm3 -lf t55xx sniff b +lf t55xx sniff 1 ``` It uses the existing `lf sniff` command to collect the data, so setting that first as per normal sniffing is recommended. Once you have a sniff, you can "re-sniff" from the stored sniffed data and try different settings, if you think the data is not clean. diff --git a/doc/commands.md b/doc/commands.md index 93e8d98fb..d5839fc52 100644 --- a/doc/commands.md +++ b/doc/commands.md @@ -291,12 +291,14 @@ Check column "offline" for their availability. |`hf mf auth4 `|N |`ISO14443-4 AES authentication` |`hf mf sim `|N |`Simulate MIFARE card` |`hf mf eclr `|N |`Clear simulator memory` -|`hf mf eget `|N |`Get simulator memory block` +|`hf mf egetblk `|N |`Get simulator memory block` +|`hf mf egetsc `|N |`Get simulator memory sector` |`hf mf eset `|N |`Set simulator memory block` |`hf mf eload `|N |`Load from file emul dump` |`hf mf esave `|N |`Save to file emul dump` |`hf mf ecfill `|N |`Fill simulator memory with help of keys from simulator` -|`hf mf ekeyprn `|N |`Print keys from simulator memory` +|`hf mf ekeyprn `|N |`Print keys from simulator memory` +|`hf mf eview `|N |`View simulator memory` |`hf mf csetuid `|N |`Set UID (magic chinese card)` |`hf mf cwipe `|N |`Wipe card to default UID/Sectors/Keys` |`hf mf csetblk `|N |`Write block (magic chinese card)` @@ -304,6 +306,7 @@ Check column "offline" for their availability. |`hf mf cgetsc `|N |`Read sector (magic chinese card)` |`hf mf cload `|N |`Load dump (magic chinese card)` |`hf mf csave `|N |`Save dump from magic chinese card into file or emulator` +|`hf mf cview `|N |`View card memory (magic chinese card)` |`hf mf mad `|N |`Checks and prints MAD` |`hf mf ndef `|N |`Prints NDEF records from card` |`hf mf ice `|N |`collect MIFARE Classic nonces to file` @@ -787,6 +790,7 @@ Check column "offline" for their availability. |`lf t55xx read `|N |`b p [password] [o] [1] -- Read T55xx block data. Optional [p password], [override], [page1]` |`lf t55xx resetread `|N |`Send Reset Cmd then lf read the stream to attempt to identify the start of it (needs a demod and/or plot after)` |`lf t55xx recoverpw `|N |`[password] Try to recover from bad password write from a cloner. Only use on PW protected chips!` +|`lf t55xx sniff `|N |`Attempt to recover T55xx commands from sample buffer` |`lf t55xx special `|N |`Show block changes with 64 different offsets` |`lf t55xx trace `|Y |`[1] Show T55x7 traceability data (page 1/ blk 0-1)` |`lf t55xx wakeup `|N |`Send AOR wakeup command` diff --git a/doc/magic_cards_notes.md b/doc/magic_cards_notes.md index c02b59e53..ffa10f04c 100644 --- a/doc/magic_cards_notes.md +++ b/doc/magic_cards_notes.md @@ -195,7 +195,7 @@ hf mf csetuid 11223344 0044 18 ``` ``` -script run remagic +script run run hf_mf_magicrevive ``` To execute commands manually: @@ -443,7 +443,7 @@ hf mf gen3freeze ``` See also ``` -script run mfc_gen3_writer -h +script run hf_mf_gen3_writer -h ``` Equivalent: @@ -518,14 +518,14 @@ Only 7b versions ### Proxmark3 commands ``` -script run ul_uid -h +script run hf_mfu_setuid -h ``` When "soft-bricked" (by writing invalid data in block0), these ones may help: ``` hf 14a config h -script run remagic -u +script run run hf_mf_magicrevive -u ``` ## MIFARE Ultralight DirectWrite @@ -723,7 +723,7 @@ Emulates partially UL EV1 48k/128k, NTAG210, NTAG212, NTAGI2C 1K/2K, NTAGI2C 1K ### Proxmark3 commands ``` -script run mfu_magic -h +script run hf_mfu_magicwrite -h ``` # DESFire @@ -840,5 +840,5 @@ hf 15 csetuid E011223344556677 ``` or (ignore errors): ``` -script run iso15_magic -u E004013344556677 +script run hf_15_magic -u E004013344556677 ``` diff --git a/doc/md/Installation_Instructions/Linux-Installation-Instructions.md b/doc/md/Installation_Instructions/Linux-Installation-Instructions.md index 688091ee8..b39dc7eab 100644 --- a/doc/md/Installation_Instructions/Linux-Installation-Instructions.md +++ b/doc/md/Installation_Instructions/Linux-Installation-Instructions.md @@ -107,7 +107,7 @@ To test you have the proper read & write rights, plug the Proxmark3 and execute: ```sh [ -r /dev/ttyACM0 ] && [ -w /dev/ttyACM0 ] && echo ok ``` -It must return `ok`. Otherwise this means you've a permissions problem to fix. +It must return `ok`. Otherwise this means you've got a permission problem to fix. # Compile and use the project diff --git a/include/pm3_cmd.h b/include/pm3_cmd.h index 78fca9c62..6cacc5ef1 100644 --- a/include/pm3_cmd.h +++ b/include/pm3_cmd.h @@ -786,6 +786,7 @@ typedef struct { #define LF_DIVISOR_125 LF_FREQ2DIV(125) #define LF_DIVISOR_134 LF_FREQ2DIV(134.2) #define LF_DIV2FREQ(d) (12000.0/((d)+1)) +#define LF_CMDREAD_MAX_EXTRA_SYMBOLS 4 // Receiving from USART need more than 30ms as we used on USB // else we get errors about partial packet reception diff --git a/tools/recover_pk.py b/tools/recover_pk.py new file mode 100755 index 000000000..b2ff2e6c7 --- /dev/null +++ b/tools/recover_pk.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python3 + +# @doegox -- 2020 + +import sslcrypto +import binascii +import sys + +debug = False + +def recover(data, signature, alghash=None): + recovered = set() + if len(signature) == 32: + curve = sslcrypto.ecc.get_curve("secp128r1") + recoverable = False + elif len(signature) == 33: + curve = sslcrypto.ecc.get_curve("secp128r1") + recoverable = True + elif len(signature) == 56: + curve = sslcrypto.ecc.get_curve("secp224r1") + recoverable = False + elif len(signature) == 57: + curve = sslcrypto.ecc.get_curve("secp224r1") + recoverable = True + else: + print("Unsupported signature size %i" % len(signature)) + exit(1) + + if (recoverable): + try: + pk = curve.recover(signature, data, hash=alghash) + recovered.add(pk) + if debug: + print("Possible Pk: ", binascii.hexlify(pk)) + except: + pass + else: + for i in range(2): + # Brute force RECID + recid = bytes([27+i]) + try: + pk = curve.recover(recid + signature, data, hash=alghash) + recovered.add(pk) + if debug: + print("Possible Pk: ", binascii.hexlify(pk)) + except: + pass + return recovered + +def recover_multiple(uids, sigs, alghash=None): + recovered = set() + assert len(uids) == len(sigs) + for i in range(len(uids)): + data = binascii.unhexlify(uids[i]) + if debug: + print("UID (%2i): " % len(data), binascii.hexlify(data)) + signature = binascii.unhexlify(sigs[i]) + if debug: + print("Signature (%2i): " % len(signature), binascii.hexlify(signature)) + recovered_tmp = recover(data, signature, alghash) + if i == 0: + if recovered_tmp == set(): + break + else: + recovered = recovered_tmp + else: + recovered &= recovered_tmp + return recovered + +if len(sys.argv) < 3 or len(sys.argv) % 2 == 0: + print("Usage: \n%s UID SIGN [UID SIGN] [...]" % sys.argv[0]) + print("Example: \n%s 04ee45daa34084 ebb6102bff74b087d18a57a54bc375159a04ea9bc61080b7f4a85afe1587d73b" % sys.argv[0]) + exit(1) + +print("Assuming no hash was used in the signature generation:") +recovered = recover_multiple(sys.argv[1:][::2], sys.argv[1:][1::2]) +print("Possible uncompressed Pk(s):") +for pk in list(recovered): + print(binascii.hexlify(pk).decode('utf8')) +print("Assuming SHA-256 was used in the signature generation:") +recovered = recover_multiple(sys.argv[1:][::2], sys.argv[1:][1::2], alghash="sha256") +print("Possible uncompressed Pk(s):") +for pk in list(recovered): + print(binascii.hexlify(pk).decode('utf8')) diff --git a/traces/README.txt b/traces/README.txt index 8d6a6733d..a6fd7b280 100644 --- a/traces/README.txt +++ b/traces/README.txt @@ -14,7 +14,7 @@ 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 +lf_idteck_4944544BAC40E069.pm3: IDTECK raw 4944544BAC40E069 , PSK, printed "806 082 43084" 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 @@ -41,4 +41,4 @@ are all encoded with identical data (hex 00 01 02 03 04 05 06 07 08 09 0A 0B) for the purpose of recognition and testing of demodulation schemes. They were created by writing Q5 tags appropriately configured. The raw data is in 'modulation-data.dat'. --- -hf_mfu.trace: Tracelog file for a MFU simulation \ No newline at end of file +hf_mfu.trace: Tracelog file for a MFU simulation diff --git a/traces/lf_idteck_idk50_PSK b/traces/lf_idteck_idk50_PSK new file mode 100644 index 000000000..ec1fa9fb3 --- /dev/null +++ b/traces/lf_idteck_idk50_PSK @@ -0,0 +1,16000 @@ +8 +-20 +-45 +85 +44 +50 +14 +18 +-13 +5 +-24 +0 +-28 +0 +-28 +0 +-27 +1 +-27 +2 +-26 +3 +-25 +4 +-24 +5 +-24 +5 +-23 +6 +-23 +6 +-22 +-47 +60 +20 +61 +22 +24 +-9 +23 +-23 +1 +-28 +-1 +-29 +-1 +-29 +0 +-28 +1 +-27 +2 +-27 +3 +-26 +4 +-25 +5 +-25 +5 +-24 +6 +-24 +6 +-23 +7 +-23 +7 +-23 +8 +-22 +8 +-22 +8 +-22 +8 +-22 +9 +-21 +9 +-21 +10 +-20 +10 +-21 +9 +-21 +10 +-20 +9 +-21 +9 +-21 +9 +-21 +9 +-20 +9 +-20 +8 +-21 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +9 +-21 +8 +-21 +9 +-21 +8 +-21 +9 +-20 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +11 +-19 +11 +-19 +11 +-19 +12 +-19 +11 +-19 +11 +-20 +11 +-20 +11 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-19 +-44 +87 +45 +52 +15 +19 +-12 +5 +-24 +0 +-28 +-1 +-29 +0 +-28 +1 +-27 +1 +-27 +2 +-26 +3 +-25 +4 +-25 +4 +-24 +5 +-24 +5 +-23 +-48 +60 +20 +61 +22 +24 +-9 +23 +-23 +0 +-29 +-1 +-30 +-1 +-30 +0 +-28 +1 +-28 +2 +-27 +3 +-26 +4 +-25 +6 +-24 +6 +-23 +7 +-23 +6 +-23 +7 +-23 +6 +-23 +8 +-22 +8 +-22 +8 +-22 +8 +-22 +8 +-22 +8 +-22 +8 +-22 +8 +-22 +9 +-22 +9 +-21 +9 +-21 +9 +-21 +10 +-21 +10 +-20 +10 +-21 +10 +-21 +10 +-21 +10 +-20 +11 +-20 +10 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +9 +-20 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +10 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +11 +-20 +10 +-20 +11 +-20 +11 +-20 +11 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +11 +-20 +10 +-20 +10 +-20 +10 +-19 +-44 +86 +45 +50 +14 +18 +-13 +4 +-24 +-1 +-29 +-2 +-30 +-1 +-29 +0 +-28 +1 +-27 +2 +-26 +3 +-25 +4 +-24 +5 +-24 +5 +-23 +6 +-22 +-48 +60 +21 +62 +22 +25 +-8 +23 +-23 +1 +-28 +0 +-29 +0 +-29 +1 +-28 +1 +-28 +2 +-27 +3 +-26 +4 +-25 +5 +-25 +5 +-24 +6 +-24 +6 +-22 +-46 +84 +43 +48 +13 +16 +-14 +3 +-25 +-2 +-29 +-2 +-30 +-2 +-30 +-1 +-29 +-1 +-28 +1 +-27 +2 +-26 +3 +-25 +4 +-25 +5 +-24 +6 +-23 +-47 +59 +20 +60 +22 +24 +-9 +23 +-23 +0 +-28 +-1 +-30 +-1 +-29 +0 +-29 +1 +-28 +2 +-27 +3 +-26 +4 +-25 +4 +-25 +5 +-24 +5 +-24 +6 +-22 +-46 +82 +42 +48 +13 +16 +-15 +2 +-26 +-2 +-30 +-3 +-30 +-2 +-30 +-1 +-29 +0 +-28 +1 +-27 +2 +-26 +4 +-25 +5 +-24 +5 +-24 +6 +-23 +-47 +60 +21 +61 +22 +24 +-9 +23 +-23 +1 +-28 +-1 +-30 +-1 +-29 +0 +-29 +1 +-28 +2 +-27 +3 +-26 +5 +-25 +5 +-24 +6 +-24 +6 +-24 +7 +-23 +7 +-23 +7 +-23 +8 +-22 +8 +-22 +8 +-22 +9 +-21 +8 +-22 +8 +-22 +8 +-22 +8 +-22 +9 +-21 +9 +-21 +10 +-21 +10 +-20 +10 +-21 +10 +-19 +-44 +86 +45 +51 +15 +19 +-12 +4 +-24 +-1 +-29 +-1 +-29 +-1 +-28 +0 +-28 +1 +-27 +2 +-26 +3 +-25 +4 +-25 +4 +-24 +5 +-24 +6 +-23 +-48 +59 +20 +60 +21 +24 +-9 +22 +-24 +0 +-29 +-2 +-30 +-1 +-29 +0 +-28 +1 +-27 +2 +-27 +4 +-26 +4 +-25 +5 +-24 +6 +-24 +6 +-23 +7 +-23 +7 +-22 +7 +-22 +8 +-22 +9 +-22 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +10 +-21 +10 +-20 +10 +-20 +10 +-20 +9 +-19 +-44 +86 +45 +52 +15 +19 +-12 +5 +-24 +0 +-28 +-1 +-29 +-1 +-29 +0 +-28 +1 +-27 +2 +-26 +3 +-25 +4 +-24 +4 +-24 +5 +-23 +6 +-23 +-48 +60 +20 +61 +22 +24 +-9 +23 +-24 +0 +-29 +-1 +-30 +-1 +-29 +0 +-28 +1 +-28 +1 +-28 +2 +-27 +3 +-26 +5 +-25 +5 +-24 +5 +-24 +5 +-23 +-47 +83 +42 +48 +13 +16 +-14 +3 +-25 +-1 +-29 +-2 +-30 +-1 +-29 +0 +-28 +1 +-27 +2 +-26 +3 +-25 +4 +-24 +5 +-24 +5 +-24 +6 +-22 +-47 +60 +20 +61 +22 +24 +-9 +22 +-24 +0 +-29 +-1 +-30 +-1 +-30 +0 +-29 +1 +-28 +2 +-27 +3 +-26 +4 +-25 +5 +-24 +5 +-24 +6 +-24 +7 +-22 +-46 +84 +43 +49 +13 +16 +-14 +2 +-26 +-2 +-30 +-3 +-30 +-2 +-30 +-1 +-29 +0 +-28 +2 +-26 +3 +-26 +4 +-25 +4 +-24 +5 +-24 +6 +-23 +-47 +59 +20 +61 +22 +24 +-9 +23 +-23 +0 +-28 +-1 +-30 +-1 +-30 +0 +-29 +0 +-29 +1 +-28 +2 +-27 +3 +-26 +4 +-26 +5 +-24 +5 +-24 +6 +-24 +5 +-24 +6 +-23 +7 +-23 +8 +-22 +8 +-22 +8 +-22 +8 +-22 +9 +-21 +9 +-21 +8 +-22 +9 +-21 +9 +-22 +10 +-21 +9 +-21 +10 +-20 +9 +-20 +-44 +87 +45 +51 +15 +19 +-12 +4 +-24 +0 +-28 +-1 +-29 +0 +-28 +1 +-28 +1 +-27 +3 +-26 +4 +-24 +5 +-24 +6 +-23 +6 +-23 +7 +-22 +8 +-22 +7 +-22 +7 +-22 +7 +-22 +8 +-22 +8 +-22 +8 +-21 +9 +-21 +9 +-20 +8 +-20 +9 +-20 +9 +-20 +9 +-20 +10 +-19 +10 +-20 +9 +-19 +-45 +62 +23 +63 +24 +26 +-7 +24 +-22 +2 +-27 +0 +-29 +-1 +-29 +0 +-28 +0 +-28 +2 +-27 +2 +-27 +4 +-25 +5 +-24 +6 +-24 +6 +-24 +7 +-23 +7 +-23 +7 +-23 +7 +-23 +8 +-22 +9 +-22 +8 +-22 +9 +-22 +9 +-22 +9 +-21 +9 +-21 +9 +-21 +10 +-20 +9 +-21 +10 +-20 +10 +-20 +10 +-19 +-44 +87 +45 +52 +15 +20 +-12 +6 +-23 +1 +-28 +0 +-28 +0 +-28 +1 +-27 +2 +-26 +3 +-25 +4 +-25 +5 +-24 +6 +-23 +6 +-23 +6 +-22 +-47 +59 +20 +60 +21 +23 +-10 +22 +-24 +0 +-29 +-1 +-30 +0 +-29 +0 +-29 +1 +-28 +2 +-27 +3 +-26 +4 +-25 +5 +-24 +5 +-24 +6 +-24 +6 +-22 +-46 +84 +43 +49 +13 +17 +-14 +3 +-26 +-2 +-30 +-3 +-30 +-3 +-30 +-1 +-29 +-1 +-29 +0 +-28 +2 +-26 +3 +-25 +4 +-24 +5 +-23 +6 +-23 +6 +-23 +6 +-22 +7 +-22 +8 +-21 +8 +-21 +8 +-21 +8 +-21 +9 +-21 +8 +-21 +8 +-21 +9 +-20 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +9 +-20 +9 +-20 +9 +-20 +9 +-20 +9 +-20 +9 +-20 +9 +-21 +9 +-20 +9 +-20 +8 +-21 +9 +-20 +10 +-19 +10 +-19 +10 +-19 +10 +-20 +9 +-20 +-45 +62 +23 +63 +24 +26 +-8 +24 +-22 +2 +-27 +1 +-28 +1 +-28 +2 +-27 +2 +-27 +3 +-26 +4 +-25 +5 +-24 +5 +-24 +6 +-24 +6 +-23 +7 +-23 +7 +-23 +7 +-22 +8 +-22 +7 +-22 +8 +-22 +8 +-22 +9 +-21 +8 +-22 +8 +-22 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-19 +-44 +87 +45 +52 +15 +20 +-12 +6 +-24 +0 +-28 +-1 +-29 +0 +-28 +1 +-28 +2 +-26 +3 +-26 +4 +-25 +5 +-24 +5 +-23 +6 +-23 +6 +-22 +-47 +59 +20 +60 +22 +24 +-9 +22 +-23 +0 +-28 +-1 +-30 +0 +-29 +0 +-28 +2 +-27 +2 +-26 +3 +-26 +4 +-25 +5 +-24 +5 +-24 +6 +-24 +6 +-22 +-47 +83 +42 +49 +13 +17 +-14 +3 +-25 +-1 +-29 +-2 +-29 +-1 +-29 +0 +-28 +0 +-27 +2 +-26 +3 +-25 +3 +-25 +4 +-24 +4 +-24 +5 +-23 +-48 +59 +20 +60 +21 +23 +-10 +22 +-24 +-1 +-29 +-2 +-31 +-2 +-30 +0 +-29 +0 +-28 +1 +-28 +2 +-26 +3 +-25 +5 +-24 +6 +-24 +6 +-23 +7 +-23 +7 +-22 +8 +-22 +8 +-22 +9 +-22 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +9 +-20 +10 +-20 +9 +-20 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +11 +-19 +11 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +9 +-21 +9 +-21 +10 +-21 +10 +-20 +9 +-21 +9 +-21 +9 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +11 +-19 +11 +-19 +11 +-19 +11 +-19 +11 +-18 +-43 +88 +46 +52 +16 +20 +-12 +5 +-24 +1 +-27 +0 +-28 +1 +-27 +1 +-27 +2 +-26 +2 +-25 +3 +-25 +4 +-24 +5 +-24 +5 +-23 +5 +-23 +-48 +59 +20 +61 +22 +24 +-9 +23 +-23 +1 +-28 +-1 +-30 +0 +-29 +0 +-28 +1 +-28 +2 +-27 +2 +-26 +3 +-25 +4 +-25 +5 +-24 +6 +-24 +6 +-23 +6 +-23 +7 +-23 +8 +-22 +8 +-22 +8 +-22 +9 +-21 +9 +-21 +8 +-21 +8 +-22 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-19 +-44 +86 +45 +51 +15 +18 +-13 +4 +-24 +0 +-28 +-1 +-29 +0 +-28 +1 +-27 +2 +-26 +2 +-25 +4 +-24 +5 +-24 +6 +-23 +6 +-22 +7 +-22 +-47 +60 +21 +61 +22 +24 +-9 +23 +-23 +1 +-28 +-1 +-29 +0 +-29 +1 +-28 +1 +-28 +2 +-27 +3 +-26 +4 +-25 +5 +-24 +6 +-24 +6 +-23 +7 +-23 +7 +-23 +7 +-23 +7 +-22 +8 +-22 +8 +-21 +9 +-21 +9 +-21 +9 +-21 +8 +-22 +8 +-22 +8 +-22 +8 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +10 +-20 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-21 +10 +-20 +9 +-20 +9 +-20 +10 +-20 +10 +-20 +10 +-20 +9 +-21 +10 +-20 +10 +-19 +-43 +87 +46 +52 +15 +19 +-12 +5 +-23 +1 +-27 +0 +-28 +0 +-27 +1 +-26 +2 +-26 +3 +-25 +4 +-24 +5 +-24 +5 +-23 +6 +-23 +6 +-22 +-47 +59 +20 +61 +22 +24 +-9 +23 +-23 +0 +-28 +0 +-29 +0 +-29 +0 +-28 +1 +-28 +2 +-27 +3 +-26 +4 +-25 +5 +-24 +5 +-24 +6 +-23 +6 +-22 +-46 +84 +43 +49 +14 +17 +-14 +3 +-25 +-1 +-29 +-2 +-30 +-2 +-30 +-1 +-29 +-1 +-28 +1 +-27 +2 +-26 +3 +-25 +4 +-24 +5 +-23 +6 +-23 +6 +-22 +6 +-22 +6 +-22 +6 +-22 +7 +-21 +7 +-22 +8 +-21 +8 +-21 +8 +-21 +8 +-21 +8 +-21 +9 +-20 +8 +-21 +8 +-21 +8 +-21 +9 +-20 +-45 +62 +23 +62 +24 +26 +-7 +24 +-22 +2 +-27 +1 +-28 +1 +-28 +2 +-27 +2 +-27 +3 +-26 +4 +-25 +6 +-24 +6 +-23 +6 +-23 +7 +-23 +7 +-22 +7 +-23 +7 +-22 +8 +-22 +9 +-21 +9 +-21 +9 +-20 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-20 +10 +-20 +10 +-20 +10 +-21 +9 +-21 +10 +-20 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +11 +-19 +10 +-19 +-44 +87 +46 +51 +15 +19 +-12 +4 +-24 +0 +-28 +-1 +-29 +0 +-28 +0 +-28 +1 +-27 +2 +-26 +3 +-25 +4 +-24 +5 +-23 +6 +-23 +6 +-22 +-47 +60 +22 +62 +23 +25 +-8 +23 +-23 +1 +-28 +0 +-29 +0 +-29 +0 +-28 +2 +-27 +2 +-26 +3 +-25 +4 +-25 +5 +-24 +5 +-24 +6 +-24 +6 +-23 +6 +-24 +7 +-23 +7 +-22 +8 +-22 +8 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +10 +-21 +10 +-20 +10 +-20 +10 +-19 +-44 +87 +45 +51 +15 +18 +-12 +4 +-24 +-1 +-29 +-2 +-30 +-1 +-29 +-1 +-28 +0 +-27 +2 +-26 +3 +-25 +4 +-25 +5 +-23 +6 +-23 +6 +-23 +-47 +59 +21 +60 +22 +23 +-10 +22 +-24 +0 +-29 +-1 +-30 +-1 +-30 +0 +-29 +1 +-28 +2 +-27 +3 +-26 +3 +-26 +5 +-24 +5 +-24 +6 +-23 +6 +-23 +6 +-23 +7 +-22 +8 +-22 +8 +-21 +8 +-21 +8 +-21 +8 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-20 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +11 +-19 +11 +-19 +10 +-19 +10 +-20 +10 +-20 +10 +-19 +10 +-19 +10 +-19 +10 +-19 +10 +-19 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +9 +-20 +9 +-19 +-44 +86 +45 +52 +16 +19 +-12 +5 +-24 +0 +-28 +0 +-28 +0 +-28 +1 +-27 +2 +-27 +2 +-26 +4 +-25 +4 +-24 +5 +-23 +6 +-23 +6 +-22 +-47 +60 +21 +61 +22 +24 +-8 +23 +-23 +0 +-28 +-1 +-30 +0 +-29 +1 +-28 +1 +-28 +2 +-27 +3 +-26 +4 +-25 +5 +-24 +5 +-24 +6 +-23 +7 +-22 +7 +-22 +7 +-22 +8 +-22 +8 +-22 +8 +-21 +9 +-21 +8 +-21 +9 +-21 +8 +-21 +9 +-21 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +9 +-21 +9 +-21 +10 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +9 +-21 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-19 +10 +-20 +11 +-19 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +11 +-20 +11 +-20 +11 +-19 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-19 +-44 +86 +45 +51 +15 +19 +-12 +5 +-24 +0 +-28 +-1 +-28 +0 +-28 +1 +-28 +1 +-27 +2 +-26 +4 +-25 +4 +-24 +5 +-23 +6 +-23 +6 +-23 +-48 +59 +20 +60 +22 +23 +-9 +22 +-24 +0 +-28 +-2 +-30 +-1 +-30 +-1 +-29 +1 +-28 +2 +-27 +3 +-26 +4 +-25 +5 +-24 +6 +-24 +6 +-23 +6 +-22 +-47 +84 +43 +49 +14 +18 +-13 +4 +-24 +-1 +-29 +-2 +-29 +-1 +-29 +0 +-28 +0 +-27 +2 +-26 +3 +-25 +4 +-24 +5 +-24 +5 +-23 +6 +-23 +-47 +60 +20 +60 +22 +24 +-9 +23 +-23 +1 +-28 +-1 +-30 +-1 +-29 +0 +-29 +0 +-28 +2 +-27 +2 +-27 +4 +-25 +5 +-24 +6 +-24 +6 +-23 +6 +-22 +-47 +84 +42 +49 +14 +17 +-14 +3 +-25 +-2 +-29 +-2 +-30 +-2 +-29 +-1 +-28 +0 +-28 +1 +-27 +3 +-25 +4 +-24 +4 +-24 +4 +-24 +5 +-23 +-48 +59 +20 +60 +22 +23 +-9 +21 +-24 +-1 +-29 +-2 +-31 +-1 +-30 +0 +-29 +0 +-28 +1 +-27 +2 +-26 +3 +-26 +3 +-25 +4 +-24 +5 +-24 +6 +-23 +6 +-23 +7 +-23 +7 +-22 +8 +-22 +8 +-22 +9 +-21 +8 +-21 +9 +-21 +9 +-21 +9 +-21 +10 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-19 +-44 +88 +46 +52 +16 +19 +-12 +5 +-23 +0 +-28 +-1 +-29 +0 +-28 +0 +-27 +1 +-27 +2 +-26 +3 +-25 +4 +-25 +5 +-24 +6 +-23 +6 +-23 +-47 +59 +20 +60 +22 +24 +-9 +22 +-24 +0 +-29 +-1 +-30 +-1 +-29 +1 +-28 +0 +-28 +2 +-27 +3 +-26 +5 +-25 +5 +-25 +5 +-25 +6 +-24 +6 +-24 +6 +-24 +7 +-23 +6 +-23 +7 +-23 +8 +-22 +8 +-22 +8 +-22 +8 +-22 +8 +-22 +8 +-22 +9 +-21 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +10 +-19 +-44 +86 +45 +52 +15 +19 +-12 +4 +-24 +0 +-28 +-1 +-29 +-1 +-28 +0 +-28 +1 +-27 +2 +-26 +3 +-25 +4 +-25 +5 +-24 +5 +-24 +6 +-23 +-47 +59 +20 +60 +22 +24 +-9 +23 +-23 +0 +-28 +-1 +-29 +-1 +-29 +0 +-29 +1 +-28 +2 +-27 +3 +-26 +4 +-25 +4 +-25 +6 +-24 +6 +-24 +7 +-22 +-46 +84 +43 +49 +14 +17 +-14 +3 +-25 +-1 +-29 +-2 +-30 +-1 +-29 +0 +-28 +1 +-27 +1 +-27 +3 +-25 +4 +-25 +4 +-25 +4 +-24 +4 +-24 +-48 +59 +20 +59 +20 +23 +-10 +21 +-25 +0 +-29 +-2 +-31 +-1 +-30 +0 +-29 +0 +-29 +1 +-28 +3 +-26 +4 +-25 +6 +-24 +6 +-24 +7 +-23 +8 +-21 +-45 +84 +43 +50 +14 +17 +-14 +3 +-25 +-1 +-29 +-2 +-30 +-1 +-29 +0 +-28 +1 +-28 +1 +-27 +3 +-26 +4 +-25 +4 +-24 +5 +-24 +6 +-22 +-47 +59 +20 +60 +21 +23 +-9 +22 +-24 +0 +-29 +-1 +-30 +-1 +-30 +0 +-29 +1 +-28 +2 +-27 +3 +-26 +4 +-25 +5 +-25 +6 +-24 +6 +-24 +7 +-23 +6 +-23 +7 +-23 +7 +-22 +8 +-22 +9 +-21 +8 +-22 +9 +-21 +8 +-22 +8 +-22 +8 +-22 +8 +-22 +9 +-21 +9 +-21 +9 +-22 +9 +-22 +9 +-20 +-45 +86 +44 +50 +14 +18 +-13 +4 +-24 +0 +-28 +-1 +-29 +0 +-28 +1 +-27 +2 +-27 +3 +-26 +4 +-24 +5 +-24 +6 +-23 +7 +-22 +7 +-22 +7 +-22 +7 +-22 +7 +-22 +8 +-22 +8 +-21 +8 +-21 +9 +-21 +9 +-21 +8 +-21 +8 +-21 +9 +-20 +9 +-20 +9 +-20 +9 +-20 +9 +-20 +9 +-20 +-45 +62 +22 +63 +24 +26 +-8 +24 +-22 +2 +-28 +0 +-29 +1 +-28 +1 +-28 +2 +-27 +2 +-27 +4 +-26 +4 +-25 +5 +-24 +6 +-24 +7 +-23 +7 +-23 +7 +-23 +7 +-23 +8 +-22 +8 +-22 +9 +-21 +9 +-21 +8 +-21 +9 +-21 +8 +-22 +8 +-22 +8 +-22 +9 +-21 +9 +-21 +9 +-22 +9 +-22 +9 +-20 +-44 +86 +45 +51 +15 +19 +-12 +4 +-24 +0 +-28 +0 +-28 +0 +-28 +1 +-27 +2 +-26 +3 +-25 +4 +-24 +5 +-24 +6 +-23 +6 +-23 +6 +-22 +-47 +60 +21 +60 +22 +24 +-9 +22 +-24 +1 +-28 +-1 +-30 +-1 +-30 +0 +-29 +1 +-28 +2 +-27 +3 +-26 +4 +-25 +5 +-24 +6 +-24 +6 +-24 +6 +-22 +-47 +84 +42 +49 +13 +16 +-14 +2 +-26 +-1 +-30 +-2 +-30 +-1 +-29 +-1 +-29 +0 +-28 +2 +-27 +2 +-26 +4 +-25 +4 +-24 +5 +-24 +5 +-23 +6 +-23 +6 +-23 +7 +-22 +7 +-21 +7 +-22 +8 +-21 +8 +-21 +8 +-21 +8 +-21 +8 +-21 +8 +-21 +8 +-21 +8 +-21 +8 +-21 +8 +-21 +9 +-20 +10 +-20 +9 +-20 +10 +-19 +10 +-19 +10 +-19 +10 +-19 +10 +-19 +10 +-19 +10 +-19 +10 +-19 +10 +-19 +10 +-19 +10 +-19 +10 +-20 +10 +-20 +9 +-20 +-45 +62 +23 +63 +24 +26 +-7 +24 +-22 +2 +-27 +0 +-28 +0 +-28 +2 +-27 +2 +-27 +3 +-26 +4 +-25 +5 +-25 +5 +-24 +6 +-24 +6 +-24 +6 +-23 +6 +-23 +7 +-23 +8 +-22 +8 +-22 +9 +-22 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-19 +-44 +87 +45 +51 +15 +18 +-13 +4 +-24 +-1 +-29 +-2 +-30 +-1 +-29 +0 +-28 +0 +-28 +1 +-27 +2 +-26 +4 +-25 +4 +-24 +5 +-23 +6 +-22 +-47 +60 +20 +60 +22 +24 +-9 +22 +-24 +1 +-28 +-1 +-30 +-1 +-29 +0 +-29 +1 +-28 +2 +-27 +3 +-26 +4 +-25 +5 +-24 +6 +-24 +6 +-23 +7 +-22 +-46 +85 +44 +50 +30 +18 +-13 +3 +-25 +-1 +-29 +-1 +-29 +-1 +-29 +0 +-28 +1 +-27 +2 +-26 +2 +-26 +3 +-25 +4 +-24 +5 +-24 +5 +-23 +-48 +59 +20 +60 +22 +24 +-9 +22 +-23 +0 +-29 +-2 +-30 +-1 +-30 +0 +-28 +2 +-27 +2 +-27 +3 +-26 +4 +-26 +4 +-25 +5 +-24 +6 +-24 +6 +-23 +7 +-23 +6 +-23 +7 +-23 +7 +-23 +7 +-23 +8 +-23 +8 +-22 +8 +-22 +8 +-22 +8 +-22 +9 +-21 +10 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +11 +-20 +11 +-20 +11 +-19 +11 +-20 +10 +-20 +10 +-20 +10 +-20 +11 +-20 +10 +-20 +10 +-20 +11 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-21 +10 +-20 +10 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +9 +-19 +-44 +86 +45 +50 +15 +19 +-12 +4 +-24 +0 +-28 +-2 +-30 +-1 +-29 +0 +-28 +1 +-27 +2 +-26 +2 +-26 +4 +-25 +4 +-24 +5 +-24 +6 +-22 +-47 +59 +20 +62 +22 +24 +-9 +23 +-23 +0 +-28 +-1 +-30 +0 +-29 +0 +-29 +1 +-28 +2 +-28 +3 +-26 +4 +-25 +5 +-24 +6 +-24 +6 +-24 +6 +-23 +7 +-23 +7 +-23 +8 +-22 +9 +-21 +9 +-21 +9 +-21 +10 +-21 +10 +-20 +10 +-21 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-19 +-44 +87 +45 +51 +15 +19 +-12 +4 +-24 +0 +-28 +-1 +-28 +0 +-28 +0 +-27 +1 +-27 +2 +-26 +3 +-25 +4 +-25 +5 +-24 +5 +-24 +6 +-23 +-47 +58 +20 +60 +21 +23 +-10 +22 +-24 +-1 +-30 +-2 +-30 +-2 +-30 +0 +-29 +1 +-28 +2 +-27 +4 +-26 +4 +-25 +6 +-24 +6 +-24 +7 +-23 +7 +-23 +7 +-23 +8 +-22 +8 +-22 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +10 +-21 +9 +-21 +9 +-21 +9 +-20 +9 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-21 +10 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-19 +-44 +87 +45 +52 +15 +19 +-12 +5 +-24 +0 +-28 +-1 +-29 +0 +-28 +0 +-28 +1 +-27 +2 +-26 +3 +-25 +4 +-25 +4 +-25 +4 +-24 +5 +-24 +-48 +58 +20 +60 +21 +23 +-10 +22 +-24 +0 +-29 +-1 +-30 +0 +-29 +1 +-28 +2 +-27 +3 +-26 +4 +-25 +5 +-24 +6 +-23 +7 +-23 +7 +-23 +7 +-21 +-46 +85 +43 +50 +14 +18 +-13 +4 +-25 +-1 +-29 +-2 +-30 +-1 +-29 +0 +-28 +0 +-28 +2 +-26 +3 +-25 +4 +-25 +4 +-24 +4 +-24 +5 +-23 +6 +-22 +6 +-22 +6 +-22 +7 +-22 +8 +-21 +8 +-21 +8 +-21 +8 +-21 +8 +-21 +8 +-21 +8 +-21 +8 +-21 +8 +-21 +9 +-20 +10 +-20 +9 +-20 +-44 +62 +23 +63 +24 +26 +-7 +24 +-22 +2 +-27 +0 +-29 +0 +-29 +0 +-28 +2 +-27 +2 +-27 +3 +-26 +3 +-26 +4 +-25 +5 +-24 +6 +-24 +6 +-23 +7 +-23 +7 +-23 +8 +-22 +9 +-21 +9 +-21 +9 +-21 +8 +-21 +9 +-21 +8 +-21 +9 +-21 +9 +-21 +9 +-20 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +11 +-20 +10 +-20 +11 +-20 +11 +-20 +10 +-20 +10 +-20 +10 +-20 +11 +-20 +11 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-19 +-43 +87 +46 +52 +16 +19 +-12 +5 +-24 +0 +-28 +-1 +-29 +0 +-28 +0 +-28 +2 +-27 +2 +-26 +3 +-25 +4 +-24 +5 +-23 +6 +-23 +6 +-22 +-47 +59 +20 +61 +22 +24 +-9 +22 +-24 +0 +-29 +-2 +-30 +-1 +-30 +0 +-29 +0 +-28 +1 +-28 +3 +-26 +3 +-26 +4 +-25 +5 +-24 +6 +-24 +7 +-22 +7 +-22 +7 +-22 +8 +-22 +8 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-20 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-19 +-44 +86 +45 +51 +15 +19 +-12 +5 +-24 +0 +-28 +-1 +-29 +0 +-28 +0 +-28 +1 +-27 +2 +-26 +3 +-25 +4 +-24 +5 +-24 +5 +-23 +6 +-22 +-47 +60 +21 +61 +22 +24 +-9 +22 +-23 +0 +-29 +-1 +-30 +-1 +-29 +0 +-28 +1 +-28 +2 +-27 +3 +-26 +4 +-25 +5 +-24 +5 +-24 +6 +-24 +6 +-24 +6 +-23 +6 +-23 +8 +-22 +8 +-22 +8 +-22 +7 +-22 +7 +-22 +8 +-22 +8 +-22 +8 +-22 +8 +-22 +9 +-21 +9 +-21 +9 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +11 +-20 +11 +-19 +11 +-19 +11 +-19 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +11 +-20 +11 +-20 +11 +-19 +10 +-19 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +9 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-21 +10 +-20 +10 +-19 +-43 +87 +46 +51 +16 +19 +-12 +5 +-24 +0 +-28 +-1 +-29 +0 +-28 +0 +-27 +2 +-26 +2 +-26 +4 +-24 +5 +-24 +5 +-23 +5 +-23 +6 +-23 +-47 +59 +20 +60 +22 +23 +-9 +22 +-24 +0 +-29 +-2 +-30 +-1 +-29 +0 +-28 +1 +-28 +2 +-27 +3 +-26 +4 +-25 +6 +-24 +7 +-23 +7 +-23 +7 +-22 +7 +-22 +8 +-22 +9 +-21 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +9 +-21 +9 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +9 +-20 +9 +-21 +9 +-21 +10 +-20 +9 +-20 +10 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +11 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-21 +10 +-20 +9 +-21 +10 +-20 +9 +-21 +10 +-20 +10 +-20 +9 +-21 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +9 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-19 +-43 +88 +46 +52 +16 +20 +-11 +6 +-22 +1 +-27 +0 +-28 +0 +-27 +1 +-27 +2 +-26 +3 +-25 +4 +-25 +4 +-24 +5 +-23 +6 +-23 +6 +-23 +-47 +59 +20 +61 +22 +24 +-8 +23 +-23 +0 +-28 +-1 +-30 +-1 +-29 +0 +-29 +0 +-28 +2 +-27 +2 +-26 +4 +-25 +5 +-25 +6 +-24 +6 +-23 +6 +-22 +-46 +84 +43 +49 +14 +16 +-14 +3 +-25 +-2 +-30 +-2 +-30 +-2 +-29 +-2 +-29 +-1 +-28 +0 +-28 +2 +-26 +3 +-25 +3 +-25 +4 +-24 +5 +-24 +-48 +58 +20 +60 +21 +23 +-9 +22 +-23 +0 +-28 +-1 +-29 +-1 +-29 +0 +-28 +1 +-28 +2 +-26 +4 +-26 +4 +-25 +5 +-24 +6 +-24 +7 +-23 +7 +-22 +-46 +84 +43 +49 +30 +17 +-13 +3 +-25 +-1 +-29 +-2 +-30 +-1 +-29 +0 +-28 +0 +-27 +2 +-26 +3 +-25 +4 +-24 +4 +-24 +5 +-24 +5 +-23 +-47 +59 +20 +60 +22 +24 +-9 +22 +-23 +0 +-28 +-1 +-30 +-1 +-29 +0 +-28 +1 +-28 +2 +-27 +3 +-26 +4 +-25 +5 +-25 +5 +-24 +6 +-23 +6 +-23 +7 +-22 +7 +-23 +7 +-22 +7 +-22 +8 +-22 +8 +-22 +8 +-21 +9 +-21 +8 +-21 +7 +-22 +8 +-22 +8 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-20 +-44 +86 +45 +50 +15 +19 +-12 +5 +-24 +0 +-28 +-1 +-29 +-1 +-29 +1 +-27 +1 +-26 +2 +-25 +3 +-25 +4 +-24 +4 +-24 +5 +-23 +5 +-23 +-48 +59 +20 +60 +22 +24 +-9 +22 +-24 +0 +-29 +-1 +-29 +-1 +-29 +0 +-28 +1 +-27 +2 +-27 +3 +-25 +4 +-25 +5 +-24 +6 +-23 +7 +-23 +8 +-22 +7 +-22 +8 +-22 +8 +-22 +8 +-22 +8 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +10 +-21 +10 +-21 +9 +-20 +10 +-20 +9 +-20 +9 +-20 +-44 +86 +45 +50 +15 +19 +-12 +5 +-24 +0 +-28 +-1 +-29 +-1 +-29 +0 +-28 +0 +-28 +2 +-26 +3 +-25 +4 +-24 +5 +-24 +5 +-23 +6 +-22 +-47 +60 +21 +62 +22 +25 +-8 +23 +-23 +1 +-28 +-1 +-30 +0 +-29 +1 +-28 +2 +-27 +2 +-26 +3 +-26 +4 +-25 +5 +-24 +6 +-23 +7 +-23 +7 +-22 +-46 +84 +43 +49 +30 +17 +-14 +4 +-25 +-1 +-29 +-2 +-29 +-1 +-29 +0 +-28 +0 +-27 +1 +-26 +2 +-26 +3 +-25 +4 +-24 +5 +-23 +5 +-23 +-48 +58 +20 +60 +22 +24 +-9 +22 +-24 +0 +-28 +-1 +-30 +-1 +-29 +0 +-28 +1 +-28 +2 +-27 +3 +-26 +3 +-25 +4 +-25 +5 +-24 +6 +-23 +6 +-22 +-47 +84 +43 +49 +13 +16 +-15 +2 +-26 +-3 +-30 +-3 +-30 +-2 +-30 +-2 +-29 +-1 +-28 +1 +-26 +2 +-26 +4 +-24 +4 +-24 +5 +-23 +6 +-22 +-47 +60 +21 +61 +22 +24 +-9 +22 +-23 +0 +-28 +-2 +-30 +-1 +-29 +0 +-28 +1 +-28 +2 +-27 +3 +-26 +5 +-25 +5 +-24 +6 +-24 +6 +-23 +7 +-23 +7 +-23 +7 +-23 +8 +-22 +8 +-21 +9 +-21 +9 +-21 +9 +-20 +9 +-20 +9 +-21 +9 +-21 +9 +-20 +9 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-19 +-44 +86 +45 +51 +15 +19 +-12 +5 +-24 +0 +-28 +-1 +-28 +0 +-28 +0 +-27 +1 +-27 +2 +-26 +3 +-25 +4 +-24 +4 +-24 +5 +-23 +5 +-23 +5 +-23 +5 +-23 +6 +-22 +7 +-22 +7 +-22 +7 +-22 +7 +-21 +8 +-22 +8 +-21 +8 +-21 +8 +-22 +8 +-21 +8 +-21 +9 +-20 +8 +-20 +9 +-20 +-45 +62 +23 +62 +24 +26 +-7 +24 +-22 +2 +-27 +0 +-29 +0 +-29 +1 +-28 +2 +-27 +3 +-26 +5 +-25 +6 +-24 +7 +-23 +7 +-22 +7 +-22 +8 +-22 +8 +-22 +8 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-20 +10 +-20 +9 +-20 +9 +-21 +9 +-21 +9 +-21 +9 +-20 +9 +-20 +9 +-20 +10 +-20 +10 +-20 +-44 +86 +45 +52 +16 +18 +-12 +4 +-24 +0 +-28 +-1 +-28 +0 +-28 +0 +-27 +1 +-27 +2 +-26 +2 +-26 +4 +-25 +4 +-24 +5 +-23 +6 +-23 +-47 +59 +20 +60 +21 +24 +-9 +22 +-23 +0 +-28 +-1 +-30 +-1 +-30 +0 +-29 +1 +-28 +2 +-27 +3 +-26 +4 +-25 +5 +-24 +6 +-24 +6 +-24 +6 +-22 +-47 +84 +43 +49 +13 +16 +-15 +2 +-26 +-3 +-30 +-2 +-30 +-2 +-30 +-1 +-29 +-1 +-29 +0 +-28 +2 +-26 +3 +-25 +4 +-25 +5 +-24 +6 +-23 +7 +-22 +7 +-22 +8 +-22 +8 +-21 +9 +-20 +9 +-20 +9 +-21 +9 +-20 +9 +-21 +9 +-21 +9 +-20 +9 +-20 +9 +-20 +9 +-20 +9 +-20 +9 +-20 +9 +-20 +9 +-20 +9 +-20 +9 +-20 +9 +-20 +9 +-20 +10 +-20 +9 +-20 +9 +-20 +8 +-21 +9 +-20 +9 +-20 +9 +-21 +9 +-21 +8 +-21 +9 +-20 +-45 +62 +22 +63 +24 +26 +-8 +24 +-22 +2 +-27 +0 +-28 +1 +-28 +2 +-28 +2 +-27 +4 +-26 +5 +-25 +6 +-24 +7 +-23 +7 +-23 +7 +-23 +7 +-23 +8 +-22 +8 +-22 +8 +-22 +8 +-22 +9 +-21 +9 +-21 +9 +-21 +10 +-20 +9 +-21 +9 +-21 +9 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-19 +-44 +87 +45 +51 +15 +19 +-12 +5 +-24 +0 +-28 +-1 +-29 +-1 +-28 +1 +-27 +1 +-27 +2 +-26 +3 +-25 +4 +-25 +5 +-24 +5 +-24 +6 +-23 +-47 +59 +20 +60 +22 +24 +-9 +22 +-24 +0 +-29 +-1 +-30 +-2 +-30 +-1 +-30 +0 +-29 +1 +-28 +2 +-27 +4 +-26 +4 +-26 +5 +-25 +6 +-24 +7 +-22 +-46 +84 +43 +49 +14 +17 +-14 +3 +-25 +-1 +-30 +-2 +-30 +-1 +-29 +0 +-28 +0 +-28 +2 +-26 +3 +-26 +4 +-25 +4 +-25 +4 +-24 +6 +-23 +-48 +59 +20 +60 +22 +24 +-9 +22 +-24 +0 +-29 +-1 +-30 +0 +-29 +0 +-28 +2 +-28 +2 +-27 +3 +-26 +4 +-25 +6 +-24 +6 +-24 +7 +-23 +7 +-23 +7 +-23 +7 +-22 +8 +-22 +8 +-22 +8 +-22 +8 +-22 +9 +-21 +9 +-21 +9 +-22 +8 +-22 +9 +-21 +9 +-21 +9 +-21 +10 +-21 +9 +-21 +10 +-20 +9 +-21 +9 +-21 +10 +-21 +9 +-21 +9 +-21 +9 +-22 +9 +-21 +9 +-21 +9 +-22 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +11 +-20 +10 +-20 +11 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-19 +-44 +87 +46 +52 +16 +19 +-12 +5 +-24 +1 +-27 +0 +-28 +0 +-28 +1 +-27 +1 +-27 +2 +-26 +3 +-25 +4 +-24 +5 +-24 +6 +-23 +6 +-23 +-47 +59 +20 +61 +22 +24 +-9 +22 +-24 +0 +-29 +-2 +-30 +-2 +-30 +-1 +-29 +0 +-29 +2 +-28 +3 +-26 +4 +-25 +5 +-25 +6 +-24 +7 +-23 +7 +-22 +7 +-23 +7 +-22 +8 +-22 +8 +-22 +8 +-22 +9 +-22 +9 +-21 +10 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +10 +-21 +9 +-21 +10 +-20 +10 +-19 +-44 +87 +45 +52 +15 +19 +-12 +5 +-24 +1 +-27 +0 +-28 +0 +-28 +1 +-27 +1 +-27 +2 +-26 +4 +-25 +4 +-24 +5 +-24 +6 +-23 +6 +-22 +-47 +59 +20 +61 +22 +24 +-9 +23 +-23 +0 +-28 +-1 +-30 +-1 +-30 +0 +-29 +1 +-28 +2 +-27 +3 +-26 +3 +-26 +4 +-25 +5 +-24 +6 +-24 +6 +-23 +6 +-24 +6 +-24 +6 +-24 +7 +-23 +7 +-23 +7 +-22 +7 +-22 +8 +-22 +8 +-22 +8 +-22 +9 +-22 +10 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +11 +-19 +10 +-20 +10 +-20 +11 +-20 +10 +-20 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-19 +-44 +87 +46 +52 +16 +20 +-12 +5 +-24 +1 +-27 +0 +-28 +0 +-28 +1 +-27 +2 +-27 +2 +-26 +4 +-25 +4 +-24 +5 +-24 +6 +-23 +6 +-23 +-47 +59 +20 +60 +22 +24 +-9 +22 +-24 +0 +-28 +-1 +-30 +-1 +-30 +0 +-29 +1 +-28 +2 +-27 +3 +-26 +4 +-26 +5 +-25 +5 +-24 +5 +-24 +6 +-23 +-47 +83 +42 +48 +13 +16 +-15 +2 +-26 +-2 +-30 +-2 +-30 +-2 +-30 +-1 +-29 +0 +-28 +2 +-26 +3 +-25 +4 +-25 +5 +-24 +6 +-23 +6 +-23 +6 +-23 +7 +-22 +8 +-22 +8 +-22 +8 +-21 +8 +-21 +8 +-21 +8 +-21 +8 +-21 +8 +-21 +8 +-21 +8 +-21 +9 +-20 +9 +-20 +9 +-20 +9 +-20 +-45 +62 +23 +64 +24 +26 +-7 +25 +-22 +2 +-27 +0 +-28 +1 +-28 +2 +-27 +2 +-27 +3 +-26 +4 +-25 +5 +-24 +6 +-24 +6 +-24 +6 +-23 +7 +-23 +7 +-23 +8 +-23 +8 +-22 +8 +-22 +9 +-22 +9 +-22 +9 +-21 +8 +-22 +8 +-22 +9 +-22 +9 +-22 +9 +-21 +8 +-22 +9 +-21 +9 +-21 +9 +-21 +8 +-21 +9 +-21 +9 +-21 +9 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +11 +-19 +-43 +87 +45 +52 +16 +19 +-12 +5 +-24 +0 +-28 +-1 +-29 +-1 +-29 +0 +-28 +1 +-27 +2 +-26 +3 +-26 +4 +-24 +5 +-24 +6 +-23 +6 +-22 +-47 +60 +20 +61 +22 +24 +-9 +23 +-23 +1 +-28 +-1 +-30 +0 +-29 +0 +-29 +1 +-28 +2 +-27 +4 +-26 +5 +-25 +5 +-24 +6 +-24 +6 +-23 +7 +-23 +7 +-23 +7 +-22 +8 +-22 +8 +-22 +8 +-22 +9 +-21 +8 +-22 +8 +-22 +8 +-22 +8 +-22 +8 +-21 +8 +-22 +8 +-22 +8 +-22 +9 +-22 +8 +-20 +-45 +86 +44 +51 +15 +18 +-12 +5 +-24 +0 +-28 +-1 +-29 +-1 +-29 +0 +-28 +1 +-27 +2 +-26 +4 +-25 +4 +-24 +5 +-23 +6 +-23 +7 +-22 +-46 +60 +21 +62 +22 +25 +-8 +23 +-23 +0 +-28 +-1 +-30 +-1 +-29 +0 +-29 +1 +-28 +2 +-27 +3 +-26 +4 +-26 +5 +-25 +6 +-24 +6 +-24 +7 +-23 +7 +-23 +7 +-23 +8 +-22 +8 +-22 +9 +-22 +9 +-21 +10 +-21 +9 +-21 +9 +-21 +9 +-20 +9 +-20 +9 +-21 +9 +-20 +10 +-20 +10 +-20 +9 +-20 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +10 +-20 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +10 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-20 +9 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +11 +-19 +11 +-19 +11 +-19 +11 +-19 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-19 +-44 +87 +45 +51 +16 +19 +-12 +4 +-24 +0 +-28 +-1 +-28 +0 +-28 +0 +-27 +1 +-27 +2 +-26 +4 +-25 +5 +-24 +6 +-23 +6 +-23 +7 +-22 +-47 +60 +21 +62 +23 +24 +-8 +23 +-23 +0 +-28 +-1 +-30 +-1 +-29 +0 +-28 +2 +-28 +2 +-27 +3 +-26 +4 +-25 +5 +-24 +6 +-24 +6 +-23 +7 +-22 +7 +-22 +6 +-23 +7 +-22 +7 +-22 +7 +-22 +7 +-22 +8 +-21 +8 +-21 +8 +-22 +8 +-22 +8 +-21 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +11 +-19 +11 +-19 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +9 +-21 +10 +-21 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +9 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +11 +-19 +10 +-20 +11 +-19 +11 +-20 +10 +-20 +10 +-20 +10 +-20 +11 +-20 +11 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +-44 +86 +45 +51 +15 +18 +-12 +4 +-24 +0 +-28 +-1 +-29 +-1 +-29 +0 +-28 +0 +-28 +2 +-26 +3 +-25 +4 +-24 +5 +-23 +6 +-23 +6 +-22 +-47 +60 +22 +62 +22 +25 +-8 +24 +-22 +2 +-28 +0 +-29 +0 +-29 +1 +-28 +1 +-27 +2 +-27 +4 +-25 +4 +-25 +5 +-24 +6 +-24 +6 +-23 +6 +-22 +-46 +84 +42 +49 +13 +17 +-14 +3 +-26 +-1 +-29 +-2 +-30 +-2 +-29 +0 +-28 +0 +-27 +2 +-26 +3 +-25 +4 +-24 +4 +-24 +5 +-24 +6 +-23 +-47 +59 +20 +60 +22 +24 +-9 +23 +-23 +1 +-28 +-1 +-29 +-1 +-29 +0 +-29 +1 +-28 +2 +-27 +2 +-26 +4 +-25 +5 +-24 +5 +-24 +6 +-24 +5 +-23 +-47 +82 +42 +48 +13 +16 +-15 +2 +-26 +-2 +-30 +-3 +-30 +-2 +-30 +-1 +-29 +-1 +-28 +1 +-26 +2 +-26 +3 +-25 +4 +-24 +5 +-23 +6 +-22 +-47 +60 +21 +62 +23 +25 +-8 +22 +-23 +1 +-28 +-1 +-29 +-1 +-29 +0 +-28 +1 +-28 +2 +-27 +3 +-26 +4 +-25 +4 +-25 +5 +-24 +6 +-23 +6 +-23 +7 +-23 +7 +-23 +8 +-22 +8 +-22 +8 +-22 +8 +-22 +9 +-22 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-19 +-44 +86 +45 +51 +15 +19 +-12 +5 +-24 +0 +-28 +-1 +-28 +0 +-28 +1 +-27 +1 +-27 +2 +-26 +2 +-26 +4 +-24 +4 +-24 +4 +-24 +5 +-23 +-48 +59 +20 +59 +21 +23 +-10 +21 +-24 +0 +-29 +-1 +-30 +-1 +-29 +-1 +-29 +0 +-28 +2 +-27 +2 +-26 +4 +-25 +5 +-24 +5 +-24 +6 +-23 +7 +-23 +7 +-22 +7 +-22 +8 +-22 +8 +-22 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +9 +-21 +10 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-19 +-43 +87 +45 +52 +16 +19 +-12 +5 +-24 +0 +-28 +-1 +-29 +0 +-28 +1 +-27 +2 +-26 +2 +-26 +4 +-25 +4 +-24 +5 +-23 +6 +-23 +6 +-22 +-47 +59 +20 +61 +22 +24 +-9 +22 +-23 +0 +-29 +-1 +-30 +-1 +-30 +0 +-29 +1 +-28 +1 +-28 +2 +-26 +3 +-26 +4 +-25 +5 +-24 +5 +-24 +6 +-23 +-47 +83 +42 +48 +13 +16 +-15 +2 +-26 +-1 +-29 +-2 +-30 +-1 +-29 +0 +-28 +0 +-27 +2 +-26 +3 +-25 +4 +-24 +5 +-23 +6 +-23 +6 +-22 +-47 +60 +21 +61 +22 +24 +-9 +22 +-23 +0 +-28 +-1 +-29 +-1 +-29 +0 +-28 +1 +-28 +2 +-27 +3 +-26 +3 +-26 +4 +-25 +5 +-24 +6 +-24 +6 +-22 +-46 +84 +43 +49 +30 +17 +-13 +3 +-25 +-1 +-29 +-2 +-29 +-1 +-29 +0 +-28 +0 +-28 +2 +-26 +3 +-25 +4 +-25 +4 +-24 +5 +-24 +6 +-23 +-47 +59 +21 +60 +22 +23 +-9 +22 +-24 +-1 +-29 +-2 +-30 +-1 +-30 +0 +-29 +0 +-29 +1 +-28 +2 +-27 +3 +-26 +4 +-26 +5 +-24 +6 +-24 +6 +-23 +6 +-24 +7 +-23 +7 +-22 +8 +-21 +8 +-21 +9 +-21 +9 +-20 +9 +-21 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-19 +-43 +86 +45 +51 +16 +19 +-12 +4 +-24 +0 +-27 +-1 +-28 +0 +-28 +1 +-27 +1 +-27 +2 +-26 +3 +-25 +4 +-24 +5 +-24 +6 +-23 +6 +-23 +6 +-22 +6 +-22 +7 +-22 +7 +-22 +8 +-21 +8 +-21 +8 +-20 +8 +-20 +8 +-20 +8 +-20 +9 +-20 +9 +-20 +10 +-20 +9 +-20 +9 +-20 +9 +-19 +-44 +62 +23 +63 +24 +26 +-7 +24 +-21 +0 +-28 +-1 +-29 +-1 +-29 +1 +-28 +2 +-27 +2 +-27 +2 +-26 +4 +-25 +5 +-25 +5 +-24 +6 +-24 +6 +-24 +6 +-23 +7 +-23 +8 +-22 +8 +-22 +8 +-21 +8 +-22 +9 +-21 +9 +-21 +9 +-20 +9 +-20 +9 +-20 +10 +-20 +9 +-20 +10 +-20 +9 +-20 +9 +-20 +-44 +86 +45 +51 +15 +19 +-12 +5 +-24 +-1 +-28 +-1 +-29 +-1 +-29 +0 +-28 +1 +-27 +1 +-26 +3 +-25 +3 +-24 +4 +-24 +4 +-24 +5 +-23 +-48 +59 +20 +60 +22 +24 +-9 +22 +-23 +0 +-29 +-1 +-29 +-1 +-29 +0 +-28 +1 +-28 +2 +-26 +4 +-25 +4 +-25 +5 +-24 +6 +-23 +6 +-23 +7 +-22 +-46 +84 +43 +50 +15 +17 +-13 +3 +-25 +-2 +-29 +-2 +-29 +-1 +-29 +0 +-28 +1 +-27 +2 +-26 +2 +-26 +4 +-24 +4 +-24 +6 +-23 +6 +-23 +6 +-22 +7 +-22 +7 +-22 +8 +-21 +8 +-21 +8 +-21 +9 +-20 +9 +-20 +9 +-20 +9 +-20 +9 +-20 +10 +-20 +10 +-20 +9 +-20 +9 +-20 +9 +-20 +9 +-20 +8 +-20 +9 +-20 +10 +-19 +10 +-19 +10 +-19 +9 +-19 +9 +-20 +9 +-20 +9 +-20 +9 +-20 +9 +-19 +9 +-20 +10 +-20 +10 +-19 +10 +-19 +-44 +62 +23 +63 +25 +26 +-6 +25 +-21 +2 +-26 +1 +-27 +2 +-27 +2 +-27 +2 +-27 +3 +-26 +4 +-25 +5 +-24 +5 +-24 +6 +-24 +6 +-24 +7 +-23 +7 +-23 +6 +-23 +7 +-23 +7 +-23 +8 +-22 +8 +-22 +8 +-22 +9 +-21 +9 +-21 +8 +-22 +9 +-21 +10 +-20 +10 +-20 +9 +-20 +10 +-20 +10 +-19 +-44 +87 +45 +52 +16 +20 +-12 +5 +-23 +0 +-28 +0 +-28 +1 +-27 +1 +-27 +1 +-27 +2 +-25 +4 +-24 +4 +-24 +5 +-24 +5 +-23 +6 +-23 +-47 +59 +20 +60 +22 +24 +-9 +22 +-24 +0 +-29 +-2 +-30 +-1 +-29 +0 +-29 +0 +-28 +2 +-27 +2 +-27 +3 +-26 +4 +-25 +5 +-24 +6 +-24 +6 +-22 +-47 +84 +43 +50 +30 +17 +-14 +3 +-25 +-1 +-29 +-1 +-29 +-1 +-29 +0 +-28 +0 +-27 +1 +-26 +2 +-25 +3 +-25 +4 +-24 +5 +-23 +6 +-23 +-48 +59 +20 +60 +22 +23 +-9 +22 +-24 +0 +-29 +-2 +-30 +-1 +-30 +0 +-28 +1 +-27 +2 +-27 +3 +-26 +4 +-25 +5 +-24 +6 +-24 +6 +-23 +7 +-23 +7 +-22 +7 +-22 +8 +-22 +8 +-22 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-20 +9 +-20 +10 +-20 +9 +-20 +9 +-20 +9 +-21 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +11 +-19 +11 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-19 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +9 +-20 +10 +-20 +9 +-21 +9 +-20 +8 +-21 +9 +-21 +8 +-22 +9 +-21 +10 +-20 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +11 +-20 +10 +-20 +10 +-20 +10 +-19 +-44 +87 +45 +52 +15 +20 +-12 +6 +-23 +1 +-27 +0 +-28 +1 +-27 +1 +-27 +2 +-26 +3 +-25 +4 +-24 +5 +-24 +6 +-22 +6 +-23 +6 +-22 +-46 +59 +20 +62 +22 +24 +-9 +23 +-23 +0 +-29 +-2 +-30 +-1 +-30 +-1 +-30 +0 +-28 +1 +-28 +2 +-27 +4 +-26 +4 +-25 +5 +-24 +6 +-23 +7 +-23 +7 +-23 +7 +-22 +8 +-22 +9 +-21 +9 +-21 +9 +-21 +8 +-22 +9 +-21 +9 +-22 +9 +-22 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-20 +-44 +86 +45 +51 +15 +19 +-12 +5 +-24 +0 +-28 +0 +-28 +0 +-28 +1 +-27 +1 +-27 +2 +-26 +4 +-25 +5 +-24 +6 +-23 +6 +-23 +6 +-22 +-47 +59 +20 +60 +22 +24 +-9 +22 +-24 +1 +-28 +-1 +-30 +-1 +-30 +0 +-29 +1 +-28 +2 +-28 +3 +-26 +4 +-25 +5 +-25 +6 +-24 +6 +-24 +6 +-24 +6 +-24 +7 +-23 +7 +-22 +8 +-22 +8 +-22 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-21 +10 +-20 +10 +-20 +10 +-21 +10 +-21 +9 +-21 +9 +-22 +8 +-22 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +10 +-20 +9 +-20 +-44 +86 +44 +50 +14 +19 +-13 +4 +-24 +0 +-28 +-1 +-29 +0 +-28 +1 +-27 +1 +-27 +2 +-26 +3 +-25 +4 +-24 +5 +-24 +6 +-23 +6 +-22 +-47 +60 +21 +62 +22 +25 +-8 +24 +-22 +2 +-28 +0 +-29 +0 +-29 +1 +-28 +1 +-28 +2 +-27 +3 +-26 +4 +-25 +5 +-24 +5 +-24 +6 +-24 +6 +-22 +-46 +84 +42 +49 +13 +17 +-14 +3 +-25 +-1 +-29 +-2 +-30 +-1 +-29 +0 +-28 +0 +-28 +2 +-27 +2 +-25 +4 +-25 +4 +-24 +5 +-23 +6 +-23 +6 +-22 +6 +-23 +6 +-22 +7 +-22 +7 +-22 +8 +-22 +7 +-22 +7 +-22 +7 +-22 +8 +-22 +7 +-22 +8 +-21 +8 +-21 +9 +-20 +9 +-20 +9 +-20 +-45 +62 +23 +63 +24 +26 +-7 +25 +-22 +3 +-26 +1 +-28 +1 +-28 +2 +-27 +3 +-26 +3 +-26 +4 +-25 +5 +-24 +6 +-24 +6 +-23 +7 +-23 +7 +-22 +7 +-23 +7 +-22 +8 +-22 +8 +-22 +8 +-22 +8 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +10 +-21 +9 +-21 +9 +-21 +9 +-21 +10 +-21 +10 +-21 +10 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-19 +-44 +86 +44 +51 +15 +18 +-13 +5 +-24 +0 +-28 +-1 +-29 +-1 +-28 +0 +-28 +1 +-27 +2 +-26 +3 +-25 +4 +-25 +4 +-24 +5 +-23 +5 +-23 +-48 +59 +20 +61 +22 +24 +-9 +23 +-23 +1 +-28 +0 +-29 +0 +-28 +2 +-27 +2 +-27 +3 +-26 +4 +-26 +4 +-25 +5 +-24 +6 +-24 +6 +-24 +7 +-23 +7 +-23 +7 +-23 +8 +-22 +8 +-22 +8 +-22 +9 +-22 +9 +-21 +9 +-21 +9 +-22 +9 +-21 +9 +-21 +9 +-21 +10 +-21 +9 +-21 +10 +-20 +10 +-20 +-44 +86 +45 +51 +15 +18 +-13 +4 +-24 +0 +-28 +-1 +-29 +0 +-28 +0 +-28 +1 +-27 +2 +-26 +3 +-25 +4 +-24 +4 +-24 +5 +-24 +5 +-23 +-48 +59 +20 +60 +22 +24 +-10 +22 +-24 +0 +-29 +-2 +-30 +-1 +-30 +0 +-29 +0 +-28 +2 +-27 +3 +-26 +4 +-25 +5 +-24 +5 +-24 +6 +-23 +7 +-23 +7 +-23 +8 +-22 +8 +-22 +8 +-22 +9 +-21 +10 +-21 +10 +-21 +10 +-21 +9 +-21 +9 +-21 +10 +-21 +9 +-21 +10 +-21 +10 +-21 +10 +-20 +10 +-20 +10 +-21 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +9 +-21 +9 +-21 +10 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +11 +-20 +11 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +9 +-19 +-44 +86 +45 +51 +15 +19 +-12 +4 +-24 +0 +-28 +-1 +-29 +0 +-28 +1 +-27 +1 +-27 +3 +-26 +4 +-25 +5 +-24 +6 +-23 +6 +-23 +6 +-22 +-47 +60 +21 +62 +22 +24 +-9 +23 +-23 +1 +-28 +-1 +-29 +-1 +-29 +0 +-29 +1 +-28 +2 +-27 +3 +-26 +3 +-26 +5 +-25 +5 +-24 +6 +-24 +7 +-23 +7 +-23 +7 +-23 +7 +-22 +8 +-22 +8 +-22 +9 +-21 +9 +-21 +8 +-22 +8 +-22 +8 +-22 +8 +-21 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-21 +10 +-21 +10 +-21 +10 +-21 +9 +-21 +10 +-21 +9 +-21 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +9 +-21 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +9 +-21 +10 +-20 +9 +-21 +10 +-20 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +11 +-20 +10 +-20 +10 +-20 +11 +-20 +10 +-20 +11 +-20 +11 +-20 +11 +-20 +11 +-20 +10 +-20 +11 +-20 +11 +-19 +11 +-19 +11 +-20 +11 +-19 +11 +-20 +10 +-18 +-43 +87 +45 +52 +16 +20 +-12 +5 +-24 +1 +-28 +-1 +-29 +0 +-28 +0 +-28 +1 +-27 +2 +-26 +3 +-25 +4 +-24 +5 +-24 +5 +-24 +6 +-23 +-47 +59 +20 +61 +22 +24 +-9 +23 +-23 +0 +-28 +-1 +-30 +-1 +-29 +0 +-29 +0 +-28 +1 +-28 +2 +-26 +4 +-26 +4 +-25 +5 +-24 +5 +-24 +6 +-23 +-47 +84 +43 +49 +14 +18 +-13 +3 +-25 +-1 +-29 +-2 +-30 +-2 +-29 +-1 +-28 +0 +-28 +2 +-27 +3 +-25 +4 +-25 +5 +-24 +5 +-24 +6 +-23 +-47 +59 +20 +61 +22 +24 +-9 +22 +-24 +0 +-29 +-2 +-30 +-1 +-30 +0 +-29 +0 +-29 +2 +-28 +3 +-26 +4 +-25 +5 +-25 +5 +-24 +6 +-24 +7 +-22 +-46 +84 +43 +49 +14 +17 +-14 +3 +-26 +-2 +-30 +-3 +-30 +-2 +-30 +-1 +-29 +0 +-28 +1 +-27 +2 +-26 +3 +-25 +4 +-25 +5 +-24 +5 +-23 +-47 +59 +20 +61 +22 +24 +-9 +22 +-23 +0 +-28 +-1 +-30 +-1 +-30 +0 +-29 +0 +-28 +1 +-28 +2 +-27 +4 +-25 +4 +-25 +5 +-24 +6 +-24 +6 +-23 +7 +-23 +7 +-23 +7 +-23 +8 +-22 +9 +-22 +9 +-22 +9 +-21 +9 +-21 +10 +-21 +10 +-20 +10 +-20 +10 +-20 +11 +-20 +10 +-20 +10 +-20 +10 +-19 +-44 +87 +45 +52 +15 +19 +-12 +5 +-24 +0 +-28 +-1 +-29 +-1 +-29 +0 +-28 +1 +-27 +2 +-26 +3 +-25 +4 +-24 +4 +-24 +5 +-23 +5 +-23 +-48 +59 +20 +60 +22 +24 +-9 +22 +-23 +0 +-28 +-1 +-30 +-1 +-30 +0 +-28 +1 +-28 +2 +-27 +3 +-26 +4 +-25 +5 +-24 +6 +-23 +6 +-23 +7 +-22 +7 +-22 +7 +-22 +7 +-22 +8 +-22 +8 +-22 +8 +-22 +8 +-22 +8 +-22 +8 +-22 +8 +-22 +9 +-21 +10 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-19 +-44 +87 +45 +52 +16 +19 +-12 +5 +-24 +0 +-28 +-1 +-29 +0 +-28 +1 +-27 +2 +-27 +2 +-26 +4 +-25 +4 +-24 +5 +-23 +6 +-23 +6 +-22 +-47 +59 +20 +60 +22 +24 +-9 +22 +-24 +0 +-28 +-1 +-30 +-1 +-30 +0 +-28 +1 +-28 +2 +-27 +3 +-26 +4 +-25 +5 +-24 +5 +-24 +6 +-23 +7 +-22 +-46 +84 +43 +48 +13 +17 +-14 +2 +-26 +-1 +-29 +-2 +-30 +-2 +-30 +-1 +-28 +-1 +-28 +0 +-27 +1 +-26 +3 +-25 +3 +-25 +4 +-24 +4 +-23 +-48 +59 +20 +60 +22 +24 +-9 +22 +-23 +0 +-28 +-1 +-29 +-1 +-29 +0 +-28 +1 +-28 +2 +-26 +4 +-25 +5 +-24 +6 +-24 +6 +-23 +7 +-22 +7 +-22 +-46 +84 +44 +50 +30 +17 +-13 +3 +-25 +-1 +-29 +-2 +-30 +-2 +-29 +-1 +-29 +-1 +-28 +1 +-27 +2 +-26 +3 +-25 +4 +-24 +5 +-24 +5 +-24 +-48 +58 +20 +60 +22 +23 +-9 +22 +-24 +0 +-28 +-1 +-30 +-1 +-30 +0 +-29 +1 +-28 +2 +-27 +3 +-26 +4 +-25 +5 +-24 +6 +-24 +6 +-23 +7 +-23 +6 +-23 +7 +-23 +7 +-22 +7 +-22 +8 +-22 +8 +-21 +9 +-21 +9 +-21 +8 +-21 +9 +-21 +9 +-20 +9 +-21 +9 +-20 +9 +-21 +9 +-21 +9 +-20 +-44 +86 +45 +51 +15 +18 +-12 +4 +-24 +0 +-28 +-2 +-29 +0 +-28 +0 +-27 +0 +-28 +2 +-26 +2 +-26 +4 +-24 +5 +-24 +6 +-23 +6 +-22 +7 +-22 +7 +-22 +8 +-21 +8 +-21 +8 +-20 +9 +-20 +8 +-20 +9 +-20 +9 +-20 +9 +-20 +9 +-20 +9 +-20 +10 +-19 +10 +-20 +9 +-20 +9 +-20 +-44 +62 +23 +63 +24 +25 +-7 +24 +-22 +2 +-27 +1 +-28 +1 +-28 +1 +-28 +2 +-27 +3 +-26 +4 +-26 +5 +-25 +6 +-24 +6 +-24 +6 +-24 +7 +-23 +7 +-23 +7 +-23 +8 +-22 +7 +-22 +8 +-22 +7 +-22 +8 +-22 +8 +-22 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +-44 +86 +45 +52 +16 +18 +-12 +4 +-24 +0 +-28 +-1 +-28 +0 +-28 +0 +-27 +1 +-27 +2 +-25 +4 +-25 +4 +-24 +5 +-24 +5 +-23 +6 +-23 +-47 +59 +21 +61 +22 +24 +-9 +23 +-23 +0 +-28 +-1 +-29 +-1 +-29 +0 +-28 +0 +-28 +2 +-27 +3 +-26 +4 +-25 +5 +-25 +6 +-24 +6 +-23 +7 +-22 +-46 +84 +43 +50 +30 +17 +-13 +3 +-25 +-1 +-29 +-1 +-29 +-1 +-29 +0 +-28 +1 +-27 +2 +-26 +3 +-25 +4 +-25 +4 +-24 +5 +-24 +5 +-23 +6 +-23 +6 +-23 +6 +-22 +7 +-22 +8 +-21 +8 +-21 +8 +-21 +8 +-20 +8 +-21 +8 +-21 +8 +-21 +8 +-21 +8 +-20 +8 +-20 +8 +-20 +9 +-20 +9 +-20 +8 +-20 +9 +-20 +9 +-20 +9 +-20 +10 +-20 +10 +-19 +10 +-19 +10 +-19 +10 +-19 +10 +-19 +10 +-19 +10 +-19 +10 +-19 +10 +-19 +10 +-19 +-44 +63 +24 +64 +24 +26 +-7 +24 +-22 +2 +-27 +1 +-28 +1 +-28 +2 +-27 +2 +-26 +3 +-26 +4 +-25 +4 +-24 +5 +-24 +6 +-24 +6 +-23 +6 +-23 +7 +-22 +7 +-22 +7 +-22 +8 +-22 +8 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +10 +-19 +-44 +86 +45 +51 +15 +18 +-13 +4 +-24 +-1 +-29 +-1 +-29 +-1 +-29 +0 +-28 +0 +-28 +2 +-26 +3 +-25 +4 +-24 +5 +-24 +5 +-23 +6 +-23 +-48 +59 +20 +60 +22 +24 +-9 +23 +-23 +1 +-28 +0 +-29 +0 +-29 +1 +-28 +2 +-27 +2 +-27 +4 +-25 +4 +-25 +5 +-25 +5 +-24 +5 +-24 +6 +-22 +-46 +83 +42 +49 +13 +16 +-15 +3 +-26 +-1 +-29 +-2 +-30 +-2 +-30 +-1 +-28 +0 +-28 +1 +-27 +2 +-26 +2 +-25 +4 +-24 +4 +-24 +6 +-23 +-48 +59 +20 +61 +22 +24 +-9 +22 +-24 +0 +-29 +-1 +-30 +0 +-29 +1 +-28 +2 +-27 +2 +-27 +3 +-26 +4 +-25 +5 +-24 +6 +-23 +6 +-23 +6 +-23 +7 +-23 +6 +-23 +7 +-22 +7 +-22 +8 +-22 +8 +-22 +9 +-21 +8 +-22 +8 +-22 +8 +-22 +9 +-21 +10 +-20 +10 +-20 +10 +-21 +10 +-20 +10 +-20 +9 +-21 +10 +-21 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +11 +-19 +11 +-19 +11 +-19 +11 +-19 +11 +-19 +11 +-19 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +9 +-20 +9 +-21 +9 +-20 +9 +-21 +9 +-20 +9 +-21 +10 +-20 +10 +-20 +-44 +86 +46 +51 +15 +19 +-12 +4 +-24 +0 +-28 +-1 +-28 +0 +-28 +0 +-27 +2 +-26 +3 +-25 +4 +-24 +5 +-23 +6 +-23 +6 +-23 +6 +-22 +-47 +60 +22 +62 +23 +25 +-8 +23 +-23 +0 +-28 +-1 +-29 +0 +-29 +0 +-28 +1 +-28 +2 +-27 +3 +-26 +4 +-25 +5 +-24 +6 +-24 +6 +-23 +7 +-23 +6 +-23 +7 +-22 +8 +-22 +8 +-22 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +8 +-21 +8 +-21 +9 +-21 +10 +-20 +9 +-20 +10 +-20 +9 +-20 +9 +-20 +-44 +86 +45 +51 +15 +19 +-12 +5 +-24 +0 +-28 +-1 +-29 +-1 +-28 +0 +-28 +0 +-28 +1 +-26 +2 +-26 +4 +-25 +4 +-24 +4 +-24 +5 +-23 +-48 +59 +20 +60 +22 +24 +-9 +22 +-23 +1 +-28 +0 +-29 +0 +-29 +1 +-27 +2 +-27 +3 +-26 +4 +-25 +4 +-24 +5 +-24 +6 +-24 +6 +-23 +7 +-23 +7 +-22 +7 +-22 +8 +-22 +8 +-22 +9 +-21 +9 +-21 +8 +-21 +9 +-21 +8 +-22 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-20 +10 +-20 +9 +-20 +9 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +9 +-20 +9 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-19 +-44 +87 +46 +52 +16 +19 +-12 +5 +-24 +0 +-28 +-2 +-29 +-1 +-29 +0 +-28 +1 +-27 +2 +-27 +3 +-25 +4 +-25 +4 +-24 +6 +-23 +6 +-23 +-47 +60 +21 +62 +22 +24 +-8 +23 +-23 +1 +-28 +0 +-29 +0 +-29 +1 +-28 +2 +-27 +3 +-26 +4 +-26 +5 +-25 +5 +-24 +6 +-24 +6 +-23 +7 +-22 +-46 +84 +43 +49 +14 +17 +-14 +3 +-26 +-2 +-30 +-2 +-30 +-2 +-30 +0 +-28 +0 +-28 +1 +-27 +2 +-26 +3 +-25 +4 +-24 +5 +-23 +6 +-23 +6 +-23 +6 +-22 +7 +-22 +7 +-21 +7 +-21 +8 +-21 +7 +-21 +8 +-21 +8 +-21 +7 +-21 +8 +-21 +9 +-20 +9 +-20 +9 +-20 +9 +-20 +9 +-20 +-45 +62 +23 +63 +24 +26 +-7 +23 +-22 +2 +-27 +0 +-29 +0 +-29 +1 +-28 +1 +-28 +2 +-27 +3 +-26 +4 +-25 +5 +-24 +5 +-24 +6 +-24 +6 +-24 +7 +-23 +7 +-23 +7 +-22 +8 +-22 +9 +-21 +9 +-21 +9 +-20 +9 +-20 +8 +-21 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +9 +-20 +10 +-20 +10 +-20 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +11 +-19 +11 +-19 +11 +-20 +11 +-18 +-43 +88 +46 +52 +16 +20 +-12 +6 +-23 +1 +-27 +0 +-28 +0 +-28 +1 +-27 +2 +-27 +3 +-26 +4 +-25 +4 +-24 +5 +-24 +6 +-23 +6 +-22 +-47 +60 +20 +60 +21 +23 +-10 +22 +-24 +0 +-29 +-1 +-30 +-1 +-30 +0 +-30 +0 +-28 +1 +-28 +3 +-27 +4 +-26 +5 +-25 +6 +-24 +7 +-23 +7 +-23 +7 +-23 +7 +-22 +8 +-22 +8 +-22 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +10 +-21 +10 +-21 +10 +-21 +10 +-21 +10 +-19 +-44 +86 +45 +51 +15 +19 +-12 +4 +-24 +0 +-28 +0 +-28 +0 +-28 +0 +-28 +1 +-27 +2 +-26 +3 +-26 +4 +-25 +5 +-24 +6 +-23 +6 +-22 +-47 +59 +21 +61 +22 +24 +-9 +22 +-23 +0 +-28 +-1 +-30 +-1 +-29 +0 +-29 +1 +-28 +2 +-27 +3 +-26 +4 +-26 +4 +-25 +5 +-25 +6 +-24 +6 +-24 +7 +-23 +7 +-23 +7 +-23 +7 +-23 +8 +-22 +9 +-22 +8 +-22 +9 +-22 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +9 +-20 +10 +-20 +10 +-20 +9 +-21 +8 +-21 +9 +-21 +10 +-20 +10 +-21 +9 +-21 +10 +-21 +9 +-20 +-44 +86 +45 +50 +15 +18 +-13 +4 +-24 +0 +-28 +-1 +-29 +0 +-28 +1 +-28 +2 +-27 +3 +-25 +4 +-25 +5 +-24 +5 +-24 +5 +-24 +6 +-23 +-48 +60 +20 +60 +21 +24 +-9 +22 +-24 +0 +-29 +-1 +-30 +-1 +-30 +0 +-29 +2 +-28 +2 +-27 +4 +-25 +5 +-25 +6 +-24 +6 +-23 +7 +-23 +8 +-22 +8 +-22 +8 +-22 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +10 +-21 +10 +-20 +10 +-21 +10 +-21 +10 +-21 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-21 +10 +-21 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +9 +-21 +9 +-21 +9 +-21 +10 +-21 +9 +-21 +10 +-21 +10 +-20 +9 +-21 +9 +-21 +9 +-21 +10 +-20 +9 +-21 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-19 +-44 +87 +46 +52 +16 +19 +-12 +5 +-24 +0 +-28 +0 +-28 +0 +-28 +2 +-27 +2 +-27 +3 +-25 +4 +-24 +6 +-23 +6 +-23 +6 +-23 +7 +-22 +-47 +60 +21 +62 +23 +24 +-8 +23 +-23 +0 +-28 +-1 +-30 +-1 +-29 +0 +-29 +1 +-28 +2 +-27 +4 +-26 +4 +-25 +5 +-25 +6 +-24 +6 +-24 +7 +-22 +-46 +84 +43 +49 +13 +17 +-14 +3 +-26 +-1 +-29 +-2 +-30 +-2 +-30 +-1 +-29 +0 +-28 +1 +-27 +2 +-26 +2 +-26 +3 +-25 +4 +-24 +4 +-24 +-48 +58 +20 +60 +21 +23 +-10 +22 +-24 +0 +-29 +-1 +-30 +-1 +-30 +1 +-28 +2 +-28 +3 +-27 +4 +-26 +5 +-25 +6 +-24 +6 +-23 +7 +-23 +7 +-21 +-46 +84 +43 +49 +13 +17 +-14 +3 +-26 +-1 +-30 +-2 +-30 +-1 +-29 +0 +-28 +0 +-28 +2 +-27 +3 +-25 +4 +-25 +4 +-24 +5 +-24 +6 +-23 +-47 +59 +20 +60 +21 +24 +-10 +22 +-24 +0 +-29 +-1 +-30 +-1 +-30 +0 +-29 +1 +-28 +2 +-27 +4 +-26 +4 +-25 +5 +-25 +5 +-24 +6 +-24 +6 +-23 +6 +-23 +7 +-23 +7 +-22 +8 +-22 +8 +-22 +8 +-22 +9 +-21 +8 +-22 +8 +-22 +8 +-22 +8 +-22 +8 +-22 +8 +-22 +9 +-21 +9 +-22 +9 +-20 +-44 +86 +45 +51 +15 +19 +-12 +5 +-24 +0 +-28 +0 +-28 +0 +-28 +1 +-27 +2 +-27 +3 +-25 +4 +-24 +5 +-24 +6 +-23 +6 +-23 +6 +-22 +-47 +59 +20 +61 +22 +24 +-9 +22 +-24 +0 +-29 +-1 +-30 +0 +-29 +1 +-28 +1 +-28 +2 +-27 +2 +-27 +3 +-26 +4 +-25 +5 +-24 +6 +-24 +6 +-24 +6 +-23 +7 +-23 +7 +-22 +8 +-22 +8 +-22 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +10 +-21 +9 +-21 +10 +-20 +10 +-20 +-44 +86 +45 +52 +16 +18 +-13 +5 +-24 +-1 +-28 +-2 +-29 +-1 +-29 +-1 +-29 +0 +-28 +1 +-27 +3 +-26 +4 +-25 +4 +-25 +5 +-24 +5 +-24 +-48 +59 +20 +60 +21 +23 +-10 +22 +-24 +1 +-28 +-1 +-30 +-1 +-30 +0 +-29 +1 +-28 +3 +-27 +4 +-26 +6 +-24 +7 +-24 +7 +-23 +7 +-22 +7 +-22 +-46 +84 +43 +49 +30 +17 +-14 +4 +-25 +-1 +-29 +-2 +-30 +-1 +-29 +0 +-28 +0 +-28 +1 +-27 +2 +-26 +4 +-24 +5 +-24 +5 +-24 +5 +-23 +-48 +59 +20 +60 +21 +24 +-9 +23 +-24 +0 +-28 +-1 +-30 +-1 +-29 +0 +-29 +1 +-28 +2 +-27 +3 +-26 +4 +-25 +4 +-25 +5 +-24 +6 +-24 +6 +-22 +-47 +84 +42 +48 +13 +17 +-14 +3 +-26 +-2 +-30 +-2 +-30 +-3 +-30 +-2 +-29 +-1 +-29 +0 +-27 +1 +-27 +3 +-25 +3 +-25 +5 +-24 +5 +-23 +-48 +59 +20 +60 +22 +23 +-9 +22 +-24 +0 +-29 +-1 +-30 +-1 +-30 +0 +-29 +1 +-28 +2 +-27 +3 +-26 +4 +-25 +4 +-25 +5 +-24 +6 +-24 +7 +-23 +6 +-24 +7 +-23 +8 +-23 +8 +-22 +8 +-22 +8 +-22 +8 +-22 +8 +-22 +9 +-22 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +10 +-20 +10 +-19 +-44 +86 +45 +51 +15 +19 +-12 +4 +-24 +0 +-28 +-1 +-29 +0 +-28 +0 +-27 +1 +-27 +2 +-26 +4 +-25 +5 +-24 +5 +-24 +5 +-23 +6 +-23 +7 +-22 +6 +-23 +7 +-22 +8 +-22 +7 +-22 +8 +-22 +8 +-22 +8 +-22 +8 +-21 +8 +-21 +9 +-21 +9 +-20 +10 +-20 +10 +-19 +10 +-20 +10 +-19 +-44 +62 +23 +64 +24 +27 +-7 +25 +-22 +2 +-27 +0 +-29 +1 +-28 +2 +-27 +2 +-26 +3 +-26 +4 +-25 +5 +-24 +6 +-24 +6 +-23 +6 +-23 +7 +-23 +7 +-22 +7 +-22 +8 +-22 +8 +-22 +9 +-21 +9 +-21 +8 +-22 +9 +-21 +8 +-22 +8 +-22 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +10 +-20 +-44 +86 +45 +52 +16 +19 +-12 +5 +-24 +0 +-28 +-1 +-29 +0 +-28 +0 +-28 +0 +-28 +1 +-26 +2 +-26 +4 +-25 +5 +-24 +5 +-24 +5 +-23 +-48 +59 +20 +60 +22 +23 +-9 +22 +-24 +0 +-28 +-1 +-30 +-1 +-30 +0 +-28 +1 +-28 +2 +-27 +4 +-26 +5 +-25 +6 +-24 +6 +-23 +7 +-23 +8 +-21 +-45 +85 +44 +50 +14 +18 +-13 +4 +-25 +-1 +-29 +-1 +-29 +-1 +-29 +0 +-28 +1 +-27 +2 +-26 +3 +-25 +4 +-24 +4 +-24 +5 +-23 +6 +-23 +5 +-23 +6 +-22 +6 +-22 +7 +-21 +8 +-21 +8 +-21 +8 +-21 +8 +-21 +8 +-21 +8 +-21 +8 +-21 +8 +-20 +9 +-20 +9 +-20 +9 +-20 +10 +-20 +9 +-20 +8 +-20 +9 +-20 +10 +-20 +10 +-20 +9 +-20 +10 +-20 +9 +-20 +10 +-19 +9 +-20 +8 +-20 +8 +-20 +8 +-21 +9 +-20 +9 +-20 +9 +-20 +-45 +62 +23 +63 +24 +26 +-8 +24 +-22 +2 +-27 +0 +-28 +1 +-28 +2 +-27 +2 +-26 +3 +-26 +4 +-24 +6 +-24 +6 +-23 +6 +-23 +7 +-22 +8 +-22 +7 +-22 +8 +-22 +8 +-22 +9 +-21 +9 +-21 +9 +-21 +10 +-20 +10 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-20 +10 +-20 +10 +-20 +9 +-20 +10 +-19 +-44 +86 +45 +52 +16 +19 +-12 +5 +-24 +0 +-28 +-1 +-28 +0 +-28 +0 +-27 +1 +-27 +2 +-26 +3 +-25 +4 +-25 +4 +-24 +5 +-23 +6 +-23 +-47 +60 +21 +61 +22 +24 +-9 +23 +-23 +0 +-28 +-1 +-30 +-1 +-30 +-1 +-29 +-1 +-29 +1 +-27 +3 +-26 +3 +-26 +4 +-25 +4 +-25 +6 +-24 +6 +-22 +-47 +83 +42 +49 +14 +16 +-14 +2 +-25 +-2 +-30 +-2 +-30 +-2 +-29 +-1 +-28 +0 +-27 +2 +-26 +3 +-25 +4 +-24 +5 +-23 +6 +-23 +6 +-22 +-46 +60 +21 +61 +22 +24 +-8 +23 +-23 +1 +-28 +0 +-29 +-1 +-29 +0 +-28 +1 +-28 +2 +-27 +3 +-26 +4 +-25 +5 +-24 +6 +-24 +6 +-24 +7 +-23 +7 +-23 +7 +-22 +8 +-22 +8 +-22 +8 +-22 +9 +-21 +9 +-21 +8 +-21 +9 +-21 +8 +-21 +8 +-21 +9 +-21 +9 +-20 +10 +-20 +10 +-20 +10 +-20 +9 +-21 +9 +-21 +8 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +10 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +11 +-19 +11 +-19 +11 +-19 +11 +-19 +10 +-20 +10 +-20 +10 +-20 +11 +-19 +11 +-19 +10 +-19 +10 +-20 +10 +-19 +10 +-20 +10 +-20 +10 +-20 +11 +-20 +11 +-19 +10 +-20 +11 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-19 +10 +-18 +-43 +87 +45 +52 +16 +20 +-12 +5 +-23 +0 +-28 +-1 +-28 +0 +-28 +0 +-27 +1 +-27 +2 +-25 +3 +-25 +4 +-24 +5 +-23 +4 +-24 +5 +-23 +-47 +58 +20 +60 +21 +23 +-10 +22 +-24 +-1 +-29 +-1 +-30 +-1 +-30 +0 +-29 +1 +-28 +2 +-27 +4 +-26 +5 +-24 +5 +-24 +6 +-23 +6 +-23 +6 +-23 +6 +-23 +7 +-22 +7 +-22 +8 +-22 +8 +-22 +9 +-21 +9 +-21 +10 +-20 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-19 +-43 +87 +46 +52 +16 +20 +-11 +5 +-23 +0 +-27 +-1 +-28 +-1 +-28 +0 +-28 +1 +-27 +2 +-26 +3 +-25 +4 +-24 +5 +-24 +6 +-23 +6 +-22 +-47 +59 +20 +61 +22 +24 +-8 +23 +-23 +0 +-28 +-1 +-30 +-1 +-30 +0 +-29 +1 +-28 +2 +-27 +4 +-26 +4 +-25 +5 +-24 +5 +-24 +6 +-24 +6 +-24 +6 +-23 +6 +-23 +7 +-23 +7 +-22 +7 +-22 +8 +-22 +8 +-22 +9 +-21 +9 +-21 +9 +-21 +10 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +9 +-20 +10 +-20 +10 +-20 +9 +-21 +10 +-20 +9 +-21 +9 +-21 +9 +-20 +9 +-21 +9 +-20 +10 +-20 +10 +-20 +10 +-19 +-43 +88 +46 +52 +16 +20 +-12 +5 +-23 +0 +-27 +-1 +-28 +0 +-28 +1 +-26 +2 +-26 +2 +-25 +3 +-25 +4 +-24 +5 +-23 +6 +-23 +6 +-23 +-47 +60 +21 +61 +23 +24 +-8 +22 +-23 +0 +-28 +-1 +-30 +-1 +-29 +0 +-28 +1 +-28 +2 +-27 +3 +-26 +4 +-25 +4 +-25 +5 +-25 +5 +-24 +6 +-22 +-46 +83 +42 +48 +13 +17 +-14 +2 +-26 +-2 +-30 +-3 +-30 +-2 +-29 +-1 +-28 +0 +-28 +1 +-26 +3 +-25 +3 +-25 +4 +-24 +4 +-24 +5 +-24 +5 +-23 +6 +-23 +6 +-22 +7 +-22 +8 +-21 +8 +-21 +9 +-21 +9 +-20 +10 +-19 +9 +-20 +9 +-20 +10 +-19 +10 +-19 +10 +-19 +10 +-19 +10 +-19 +-44 +62 +23 +63 +24 +26 +-7 +25 +-21 +2 +-27 +0 +-28 +1 +-28 +1 +-27 +2 +-27 +3 +-26 +4 +-25 +4 +-24 +5 +-24 +6 +-24 +7 +-23 +7 +-22 +7 +-23 +7 +-23 +7 +-22 +8 +-22 +8 +-22 +9 +-21 +8 +-22 +9 +-22 +9 +-21 +9 +-21 +8 +-22 +9 +-21 +9 +-21 +9 +-20 +9 +-21 +9 +-21 +9 +-21 +8 +-21 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +11 +-20 +10 +-19 +-43 +87 +46 +52 +16 +19 +-12 +5 +-23 +0 +-27 +0 +-28 +0 +-28 +1 +-27 +1 +-27 +2 +-26 +4 +-25 +5 +-24 +5 +-23 +7 +-22 +6 +-22 +-47 +59 +21 +60 +22 +24 +-9 +22 +-23 +0 +-28 +-2 +-30 +0 +-29 +0 +-28 +1 +-28 +2 +-27 +3 +-26 +4 +-25 +5 +-24 +6 +-24 +7 +-23 +7 +-22 +7 +-23 +7 +-22 +8 +-22 +8 +-22 +8 +-22 +8 +-21 +9 +-21 +8 +-21 +8 +-21 +8 +-22 +8 +-22 +8 +-22 +9 +-20 +9 +-20 +9 +-20 +8 +-20 +-45 +86 +45 +50 +15 +18 +-12 +4 +-24 +0 +-28 +-2 +-29 +-1 +-28 +0 +-28 +1 +-27 +2 +-26 +3 +-25 +4 +-24 +5 +-23 +6 +-22 +7 +-22 +-46 +60 +22 +62 +23 +25 +-8 +23 +-22 +1 +-28 +0 +-29 +0 +-29 +1 +-28 +1 +-28 +3 +-26 +4 +-25 +5 +-25 +6 +-24 +6 +-24 +6 +-23 +7 +-23 +7 +-23 +7 +-22 +8 +-22 +8 +-22 +8 +-21 +8 +-22 +8 +-21 +8 +-21 +9 +-21 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +9 +-21 +9 +-21 +10 +-20 +9 +-21 +10 +-20 +9 +-21 +10 +-20 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +8 +-21 +9 +-20 +9 +-21 +10 +-20 +10 +-20 +9 +-21 +9 +-20 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +11 +-20 +11 +-19 +11 +-20 +11 +-19 +11 +-19 +11 +-18 +-43 +88 +46 +52 +16 +20 +-11 +6 +-23 +1 +-27 +0 +-28 +0 +-28 +1 +-27 +2 +-26 +3 +-25 +4 +-24 +5 +-24 +5 +-23 +6 +-23 +6 +-23 +-47 +59 +20 +61 +22 +23 +-9 +22 +-23 +0 +-28 +-1 +-30 +-1 +-29 +0 +-28 +1 +-28 +2 +-27 +3 +-26 +4 +-25 +5 +-24 +5 +-24 +6 +-23 +6 +-23 +6 +-23 +6 +-23 +7 +-22 +7 +-22 +8 +-22 +8 +-22 +8 +-22 +8 +-22 +8 +-22 +8 +-21 +9 +-22 +9 +-21 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +9 +-20 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-19 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +11 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-21 +10 +-19 +-44 +87 +45 +51 +15 +18 +-13 +4 +-24 +-1 +-28 +-1 +-29 +-1 +-29 +0 +-28 +0 +-28 +2 +-26 +3 +-26 +4 +-25 +5 +-24 +6 +-23 +7 +-22 +-47 +60 +21 +62 +22 +25 +-8 +23 +-23 +0 +-28 +-1 +-30 +-1 +-30 +0 +-29 +1 +-28 +2 +-27 +3 +-26 +4 +-25 +5 +-24 +6 +-24 +6 +-23 +7 +-22 +-46 +84 +43 +49 +29 +17 +-14 +3 +-26 +-1 +-29 +-2 +-30 +-1 +-29 +0 +-28 +0 +-28 +2 +-26 +3 +-26 +4 +-25 +4 +-24 +5 +-24 +6 +-22 +-47 +59 +20 +60 +22 +23 +-9 +22 +-23 +0 +-28 +-1 +-30 +-1 +-30 +0 +-29 +1 +-28 +2 +-27 +3 +-26 +4 +-26 +4 +-25 +5 +-25 +6 +-24 +6 +-22 +-46 +84 +43 +48 +13 +16 +-15 +2 +-26 +-3 +-30 +-4 +-31 +-3 +-31 +-1 +-29 +0 +-28 +0 +-28 +2 +-26 +2 +-26 +4 +-25 +4 +-24 +6 +-23 +-47 +59 +20 +60 +22 +24 +-9 +22 +-24 +0 +-29 +-2 +-30 +-1 +-30 +0 +-29 +1 +-28 +2 +-27 +4 +-25 +5 +-25 +6 +-24 +6 +-24 +7 +-23 +7 +-23 +7 +-22 +8 +-22 +8 +-22 +9 +-21 +9 +-21 +9 +-21 +10 +-20 +9 +-20 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +10 +-21 +10 +-19 +-44 +86 +45 +51 +15 +19 +-12 +5 +-24 +0 +-28 +-1 +-29 +0 +-28 +0 +-28 +1 +-27 +2 +-26 +2 +-26 +4 +-24 +4 +-24 +5 +-24 +5 +-24 +-48 +58 +20 +59 +21 +23 +-9 +22 +-24 +0 +-28 +-1 +-30 +-1 +-30 +0 +-29 +1 +-28 +2 +-27 +3 +-26 +5 +-25 +6 +-24 +6 +-23 +7 +-23 +8 +-22 +8 +-22 +7 +-23 +8 +-22 +8 +-22 +9 +-22 +9 +-22 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-19 +-44 +87 +45 +52 +15 +19 +-12 +5 +-24 +1 +-27 +-1 +-28 +-1 +-28 +0 +-28 +1 +-27 +2 +-26 +3 +-25 +4 +-24 +5 +-24 +5 +-24 +5 +-23 +-48 +59 +20 +61 +22 +24 +-9 +22 +-24 +0 +-29 +-1 +-30 +-1 +-29 +0 +-29 +0 +-28 +2 +-27 +2 +-27 +3 +-26 +4 +-25 +5 +-25 +5 +-24 +5 +-23 +-47 +82 +42 +48 +12 +16 +-15 +2 +-26 +-2 +-30 +-3 +-30 +-2 +-30 +-1 +-29 +0 +-28 +2 +-27 +3 +-25 +4 +-25 +5 +-24 +5 +-23 +6 +-23 +-48 +59 +20 +60 +22 +23 +-9 +22 +-24 +0 +-28 +-1 +-30 +-1 +-29 +0 +-29 +1 +-28 +2 +-27 +3 +-26 +4 +-25 +5 +-25 +6 +-24 +6 +-24 +7 +-22 +-46 +84 +43 +50 +30 +18 +-13 +4 +-25 +-1 +-29 +-2 +-30 +-1 +-29 +0 +-29 +0 +-28 +2 +-27 +2 +-26 +4 +-25 +4 +-25 +5 +-24 +5 +-23 +-48 +58 +20 +60 +21 +24 +-10 +22 +-24 +0 +-29 +-2 +-30 +-1 +-30 +-1 +-30 +0 +-28 +1 +-28 +3 +-26 +4 +-25 +4 +-25 +5 +-25 +5 +-24 +6 +-24 +5 +-24 +7 +-23 +7 +-23 +8 +-22 +8 +-22 +8 +-22 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +10 +-20 +11 +-20 +11 +-20 +10 +-20 +10 +-20 +10 +-19 +-44 +86 +45 +51 +15 +19 +-12 +5 +-24 +0 +-28 +-1 +-29 +0 +-28 +1 +-28 +2 +-27 +3 +-26 +3 +-25 +4 +-25 +5 +-24 +5 +-24 +6 +-23 +7 +-22 +7 +-22 +8 +-22 +8 +-21 +8 +-21 +8 +-21 +8 +-21 +8 +-21 +8 +-21 +8 +-21 +9 +-20 +9 +-20 +9 +-20 +9 +-20 +9 +-20 +10 +-20 +-45 +62 +23 +64 +24 +26 +-7 +24 +-22 +2 +-27 +0 +-29 +0 +-29 +0 +-29 +2 +-28 +2 +-27 +3 +-26 +4 +-25 +6 +-24 +6 +-24 +7 +-23 +7 +-23 +8 +-22 +8 +-22 +8 +-22 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +10 +-21 +9 +-21 +9 +-21 +9 +-20 +-44 +86 +45 +51 +15 +19 +-12 +5 +-24 +0 +-28 +0 +-28 +0 +-28 +1 +-27 +2 +-26 +2 +-26 +4 +-25 +5 +-24 +5 +-23 +6 +-23 +6 +-23 +-47 +60 +21 +61 +22 +24 +-9 +22 +-23 +0 +-28 +-1 +-30 +-1 +-29 +0 +-28 +1 +-28 +2 +-27 +2 +-27 +3 +-26 +3 +-26 +5 +-25 +5 +-24 +6 +-22 +-47 +83 +42 +48 +13 +16 +-15 +2 +-26 +-2 +-29 +-2 +-30 +-2 +-30 +-1 +-29 +0 +-28 +1 +-27 +2 +-26 +4 +-25 +5 +-24 +5 +-23 +6 +-23 +7 +-22 +7 +-22 +7 +-22 +8 +-22 +8 +-21 +8 +-21 +9 +-21 +8 +-21 +9 +-20 +9 +-20 +8 +-21 +8 +-21 +8 +-21 +8 +-21 +8 +-21 +8 +-21 +8 +-20 +8 +-20 +9 +-20 +9 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-19 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-19 +10 +-19 +10 +-19 +-44 +63 +24 +63 +24 +26 +-7 +24 +-22 +2 +-27 +0 +-28 +0 +-29 +1 +-28 +2 +-27 +3 +-27 +4 +-26 +5 +-24 +5 +-25 +6 +-24 +7 +-23 +6 +-24 +6 +-24 +6 +-24 +8 +-22 +8 +-22 +8 +-22 +8 +-22 +8 +-22 +8 +-22 +8 +-22 +8 +-21 +8 +-22 +9 +-21 +8 +-22 +9 +-21 +9 +-21 +9 +-20 +-44 +87 +45 +52 +15 +18 +-13 +4 +-24 +-1 +-28 +-1 +-28 +-1 +-29 +0 +-28 +1 +-27 +2 +-25 +3 +-25 +4 +-24 +5 +-24 +6 +-23 +6 +-22 +-47 +60 +21 +62 +22 +23 +-9 +22 +-23 +0 +-29 +-2 +-30 +-1 +-29 +0 +-28 +1 +-28 +2 +-27 +4 +-26 +5 +-25 +5 +-24 +6 +-23 +6 +-24 +7 +-22 +-46 +84 +42 +49 +14 +17 +-14 +3 +-25 +-2 +-30 +-2 +-30 +-2 +-30 +0 +-28 +0 +-28 +1 +-27 +2 +-26 +3 +-25 +4 +-24 +5 +-24 +5 +-23 +-48 +59 +20 +60 +22 +23 +-10 +22 +-24 +0 +-29 +-1 +-30 +-1 +-30 +0 +-29 +1 +-28 +2 +-27 +3 +-26 +4 +-26 +4 +-26 +6 +-24 +7 +-23 +7 +-23 +7 +-23 +7 +-23 +8 +-22 +8 +-22 +9 +-22 +8 +-22 +9 +-21 +8 +-22 +9 +-21 +8 +-22 +10 +-20 +10 +-20 +10 +-20 +10 +-21 +10 +-21 +10 +-21 +8 +-22 +9 +-21 +9 +-21 +10 +-20 +10 +-21 +10 +-20 +10 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +9 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +9 +-20 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +11 +-20 +11 +-19 +11 +-19 +11 +-19 +11 +-19 +10 +-20 +11 +-20 +11 +-19 +11 +-19 +11 +-19 +10 +-19 +10 +-20 +10 +-19 +-44 +87 +45 +52 +16 +20 +-12 +6 +-23 +1 +-27 +-1 +-28 +0 +-28 +0 +-28 +1 +-27 +2 +-26 +3 +-25 +4 +-24 +5 +-23 +5 +-23 +6 +-23 +-47 +60 +21 +62 +23 +25 +-8 +23 +-23 +1 +-28 +-1 +-29 +-1 +-29 +0 +-28 +1 +-28 +2 +-27 +3 +-25 +4 +-25 +5 +-24 +6 +-24 +6 +-24 +7 +-23 +7 +-23 +7 +-23 +8 +-22 +8 +-22 +8 +-21 +9 +-21 +8 +-21 +8 +-21 +8 +-22 +8 +-21 +8 +-22 +9 +-21 +9 +-21 +8 +-21 +8 +-21 +8 +-20 +-45 +86 +45 +51 +15 +18 +-12 +4 +-24 +0 +-28 +-1 +-28 +0 +-28 +1 +-27 +2 +-26 +3 +-25 +4 +-24 +5 +-24 +5 +-23 +6 +-23 +6 +-22 +-47 +60 +21 +61 +22 +24 +-8 +23 +-23 +0 +-28 +-1 +-30 +-1 +-30 +-1 +-29 +0 +-28 +2 +-27 +3 +-26 +4 +-25 +5 +-25 +5 +-24 +6 +-23 +7 +-23 +7 +-22 +8 +-22 +8 +-22 +8 +-22 +9 +-21 +9 +-21 +9 +-21 +9 +-20 +9 +-21 +9 +-20 +9 +-20 +9 +-20 +10 +-20 +9 +-20 +10 +-20 +9 +-20 +9 +-20 +9 +-21 +9 +-20 +9 +-21 +10 +-20 +9 +-21 +10 +-20 +10 +-20 +9 +-21 +8 +-22 +9 +-21 +8 +-21 +10 +-20 +10 +-21 +10 +-20 +9 +-20 +-44 +86 +45 +51 +16 +19 +-12 +5 +-23 +1 +-27 +0 +-28 +0 +-27 +1 +-27 +2 +-26 +3 +-25 +3 +-25 +4 +-24 +4 +-24 +6 +-23 +6 +-23 +-47 +60 +21 +60 +22 +23 +-9 +21 +-24 +0 +-28 +-1 +-29 +-1 +-30 +-1 +-29 +0 +-28 +1 +-28 +2 +-27 +4 +-25 +5 +-24 +6 +-24 +7 +-23 +8 +-21 +-45 +84 +44 +50 +30 +18 +-13 +4 +-24 +-1 +-28 +-1 +-29 +-1 +-28 +0 +-27 +1 +-27 +2 +-26 +3 +-25 +4 +-25 +4 +-24 +5 +-23 +6 +-23 +6 +-23 +6 +-23 +6 +-22 +7 +-22 +7 +-22 +7 +-22 +7 +-22 +8 +-21 +7 +-22 +7 +-22 +7 +-21 +8 +-20 +8 +-20 +8 +-20 +9 +-20 +9 +-20 +-45 +62 +23 +63 +24 +27 +-6 +25 +-21 +2 +-26 +1 +-28 +1 +-27 +2 +-27 +2 +-26 +3 +-26 +4 +-25 +5 +-24 +6 +-24 +6 +-23 +7 +-22 +7 +-22 +7 +-22 +7 +-22 +7 +-22 +8 +-22 +8 +-22 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-19 +-43 +86 +45 +51 +16 +19 +-12 +4 +-24 +0 +-28 +-2 +-30 +-1 +-29 +0 +-28 +0 +-28 +2 +-27 +3 +-26 +4 +-25 +4 +-24 +6 +-23 +6 +-22 +-47 +60 +21 +61 +22 +24 +-8 +23 +-23 +1 +-28 +-1 +-30 +0 +-29 +0 +-29 +0 +-28 +2 +-27 +3 +-26 +4 +-25 +5 +-24 +6 +-24 +7 +-22 +7 +-22 +7 +-22 +7 +-23 +7 +-22 +8 +-22 +8 +-22 +8 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +11 +-20 +10 +-20 +10 +-20 +10 +-19 +-43 +87 +46 +52 +16 +20 +-12 +5 +-24 +0 +-28 +0 +-28 +0 +-28 +1 +-27 +1 +-27 +2 +-26 +3 +-25 +4 +-25 +5 +-24 +5 +-24 +6 +-22 +-47 +59 +20 +60 +22 +23 +-9 +22 +-24 +-1 +-30 +-2 +-30 +-1 +-30 +-1 +-29 +0 +-28 +2 +-27 +3 +-26 +4 +-25 +5 +-24 +6 +-23 +6 +-23 +7 +-22 +7 +-22 +8 +-22 +8 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +8 +-21 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +9 +-21 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +9 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +9 +-20 +-44 +86 +45 +50 +15 +18 +-13 +4 +-24 +0 +-28 +-1 +-29 +-1 +-29 +0 +-28 +1 +-27 +2 +-26 +4 +-25 +5 +-24 +5 +-23 +6 +-22 +6 +-22 +-47 +60 +21 +61 +22 +25 +-8 +23 +-23 +0 +-28 +-1 +-29 +-1 +-29 +0 +-28 +1 +-28 +2 +-27 +3 +-26 +5 +-24 +5 +-24 +5 +-24 +6 +-24 +6 +-23 +6 +-23 +6 +-23 +7 +-22 +8 +-22 +8 +-22 +8 +-22 +8 +-22 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +9 +-20 +10 +-20 +9 +-20 +9 +-20 +9 +-21 +10 +-20 +10 +-20 +9 +-21 +8 +-21 +9 +-21 +10 +-20 +9 +-21 +9 +-21 +9 +-21 +10 +-20 +10 +-21 +10 +-21 +10 +-20 +10 +-20 +11 +-19 +11 +-19 +11 +-19 +11 +-20 +10 +-19 +11 +-19 +11 +-19 +10 +-19 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +11 +-19 +11 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-19 +-44 +86 +45 +51 +16 +19 +-12 +5 +-24 +0 +-28 +-1 +-28 +0 +-28 +1 +-27 +2 +-26 +2 +-26 +3 +-25 +4 +-24 +5 +-24 +6 +-23 +6 +-22 +-47 +60 +21 +61 +22 +24 +-8 +23 +-23 +0 +-28 +-1 +-29 +0 +-29 +0 +-29 +1 +-28 +2 +-27 +2 +-27 +4 +-26 +4 +-25 +5 +-25 +6 +-24 +6 +-22 +-46 +83 +42 +48 +13 +16 +-15 +2 +-26 +-1 +-29 +-2 +-30 +-1 +-29 +0 +-28 +1 +-27 +2 +-26 +3 +-25 +4 +-24 +5 +-23 +5 +-23 +6 +-22 +-47 +60 +21 +60 +22 +24 +-9 +23 +-23 +0 +-28 +-1 +-30 +-1 +-29 +0 +-28 +1 +-28 +2 +-27 +3 +-26 +4 +-26 +4 +-25 +5 +-24 +5 +-24 +6 +-22 +-47 +84 +42 +49 +29 +17 +-14 +3 +-25 +-1 +-29 +-2 +-30 +-1 +-29 +0 +-28 +1 +-27 +2 +-26 +3 +-25 +4 +-24 +5 +-24 +5 +-23 +6 +-22 +-47 +60 +20 +60 +22 +23 +-9 +22 +-24 +0 +-29 +-1 +-30 +-1 +-30 +-1 +-29 +0 +-29 +1 +-27 +2 +-26 +3 +-26 +4 +-25 +4 +-25 +5 +-24 +6 +-23 +6 +-23 +6 +-23 +7 +-22 +8 +-22 +8 +-21 +8 +-21 +9 +-21 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-19 +-44 +86 +45 +51 +16 +19 +-12 +5 +-24 +0 +-28 +0 +-28 +0 +-28 +1 +-27 +1 +-27 +2 +-26 +3 +-25 +4 +-24 +5 +-24 +5 +-23 +6 +-23 +-47 +59 +20 +61 +22 +24 +-8 +23 +-23 +0 +-28 +-1 +-29 +0 +-29 +1 +-28 +1 +-28 +2 +-26 +4 +-26 +5 +-25 +5 +-24 +6 +-24 +7 +-23 +7 +-23 +6 +-23 +7 +-22 +7 +-22 +8 +-22 +8 +-22 +8 +-22 +8 +-22 +7 +-22 +7 +-22 +7 +-23 +8 +-22 +9 +-21 +9 +-21 +8 +-22 +8 +-22 +9 +-20 +-45 +86 +45 +51 +16 +19 +-12 +4 +-24 +1 +-27 +0 +-28 +0 +-28 +1 +-27 +2 +-26 +3 +-25 +4 +-25 +5 +-24 +6 +-23 +6 +-23 +6 +-22 +-47 +59 +20 +61 +22 +24 +-9 +23 +-23 +0 +-28 +-1 +-29 +0 +-29 +0 +-28 +1 +-28 +2 +-27 +3 +-26 +3 +-26 +4 +-24 +5 +-24 +6 +-23 +6 +-22 +-47 +84 +43 +49 +13 +17 +-14 +3 +-25 +-1 +-29 +-2 +-30 +-2 +-29 +-1 +-28 +0 +-28 +1 +-27 +2 +-26 +3 +-25 +3 +-25 +4 +-24 +4 +-24 +-48 +58 +20 +60 +21 +23 +-9 +22 +-24 +0 +-28 +-2 +-30 +-1 +-29 +0 +-28 +0 +-28 +2 +-27 +3 +-26 +4 +-25 +5 +-24 +6 +-24 +6 +-23 +7 +-22 +-46 +84 +43 +50 +30 +18 +-13 +4 +-24 +-1 +-29 +-2 +-29 +-1 +-28 +0 +-28 +0 +-28 +2 +-26 +3 +-25 +4 +-24 +4 +-24 +5 +-24 +5 +-23 +-48 +59 +20 +60 +21 +23 +-9 +22 +-24 +0 +-28 +-1 +-30 +-1 +-30 +0 +-29 +0 +-29 +2 +-27 +3 +-26 +4 +-26 +5 +-25 +6 +-24 +6 +-24 +7 +-23 +7 +-23 +7 +-22 +8 +-22 +9 +-22 +8 +-22 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-20 +9 +-21 +9 +-21 +9 +-21 +9 +-20 +-44 +86 +45 +50 +15 +18 +-12 +4 +-24 +-1 +-29 +-2 +-30 +-2 +-29 +0 +-28 +0 +-28 +2 +-26 +4 +-25 +4 +-24 +5 +-24 +6 +-23 +6 +-23 +6 +-22 +6 +-22 +7 +-22 +8 +-22 +9 +-21 +9 +-21 +8 +-21 +8 +-21 +8 +-21 +8 +-21 +8 +-21 +8 +-21 +8 +-21 +9 +-20 +9 +-20 +9 +-20 +-45 +62 +22 +63 +23 +26 +-8 +24 +-22 +2 +-28 +0 +-29 +1 +-28 +1 +-28 +2 +-27 +3 +-26 +4 +-25 +6 +-24 +6 +-23 +7 +-23 +8 +-22 +8 +-22 +8 +-22 +8 +-22 +8 +-22 +8 +-22 +9 +-21 +9 +-21 +10 +-21 +9 +-21 +9 +-21 +8 +-22 +9 +-21 +10 +-21 +9 +-21 +9 +-22 +8 +-22 +9 +-20 +-44 +86 +45 +51 +15 +18 +-13 +4 +-25 +-1 +-29 +-1 +-29 +-1 +-29 +0 +-28 +0 +-28 +2 +-27 +3 +-26 +4 +-24 +5 +-24 +6 +-23 +7 +-22 +-46 +60 +21 +62 +23 +24 +-8 +23 +-23 +1 +-28 +0 +-29 +-1 +-29 +1 +-28 +1 +-28 +2 +-27 +4 +-26 +4 +-25 +5 +-24 +6 +-24 +7 +-24 +7 +-22 +-46 +84 +43 +49 +13 +16 +-14 +2 +-26 +-2 +-30 +-2 +-30 +-2 +-30 +-1 +-29 +0 +-28 +1 +-27 +2 +-26 +4 +-25 +5 +-24 +4 +-24 +5 +-24 +5 +-24 +5 +-23 +6 +-23 +6 +-22 +7 +-22 +8 +-21 +8 +-21 +8 +-21 +8 +-21 +8 +-21 +9 +-21 +8 +-21 +8 +-21 +9 +-21 +9 +-21 +9 +-21 +9 +-20 +9 +-21 +9 +-20 +9 +-20 +10 +-20 +10 +-19 +10 +-19 +10 +-19 +10 +-19 +10 +-20 +9 +-19 +10 +-20 +10 +-19 +10 +-20 +9 +-20 +10 +-20 +-44 +62 +23 +64 +24 +27 +-7 +25 +-21 +2 +-27 +1 +-28 +1 +-28 +2 +-27 +2 +-27 +3 +-26 +4 +-25 +5 +-25 +6 +-24 +6 +-24 +6 +-23 +7 +-23 +7 +-22 +8 +-22 +8 +-22 +8 +-22 +8 +-22 +9 +-22 +9 +-22 +9 +-21 +9 +-22 +9 +-21 +9 +-21 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-19 +-44 +87 +45 +52 +15 +19 +-12 +5 +-24 +0 +-28 +-1 +-29 +-1 +-29 +0 +-28 +1 +-28 +2 +-26 +3 +-26 +3 +-25 +4 +-25 +4 +-24 +5 +-23 +-48 +59 +20 +60 +22 +24 +-9 +23 +-23 +1 +-29 +0 +-29 +0 +-29 +1 +-28 +2 +-28 +2 +-27 +4 +-26 +4 +-25 +5 +-24 +6 +-24 +6 +-23 +7 +-22 +-46 +84 +42 +49 +13 +17 +-14 +3 +-25 +-1 +-29 +-2 +-30 +-2 +-29 +-1 +-29 +0 +-28 +1 +-27 +2 +-26 +3 +-25 +4 +-24 +5 +-24 +6 +-23 +-48 +59 +20 +60 +21 +23 +-10 +22 +-24 +0 +-28 +-1 +-30 +-1 +-30 +0 +-29 +0 +-28 +2 +-27 +3 +-26 +4 +-25 +5 +-24 +6 +-24 +6 +-24 +6 +-23 +7 +-23 +7 +-23 +7 +-22 +7 +-22 +8 +-22 +8 +-23 +8 +-22 +9 +-22 +8 +-22 +8 +-22 +8 +-22 +9 +-21 +9 +-20 +10 +-20 +10 +-20 +10 +-21 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +11 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +9 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +9 +-21 +9 +-21 +10 +-20 +10 +-21 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +10 +-20 +11 +-20 +11 +-20 +11 +-19 +10 +-20 +10 +-20 +10 +-19 +-44 +86 +45 +51 +15 +18 +-13 +4 +-25 +0 +-28 +-1 +-29 +-1 +-30 +0 +-29 +1 +-28 +2 +-26 +3 +-26 +4 +-25 +5 +-24 +5 +-24 +6 +-23 +-47 +60 +21 +61 +22 +24 +-9 +23 +-23 +1 +-28 +0 +-29 +0 +-29 +1 +-28 +2 +-28 +3 +-27 +4 +-26 +5 +-25 +5 +-24 +6 +-24 +7 +-23 +7 +-23 +7 +-23 +7 +-23 +8 +-22 +8 +-22 +8 +-22 +8 +-22 +8 +-22 +9 +-21 +8 +-22 +9 +-22 +9 +-21 +9 +-21 +10 +-21 +9 +-21 +9 +-21 +9 +-20 +-44 +86 +45 +51 +15 +19 +-12 +5 +-24 +0 +-28 +0 +-28 +0 +-28 +1 +-27 +2 +-26 +3 +-26 +3 +-25 +4 +-25 +5 +-24 +5 +-23 +6 +-23 +-47 +59 +20 +60 +21 +23 +-10 +22 +-24 +0 +-29 +-1 +-30 +-1 +-30 +0 +-29 +1 +-28 +2 +-27 +4 +-26 +4 +-25 +5 +-24 +6 +-24 +7 +-23