Author Topic: Calling an api  (Read 842 times)

ewok

  • Regular Member
  • *
  • Posts: 10
Calling an api
« on: May 14, 2021, 05:12:29 AM »
Good day everyone,
I'm trying to experiment with winscard.dll for smart card interaction.
But seem i'm not clever enough to understand how to use fews apis.

Here is my code:
Code: [Select]
.386
.model flat, stdcall
option casemap :none

include \masm32\include\windows.inc ; Win32 API
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\winscard.inc ; SmartCard API

includelib \masm32\lib\winscard.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
include \masm32\macros\macros.asm ; need that one too as i use chr$()

.data
SzReader               db "HID Global OMNIKEY 3x21 Smart Card Reader 0",0

.data?
SzphContext            DWORD ?
SzComActiveProtocol    DWORD ?

SzCardHandle           DWORD ?
chReaderLen            DWORD ?
atrlen                 DWORD ?
SzpdwState             DWORD ?
SzpdwProtocol          DWORD ?
SzpbAtr                LPBYTE 32 dup(?)
SzpbAtrlen             DWORD 32 dup(?)
SzReaderlen            DWORD 32 dup(?)
.code
start:
invoke SCardEstablishContext,SCARD_SCOPE_USER,NULL,NULL,addr SzphContext
invoke SCardConnect,SzphContext,addr SzReader,SCARD_SHARE_SHARED,SCARD_PROTOCOL_T0 or SCARD_PROTOCOL_T1,addr SzCardHandle,addr SzComActiveProtocol
invoke SCardGetAttrib,SzCardHandle,07A007h,addr SzpbAtr,addr SzpbAtrlen; 7A007h: SCARD_ATTR_MAXINPUT (maximum size of an APDU supported by the reader).
.if eax == ERROR_NOT_SUPPORTED ;One or more of the supplied parameters could not be properly interpreted.
invoke MessageBox,NULL,chr$("Could not determinate reader maximum input length"),chr$("problem"),MB_ICONINFORMATION
.endif

; Provides the current status of a smart card in a reader.
;LONG SCardStatusA(
;  SCARDHANDLE hCard,          (Reference value returned from SCardConnect.)
;  LPSTR       mszReaderNames, (List of display names (multiple string) by which the currently connected reader is known.)
;  LPDWORD     pcchReaderLen,  (On input, supplies the length of the szReaderName buffer. On output, receives the actual length (in characters) of the reader name list, including the trailing NULL character)
;  LPDWORD     pdwState,       (Current state of the smart card in the reader. Upon success, it receives state indicators)
;  LPDWORD     pdwProtocol,    (Current protocol, if any. The returned value is meaningful only if the returned value of pdwState is SCARD_SPECIFICMODE.)
;  LPBYTE      pbAtr,          (Pointer to a 32-byte buffer that receives the ATR string from the currently inserted card, if available.)
;  LPDWORD     pcbAtrLen       (On input, supplies the length of the pbAtr buffer. On output, receives the number of bytes in the ATR string (32 bytes maximum).)
;);
invoke SCardStatus,SzCardHandle,addr SzReader,addr SzReaderlen,addr SzpdwState,addr SzpdwProtocol,addr SzpbAtr,addr SzpbAtrlen
invoke SCardDisconnect,SzCardHandle,SCARD_LEAVE_CARD
invoke ExitProcess,0
end start

SCardGetAttrib return me eax=32 (ERROR_NOT_SUPPORTED), i reproduced a call to SCardGetAttrib with cardpeak (a software) and i got the same error code with this dwAttrId.
I saw also this thread on stackoverflow and after reading the answer i guess my code is ok? at least that this behavior might be normal. But if someone can check that my convention is good?
My problem is more with SCardStatus, something is wrong with my buffers, i should normally expect to have in pbAtr: 3B F9 13 00 00 81 31 FE 45 4A 43 4F 50 32 34 32 52 33 A2 but all i got are zeros

jj2007

  • Member
  • *****
  • Posts: 11782
  • Assembler is fun ;-)
    • MasmBasic
Re: Calling an api
« Reply #1 on: May 14, 2021, 05:45:27 AM »
You should check the return values: on my machine, I get SCARD_E_NO_SERVICE:

//
// The Smart card resource manager is not running.
//
#define SCARD_E_NO_SERVICE               ((DWORD)0x8010001DL)


