Взлом через покрытие

       

Демонстрационный пример взлома


Давайте, в качестве упражнения напишем простейшую триальную защиту и попробуем ее взломать методом сравнения покрытий до истечения испытательного срока и после. Исходной код подопытной программы может выглядеть, например, так, как показано в листинге 2. Срок "годности" задается константами ye (год), me (месяц), md (день), которые должны быть установлены в соответствии с текущей датой (так, чтобы программа еще работала).

int expired = 0;

#define md 3

#define me 8

#define ye 2006

foo()

{

       SYSTEMTIME sy;

      

       GetSystemTime(&sy);

       if ((sy.wYear&0xF)*sy.wMonth*sy.wDay > (ye&0xF)*me*md) expired=1;



}

main()

{

       printf("coverage trial\n");

       foo();

       if (expired)

       {

              printf("trial has expired!\n");

       }

              else

       {

              printf("trial ok\n");

       }

}

Листинг 2 листинг программы coverage.c, защищенной испытательным сроком, которую мы будем ломать

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

Запускаем coverage.exe, убеждаемся, что работает (программа пишет: trial ok), а затем переводим дату за конец испытательного срока и запускаем вновь. Ага! trial has expired! Значит, надо ломать!

Рисунок 6 демонстрационная программа coverage.exe, с ограниченным сроком использования

Возвращаем дату на прежнее место и загружаем coverage.exe в OllyDbg. Затем в "View" выбираем "Run trace" и нажимаем <SHFT-F10> для вызова контекстного меню в котором говорим "log to file" и в появившемся диалоговом окне вводим имя файла — "coverage1.txt". После чего нажимаем <CTRL-F11> (Trace Into) и дожидаемся завершения работы программы.
На диске образуется файл coverage1.txt размером ~3 Мбайта. В том же самом окне "Run trace" нажимаем <SHIFT-F10> еще раз и закрываем лог-файл ("close log file").

Перезапускаем программу по <CTRL-F2>, переводим системную дату вперед (из командной строки командной date или щелкнув по часам в правом нижнем углу), возвращаемся в окно "Run Trace", нажимаем <SHIFT-F10>, "log to file" и вводим имя "coverage2.txt". Запускаем трассировку по <CTRL-F11> и по завершении выполнения программы закрываем log-файл (<SHIFT-F10>, "close log file").



Рисунок 7 определение покрытия (Run Trace) с помощью отладчика OllyDbg

Теперь у нас есть два log-файла, которые можно скормить утилите log-coverage-diff.exe, чтобы увидеть различия в покрытии до истечения испытательного срока и после:

$log-coverage-diff.exe coverage1.txt coverage2.txt

diff p1 -> p2

00401076 Main PUSH coverage.00406054

0040107B Main CALL coverage.00401085

00401080 Main ADD ESP,4

diff p2 -> p1

0040103B Main MOV DWORD PTR DS:[4068F0],1

00401067 Main PUSH coverage.00406040

0040106C Main CALL coverage.00401085

00401071 Main ADD ESP,4

00401074 Main JMP SHORT coverage.00401083

Листинг 3 результат сравнения покрытия программы до и после истечения испытательного срока

Проанализировав полученный результат (см. листинг 3), даже начинающий хакер может долгаться, что двойное слово по адресу 4068F0h представляет собой глобальный флаг истечения испытательного срока, а команда "MOV DWORD PTR DS:[4068F0], 1" — как раз и есть та редиска, которая его взводит, когда испытательный срок заканчивается. Чтобы заполучить программу в бессрочное использование достаточно заменить "MOV DWORD PTR DS:[4068F0], 1" на "MOV DWORD PTR DS:[4068F0], 0".

Загружаем coverage.exe в hiew, дважды нажимаем <ENTER> для перехода в дизассемблерный режим, давим <F5> (Goto) и вводим адрес команды MOV, предварив его символом точки, чтобы указать hiew'у, что это именно адрес, а не смещение от начала файла — ".40103B", затем нажимаем <F3> для активации режима редактирования и <ENTER> для ввода ассемблерной команды.


