### Author Topic: Calling an api  (Read 1240 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, stdcalloption casemap :noneinclude \masm32\include\windows.inc ; Win32 APIinclude \masm32\include\user32.incinclude \masm32\include\kernel32.incinclude \masm32\include\winscard.inc ; SmartCard APIincludelib \masm32\lib\winscard.libincludelib \masm32\lib\user32.libincludelib \masm32\lib\kernel32.libinclude \masm32\macros\macros.asm ; need that one too as i use chr\$().dataSzReader               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(?).codestart: 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,0end 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: 12471
• Assembler is fun ;-)
##### 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]
`SCardConnecteax             6SzCardHandle    0SCardGetAttribeax             6SzCardHandle    0SCardStatuseax             6SzCardHandle    0SzReader        72SzReaderlen     0SzpdwState      0SzpdwProtocol   0SzpbAtr         0SzpbAtrlen      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, pdwActiveProtocol00401015  |.  68 70304000   PUSH ; |Arg5 = scard.403070, phCard0040101A  |.  6A 03         PUSH ; |Arg4 = 3, dwPreferredProtocols0040101C  |.  6A 02         PUSH ; |Arg3 = 2, dwShareMode0040101E  |.  68 00304000   PUSH ; |Arg2 = ASCII "HID Global OMNIKEY 3x21 Smart Card Reader 0", szReader00401023  |.  FF35 68304000 PUSH ; |Arg1 = CD010000, hContext00401029  |.  E8 70000000   CALL ; \winscard.SCardConnectA0040102E  |.  68 04314000   PUSH ; /Arg4 = scard.403104, pcbAttrLen00401033  |.  68 84304000   PUSH ; |Arg3 = scard.403084, pbAttr00401038  |.  68 07A00700   PUSH ; |Arg2 = 7A007, dwAttrId0040103D  |.  FF35 70304000 PUSH ; |Arg1 = EA010000, hCard00401043  |.  E8 68000000   CALL ; \winscard.SCardGetAttrib00401048  |.  83F8 32       CMP0040104B  |.  75 13         JNE0040104D  |.  6A 40         PUSH ; /Type = MB_OK|MB_ICONASTERISK|MB_DEFBUTTON1|MB_APPLMODAL0040104F  |.  68 60304000   PUSH ; |Caption = "problem"00401054  |.  68 2C304000   PUSH ; |Text = "Could not determinate reader maximum input length"00401059  |.  6A 00         PUSH ; |hOwner = NULL0040105B  |.  E8 5C000000   CALL ; \USER32.MessageBoxA00401060  |>  68 04314000   PUSH ; /Arg7 = scard.403104, pcbAtrLen00401065  |.  68 84304000   PUSH ; |Arg6 = scard.403084, pbAtr0040106A  |.  68 80304000   PUSH ; |Arg5 = scard.403080, pdwProtocol0040106F  |.  68 7C304000   PUSH ; |Arg4 = scard.40307C, pdwState00401074  |.  68 84314000   PUSH ; |Arg3 = scard.403184, pcchReaderLen00401079  |.  68 00304000   PUSH ; |Arg2 = ASCII "HID Global OMNIKEY 3x21 Smart Card Reader 0", szReader0040107E  |.  FF35 70304000 PUSH ; |Arg1 = EA010000, hCard00401084  |.  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: 1804
##### 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: 12471
• Assembler is fun ;-)
##### 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

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,1`But i get the error code 80100004 (SCARD_E_INVALID_PARAMETER)
why does it fail?

#### jj2007

• Member
• Posts: 12471
• Assembler is fun ;-)
##### 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,0`now 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: 12471
• Assembler is fun ;-)
##### 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: 1804
##### 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,20invoke 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