"Исчезает" guardant Code
Обнаружено непонятное поведение, мне кажется, что это ошибка в GuardantAPI или
драйверах.
Условия возникновения: Программа аварийно завершается во время выполнения GrdCodeLoad()
Проблема: При последующих запусках Guardant Code заблокирован, защита блокирует программу.
Наша программа загружает код в Guardant Code. Если во время загрузки пограмму аварийно прервать, то после этого ключик постоянно будет выдавать ошибку:
FAILURE IN : GrdCodeLoad(teh_guardant, 0x00, gcexe.size(), &gcexe[0], NULL)
ERROR CODE : 23
: Guardant dongle locked by another copy of protected application
Избавиться от ошибки (и запустить программу) можно только переподключив ключ
защиты (вытащить из USB порта, вставить обратно).
Для иллюстрации написан короткий пример, который запускает отдельный поток работы с ключом защиты. В этом потоке открывается новая сессия, происходит login, после этого в память ключа записывается программа (в принципе, любая, она всё равно не будет запускаться, при тестировании использовалась программа размером 8 кб) перед началом заливки программы в ключ, поток guardant информирует главный поток о начале операции, а главный поток с небольшой задержкой экстренно завершает выполнение программы.
Результат первого запуска:
D:\Projects\GrdTest\Release>grdtest
GrdTest sample application by iRacly 2012
A initialize and start thread...
T begin
T Opening guardant session...
T logged in, flushing...
A grd thread is flushing...
A done, aborting...
Видно, что запустился поток защиты (строки, начинающиеся с T), открыта сессия, логин на ключе, начата загрузка программы. Главный поток получил сигнал о начале загрузки и самоубился. Поведение ожилаемое, всё нормально (пока, вроде бы)
Второй запуск:
D:\Projects\GrdTest\Release>grdtest
GrdTest sample application by iRacly 2012
A initialize and start thread...
T begin
T Opening guardant session...
T logged in, flushing...
A grd thread is flushing...
FAILURE IN : GrdCodeLoad(teh_guardant, 0x00, gcexe.size(), &gcexe[0], NULL)
ERROR CODE : 23
: Guardant dongle locked by another copy of protected application
T guardant ready
T Using guardant session...
T Closing guardant session...
A done, aborting...
Видно, что поток защиты не может загрузить программу в ключ.
Дополнительный наблюдения:
Ожидание 15+ минут (как в документации к GrdCloseHandle()) -- ситуация не меняется
После переподключения Guardant Code (вытащить/вставить из USB порта) - ключ работает штатно.
Попытки вызывать GrdSetDriverMode() положительных результатов не дали
Конфигурация:
GRD API:
Version: 5.51
Release: 22.06.2011
Процессор Intel(R) Core(TM) i5-2500 CPU @ 3.30GHz
Операционная система Microsoft Windows 7 (Build 7600)
Версия драйвера Guardant 5.50.85
Модель Guardant Code USB
Дата и время выпуска 07 Jun 2010 16:20:30
Версия ключа 0.1
Тип микроконтроллера 09
Номер программы 1, 0, 0, 14
Диагностика установленных ключей Guardant: (grddiag.exe после запуска теста)
Создание дескриптора ключа (GrdCreateHandle) Успешно
Установка режима поиска ключа (GrdSetFindMode) Успешно
Поиск ключа (GrdFind) Успешно
Проверка кода доступа к ключу Данная утилита не может произвести подробное тестирование этого ключа.
Удаление дескриптора ключа (GrdCloseHandle) Успешно
Исходный код теста
// GrdTest.cpp : Defines the entry point for the console application.
//
// iRacly 2012
#include <iostream>
#include <assert.h>
#include <Windows.h>
#include <process.h>
#include <fstream>
#include "GrdAPI\grdapi.h"
#pragma comment (lib, "Grdapi32.lib")
HANDLE beginWriteEvent;
#define VERIFY_GRD(X) { int result = (X); \
if (GrdE_OK != result) { \
char szErrorMsg[1024]; \
int nRet = GrdFormatMessage(NULL, result, GrdLng_ENG, szErrorMsg, \
1024, NULL); \
std::cerr \
<< " FAILURE IN : " << #X << std::endl \
<< " ERROR CODE : " << result << std::endl \
<< " : " << szErrorMsg << std::endl; \
} \
}
unsigned __stdcall GrdThread(void* arguments)
{
std::cout << " T begin" << std::endl;
int a, b, c, d;
{
std::ifstream codes("codes.txt");
codes >> a >> b >> c >> d;
}
std::string gcexe;
{
std::ifstream app("dongle.gcexe", std::ios::binary);
assert(app.good());
size_t const chunkSize = 64 * 1024;
char chunk[chunkSize];
// Program is 64K max!
app.read(chunk, chunkSize);
std::streamsize sz = app.gcount();
assert(!app.good());
assert(sz < chunkSize);
gcexe.assign(chunk, chunk + sz);
}
HANDLE teh_guardant;
unsigned int id = 0;
BYTE abyGrd[GrdContainerSize];
{
std::cout << " T Opening guardant session..." << std::endl;
int grdRz;
grdRz = GrdStartup(GrdFMR_Local);
assert(GrdE_OK == grdRz);
teh_guardant = GrdCreateHandle(
(HANDLE)abyGrd, // Pointer to memory allocated for Grd protected container, if NULL, Grd API allocates memory for new Grd protected container by itself
GrdCHM_MultiThread,
NULL); // Reserved and must be NULL
assert(teh_guardant);
VERIFY_GRD(GrdSetAccessCodes(teh_guardant, a, b, c, d));
VERIFY_GRD(GrdSetFindMode(teh_guardant, GrdFMR_Local, 0, 0, 0, 0, 0, 0, 0, 0, GrdFMI_USB));
TGrdFindInfo GrdFindInfo;
//always look first and the only key
VERIFY_GRD(GrdFind(teh_guardant, GrdF_First, (DWORD*)&id, &GrdFindInfo));
VERIFY_GRD(GrdLogin(teh_guardant, -1, GrdLM_PerStation));
std::cout << " T logged in, flushing..." << std::endl;
BOOL resetRz = SetEvent(beginWriteEvent);
assert(resetRz);
VERIFY_GRD(GrdCodeLoad(teh_guardant, 0x00, gcexe.size(), &gcexe[0], NULL));
std::cout << " T guardant ready" << std::endl;
}
{ // use guardant here
std::cout << " T Using guardant session..." << std::endl;
}
{ // finalize
std::cout << " T Closing guardant session..." << std::endl;
VERIFY_GRD(GrdCloseHandle(teh_guardant));
VERIFY_GRD(GrdCleanup());
}
std::cout << " T end" << std::endl;
return 0;
}
int main(int argc, char* argv[])
{
std::cout << "GrdTest sample application by iRacly 2012" << std::endl;
std::cout << " A initialize and start thread..." << std::endl;
beginWriteEvent = CreateEventW(NULL, TRUE, FALSE, L"FlashingGrdProgram");
assert(beginWriteEvent);
unsigned threadID = 0;
HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, &GrdThread, NULL, 0, &threadID);
DWORD waitRz = WaitForSingleObject(beginWriteEvent, INFINITE);
assert(WAIT_OBJECT_0 == waitRz);
std::cout << " A grd thread is flushing..." << std::endl;
Sleep(30); // this is empirical value: let T print something
// harakiri
std::cout << " A done, aborting..." << std::endl;
TerminateProcess(OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId()), 0);
WaitForSingleObject(hThread, INFINITE);
return 0;
}