Ассемблерные головоломки Крис Касперски ака мыщъх Хакер, номер #081, стр. 081-112-3 В третью группу попадают все остальные команды. Использовать их можно, но только с осторожностью. Короче говоря, первые две группы — это наш активный лексикон, а третья — про запас. Получившуюся азбуку ты можешь увидеть в таблицах. Смотри! В первую группу попали все заглавные английские буквы, немного строчечных и значительная часть знаков препинания. То есть, закодировать можно практически все, что угодно, только бери и пиши! Компьютер не выбросит исключения, и наш код будет вполне успешно выполнен. Правда, восклицательного знака здесь нет. А как же "HELLO,WORLD!". Ведь без восклицательного знака оно будет ущербным, если не сказать неполноценным. Во второй группе команд ничего подобного тоже не наблюдается. Все они начинаются с "посторонних" знаков и даже если передать восклицательный знак как непосредственное значение, получится полная ахинея. Например, AND AL,21h ("$!") или CMP AL,21h ("<!"). Выглядит отвратно. На самом деле, команда с опкодом 21h все-таки есть. Это, как подсказывает Матрица, AND r/m,r16. Правда, здесь возникает побочный эффект — обращение к памяти, поэтому приходится подбивать такую регистровую пару, которая бы не вызывала исключений, например, AND [SI],SP (21h 24h или "!$") в текстовом представлении. Только надо следить, чтобы SI указывал на память, не содержащую ничего интересного, иначе последствия себя не заставят ждать. Кстати говоря, символ "$" нам очень пригодится, поскольку он служит завершителем MS-DOS строк. Для Си-кодеров, привыкших к нулевому байту, это может быть несколько неожиданно. Давайте для разминки наберем в HEX-редакторе строку "HELLO,WORLD!$" и попробуем ее дизассемблировать: 00000000: 48 dec ax ; уменьшить регистр ax на 1 00000001: 45 inc bp ; увеличить регистр bp на 1 00000002: 4C dec sp ; уменьшить регистр sp на 1 00000003: 4C dec sp ; уменьшить регистр sp на 1 00000004: 4F dec di ; уменьшить регистр di на 1 00000005: 2C 57 sub al,057 ; отнять от регистра al 57h 00000007: 4F dec di ; уменьшить регистр di на 1 00000008: 52 push dx ; затолкать в стек регистр dx 00000009: 4C dec sp ; уменьшить регистр sp на 1 0000000A: 44 inc sp ; увеличить регистр sp на 1 0000000B: 21 24 and [si],sp ; *si = sp Как видно, программа тасует регистры и в хвост, и в гриву. При этом на выходе стек оказывается несбалансированным. С одной стороны мы имеем три команды DEC SP и одну команду PUSH DX (которая уменьшает SP на 2), уменьшающие указатель вершины стека на 5 байт, а с другой — одну команду INC SP. Итого, счет 5:1! Стек оказывается опущенным на 4 байта. Следовательно, далеко не всякую текстовую строку можно непосредственно запихнуть в машинный код. В данном случае, для достижения баланса к тексту требуется добавить еще четыре буквы "D" или две команды POP reg16, которым соответствуют следующие символы: "X[YZ^_]". Например, это может быть "^HELLO,WORLD!$^". А что, выглядит вполне достойно! Теперь, разобравшись с машинным кодом, перейдем к настоящим головоломкам. [извращения начинаются] Попробуем подобрать текстовую строку, выводящую заданный текст на экран. В каноническом варианте это выглядит так: |