用c++测量APDU命令到Java卡的时间的最佳方法



我正试图对Java卡进行某种定时攻击。我需要一种方法来测量从发送命令到获得答案之间的时间。我使用的是winscard.h接口,语言是c++。我创建了一个winscard.h接口的包装器,以使我的工作更容易。例如,为了发送一个APDU,我现在使用的代码似乎很有效。基于这个答案,我更新了我的代码

 byte pbRecvBuffer[258];
long rv;
if (this->sessionHandle >= this->internal.vSessions.size())
    throw new SmartCardException("There is no card inserted");
SCARD_IO_REQUEST pioRecvPci;
pioRecvPci.dwProtocol = (this->internal.vSessions)[sessionHandle].dwActiveProtocol;
pioRecvPci.cbPciLength = sizeof(pioRecvPci);
LPSCARD_IO_REQUEST pioSendPci;
if ((this->internal.vSessions)[sessionHandle].dwActiveProtocol == SCARD_PROTOCOL_T1)
    pioSendPci = (LPSCARD_IO_REQUEST)SCARD_PCI_T1;
else
    pioSendPci = (LPSCARD_IO_REQUEST)SCARD_PCI_T0;
word expected_length = 258;//apdu.getExpectedLen();
word send_length = apdu.getApduLength();
CardSession session = (this->internal.vSessions).operator[](sessionHandle);
byte * data = const_cast<Apdu&>(apdu).getNonConstantData();
auto start = Timer::now();
rv = SCardTransmit(session.hCard, pioSendPci,data,
    send_length, &pioRecvPci, pbRecvBuffer,&expected_length);
auto end = Timer::now();
auto duration = (float)(end - start) / Timer::ticks();
return *new ApduResponse(pbRecvBuffer, expected_length,duration);
class Timer
{
public:
static inline int ticks()
{
    LARGE_INTEGER ticks;
    QueryPerformanceFrequency(&ticks);
    return ticks.LowPart;
}
static inline __int64 now()
{
    struct { __int32 low, high; } counter;
    __asm cpuid
    __asm push EDX
    __asm rdtsc
    __asm mov counter.low, EAX
    __asm mov counter.high, EDX
    __asm pop EDX
    __asm pop EAX
    return *(__int64 *)(&counter);
}

};

我的代码失败,出现错误The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.。我猜我的英特尔处理器不支持指令rdtsc。我有一个英特尔Broadwell 5500U。。我正在寻找一种合适的方法来进行这种测量,并最终获得更准确的响应。

您提供的错误消息

ESP的值没有在函数调用中正确保存。这通常是调用用一个调用声明的函数的结果使用不同调用声明的函数指针的约定习俗

指示您调用的内联程序集函数中存在错误。假设在调用它时使用默认的调用约定,那么它就有根本的缺陷:cpuid破坏了ebx,这是一个被调用者保存的寄存器。此外,它只向堆栈推送一个参数,并弹出两个:第二个弹出实际上(很可能)是函数的返回地址,或者是作为堆栈帧一部分保存的基指针。因此,函数在调用ret时失败,因为它没有可返回的有效地址,或者运行时检测到esp的新值(从函数开头的值恢复)根本无效。这与您使用的CPU无关,因为所有x86 CPU都支持RDTSC,尽管它使用的基本时钟可能会根据CPU的当前速度状态而有所不同,这就是为什么不鼓励直接使用该指令,而且操作系统设施应该比它更受青睐,因为它们可以在各种步进中为指令的不同实现提供补偿。

看看你是如何使用C++11的-通过使用auto来判断-使用std::chrono来测量时间间隔。如果由于某种原因,这不起作用,请使用操作系统提供的功能(这看起来像Windows,所以QueryPerformanceCounter可能是要使用的)。如果这仍然不能满足您的要求,您可以通过使用__rdtsc内部函数生成rdtsc,而不必担心内联汇编。

最新更新