Code: [Select]
SCardConnect
eax             6
SzCardHandle    0

SCardGetAttrib
eax             6
SzCardHandle    0

SCardStatus
eax             6
SzCardHandle    0
SzReader        72
SzReaderlen     0
SzpdwState      0
SzpdwProtocol   0
SzpbAtr         0
SzpbAtrlen      0

Code: [Select]
invoke SCardEstablishContext,SCARD_SCOPE_USER,NULL,NULL,addr SzphContext
invoke SCardConnect,SzphContext,addr SzReader,SCARD_SHARE_SHARED,SCARD_PROTOCOL_T0 or SCARD_PROTOCOL_T1,addr SzCardHandle,addr SzComActiveProtocol
deb 4, "SCardConnect", eax, SzCardHandle
invoke SCardGetAttrib,SzCardHandle,07A007h,addr SzpbAtr,addr SzpbAtrlen; 7A007h: SCARD_ATTR_MAXINPUT (maximum size of an APDU supported by the reader).
deb 4, "SCardGetAttrib", eax, SzCardHandle

ewok

  • Regular Member
  • *
  • Posts: 10
Re: Calling an api
« Reply #2 on: May 14, 2021, 07:35:00 AM »
Hi jj2007,
the handles are good when connected to a smart card reader and when a smart card is inside.
EA010000 (SzCardHandle, hCard)
Code: [Select]
00401010  |.  68 6C304000   PUSH ; /Arg6 = scard.40306C, pdwActiveProtocol
00401015  |.  68 70304000   PUSH ; |Arg5 = scard.403070, phCard
0040101A  |.  6A 03         PUSH ; |Arg4 = 3, dwPreferredProtocols
0040101C  |.  6A 02         PUSH ; |Arg3 = 2, dwShareMode
0040101E  |.  68 00304000   PUSH ; |Arg2 = ASCII "HID Global OMNIKEY 3x21 Smart Card Reader 0", szReader
00401023  |.  FF35 68304000 PUSH ; |Arg1 = CD010000, hContext
00401029  |.  E8 70000000   CALL ; \winscard.SCardConnectA
0040102E  |.  68 04314000   PUSH ; /Arg4 = scard.403104, pcbAttrLen
00401033  |.  68 84304000   PUSH ; |Arg3 = scard.403084, pbAttr
00401038  |.  68 07A00700   PUSH ; |Arg2 = 7A007, dwAttrId
0040103D  |.  FF35 70304000 PUSH ; |Arg1 = EA010000, hCard
00401043  |.  E8 68000000   CALL ; \winscard.SCardGetAttrib
00401048  |.  83F8 32       CMP
0040104B  |.  75 13         JNE
0040104D  |.  6A 40         PUSH ; /Type = MB_OK|MB_ICONASTERISK|MB_DEFBUTTON1|MB_APPLMODAL
0040104F  |.  68 60304000   PUSH ; |Caption = "problem"
00401054  |.  68 2C304000   PUSH ; |Text = "Could not determinate reader maximum input length"
00401059  |.  6A 00         PUSH ; |hOwner = NULL
0040105B  |.  E8 5C000000   CALL ; \USER32.MessageBoxA
00401060  |>  68 04314000   PUSH ; /Arg7 = scard.403104, pcbAtrLen
00401065  |.  68 84304000   PUSH ; |Arg6 = scard.403084, pbAtr
0040106A  |.  68 80304000   PUSH ; |Arg5 = scard.403080, pdwProtocol
0040106F  |.  68 7C304000   PUSH ; |Arg4 = scard.40307C, pdwState
00401074  |.  68 84314000   PUSH ; |Arg3 = scard.403184, pcchReaderLen
00401079  |.  68 00304000   PUSH ; |Arg2 = ASCII "HID Global OMNIKEY 3x21 Smart Card Reader 0", szReader
0040107E  |.  FF35 70304000 PUSH ; |Arg1 = EA010000, hCard
00401084  |.  E8 2D000000   CALL ; \winscard.SCardStatusA
If it wasn't good i would get the error code SCARD_E_INVALID_HANDLE, but here i got everywhere SCARD_S_SUCCESS (no prob) after invokes.
I still think there is a problem with the last arguments addr SzpbAtr,addr SzpbAtrlen, it should be related to this i suppose, i'm unsure of these twos as SzpbAtr is lpbytes; i don't know if i'm doing it good, or if it looks incorrect of the C++ Syntax example in msdn, but my doubts are on this, i may be wrong.
« Last Edit: May 14, 2021, 10:30:16 AM by ewok »

