SCardSniffer2 spies the exchanges between a PC/SC application and a smart card

5 years ago, SpringCard introduced SCardSniffer, a tool that spies the exchanges between Windows applications and the PC/SC subsystem. SCardSniffer works by introducing a hook over winscard.dll.

Although this method is still perfectly working in most cases, it comes with some technical complexity (1. the sniffer and the sniffed application must both run on the same subsystem, either Win32 or Win64, hence 2 versions of the sniffer and 2. the injection of the hook is likely to be disabled on security-enforced computers and 3. it may also triggers some antivirus/malware detection tools, which leads to an unnecessary stress).

SCardSniffer2 is a new tool that offers basically the same function, but with a much simpler architecture.

SCardSniffer2 installs a new virtual smart card reader and acts as a relay between this virtual reader and the real reader, where the real card is.

The application to be spied must be reconfigured to connect to the virtual reader (instead of the real reader); SCardSniffer2 is then able to record all the APDUs exhanged between the application and the card.

Read More

SCardSniffer spies the exchanges between a PC/SC application and PC/SC middleware

SCardSniffer is a new tool used to spy the exchanges between Windows applications and the smart cards or NFC tags that are accessed through a PC/SC reader (or coupler).

SCardSniffer
SCardSniffer main window

On a Windows computer, all card-aware applications communicate with smart cards or NFC tags through the system's PC/SC library, winscard.dll.

Read More

Using SCardControl under Linux and from a Java program

