Архитектура Loadable Code

Добрый день!

Подскажите, как с точки зрения разработчиков правильно поместить в ключ типа Code несколько функционально независимых модулей кода? Править адреса в makefile, и "разносить" модули по flash-памяти, или сделать одну main-функцию, а модули вызывать как показано в примере "04 - Using Subfunctions" через switch-case?

С уважением,
Михаил

Re: Архитектура Loadable Code

Добрый.

Если нет необходимости обновлять модули загружаемого кода по-отдельности (и при прочих равных), то для повышения сложности анализа загружаемого кода (по принципу черного ящика), думаю, имеет смысл объединить все в один загружаемый код и передавать номер реально вызываемой функции в составе буфера ввода-вывода (не через dwP1), может быть даже не в "чистом" виде.

Re: Архитектура Loadable Code

Спасибо, интересная идея! Именно от использования dwP1 и хотелось уйти, слишком уж явно её "видно".

Re: Архитектура Loadable Code

Добрый день!

Ещё вопрос по загружаемому коду. Правильно ли я понимаю, что при вызове функции

int GRD_API GrdCodeRun(
HANDLE  hGrd,
DWORD   dwAlgoName,
DWORD   dwP1,
DWORD   *pdwRet,
DWORD   dwDataFromDongleLng,
void    *pDataFromDongle,
DWORD   dwDataToDongleLng,
void    *pDataToDongle,
void    *pReserved ); 

параметры dwDataFromDongleLng и dwDataToDongleLng всегда должны содержать размер буфера в байтах, не зависимо от того, каким типом он объявлен в программе?

Объявляю в коде ключа

extern DWORD idata[] ALIGNED;
extern DWORD odata[] ALIGNED;

а в основной программе

DWORD abInBuffer[128], abOutBuffer[128];

При вызове

 nRet = GrdCodeRun(GrdDongle.GetHandle(),
                        0x01,                   // dwAlgoName
                        1,                        // dwP1
                        &dwRet,              // pdwRet
                        0,                        // dwDataFromDongleLng
                        NULL,                  // pDataFromDongle
                        1,                        // dwDataToDongleLng
                        abOutBuffer,       // pDataToDongle
                        NULL);                // pReserved

в ключ попадает один байт, а при вызове

 nRet = GrdCodeRun(GrdDongle.GetHandle(),
                        0x01,                   // dwAlgoName
                        1,                        // dwP1
                        &dwRet,              // pdwRet
                        0,                        // dwDataFromDongleLng
                        NULL,                  // pDataFromDongle
                        sizeof(DWORD),  // dwDataToDongleLng
                        abOutBuffer,       // pDataToDongle
                        NULL);                // pReserved

всё работает корректно.

Re: Архитектура Loadable Code

Да, все верно. Размер входного и выходного буферов передается в байтах.

Re: Архитектура Loadable Code

Продолжаем вопросы по загружаемому коду.

Понятно, что выходной буфер функции GrdCodeRun шифруется и подписывается где-то в драйвере, и затем передаётся в ключ, а ответ ключа расшифровывается и помещается во входной буфер. Как влияет размер буферов ввода/вывода на скорость обмена с ключем, хотя бы порядок цифр? Если это какие-то микро-мили-секунды, то можно считать, что не влияет.

Re: Архитектура Loadable Code

На передачу 1Кб в одну сторону сейчас уходит порядка 40 мс.

Re: Архитектура Loadable Code

Спасибо, вполне приемлемая цифра!

Re: Архитектура Loadable Code

Не обнаружил во внутреннем API ключа Code функций активации/деактивации ячеек и алгоритмов. Значит ли это, что такие операции нужно выполнять через прямой доступ к определителям?

Re: Архитектура Loadable Code

Нет, прямого доступа к EEPROM получить из загружаемого кода не удастся.

Такие функции, наверное, были бы полезны, если нужно в случае чего деактивировать весь функционал ключа. Передал мысль разработчикам. Однако эти функции будут добавлены, если потребуется еще какое-то изменение микропрограммы.

Тем не менее сейчас можно использовать функцию GcaPI_Update(). К примеру, при подозрении на брутфорс выполнять XOR всех определителей алгоритмов с каким-нибудь вектором. А при необходимости их "активировать" - выполнять повторный XOR с тем же вектором.

А информацию об истории вызовов можно также хранить в защищенной ячейке / не инициализируемой области RAM.

Re: Архитектура Loadable Code

Именно против брутфорса и хотелось использовать. Например, деактивировать алгоритм, используемый автозащитой или (совсем жестоко) ячейку загружаемого кода.

Поробую сделать GcaPI_Update (жаль только, что она учитывает StatusUnchangeable).

Re: Архитектура Loadable Code

Продолжаем развивать тему. :)

Можно ли как-то узнать версию кода, находящегося во внешнем GEXE-файле, чтобы принимать решение о загрузке его в ключ? Из дескриптора ячейки кода такое значение получить можно, а вот "новее" или "старее" код в файле - не известно.

Re: Архитектура Loadable Code

Нет, стандартных механизмов для этого не предусмотрено, так как загружаться должен любой код, ключи шифрования и подписи которого соответствуют тем, что в маске. Жестко привязывать его к версии тоже нельзя, так как может потребоваться "откатиться" на предыдущую в случае чего.

В качестве решения можно попробовать именовать загружаемый файл GCEXE соответствующим образом или добавить в его начало собственную переменную с версией.

Re: Архитектура Loadable Code

Алексей Перепелов пишет:

загружаться должен любой код, ключи шифрования и подписи которого соответствуют тем, что в маске

Стандартный способ программирования ясен, но вот используются ли какие средства защиты от банального чтения взломщиком кода из микроконтроллера? Да и возможно ли это вообще -  есть ведь JTAG...

Re: Архитектура Loadable Code

Alexey_Donskoy пишет:
Алексей Перепелов пишет:

загружаться должен любой код, ключи шифрования и подписи которого соответствуют тем, что в маске

Стандартный способ программирования ясен, но вот используются ли какие средства защиты от банального чтения взломщиком кода из микроконтроллера? Да и возможно ли это вообще -  есть ведь JTAG...

Чтение взломщиком кода из микроконтроллера не удастся. Возможность доступа к микроконтроллеру через интерфейс JTAG отключается на стадии производства.