Too much technology, in too little time...

Smart Card Middleware Reversing Tricks

Sep 15th, 2013

In order for a smart card to be usable by a third party application, a vendor-supplied
driver or a middleware needs to be available. On the Windows platform, a smart card
middleware must follow the Windows Smart Card Minidriver specification which is
designed to present a consistent interface to the card. This is not always the case,
and card vendors sometimes implement custom and non-standard interfaces.

Since smart cards are designed to be tamper-resistant and secure, reverse
engineering of the smart card itself can be time consuming and expensive so it
is ofthen the best to take a look at the middleware.

Identifying key middleware functions

When faced with a smart card of a unknown specification, the middleware functions
that directly communicate with the card should be examined. The middleware is
responsible for abstracting the card to the programmer and examining these
abstractions gives further insight into the smart card’s design. The smart card
middleware is distributed as a DLL (Dynamic Loadable Library) file which exports
a specific set of functions defined by the minidriver specification.

Before accessing the card in any way, the middleware must be initialized.
Initialization is done by calling CardAcquireContext function.
CardAcquireContext must be exported by the middleware and is usually the only
exported function.

CardAcquireContext is responsible, amongst other tasks, for setting the function
pointers in the CARD_DATA structure. In the assembled code, this will usually be
represented by the series of the pointer assignment operations to the appropriate
offsets into the CARD_DATA structure. By loadin apropriate C header file
for CARD_DATA structure in IDA, it will be able to determine the locations of
specific functions:

From this, we can clearly determine what each function does (at least on the)
high level.

Capturing data trafic

middleware sends the APDU commands with specific parameters to the smart card and
the smart card responds with the APDU response. Capturing this data exchange can
help greatly in understanding the smart card and middleware design. The APDU structure
is defined by the ISO/IEC 7816-4 standard. The command APDU contains a
mandatory 4 byte long header and up to 255 bytes of data.
The response APDU is sent by the card to the reader and contains 2 byte status
word and up to 255 bytes of data. . The command status 00 90 in hexadecimal
signifies that the command has been executed successfully.

On the Windows operating systems, all smart card communication is done trough
WinSCard API which defines the low level smart card access function. The ScardTransmit
function sends the command APDUs to the card and returns the response. One solution
for monitoring the data transmission from and to the cards is to intercept
SCardTransmit function calls and inspecting the arguments and return values.

I wrote a simple DLL that hooks SCardTransmit and records sent and received data.
The code is available on my github repository and precompiled binaries are
available here. During the communication between the Windows process and
the smart card, a log file is created. Log file is named after the process.
The transmitted data is prefixed with the >>> symbol, while the received data
is prefixed with the <<< symbol. Each data transmission is recorded in the
log file immediately and file access is freed to combine the log analysis with
the process instrumentation in the debugger.

The first APDU command in the listing 4 has the instruction A4 which, by the
ISO/IEC 7816-4 standard, specifies the SELECT FILE instruction responsible
for selecting a particular elementary file on the smart card with the name 0F 02.
The last two bytes of the response APDU are 90 00 which indicates the success.
By enumerating all unique SELECT FILE instructions executed, a list of the elementary
files present on the card can be created. The next three commands have the INS
byte set to B0 which corresponds to the READ BINARY instruction. The READ BINARY
instruction can read the maximum of 255 bytes of data at a time so multiple
requests with incrementing offsets would be needed to read a large file. The
file can then be reconstructed by the log. The Last command is the SELECT FILE
instruction which response indicates an error has occurred.

The extensive list of known command APDU instructions can be found in this page on web archive.
Repackaging the sniffed data into something that Wireshark can eat would be
useful but I’ll leave that for the next time.