SCardControl is the PC/SC function that makes it possible for the application to invoke 'proprietary' functions, implemented either in the PC/SC reader itself (CSB6Prox’N'Roll PC/SCEasyFinger or CrazyWriter) , or in its driver running on the PC, or in the PC/SC middleware.

The prototype is:

LONG SCardControl(
  SCARDHANDLE hCard,
  DWORD dwControlCode,
  LPCVOID lpInBuffer,
  DWORD nInBufferSize,
  LPVOID lpOutBuffer,
  DWORD nOutBufferSize,
  LPDWORD lpBytesReturned
);

(see http://pcsclite.alioth.debian.org/api/group__API.html for the PCSC-Lite documentation, and http://msdn.microsoft.com/en-us/library/windows/desktop/aa379474%28v=vs.85%29.aspx for Microsoft's version).

The lpInbuffer / nInBufferSize parameters hold the command buffer that will be processed by either target -reader, driver, or PC/SC middleware-.

SpringCard PC/SC Readers do provide a few 'proprietary' functions (called 'Escape commands' in the USB CCID specification). For instance, an application would send the command 58 1E 01 00 to switch the reader's red LED ON. A question remains: what must the value of dwControlCode be, when the application wants to send the command right to the reader, bypassing both the PC/SC middleware and the driver? The answer varies with the operating system, which doesn't help implementing portable code.

Differences between Windows and PCSC-Lite implementations

Windows

In Microsoft's CCID driver (http://msdn.microsoft.com/en-us/library/windows/hardware/gg487509.aspx), the dwControlCode for the Escape command is defined as follows:

#define IOCTL_CCID_ESCAPE SCARD_CTL_CODE(3500)

SpringCard PC/SC Readers follow the CCID specification. SpringCard's CCID driver (SDD480) uses the same dwControlCode as Microsoft's.

Therefore, on Windows, the application would switch the red LED on this way:

#include <windows.h>
#include <winscard.h>

#define IOCTL_CCID_ESCAPE SCARD_CTL_CODE(3500)

(...)

const BYTE SET_RED_LED_ON[4] = { 0x58, 0x1E, 0x01, 0x00 };

SCARDCONTEXT hContext;
SCARDHANDLE hCard;
DWORD dwProtocol;
BYTE abResponse[256];
DWORD dwRespLen;
LONG rc;

(...)

/* Instanciate the winscard.dll library */
rc = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &amp;hContext);
if (rc != SCARD_S_SUCCESS) { /* TODO: handle error */ }

/* Get a direct connection to the reader (we don't need a card to send Escape commands) */
rc = SCardConnect(hContext, szReader, SCARD_SHARE_DIRECT, 0, &amp;hCard, &amp;dwProtocol);
if (rc != SCARD_S_SUCCESS) { /* TODO: handle error */ }

/* Send the command */
rc = SCardControl(hCard, IOCTL_CCID_ESCAPE, SET_RED_LED_ON, sizeof(SET_RED_LED_ON), abResponse, sizeof(abResponse), &amp;dwRespLen);
if (rc != SCARD_S_SUCCESS) { /* TODO: handle error */ }

SCardDisconnect(hCard, SCARD_LEAVE_CARD);
SCardReleaseContext(hContext);

 

Important notes:

Working with MS' CCID driver

With Microsoft's CCID driver, the Escape feature is disabled by default.

In order to send or receive an Escape command to a reader, the DWORD registry value EscapeCommandEnable must be added and set to a non-zero value under one of the following keys.

  • HKLM\SYSTEM\CCS\Enum\USB\Vid*Pid*\*\Device Parameters (prior to Windows 7).
  • HKLM\SYSTEM\CCS\Enum\USB\Vid*Pid*\*\Device Parameters\WUDFUsbccidDriver (Windows 7 and later).

This is clearly explained in the Developer's Manual for every PC/SC reader.

Using SpringCard's SDD480 CCID driver shall be preferred.

Early versions of SDD480

Branch -Ax of SpringCard's SDD480 CCID driver uses a different value for the dwControlCode parameter.

#define IOCTL_CCID_ESCAPE SCARD_CTL_CODE(2048)

Switching to the latest version of SpringCard's SDD480 CCID driver (branch -Bx and onwards) shall be preferred.

Linux, MacOS and other Unix*

In Ludovic Rousseau's open-source CCID driver (http://pcsclite.alioth.debian.org/ccid.html), the dwControlCode for the Escape command is defined as follows:

#define IOCTL_CCID_ESCAPE SCARD_CTL_CODE(1)

(See http://anonscm.debian.org/viewvc/pcsclite/trunk/Drivers/ccid/SCARDCONTOL.txt?view=markup for details)

Therefore, when working with PCSC-Lite, the application would switch the red LED on this way:

#ifdef __APPLE__
#include <pcsc/winscard.h>
#include <pcsc/wintypes.h>
#else
#include <winscard.h>
#endif

#define IOCTL_CCID_ESCAPE SCARD_CTL_CODE(1)

(...)

const BYTE SET_RED_LED_ON[4] = { 0x58, 0x1E, 0x01, 0x00 };

SCARDCONTEXT hContext;
SCARDHANDLE hCard;
DWORD dwProtocol;
BYTE abResponse[256];
DWORD dwRespLen;
LONG rc;

(...)

/* Instanciate the winscard.dll library */
rc = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
if (rc != SCARD_S_SUCCESS) { /* TODO: handle error */ }

/* Get a direct connection to the reader (we don't need a card to send Escape commands) */
rc = SCardConnect(hContext, szReader, SCARD_SHARE_DIRECT, 0, &hCard, &dwProtocol);
if (rc != SCARD_S_SUCCESS) { /* TODO: handle error */ }

/* Send the command */
rc = SCardControl(hCard, IOCTL_CCID_ESCAPE, SET_RED_LED_ON, sizeof(SET_RED_LED_ON), abResponse, sizeof(abResponse), &dwRespLen);
if (rc != SCARD_S_SUCCESS) { /* TODO: handle error */ }

SCardDisconnect(hCard, SCARD_LEAVE_CARD);
SCardReleaseContext(hContext);

Enabling the Escape commands

With this CCID driver, the Escape feature is also disabled by default.

You'll have to edit the CCID driver's Info.plist file to enable this feature:

  • Open /usr/local/lib/pcsc/drivers/ccid/Info.plist in edit mode with root priviledge,
  • Locate the line <key>ifdDriverOptions</key>,
  • The following line is typically <string>0000</string>,
  • Define the new value: <string>0001</string>,
  • Save the file and restard pcscd.

(More details on http://ludovicrousseau.blogspot.fr/2011/10/featureccidesccommand.html)

Writing portable code

The idea is only to use a #ifdef to compile the correct value:

#ifdef WIN32
#define IOCTL_CCID_ESCAPE SCARD_CTL_CODE(3500)
#else
#define IOCTL_CCID_ESCAPE SCARD_CTL_CODE(1)
#endif

Java

The javax.smartcardio API provides Java methods that are stricly bound to the underlying PC/SC subsystem. The Card.transmitControlCommand method is the wrapper for SCardControl. The prototype is coherent:

java decode:true">public abstract byte[] transmitControlCommand(
  int controlCode,
  byte[] command)
    throws CardException

Now the same question: what must the value of controlCode be? The answer is short: it depends on the PC/SC stack! SCARD_CTL_CODE(3500) for Windows, and SCARD_CTL_CODE(1) for PCSC-Lite. But with another difference: the macro SCARD_CTL_CODE is not computed the same way between both systems!

 

As a consequence, the Java application must detect the OS, and compute the controlCode parameter accordingly.

Same example to switch the red LED on:

java decode:true">import javax.smartcardio.*;

(...)

static boolean isWindows()
{
  String os_name = System.getProperty("os.name").toLowerCase();
  if (os_name.indexOf("windows") > -1) return true;
  return false;
}

static int SCARD_CTL_CODE(int code)
{
  int ioctl;
  if (isWindows())
  {
    ioctl = (0x31 < < 16 | (code) << 2);
  } else
  {
    ioctl = 0x42000000 + (code);
  }
  return ioctl;
}

static int IOCTL_CCID_ESCAPE()
{
  if (isWindows())
  {
    return SCARD_CTL_CODE(3500);
  } else
  {
    return SCARD_CTL_CODE(1);
  }
}

static final byte[] SET_RED_LED_ON = { (byte) 0x58, (byte) 0x1E, (byte) 0x01, (byte) 0x00 };

(...)

String readerName;

/* Note that the reader's name vary with the OS too!!! */
if (isWindows())
  readerName = "SpringCard Prox'N'Roll Contactless 0";
else
  readerName = "SpringCard Prox'N'Roll (00000000) 00 00";

CardTerminal terminal = CardTerminals.getTerminal(readerName);

Card virtualCard = terminal.connect("DIRECT");

virtualCard.transmitControlCommand(IOCTL_CCID_ESCAPE(), SET_RED_LED_ON);

virtualCard.disconnect(false);

Of course this code works only if the Escape feature is enable by the underlying CCID driver, as seen above.