2016-05-12 42 views
1

我试图对Java Card做一些定时攻击。我需要一种方法来测量发送命令和获取答案。我使用的接口是winscard.h,语言是c++。 。我创建了一个包装到winscard.h界面,以便让我的工作更轻松。例如,发送一个APDU现在我使用这个代码似乎工作。 基于this答案,我更新了我的代码在C++中测量APDU命令到Java卡的时间的最佳方法

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。 。我正在寻找一种合适的方式来做这种测量,并最终得到更准确的答案。

+1

可能的[在Linux/Windows上测量CPU时间和挂钟时间?]的重复(http://stackoverflow.com/questions/17432502/how-can-i-measure-cpu-time-and -wall-clock-time-on-both-linux-windows) –

+0

@MichaelRoland更新了代码,更清楚地解释了我的问题 – Marga

回答

4

您提供

ESP的值未正确保存跨函数调用中的错误消息。这个 通常是调用一个函数声明的函数的结果,其中一个调用 约定,其中函数指针声明的约定为不同的调用 。

指示您调用的内联汇编函数中存在错误。假设在调用它时使用默认调用约定,它基本上是有缺陷的:cpuid销毁ebx,这是一个被调用者保存的寄存器。此外,它只将一个参数压入堆栈,并弹出两个参数:第二个弹出窗口实际上(最有可能)是该函数的返回地址,或基本指针保存为堆栈框架的一部分。因此,函数在调用ret时失败,因为它没有有效的地址返回,或者运行时检测到新值esp(它从函数开头的值恢复)仅仅是无效的。这与您使用的CPU无关,因为所有x86 CPU都支持RDTSC - 尽管它使用的基准时钟可能会因CPU的当前速度状态而有所不同,这就是为什么不直接使用该指令的原因,以及操作系统设施应该受到青睐,因为它们为不同的步进指令的不同实施提供了补偿。

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