hiew автоматически копирует текущую инструкцию в строку редактирования и нам остается всего лишь заменить "1" на "0", нажать <F9> для сохранения изменений в файле и после выхода из hiew'а его можно запускать невзирая на текущую дату.



Рисунок 8 взлом программы coverage.exe в hiew'e

Как вариант, можно открыть coverage.exe в IDA Pro и посмотреть, что находится по адресам, выданным утилитой log-coverage-diff.exe и вокруг них. Возможно, мы найдем более быстрый путь взлома:

0401000 sub_401000   proc near

0401000                    push   ebp

0401001                    mov    ebp, esp

0401003                    sub    esp, 10h

0401006                    lea    eax, [ebp+SystemTime]

0401009                    push   eax           ; lpSystemTime

040100A                    call   ds:GetSystemTime

0401010                    mov    ecx, dword ptr [ebp+SystemTime.wYear]

0401013                    and    ecx, 0FFFFh

0401019                    and    ecx, 0Fh

040101C                    mov    edx, dword ptr [ebp+SystemTime.wMonth]

040101F                    and    edx, 0FFFFh

0401025                    imul   ecx, edx

0401028                    mov    eax, dword ptr [ebp+SystemTime.wDay]

040102B                    and    eax, 0FFFFh

0401030                    imul   ecx, eax

0401033                    cmp    ecx, 90h

0401039                    jle    short loc_401045

040103B                    mov    dword_4068F0, 1

0401045 loc_401045:

0401045                    mov    esp, ebp

0401047                    pop    ebp

0401048                    retn

0401048 sub_401000   endp

0401048

0401049 _main proc near

0401049                    push   ebp

040104A                    mov    ebp, esp

040104C                    push   offset aCoverageTrial ; "coverage trial\n"

0401051                     call   _printf

0401056                     add    esp, 4

0401059                     call   sub_401000



040105E                     cmp    dword_4068F0, 0

0401065                     jz     short loc_401076

0401067                     push   offset aTrialHasExpire ; "trial has expired!\n"

040106C                     call   _printf

0401071                    add    esp, 4

0401074                    jmp    short loc_401083

0401076 loc_401076:

0401076                    push   offset aTrialOk ; "trial ok\n"

040107B                    call   _printf

0401080                    add    esp, 4

0401083

0401083 loc_401083:

0401083                    pop    ebp

0401084                    retn

Листинг 4  фрагмент дизассемблерного листинга ломаемой программы coverage.exe, различия в покрытии до и после истечения испытательного срока выделены подчеркиванием

Как можно видеть, сердце защитного механизма сосредоточено в процедуре sub_401000, которая сравнивает текущую дату с жестко прошитой (hard-coded) константой, после чего делает jle на loc_401045 (испытательный срок еще не истек) или… не делает и тогда выполняется команда mov dword_4068F0, 1, устанавливающая глобальный флаг истечения испытательного срока, проверяемый лишь в одном-единственном месте — по адресу 040105Eh, за которым идет условный переход 0401065 jz short loc_401076, выбирающий какое из двух сообщений выводить на экран (в реальных программах флаг регистрации обычно проверяется многократно). Если мы заменим jle short loc_401045 на jmp short loc_401045, флаг истечения испытательного срока никогда не будет взведен!



Рисунок 9 наглядное отображение расхождения в покрытии исследуемой программы в IDA Pro, выполненное специальным скриптом и оформленное в виде комментариев

Для наглядности можно написать несложный скрипт на IDA-Си, считывающий результат работы log-coverage-diff.exe и отмечающий различия в покрытиях каким ни будь символом, например, "*1*" будет означать, что данная машинная команда выполнялась только в первом прогоне, а "*2*" – только во втором (см. рис. 9).Подробности о синтаксисе IDA-Си и технике написания скпитов — в книге "образ мышления — IDA PRO" электронную копию которой можно бесплатно скачать с мыщъх'иного сервера ftp://nezumi.org.ru


Содержание раздела