Тормоза при активации опции "Защита ресурсов"

Issues related to VMProtect
Post Reply
Petrov Dmitriy
Posts: 7
Joined: Fri Jan 22, 2016 8:41 pm

Тормоза при активации опции "Защита ресурсов"

Post by Petrov Dmitriy »

Здравствуйте!

Обновился с версии 2.12 до последней версии VMProtect. Заметил одну неприятную особенность: моя программа стала работать намного медленее, причём в тех местах, где защита не применяется вовсе (например, при построении дерева оргструктуры). При тех же настройках проекта в версии 2.12 никаких тормозов нет.

Эксперементальным путём выяснил, что тормоза появляются при активации опции "Защита ресурсов". Из руководства пользователя я не понял до конца, какие именно ресурсы имеются в виду. Если программа шифрует, например, иконки и bitmap`ы, то это может объяснить тормоза при построении графических элементов. Влияет ли эта опция на саму защиту приложения от взлома или просто прячет ресурсы от любопытных глаз?
Admin
Site Admin
Posts: 2585
Joined: Mon Aug 21, 2006 8:19 pm
Location: Russia, E-burg
Contact:

Re: Тормоза при активации опции "Защита ресурсов"

Post by Admin »

Защита ресурсов шифрует все ресурсы (битмапы, диалоги и т.д.) и возвращает указатель на них только по требованию программы, таким образом злоумышленник не сможет добраться до этой информации. В вашем случае скорее всего необходима оптимизация в плане работы с ресурсами (например все необходимые иконки можно было бы кешировать на старте или в процессе построения дерева).
Petrov Dmitriy
Posts: 7
Joined: Fri Jan 22, 2016 8:41 pm

Re: Тормоза при активации опции "Защита ресурсов"

Post by Petrov Dmitriy »

Если честно, я не понимаю что именно можно оптимизировать в моём случае. Для примера я взял процедуру загрузки должностей в таблицу TcxTreeList (компонент DexExpress).

Ниже упрощённый вариант моей процедуры.

Code: Select all

Procedure LoadPosts;
Begin
 // очищаем таблицу

 c := GetTickCount; // измеряем производительность

 PostsList.BeginUpdate;
 PostsList.Clear;

 // считывает элементы из БД
 Results := Manager.CreateCriteria<TLiteOrgTree>.AddOrder(TOrder.Asc('ElementOrder')).List;
 
  if Results.Count > 0 then
   for i := 0 to Results.Count - 1 do
    Begin
     Node := PostsList.AddChild(nil); // Добавляем строчку в таблицу
     // В зависимости от доступа и типа каждому элементу присваивается одна из иконок в TImageList. 
     // В ImageList всего загружено 9 иконок размером 16х16.
     Node.ImageIndex := Results.Items[i].ElementType;
     Node.Texts[0] := Results.Items[i].ElementName; // название должности
    End;

  Results.Free;

 PostsList.EndUpdate;

 ShowMessage(FloatToStr(GetTickCount - c) + ' мсек'); // выводим результат, сколько заняло построение таблицы
End.
Обращаю внимание, что процедура LoadPosts не включена в перечень процедур для защиты.

Запаковуем EXE и измеряем производительность:

Чистый EXE без VMProtect - 3,226 сек.
EXE с VMProtect 2.12 без защиты ресурсов - 3,328 мсек
EXE с VMProtect 3.0 без защиты ресурсов - 3,282 мсек
EXE c VMProtect 2.12 и защитой ресурсов - 10,688 мсек
EXE c VMProtect 3.0 и защитой ресурсов - прождал более 5 мин, и закрыл программу

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

Чистый EXE без VMProtect - 3,719 сек.
EXE c VMProtect 2.12 и защитой ресурсов - 12,859 мсек
EXE c VMProtect 3.0 и защитой ресурсов - снова не дождался

Как видим дело не в иконках.
Второе предположние - дело в скинах DevExpress, возможно при построении таблицы идёт запрос к каким-то графическим элементам, которые VMProtect зашифровал.
Отключаю скины (ставлю в настройках NativeStyle = TRUE) и перекомпилирую проект.

Чистый EXE без VMProtect - 3,250 сек.
EXE c VMProtect 3.0 и защитой ресурсов - без изменений

Теперь я в тупике. В таблице всего-то около 500 должностей, что там шифруется и расшифровуется так долго понять не могу. Все необходимые файлы готов сбросить куда скажите.
Last edited by Petrov Dmitriy on Mon Jan 25, 2016 9:40 pm, edited 1 time in total.
Petrov Dmitriy
Posts: 7
Joined: Fri Jan 22, 2016 8:41 pm

Re: Тормоза при активации опции "Защита ресурсов"

Post by Petrov Dmitriy »

После дальнейших экспериментов нашёл конкретный кусок кода, который томозит. Вот он:

Code: Select all

  
 if PostsList.Count > 0 then
    Begin
      for i := PostsList.Count - 1 downto 0 do
        for z := PostsList.Count - 1 downto 0 do
          if (PostsList.Items[i].StateIndex = PostsList.Items[z].StateIndex) and
            (i <> z) then
            PostsList.Items[i].StateIndex := -1;

      for i := PostsList.Count - 1 downto 0 do
        if PostsList.Items[i].StateIndex = -1 then
          PostsList.Items[i].Delete;
    End;
В этом куске я просто проверяю чтобы элементы в таблице не дублировались, нахожу дубли и удаляю. В StateIndex хранится не иконка, а ID элемента, мне так удобнее.
Да, код немного топорный, но проблем с быстродействием не возникало. Каким образом шифрование ресурсов на него влияет непонятно.

Естественно, я могу искать дубликаты более эффективно, например, при помощи TStringList и dupIgnore, но всёже, мне кажеться, что в любом случае, VMProtect не должен замедлять выполнение данного куска кода более чем в 100 раз.
Admin
Site Admin
Posts: 2585
Joined: Mon Aug 21, 2006 8:19 pm
Location: Russia, E-burg
Contact:

Re: Тормоза при активации опции "Защита ресурсов"

Post by Admin »

Присылайте минимальный пример (оригинальный EXE+VMP+MAP файлы), на котором можно воспроизвести проблему.
Petrov Dmitriy
Posts: 7
Joined: Fri Jan 22, 2016 8:41 pm

Re: Тормоза при активации опции "Защита ресурсов"

Post by Petrov Dmitriy »

Отправил пример на почту
Admin
Site Admin
Posts: 2585
Joined: Mon Aug 21, 2006 8:19 pm
Location: Russia, E-burg
Contact:

Re: Тормоза при активации опции "Защита ресурсов"

Post by Admin »

В отладчике видно, что программа постоянно формирует текст ошибки "Index %d out of bounds". Почему она не показывается пользователю - вопрос или к вам или к разработчикам грида. В процессе формирования текста ошибки идет запрос к ресурсам в результате получаются вот такие тормоза.

Стек вызовов:
Unit1.TForm1.cxButton1Click
cxTL.TcxCustomTreeList.GetItem
cxTL.TcxTreeListNode.GetItem
dxCore.cxGetResourceString
System.LoadResString

Поставьте точку останова в незащищенном приложении на System.LoadResString и по стеку посмотрите из-за чего идет обращение к невалидному индексу.

Code: Select all

 for i := 0 to cxTreeList1.Count - 1 do
  for z := 0 to cxTreeList1.Count - 1 do
   if cxTreeList1.Items[i].StateIndex = cxTreeList1.Items[z].StateIndex
    then
     Begin
      cxTreeList1.Items[i].StateIndex := -1;
     End;
Тормоза возникают конкретно здесь: if cxTreeList1.Items.StateIndex = cxTreeList1.Items[z].StateIndex
Petrov Dmitriy
Posts: 7
Joined: Fri Jan 22, 2016 8:41 pm

Re: Тормоза при активации опции "Защита ресурсов"

Post by Petrov Dmitriy »

Спасибо большое за ответ. Вы абсолютно правы! Ошибка в компоненте DevExpress. Код этого компонента очень запутанный, я не смог найти причину, по которой возникает ошибка, но зато я устранил тормоза, зайдя в файл cxTL.pas и в процедуре TcxTreeListNode.GetItem закоментировал строчку:

Code: Select all

  cxError((AIndex < 0) or (AIndex >= FCount),  cxGetResourceString(@scxIndexOutOfBounds), [AIndex]); // <!-- здесь происходит загрузка ресурсов, которая тормозит

  if Parent <> nil then
    Parent.AdjustIndexes;
  if (FLast.Index shr 1) <= AIndex  then
  begin
    Result := FLast;
    while Result.FIndex <> AIndex do
      Result := Result.FPrev;
  end
  else
  begin
    Result := FFirst;
    while Result.FIndex <> AIndex do
      Result := Result.FNext;
  end;
Это информация может быть полезна другим программистам, так как DevExpress один из самых популярных компонентов для Delphi.
Admin
Site Admin
Posts: 2585
Joined: Mon Aug 21, 2006 8:19 pm
Location: Russia, E-burg
Contact:

Re: Тормоза при активации опции "Защита ресурсов"

Post by Admin »

На самом деле можно было не лазить в чужие компоненты. Достаточно завести локальный ObjectList под создаваемые ноды и бегать уже по нему (шаблонный тип для TObjectList добавить по вкусу):

Code: Select all

var Nodes: TObjectList;
...
  Nodes := TObjectList.Create();
  for i := 0 to 300 do
   Begin
    Node := cxTreeList1.AddChild(nil);
    Node.StateIndex := i;
    Node.Texts[0] := 'Элемент ' + IntToStr(i);

    Nodes.Add(Node);
   End;

 for i := 0 to Nodes.Count - 1 do
  for z := 0 to Nodes.Count - 1 do
   if Nodes[i].StateIndex = Nodes[z].StateIndex
    then
     Begin
      Nodes[i].StateIndex := -1;
     End;

  Nodes.Free;
Post Reply