Категория > Новости > Фундаментальные основы хакерства. Определяем курс выполнения программ при реверсинге - «Новости»
Фундаментальные основы хакерства. Определяем курс выполнения программ при реверсинге - «Новости»18-05-2022, 00:02. Автор: Paterson |
странице автора. Раньше мы уже встречались с условным ходом выполнения программ, однако ограничивались короткими описаниями команд и поверхностным разбором выполняемых ими операций. Управляемый ход выполнения, без сомнения, самая важная веха развития программирования своего времени и затмевает многие последующие, даже такие, как структурное программирование или ООП. Только с высоты высокоуровневого языка кажется, что в условии В процессорной архитектуре x86 предусмотрен весьма «оригинальный» набор команд для перенаправления хода выполнения программного кода. «Оригинальный» не значит хороший или плохой, это значит, что он отличается от набора микропроцессоров других архитектур и производителей: ARM, MIPS, SPARC и так далее. Как ты знаешь, первый процессор этой серии создавался впопыхах для временной замены еще не готового iAPX-432, последний, в свою очередь, должен был уметь в многозадачность и управление памятью на аппаратном уровне. Чего в итоге не случилось. А x86 продолжил свое развитие. Поэтому сейчас, когда за годы эволюции процессоров серии x86 скопился набор инструкций, хакерам приходится разгребать весь этот хлам, дабы раскрутить порядок выполнения машинных инструкций. Идентификация условных операторовСуществует два вида алгоритмов — безусловные и условные. Порядок действий безусловного алгоритма всегда постоянен и не зависит от входных данных. Например, a = b + c. Порядок действий условных алгоритмов, напротив, зависит от данных, поступающих «на вход». Например:
Обрати внимание на выделенные жирным шрифтом ключевые слова «если», «то» и «иначе», называемые операторами условия или условными операторами. Без них не обходится ни одна программа (вырожденные примеры наподобие «Hello, World!» не в счет). Условные операторы — сердце любого языка программирования. Поэтому чрезвычайно важно уметь их правильно определять. В общем виде (не углубляясь в синтаксические подробности отдельных языков) оператор условия схематично изображается так:
Задача компилятора — преобразовать эту конструкцию в последовательность машинных команд, выполняющих оператор1, оператор2, если условие истинно, и операторa, операторb — если оно ложно. Однако микропроцессоры серии 80x86 поддерживают весьма скромный набор условных команд, ограниченный фактически одними условными переходами. Программистам, знакомым лишь с IBM PC, такое ограничение не покажется чем‑то неестественным, между тем существует масса процессоров, поддерживающих префикс условного выполнения инструкции. То есть вместо того, чтобы писать:
TEST ECX,ECX
JNZ xxx
MOV EAX,0x666
там поступают так:
TEST ECX,ECX
IFZ MOV EAX,0x666
Старый диалект Basic:
10 IF A=B THEN GOTO 30
20 GOTO 40
30 PRINT "A=B"
40 ... // Прочий код программы
Новый диалект Basic:
IF A=B THEN PRINT "A=B"
Если ты когда‑нибудь программировал на старых диалектах Basic, то, вероятно, помнишь, что гораздо выгоднее выполнять Большинство компиляторов (даже не оптимизирующих) инвертируют истинность условия, транслируя конструкцию
в следующий псевдокод: IF (NOT условие) THEN continue Следовательно, для восстановления исходного текста программы нам придется вновь инвертировать условие и «подцепить» блок операторов { оператор1; оператор2; } к ключевому слову
10 IF A<>B THEN 30
20 PRINT "A=B"
30 ...// Прочий код программы
можно с уверенностью утверждать, что в исходном тексте присутствовали строки
10 IF A=B THEN 30
20 PRINT "A<>B"
30 ... // Прочий код программы
Конечно, встречаются и компиляторы, страдающие многословием. Их легко распознать по безусловному переходу, следующему сразу же после условного оператора: IF (условие) THEN do В таком случае инвертировать условие не нужно. Впрочем, если это сделать, ничего страшного не произойдет, разве что код программы станет менее понятным, да и то не всегда. Рассмотрим теперь, как транслируется полная конструкция
Одни компиляторы поступают так: IF (условие) THEN do_it А другие — так: IF (NOT условие) THEN else Разница между ними в том, что вторые инвертируют истинность условия, а первые — нет. Поэтому, не зная «нрава» компилятора, определить, как выглядел подлинный исходный текст программы, невозможно! Однако это не создает проблем, ибо условие всегда можно записать так, как это удобно. Допустим, не нравится тебе вот такая конструкция:
Пиши ее так:
И никаких гвоздей! Перейти обратно к новости |