LINUX.ORG.RU
решено ФорумTalks

Защита программ от отладки


0

1

Недавно столкнулся с новым для меня способом защиты программ от отладки. При старте программа считает md4 от своей секции .text, далее сумма обрабатывается нетривиальным образом, чтобы запутать и затруднить отслеживание того, что происходит только по дизассемблерному выхлопу. Таким образом отлаживать программу, чтобы отследить ход проверки нельзя, так как отладчик, ставя брейкпоинты, изменяет код и тем самым изменяет контрольную сумму.

Сложность взлома такой защиты соответствует сложности алгоритма запутывания, так как в конце все равно идет проверка на заранее известное значение.

Возник вопрос, а возможно-ли действуя по тому-же принципу (только проверка целостности секции .text, никаких противо-отладчиковых приемов, расчитанных на конкретные отладчики) создать более стойкую защиту? То-есть нужно как-то исключить сравнение в конце.

PS: защита только от отладки, не от копирования и распространения.

★★★★

>отладчик, ставя брейкпоинты, изменяет код и тем самым изменяет контрольную сумму.

Ты уверен в этом?

Yareg ★★★
()

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

alexru ★★★★
() автор топика
Ответ на: комментарий от Yareg

Ты уверен в этом?

Если не используются апптаратные брейкпоинты, то абсолютно уверен. А аппратные работают как-то странно, по крайней мере на моей машине.

alexru ★★★★
() автор топика

>Сложность взлома такой защиты соответствует сложности алгоритма запутывания, так как в конце все равно идет проверка на заранее известное значение.

Алсо, нифига не равна, потому что можно взломать, тупо убрав проверку.

Yareg ★★★
()
Ответ на: комментарий от Yareg

Отладчик ставит на место брейпоинта код инструкции int 3 (0xcc вроде) и в прерывании все возвращает назад, чтобы продолжить выполнение.

alexru ★★★★
() автор топика
Ответ на: комментарий от Yareg

Чтобы найти место проверки нужно понять сложный алогритм, что без возможности по нему походить отладчиком не сильно легко.

alexru ★★★★
() автор топика

Исключить сравнение нельзя, но можно растиражировать. Чтобы проверялось 100 разных кусков и результат каждой проверки использовался в 100 разных местах.

AEP ★★★★★
()
Ответ на: комментарий от Yareg

И что с ним делать? Оно запускает проверку, потом в какой-то глобальной переменной сбрасывет битик и выходит, а потом совершенно в другом месте проверяет этот битик. Нужно иметь брейкпоит непосредственно на рассчете контрольной суммы.

alexru ★★★★
() автор топика
Ответ на: комментарий от Yareg

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

segfault ★★★★★
()

Можно шифровать кусочки кода, используя в качестве ключа хеш сумму либо всей секции .text, либо критического участка кода. Но ИМХО это все равно не очень стойко, так как можно снять дамп. Можно расшифровывая одни участки кода, зашифровывать другие.

uighur
()
Ответ на: комментарий от Yareg

После проверки уже поздно, все суммы храниятся на стеке и теряются сразу.

alexru ★★★★
() автор топика
Ответ на: комментарий от alexru

>Нужно иметь брейкпоит непосредственно на рассчете контрольной суммы.

Зачем? Ты же хочешь защиту от отладки, не? Я запустил отладку, послал сигнал, дальше могу хоть заотлаживаться.

Yareg ★★★
()
Ответ на: комментарий от uighur

Не понял из обсуждения, как эта защита спасает от дизассемблера?

IDA -> hex-редактор -> рабочая программа и рабочая отладка, если надо.

delete83 ★★
()
Ответ на: комментарий от segfault

Можно более извращенно - проследить, какое значение сравнивается с эталоном

Сложность заключается в поиске места сравнения, это не одна инструкция, а целая функция с кучей циклов, проверок и т.д.

alexru ★★★★
() автор топика

а еще можно пропатчить ядро чтобы оно проверяло суммы запускаемых бинарей :3

d0de-stillhet
()
Ответ на: комментарий от Yareg

Зачем? Ты же хочешь защиту от отладки, не? Я запустил отладку, послал сигнал, дальше могу хоть заотлаживаться.

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

alexru ★★★★
() автор топика
Ответ на: комментарий от delete83

Так вроде бы ОП хотел защиту от отладки, а не от дизассемблирования. Понятно, что можно снять, но такой вариант, по идее, должен давать большую стойкость по сравнению с проверкой хеша.

uighur
()
Ответ на: комментарий от delete83

Не понял из обсуждения, как эта защита спасает от дизассемблера?

От дизассемблера - никак.

IDA -> hex-редактор -> рабочая программа и рабочая отладка, если надо.

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

alexru ★★★★
() автор топика
Ответ на: комментарий от uighur

Прошу прощения. Сообщение было адресовано топик-стартеру, конечно же. Ошибочно ткнул на ваш ник. Спать пора видимо уже. :)

delete83 ★★
()
Ответ на: комментарий от alexru

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

uighur
()

В крайнем случае можно отлаживать в виртуальной машине. Bochs, например, имеет встроенный отладчик. Там уж точно программа никак не узнает, что её отлаживают.

Yareg ★★★
()
Ответ на: комментарий от uighur

брейкпоинт на чтение в этом самом месте и отладчик мгновенно спалит код, проверяющий хеш.

В каком месте? Во время обработки хеш лежит на стеке, и кроме того не стравнивается напрямую. Ставить memory breakpoint на стек - это самоубийственно, туда пишут/читают все :)

alexru ★★★★
() автор топика
Ответ на: комментарий от alexru

Вы видели IDA когда-нибудь в действии? Если код программы никак не модифицируется при запуске, то взломщику ничего не стоит разобрать алгоритм проверки md4 по шагам вплоть до итогового сравнения с предопределенным числом. Думаю, найти в ассемблерном коде участок кода, отвечающий за подсчет md4-суммы, для знающего человека не составит труда.

delete83 ★★
()
Ответ на: комментарий от Yareg

крайнем случае можно отлаживать в виртуальной машине.

Да, я об этом подумал. Не знаю правда насколько легко там делается отладка, ведь одновременно работает и ОС и друие программы.

alexru ★★★★
() автор топика
Ответ на: комментарий от delete83

то взломщику ничего не стоит разобрать алгоритм проверки md4 по шагам вплоть до итогового сравнения с предопределенным числом.

Еще раз - мы об этом знаем, я уже несколько раз написал - сложность взлома = сложности алгоритма «проверки» хеша (он не проверятеся напрямую, а через навороченную запутанную функию).

Именно в этом и вопрос - можно-ли надежнее?

alexru ★★★★
() автор топика
Ответ на: комментарий от alexru

Ну к примеру так:

1)Я хочу модифицировать код по адресу A.

2)Ставлю на адрес A брейкпоинт на чтение.

3)Запускаю прогу.

4)Отладчик останавливается на коде, вычисляющем хеш.

5)Трассирую его до моментна, когда хеш вычислен(трассировка код не модифицирует, но тормозиииит...)

6)Записываю на бумажке правильный хеш.

7)Меняю код вычисления хеша так, чтобы он всегда возвращал нужный(ну или расшифровываю зашифрованное этим хешем).

uighur
()
Ответ на: комментарий от uighur

Ну к примеру так:

Да, вариант: ставим брейкпоинт на чтение в месте расчета md4 и после этого ставим настоящий брейкпоинт там-же, так как сумма от этого места уже посчитанна. :)

alexru ★★★★
() автор топика
Ответ на: комментарий от alexru

Наиболее надежным видится метод, уже упомянутый тут мною. Правда смутно представляю, как он может быть реализован...

В любом случае, вот идея: ваш меганавороченный алгоритм, который вы пытаетесь защитить от отладчика, вы шифруете по хешу, который получаете путем подсчета контрольной суммы участка секции .text. Участка, потому что иначе непонятно, как эту контрольную сумму посчитать. Из обработки сам защищаемый алгоритм надо исключить. В итоге имеем: дизассемблер нервно курит в сторонке. Нет никакого сравнения с шаблоном, а значит, нечего корректировать для быстрого взлома программы. Попытка отладки приводит к изменению контрольной суммы и как следствие к полной неработоспособности алгоритма.

Фиг знает, насколько эта идея бредовая. Наверное полностью. Давно уже такими вещами не интересовался и не занимался.

delete83 ★★
()
Ответ на: комментарий от alexru

> Сложность заключается в поиске места сравнения, это не одна инструкция, а целая функция с кучей циклов, проверок и т.д.\

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

П.С. Хватит заниматься ерундой. Как криптолог я вам скажу: запутывание - это ни капли не защита, а в лучшем случае ее видимость. Даже возможность взлома со сложностью написания (линейно зависящей от нее) не даст права ей называть «защитой».

П.П.С. Физически нельзя дать информацию в пользование (в данном случае - код программы) и в то же время защитить ее от модификации/копирования и т.п. Шифрование блоков программы, предложенное выше, тоже не поможет. Это то же «запутывание».

segfault ★★★★★
()
Ответ на: комментарий от alexru

Единственное что, брейкпоинты на чтение тормозят все очень серьезно, несколько часиков подождать придется.

alexru ★★★★
() автор топика
Ответ на: комментарий от delete83

>Попытка отладки приводит к изменению контрольной суммы и как следствие к полной неработоспособности алгоритма.

Противоречит условию:

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

Yareg ★★★
()
Ответ на: комментарий от Yareg

Противоречит условию:

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

alexru ★★★★
() автор топика

На эту тему мыщъх статью писал, давно правда, но, вероятно, всё ещё актуально.

undertaker ★★
()
Ответ на: комментарий от Yareg

Это как раз несложно. Фейковый алгоритм можно и не шифровать. После старта программы вычисляем хеш -> расшифровываем критичный часток памяти -> подсчитываем контрольную сумму этого участка памяти и если она корректная, то работаем по нормальному алгоритму -> если контрольная сумма не сходится, идем на работающий фейковый алгоритм. Все довольны, никто ничего не заподозрит.

delete83 ★★
()
Ответ на: комментарий от alexru

Откуда информация? В бытность мою виндузятником приходлось немного этим заниматься, и существенной потери производительности замечанно не было. Тормозили memory breakpoint'ы безбожно в те времена, когда не было их аппаратной поддержки. Тогда да, приходилось изменять атрибуты страницы с нужным участком и ловить page fault'ы, сравнивая адрес с нужным.

uighur
()
Ответ на: комментарий от segfault

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

Алгоритм, управляемый битами в хеше, он модифицирует по ходу своего действия глобальные переменные и выходит.

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

П.С. Хватит заниматься ерундой.

Задача - не создать мегасовершенную защиту, а занять всех желающих заняться реверс инжинирингом на несколько часов-дней-недель.

alexru ★★★★
() автор топика
Ответ на: комментарий от uighur

Я пробовал из под виртуалки с виндой (программа есть и под винду) и OllyDbg в качестве отладчика и gdb на реальной машине (Core 2 Duo, думаю он должен уметь все что нужно) - во всех случаях исполнение замедляется оченб сильно и процесс жрет 100% CPU. Возможно я как-то не так это все готовил, конечно.

alexru ★★★★
() автор топика

ring-0 debugger смотрит на тебя как на говно

devnullopers
()
Ответ на: комментарий от alexru

t.c:

#include <stdio.h>
char str[]="Hello, world!";
main() {
		int sum=0;
		char *p=str;
		int i;
		while(*p!=0) {
				for(i=0;i<10000000; i++)
						sum+=*p;	
				p++;
		}
		printf("%d\n",sum);
}
t.gdb:
rwatch *0x80495cc
r
q
Результат:
$gcc -ggdb -O0 -o t t.c
$time gdb t -x t.gdb
GNU gdb 6.1.1 [FreeBSD]
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "i386-marcel-freebsd"...
Hardware read watchpoint 1: *134518220
Hardware read watchpoint 1: *134518220
Hardware read watchpoint 1: *134518220
Hardware read watchpoint 1: *134518220

Value = 33
0x0804848d in main () at t.c:7
7			while(*p!=0) {
gdb t -x t.gdb  0,02s user 0,02s system 2% cpu 1,534 total
$time ./t
-1274901888
./t  1,45s user 0,00s system 91% cpu 1,585 total
Просьба, за код не пинать, ибо он только для теста написан :)

uighur
()
Ответ на: комментарий от uighur

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

Единственное что, у меня GDB почему-то на не запущенную программу отказывается ставить точки останова на чтение и запись, пишет «Target does not support this type of hardware watchpoint». При этом если программу запустить и остановить, то нормально ставит.

alexru ★★★★
() автор топика

Нельзя. Более того, ты^Wавтор такой защиты соснет, когда программу запустят в эмуляторе процессора.

tailgunner ★★★★★
()

Во-первых, защита — это метод предотвращения чего-то вроде вторжения или заражения. Отладка программы — это естественный способ взаимодействия пользователя с компьютером, следовательно она не является «атакой» или «вторжением» и следовательно от неё не может быть защиты. Если же ты пытаешься препятствовать ей, ты делаешь неправильно и делать это не следует.

Xenius ★★★★★
()

Эта...это ты код вин95 наверно увидел?

darkshvein ☆☆
()
Ответ на: комментарий от tailgunner

Нельзя. Более того, ты^Wавтор такой защиты соснет, когда программу запустят в эмуляторе процессора.

Я не автор, программа чужая.

alexru ★★★★
() автор топика
Ответ на: комментарий от alexru

> Ценное в программе - алгоритм вычислений (его и защищают собственно)
Звучит как копирастия. Ценное в программе — человекочитаемый исходный код. Без него программа не стоит выеденного яйца, разве что она настолько уникальна, что раньше ничего подобного не было. В любом случае, ограничивать свободу пользователя распоряжаться своим компьютером, включая все запускаемое на нём ПО — аморально.

Xenius ★★★★★
()
Ответ на: комментарий от Xenius

Отладка программы — это естественный способ взаимодействия пользователя с компьютером,

Отладка - это одно, реверс-инжиниринг - совсем другое :)

alexru ★★★★
() автор топика
Ответ на: комментарий от Xenius

Ценное в программе — человекочитаемый исходный код

У авторов он есть, у меня - нет, программа проприетарная.

alexru ★★★★
() автор топика
Ответ на: комментарий от alexru

> Если не используются апптаратные брейкпоинты, то абсолютно уверен. А аппратные работают как-то странно, по крайней мере на моей машине.

А если под гипервизором?

cvs-255 ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.