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

Best way to measure the time of an APDU command to a Java Card in c++

我正在尝试对 Java Card.I 进行某种定时攻击,需要一种方法来测量发送命令和获取 answer.I 之间经过的时间使用 winscard.h 界面,语言为 c++。 .我为 winscard.h 接口创建了一个包装器,以使我的工作更轻松。例如发送 APDU 现在我正在使用这个似乎有效的代码。 根据 this 的回答,我更新了我的代码

 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. 而失败。我的猜测是我的 Intel Processor.I 不支持指令 rdtsc 有一个 Intel Broadwell 5500U。 .我正在寻找一种合适的方法来进行这种测量并最终获得更准确的响应。

您提供的错误信息

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.

表示您调用的内联汇编函数有错误。假设在调用它时使用默认调用约定,它从根本上是有缺陷的:cpuid 破坏了 ebx,这是一个被调用者保存的寄存器。此外,它只将一个参数压入堆栈,并弹出两个:第二个弹出实际上(最有可能)是函数的 return 地址,或者作为堆栈帧的一部分保存的基指针。结果,该函数在调用 ret 时失败,因为它没有指向 return 的有效地址,或者运行时检测到 esp 的新值(从函数开头的值)根本无效。这与您正在使用的 CPU 无关,因为所有 x86 CPUs 都支持 RDTSC - 尽管它使用的基本时钟可能会有所不同,具体取决于 CPU 的当前速度状态,这就是为什么不鼓励直接使用该指令的原因,OS 设施应该比它更受青睐,因为它们为指令在各种步进上的不同实现提供补偿。

了解您如何使用 C++11 - 通过使用 auto 判断 - 使用 std::chrono 测量时间间隔。如果由于某种原因这不起作用,请使用 OS 提供的工具(这看起来像 Windows,所以 QueryPerformanceCounter is probably the one to use). If this still doesn't satisfy you, you can just generate the rdtsc by using the __rdtsc 内部函数而不用担心内联汇编。