TouEnMasm

  • Member
  • *****
  • Posts: 1805
    • EditMasm
Re: Calling an api
« Reply #3 on: May 14, 2021, 03:44:18 PM »
Hello,
I have rebuild your code in windows 10.No error in my computer ,try it and see what happen
Fa is a musical note to play with CL

jj2007

  • Member
  • *****
  • Posts: 11782
  • Assembler is fun ;-)
    • MasmBasic
Re: Calling an api
« Reply #4 on: May 14, 2021, 05:28:40 PM »
I've modified Yves' code a little bit, so that it builds with the Masm32 SDK, but no luck, I get runtime errors. Probably because I don't have a smart card reader :biggrin:

Does it work for people who do have a smard card reader? Source & exe attached.

ewok

  • Regular Member
  • *
  • Posts: 10
Re: Calling an api
« Reply #5 on: May 14, 2021, 10:37:50 PM »
Hi guys,
both of your example works for me, and it express the same behavior as my code.

After calling SCardStatusA this is what i have on the memory dump:
Code: [Select]
SzpdwState: 06 (SCARD_SPECIFIC)
SzpdwProtocol: 02 (meaning SCARD_PROTOCOL_T1 is in use)
SzpbAtr: 00 (?)
SzpbAtrlen: 12 (SzpbAtr has a buffer size of 18 zeros?)
SzReaderlen: 2D
I'm looking at cardpeak under a debugger again to understand the differences, i figured out with a hw breakpoint on their atr buffer that it does SCardGetStatusChangeA before SCardStatus. (but they have already the handle as they call SCardEstablishContext at initialization to after do a SCardListReadersA)
And that seem to return the atr, i don't understand where did that come from, it seem not for that and they havent called SCardStatus yet? https://docs.microsoft.com/en-us/windows/win32/api/winscard/nf-winscard-scardgetstatuschangea
After looking at cardpeak code, this is done on pcsc_driver.c https://github.com/L1L1/cardpeek/blob/master/drivers/pcsc_driver.c#L141
I tried to translate it to masm, i've added this line after invoke SCardEstablishContext:
Code: [Select]
invoke SCardGetStatusChange,SzphContext,INFINITE,SCARD_STATE_UNAWARE,1But i get the error code 80100004 (SCARD_E_INVALID_PARAMETER)
why does it fail?

jj2007

  • Member
  • *****
  • Posts: 11782
  • Assembler is fun ;-)
    • MasmBasic
Re: Calling an api
« Reply #6 on: May 14, 2021, 10:48:58 PM »
Handle is ok?
SzphContext is a pointer to one properly filled SCARD_READERSTATE structure?

ewok

  • Regular Member
  • *
  • Posts: 10
Re: Calling an api
« Reply #7 on: May 14, 2021, 11:28:26 PM »
yes handle SzphContext (the handle of the smart card reader got from previous call on SCardEstablishContext) is correct, i can see it while debugging.
Code: [Select]
00401010  |.  6A 01    PUSH 1                              ; /Arg4 = 1                        (1)
00401012  |.  6A 00    PUSH 0                              ; |Arg3 = 0                        (SCARD_STATE_UNAWARE)
00401014  |.  6A FF    PUSH -1                             ; |Arg2 = -1                       (INFINITE)
00401016  |.  FF35 683 PUSH DWORD PTR DS:[403068]          ; |Arg1 = CD010000                 (SzphContext)
0040101C  |.  E8 A5000 CALL <JMP.&winscard.SCardGetStatusC ; \winscard.SCardGetStatusChangeA
It is rgReaderStates who should point to SCARD_READERSTATE?, in my case it is: SCARD_STATE_UNAWARE (0x0000), looks good too in the debugger
edit: oh my bad.. rgReaderStates is array so it start at zero.
Code: [Select]
invoke SCardGetStatusChange,SzphContext,INFINITE,SCARD_STATE_UNAWARE,0now it return SCARD_S_SUCCESS but i still don't see any trace of my atr inside SzpbAtr after calling SCardStatus hmm...

