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.
Here’s the example dump:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
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.