PCSC API spy, update

10 years ago I documented in "PCSC API spy, third try" a way to generate PC/SC API traces when using pcsc-lite.

Since then the ecosystem has changed. This article is an update of the previous blog article with more up-to-date information.

Changes

  • The pcsc-spy.py command has been renamed pcsc-spy (in 2012)
  • The libpcscspy.so library has been moved from /usr/lib/ to /usr/lib/x86_64-linux-gnu/ (for Intel 64-bits CPU systems)
  • opensc-tool can't be used with LD_PRELOAD= any more

Demo

As before we have two cases for the use of libpcsclite.so.1.

Applications linked with libpcsclite.so.1

This is the case of the pcsc_scan command for example.

You can use the ldd command to know what library has been dynamically linked at build time:

$ ldd /usr/bin/pcsc_scan 
	linux-vdso.so.1 (0x00007fffac11b000)
	libpcsclite.so.1 => /lib/x86_64-linux-gnu/libpcsclite.so.1 (0x00007f85a5f24000)
	libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f85a5f03000)
	libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f85a5d2a000)
	/lib64/ld-linux-x86-64.so.2 (0x00007f85a5f4f000)

You can use the LD_PRELOAD solution by doing:

In on terminal you run the pcsc-spy program. In another terminal you run:

$ LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libpcscspy.so.0 pcsc_scan -r
libpcsclite_nospy.so.1: cannot open shared object file: No such file or directory
No reader found.

In the first terminal you get the trace:

$ pcsc-spy 
SCardEstablishContext
 i dwScope: SCARD_SCOPE_SYSTEM (0x00000002)
 o hContext: 0x0E4C693B
 => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.002456]
SCardGetStatusChange
 i hContext: 0x0E4C693B
 i dwTimeout: 0x00000000 (0)
 i cReaders: 1
 i szReader: \\?PnP?\Notification
 i  dwCurrentState:  (0x00000000)
 i  dwEventState: SCARD_STATE_IGNORE, SCARD_STATE_UNKNOWN, SCARD_STATE_UNAVAILABLE, SCARD_STATE_EMPTY, SCARD_STATE_INUSE, SCARD_STATE_MUTE (0x55EDE352031D)
 i  Atr length: 0x55EDE352032C (94480209412908)
 i  Atr: NULL
 o szReader: \\?PnP?\Notification
 o  dwCurrentState:  (0x00000000)
 o  dwEventState:  (0x00000000)
 o  Atr length: 0x55EDE352032C (94480209412908)
 o  Atr: NULL
 => Command timeout. (SCARD_E_TIMEOUT [0x8010000A])  [0.007774]
SCardListReaders
 i hContext: 0x0E4C693B
 i mszGroups: (null)
 o pcchReaders: 0x00000001
 o mszReaders: NULL
 => Cannot find a smart card reader. (SCARD_E_NO_READERS_AVAILABLE [0x8010002E])  [0.000908]
SCardListReaders
 i hContext: 0x0E4C693B
 i mszGroups: (null)
 o pcchReaders: 0x00000001
 o mszReaders: NULL
 => Cannot find a smart card reader. (SCARD_E_NO_READERS_AVAILABLE [0x8010002E])  [0.000531]

Thread 1/1
Results sorted by total execution time
total time: 0.011769 sec
0.007774 sec (  1 calls) 66.06% SCardGetStatusChange
0.002456 sec (  1 calls) 20.87% SCardEstablishContext
0.001439 sec (  2 calls) 12.23% SCardListReaders

Application loading libpcsclite.so.1

In this case you need to modify the system configuration to replace the libpcsclite.so.1 library. This is done by the install_spy.sh script. You only need to run the script once.

$ sudo bash /usr/share/doc/libpcsclite-dev/install_spy.sh
Using directory: /lib/x86_64-linux-gnu
Spying library is: /lib/x86_64-linux-gnu/libpcscspy.so.0

On Debian (and derivatives like Ubuntu) and with pcsc-lite version 1.9.8 and more the script is provided by the libpcsclite-dev package.

In on terminal you run the pcsc-spy program. In another terminal you run the program you want to spy. For example:

$ opensc-tool -a
No smart card readers found.
Failed to connect to reader: No readers found

In the first terminal you get the trace:

SCardEstablishContext
 i dwScope: SCARD_SCOPE_USER (0x00000000)
 o hContext: 0x2667F6DA
 => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.005316]
SCardListReaders
 i hContext: 0x2667F6DA
 i mszGroups: (null)
 o pcchReaders: 0x00000001
 o mszReaders: NULL
 => Cannot find a smart card reader. (SCARD_E_NO_READERS_AVAILABLE [0x8010002E])  [0.000079]
SCardReleaseContext
 i hContext: 0x2667F6DA
 => Command successful. (SCARD_S_SUCCESS [0x00000000])  [0.000074]

Thread 1/1
Results sorted by total execution time
total time: 0.007195 sec
0.005316 sec (  1 calls) 73.88% SCardEstablishContext
0.000079 sec (  1 calls)  1.10% SCardListReaders
0.000074 sec (  1 calls)  1.03% SCardReleaseContext

Do not forget to restore the system configuration using the uninstall_spy.sh script.

$ sudo bash /usr/share/doc/libpcsclite-dev/uninstall_spy.sh
Using directory: /lib/x86_64-linux-gnu

Redirection in a file

It is still possible to redirect the traces in a file. Instead of running pcsc-spy you do:

$ mkfifo ~/pcsc-spy
$ cat ~/pcsc-spy > logfile

And in another terminal you start the application as indicated above (i.e. using LD_PRELOAD= or after running install_spy.sh)

You can then analyse the logs later using:

$ pcsc-spy logfile

Remarks

Bugs found

I note that SCardReleaseContext() is not always called by pcsc_scan before exit. I just fixed this problem in pcsc-tools.

Install/uninstall

It is important to run the uninstall_spy.sh script to undo the changes made by the install_spy.sh script.

It is important you undo the changes before any execution of the ldconfig (configure dynamic linker run-time bindings) administration command. ldconfig is used, for example, during the installation of a package.

If you run uninstall_spy.sh after an execution of ldconfig you may get a broken libpcsclite installation with an error like:

$ pcsc_scan 
pcsc_scan: error while loading shared libraries: libpcsclite.so.1: cannot open shared object file: No such file or directory

To fix te problem you can force reinstall the libpcsclite1 (or equivalent) package.

Order of execution

It is important to start pcsc-spy before the application you want to spy. If you start pcsc-spy after the application you have 2 cases:

  1. if the fifo file ~/pcsc-spy does not yet exist then pcsc-spy will display nothing
  2. if the fifo file ~/pcsc-spy already exists then libpcscspy.so will use it to send logs and will be blocked until something reads the file (pcsc-spy or the cat command to redirect the content)

Conclusion

I hope this update is useful.

if you have ideas to improve the logs please contact me.