jj2007

  • Member
  • *****
  • Posts: 11782
  • Assembler is fun ;-)
    • MasmBasic
Re: Calling an api
« Reply #8 on: May 15, 2021, 12:25:52 AM »
I see two examples on SOF with different types of parameters:
Code: [Select]
SCardGetStatusChange(
              context.get(),
              INFINITE,
              readersstaterange.begin(),
              lib::rng::size_cast<DWORD>(readersstaterange.size())

M$ doc looks like this::
Code: [Select]
SCardGetStatusChangeA(
  SCARDCONTEXT         hContext,
  DWORD                dwTimeout,
  LPSCARD_READERSTATEA rgReaderStates,
  DWORD                cReaders
)

... where rgReaderStates is "An array of SCARD_READERSTATE structures". You put the SCARD_STATE_UNAWARE constant, i.e. zero, but your #readers is 1. Have you tried 0?

TouEnMasm

  • Member
  • *****
  • Posts: 1805
    • EditMasm
Re: Calling an api
« Reply #9 on: May 15, 2021, 02:28:06 AM »

dumpbin on the obj can help
Code: [Select]
00000026: 68 00 00 00 00     push        offset _SzphContext
  0000002B: 6A 00              push        0
  0000002D: 6A 00              push        0
  0000002F: 6A 00              push        0
  00000031: E8 00 00 00 00     call        _SCardEstablishContext@16
  00000036: 68 00 00 00 00     push        offset _SzComActiveProtocol
  0000003B: 68 00 00 00 00     push        offset _SzCardHandle
  00000040: 6A 03              push        3
  00000042: 6A 02              push        2
  00000044: 68 00 00 00 00     push        offset _SzReader
  00000049: FF 35 00 00 00 00  push        dword ptr [_SzphContext]
  0000004F: E8 00 00 00 00     call        _SCardConnectA@24
  00000054: 68 00 00 00 00     push        offset _SzpbAtrlen
  00000059: 68 00 00 00 00     push        offset _SzpbAtr
  0000005E: 68 07 A0 07 00     push        7A007h
  00000063: FF 35 00 00 00 00  push        dword ptr [_SzCardHandle]
  00000069: E8 00 00 00 00     call        _SCardGetAttrib@16
  0000006E: 83 F8 32           cmp         eax,32h
  00000071: 75 13              jne         00000086
  00000073: 6A 40              push        40h
  00000075: 68 00 00 00 00     push        offset _??000D
  0000007A: 68 00 00 00 00     push        offset _??000C
  0000007F: 6A 00              push        0
  00000081: E8 00 00 00 00     call        _MessageBoxA@16
  00000086: 68 00 00 00 00     push        offset _SzpbAtrlen
  0000008B: 68 00 00 00 00     push        offset _SzpbAtr
  00000090: 68 00 00 00 00     push        offset _SzpdwProtocol
  00000095: 68 00 00 00 00     push        offset _SzpdwState
  0000009A: 68 00 00 00 00     push        offset _SzReaderlen
  0000009F: 68 00 00 00 00     push        offset _SzReader
  000000A4: FF 35 00 00 00 00  push        dword ptr [_SzCardHandle]
  000000AA: E8 00 00 00 00     call        _SCardStatusA@28
  000000AF: 6A 00              push        0
  000000B1: FF 35 00 00 00 00  push        dword ptr [_SzCardHandle]
  000000B7: E8 00 00 00 00     call        _SCardDisconnect@8
  000000BC: 68 00 00 00 00     push        offset _firstreverse
  000000C1: 68 00 00 00 00     push        offset _??000E
  000000C6: E8 00 00 00 00     call        _printf
  000000CB: 83 C4 08           add         esp,8
  000000CE: E8 00 00 00 00     call        __getch
  000000D3: C3                 ret
Fa is a musical note to play with CL

ewok

  • Regular Member
  • *
  • Posts: 10
Re: Calling an api
« Reply #10 on: October 05, 2021, 04:56:32 AM »
a bit late but solved.
needed simply to give SzpbAtrlen something else than zero.

Code: [Select]
mov SzpbAtrlen,20
invoke SCardStatus,SzCardHandle,addr SzReader,addr SzReaderlen,addr SzpdwState,addr SzpdwProtocol,addr SzpbAtr,addr SzpbAtrlen
works and return the smart card atr as well as it's size on SzpbAtrlen  :thumbsup: