Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

3204

.pdf
Скачиваний:
9
Добавлен:
15.11.2022
Размер:
3.44 Mб
Скачать

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

Поиск перехватчиков API, работающих в KernelMode Драйвер успешно загружен SDT найдена (RVA = 082В80)

Ядро ntoskrnl.exe обнаружено в памяти по адресу 804D7000 SDT = 80559В80 KiST = 804E2D20 (284)

Функция ZwCreateFile (25) перехвачена

(8057164С ->

FAB6436A), перехватчик

C:\WINDOWS\system32\wiridrvNT.sys Функция ZwOpenFile (74) перехвачена (805715Е7 -> FAB64CD8), перехватчик

C:\WINDOWS\system32\winclrvNT.sys Функция ZwQueryDirectoryFile (91) перехвачена (80574DAD - FAB64842), перехватчик C:\WINDOWS\system32\winclrvNT.sys Функция ZwQuerylnformationProcess (9А) перехвачена

(8056С537 - FAB611E0), перехватчик C:\WINDOWS\system32\ windrvNT.sys

Функция ZwSetlnformationFile (ЕО) перехвачена (80579Е7Е - FAB65142), перехватчик C:\WINDOWS\system32\windrvNT.sys

Проверено функций: 284, перехвачено: 5, восстановлено: 0

1.7. Защита программ от анализа

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

81

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

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

Исходя из изложенного выше, у разработчиков программной системы защиты информации часто возникает естественное желание затруднить анализ разрабатываемой системы потенциальным нарушителем. За последние 20 – 30 лет в данной области было проведено множество исследований, в результате которых был разработан целый ряд средств и методов, позволяющих увеличить трудоемкость анализа защищаемой программы в десятки раз.

В конце 1980-х и начале 1990-х гг. защита программ от анализа применялась очень широко. Доходило до того, что отсутствие в программе средств защиты от анализа рассматривалось как проявление непрофессионализма разработчиков. Однако в первой половине 1990-х гг. ситуация кардинально изменилась, большинство разработчиков программного обеспечения перестали включать в свои программы средства защиты от анализа. Это обусловлено следующими факторами:

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

82

отлаживать защиту от отладки?» не имеет удовлетворительного ответа;

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

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

операционная система реального режима MSDOS стала вытесняться операционными системами защищенного режима Windows, OS/2 и UNIX, в которых защита от анализа реализуется заметно сложнее.

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

программы, оснащенные защитой от несанкционированного копирования, – обычно очень дорогие программы либо про граммы, предназначенные для обработки строго конфиденциальной информации;

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

83

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

Пожалуй, самым известным примером чрезмерного увлечения разработчиков программного обеспечения защитой от анализа являются системы защиты от копирования, разработанные компанией StarForce. До 40 % пользователей программ, защищенных с помощью StarForce, испытывают те или иные проблемы, связанные с системой защиты от копирования [20]. Автору лично приходилось неоднократно сталкиваться с ситуациями, когда лицензионная компьютерная игра, оснащенная защитой StarForce, воспринимает себя как контрафактную копию и отказывается запускаться. Кроме того, некоторые источники [25] отмечают наличие до августа 2006 г. программных уязвимостей StarForce, позволяющих непривилегированному пользователю несанкционированно получать административные полномочия в операционной системе. Интересно, что CNET начиная с 2006 г. классифицирует StarForce как вредоносное программное обеспечение.

Существуют специальные программные средства

StarFuck и StarForce Nightmare, отключающие защиту от копирования StarForce. Известны и методы обхода некоторых систем StarForce, не использующие специально разработанное программное обеспечение, а использующие лишь широко распространенные программные продукты Alcohol 120 % и

Daemon Tools [23].

Впрочем, бывают и удачные реализации защиты от анализа кода. Например, известная программа Skype оснащена мощнейшей защитой от анализа, которая, как ни странно,

84

ничуть не снижает эксплуатационных качеств программы и не вызывает заметных сбоев. Видимо, Skype защищали от анализа специалисты высочайшей квалификации. Другой пример удачной реализации защиты от анализа – вирус Sober, алгоритм функционирования которого удалось полностью восстановить лишь спустя четыре месяца после начала распространения вируса [17].

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

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

Пристыковочная защита. Средства защиты от анализа пристыковываются к готовому программному модулю с использованием «вирусных» алгоритмов уже после компиляции модуля. В этом случае защита от анализа не оказывает никакого влияния на отладку и сопровождение программного продукта. Разработка защитных функций выполняется отдельной группой программистов, никак не связанной с программистами, разрабатывающими основную функциональность защищаемого продукта. Часто создание пристыковочной защиты от анализа поручается отдельным фирмам, есть даже фирмы, специализирующиеся на создании пристыковочных защит, например, упомянутая выше StarForce. Если к мощности защиты от анализа не предъявляются повышенные требования, то для защиты программы может быть применена типовая система, ранее разработанная для другого программного продукта или вообще универсальная, способная пристыковаться практически к любому программному модулю заданного класса. С другой стороны,

85

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

– как только аналитик сумеет «прорваться» через барьер, создаваемый пристыковочной защитой, дальнейший анализ программы не вызывает никаких проблем.

Далее мы рассмотрим типовые методы защиты программ от анализа. Сразу отметим, что ни один из этих методов, примененный по отдельности, не дает заметного эффекта. Для построения по-настоящему мощной защиты следует применить в одной программе не менее 10 –15 различных методов защиты от анализа.

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

Динамическое изменение кода программы Данный метод является основным методом

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

Суть преобразования кода может быть различной. В простейшем случае используются стандартные программыупаковщики наподобие UPX, которые, помимо защиты от дизассемблирования, дают еще один приятный побочный эффект – исполняемый файл программы занимает в 1,5–4 раза меньше, чем до упаковки, впрочем, это преимущество в значительной степени компенсируется увеличивающимся

86

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

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

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

87

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

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

«засеивание» кода «пустышками» – командами или наборами команд, не выполняющими никаких действий, например:

xchg еах, ebx xchg ebx, еах

или push f

add еах, ebx pub еах, ebx popf

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

push f

хог еах, еах jnz RandomAddress popf

замена команд синонимами, например, замена mov еах, ebx

на

pushf push ebx sub ebx, еах add еах, ebx pop ebx popf

замена регистров и (или) локальных переменных, используемых командами, например, замена

mov еах, [ebp - 4] mov ebx, [еах + 4] mov [ebp-8], ebx

на

mov ebx, [ebp - 8] mov eax, [ebx + 4] mov [ebp-4], eax

88

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

Искусственное усложнение структуры программы Данный метод заключается в том, что для передачи

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

вызов функции через указатель на нее (косвенный вызов):

pFunction = Function;

а = pFunction (х, у, z);

Обычный вызов функции а = Function (х, у, z) ; транслируется в машинные команды:

push z push у push x

call Function mov eax, a

а вызов функции через указатель транслируется в машинные команды:

push z push у push х

call [pFunction] mov eax, a

Дизассемблеру, анализирующему данный фрагмент кода, обычно не удается определить, что указатель pFunction указывает именно на функцию Function. Если функция Function нигде не вызывается «естественным» образом, дизассемблер, возможно, будет интерпретировать ее команды как данные.

89

Даже если дизассемблер сумеет понять, что тело функции Function содержит машинные команды, дизассемблеру, скорее всего, не удастся определить, что в команде call [pFunction] вызывается именно функция Function. Если же перед разработчиком защиты ставится задача организовать противодействие «особо умным» дизассемблерам, можно порекомендовать выполнить над указателем pFunction дополнительные операции, усложняющие код настолько, что его анализ становится совершенно не по силам программе, не обладающей искусственным интеллектом. Например:

(DWORD) pFunction = (DWORD) Function -

68;

(DWORD) pFunction

+= 68;

a = pFunction (x,

y, z) ;

или

 

pFunctions[125] =

Function;

a = pFunctions[0] (125, x, y, z ) ;

-вызов функции посредством машинной команды ret (возврат из функции):

push offset m push Function ret m:

-вызов функции через обработчик исключительной ситуации:

try { a = 1 / (a - a) ;}

except(TRUE)

{a = Function (x, y, z) ;}

При этом могут использоваться обработчики исключительных ситуаций, специфичных для отладки программ:

try { asm int 3; } " except(TRUE)

{ a = Function (x, y, z) ; }

- вызов функции в отдельном потоке: s.х = х; s.y = у; s.z = z;

hThread = CreateThread (NULL, 0, Function, &s, 0, &dw);

WaitForSingleObject (hThread, TIMEOUT);

90

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]