1

我正在尝试对 Java Card 进行某种定时攻击。我需要一种方法来测量从发送命令到获得答案之间经过的时间。我正在使用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。.我正在寻找一种适当的方法来进行这种测量并最终获得更准确的响应。

4

1 回答 1

4

您提供的错误消息

ESP 的值未在函数调用中正确保存。这通常是调用使用一种调用约定声明的函数和使用另一种调用约定声明的函数指针的结果。

表示您调用的内联汇编函数有错误。假设调用时使用默认的调用约定,它的根本缺陷是:cpuiddestroys ebx,它是一个被调用者保存的寄存器。此外,它只将一个参数压入堆栈,并弹出两个:第二个弹出实际上(很可能)是函数的返回地址,或者保存为堆栈帧的一部分的基指针。结果,函数在调用 时会失败ret,因为它没有可返回的有效地址,或者运行时检测到 的新值esp(从函数开头的值恢复)根本无效。这与您使用的 CPU 无关,因为所有 x86 CPU 都支持RDTSC- 尽管它使用的基本时钟可能会根据 CPU 的当前速度状态而有所不同,这就是不鼓励直接使用指令的原因,并且应该优先使用 OS 设施,因为它们为各种指令的不同实现提供补偿踏步。

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

于 2016-05-12T21:51:14.020 回答