我正在尝试对 Java Card 进行某种定时攻击。我需要一种方法来测量发送命令和获得答案之间耗时。我正在使用 winscard.h
接口(interface),语言为c++
。 .我为 winscard.h
接口(interface)创建了一个包装器,以简化我的工作。例如发送一个 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);
}
};
我的代码因错误 ESP 的值未在函数调用中正确保存而失败。这通常是调用以一种调用约定声明的函数和以不同调用约定声明的函数指针的结果。
。我的猜测是我的英特尔处理器不支持指令 rdtsc
。我有一个英特尔 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
,这是一个被调用者保存的寄存器。此外,它只将一个参数压入堆栈,并弹出两个:第二个弹出实际上(最有可能)是函数的返回地址,或者作为堆栈帧的一部分保存的基指针。结果,该函数在调用 ret
时失败,因为它没有可返回的有效地址,或者运行时检测到 esp
的新值(已恢复来自函数开头的值)是完全无效的。这与您使用的 CPU 无关,因为所有 x86 CPU 都支持 RDTSC
- 尽管它使用的基本时钟可能因 CPU 当前速度状态而异,这就是为什么使用不鼓励直接使用指令,应该优先使用操作系统设施,因为它们为指令在不同步进上的不同实现提供补偿。
了解您如何使用 C++11 - 通过使用 auto
来判断 - 使用 std::chrono
测量时间间隔。如果由于某种原因这不起作用,请使用您的操作系统提供的工具(这看起来像 Windows,所以可能要使用 QueryPerformanceCounter
)。如果这仍然不能满足您的要求,您可以使用 __rdtsc
生成 rdtsc
内在函数,不用担心内联汇编。
关于c++ - 在 C++ 中测量 APDU 命令到 Java Card 的时间的最佳方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37196673/