Как бороться с закрытыми кодами. (в дополнение саги об адаптации) (C) А. Аксенов 1996 ________________________________ Я безмерно рад, что кто-то сумел выжить после прочтения мо- ей занудной статьи об адаптации программ к TR-DOS. O чем сейчас пойдет речь? Представим такую ситуацию: начитавшись статей о переделке кодовых загрузчиков, юный хакер FEAR Soft решил продемонстриро- вать свою крутость на Родио- новской версии BATMAN-3. Если его знакомство с ассемблером ог- раничивается содержимым вышеука- занной статьи, то скорее всего через два часа он выйдет на кру- той обрыв, привяжет на шею свой монитор и застрелится. В чем дело? А дело в том, что любой мало-мальски уважающий се- бя хакер не оставит свой загруз- чик открытым для взоров дилетан- тов. Загрузчики заксоривают при помощи небольших процедурок, а при старте они расксориваются - т.е. приводятся в рабочее поло- жение. Автором термина "ксорка" считается Н.Родионов, а название происходит от того, что обычно для кодирующих процедур ис- пользуют команду XOR. XOR - сло- жение по модулю 2. Главное свойство этой операции A XOR B XOR B = A, т.е. дважды повторен- ная с одним аргументом операция нейтролизует себя, восстанавли- вая прежнее число (для XOR действует переместительный за- кон, а кому интересна теория, почитайте алгебру логики). Коро- че, рассмотрим такую программку: LD HL,adr LD BC,len LD A,(HL) <- L1 XOR 176 LD (HL),A INC HL LD A,B OR C опции цикла. JR NZ,L1 Этот пример взят из книги Н. Родионова. Как видим, эта очень простая программка при запуске обратит в полный бред то, что находится по адресу adr (len - количество кодируемых байт). Ес- ли эту программку запустить вто- рой раз, то по означенному адре- су восстановится прежняя инфор- мация. Полагаю, что суть процесса более-менее ясна. Реальные прог- раммы отличаются только способом получения аргумента ксорки. Естественно, что такой идио- тически простой ксорки Вы не встретите никогда. Как правило, для ксорки используется регистр R - своего рода внутренние часы компьютера. При выполнении каж- дой операции R увеличивает свое значение. Увы, его показания трудно связать с временем выпол- нения команды в циклах процессо- ра, которое можно взять из таб- лицы. Вот простейший пример ксорки с использованием R: XOR A LD R,A обнуление R LD HL,adr LD B,len LD A,R <- L1 XOR (HL) LD (HL),A INC HL DJNZ L1 R обнуляется при старте, так как он должен иметь конкретное значение (чтобы ксорка могла от- крыться). Теперь, - что делать, встре- тив заксоренный загрузчик? Ес- тественно, его нужно раскрыть. Как? Прокрутить ксорку и выйти обратно в монитор. Практически всегда цикл декодирования ставят в упор к программе так, что по прохождении ксорки запустятся открытые коды. Для того, чтобы по окончании декодирования выйти в монитор, нужно перенести прог- рамму немного назад (на меньшие адреса) и после цикла поставить команду, которая выполнит нужный переход. Это может быть ловушка монитора или прямой переход. Для приведенного примера можно пере- нести коды цикла на 3 байта на- зад (начиная с XOR A, до DJNZ L1 включительно), а по окончании его поставить ловушку: DJNZ L1 <-конец цикла JP MON. <-переход в монитор Перенос нужен, так как ловуш- ка занимает мeсто в памяти (2 байта - теневик Скорпиона, 3 байта - STS). Если не сделать сдвига, то ловушка будет испор- чена и по завершении цикла маши- на вылетит отнюдь не в монитор. На практике в большинстве ксорок применяется один трюк: цикл на- чинается со своего последнего байта, т.е. с числа, задающего смещение для перехода. Если пе- ренести такой цикл, то придется посчитать этот последний байт, иначе процедура просто не зацик- лится и перескочит в заксоренную область. Для раскрутки таких ксорок как нельзя более подходит STS 3.2, позволяющий набивать не коды, а ассемблерную мнемонику (т.е. можно написать адрес пря- мым текстом). Адрес вычисляется, исходя из здравого смысла: LD HL,5F52 LD DE,03EB LD A,(HL) XOR L LD (HL),A INC HL DEC DE LD A,D OR E JR NZ,? <-5F51 Очевидно, что данную процеду- ру нужно зациклить на LD A,(HL) (кстати, это из загрузчика TRANTOR). Еще одна хитрость: па- раметры ксорки иногда корректи- руются из бейсика, т.е. если взять только коды, не запуская загрузчик, то их не удастся рас- крыть простой прокруткой. Обычно меняют адреса в циклах или на- чальное значение R, а иногда ксорка использует куски бейсик- программы. Так часто делали ха- керы стран бывшего соцлагеря (deBILL GILBERT, c.c.cAPTAIN и т.п.). В наших программах иногда делают нечто подобное из кодов. Помимо XOR, для кодирования при- меняются команды циклического сдвига и просто сдвига (такая процедура будет похожа на скрол- лер бегущей строки). Очень часто встречаются вложенные ксорки, т.е. одна ксорка раскрывает сле- дующую, та - еще одну и т.д., при этом каждая проходится по всей информации. Лично мне приш- лось повозиться с процедурой, состоящей примерно из 150 вло- женных циклов на опциях сдвига, после чего я очень не люблю имя c.c.cAPTAIN (кстати, тогда я ра- ботал на ленточном 48-м при по- мощи MONS4). В последнее время достаточно часто можно встретить защиту с серией вложенных ксорок на регистре R, работающих от од- ной его установки, - т.е. при их раскрытии нужно принимать специ- альные меры для сохранения R. При использовании теневика или STS ничего делать не надо, они сами отслеживают изменения этого регистра, однако ни один другой монитор так делать не умеет. Ввиду этого перед точкой остано- ва нужно запомнить значение R: LD HL,#715E LD A,#76 LD R,A LD BC,#0133 LD A,R <-L7020 XOR B XOR C XOR (HL) LD (HL),A DEC HL DEC BC LD A,B OR C JR NZ,L7020 LD A,R <-R сохраняется в А JP MON. А перед началом следующей ксорки поставить: DEC A А уменьшается на 2 DEC A LD R,A "А" нужно уменьшить, т.к. вы- полнение LD R,A и перехода на следующий адрес увеличит R на 2. Как правило реальный цикл выгля- дит весьма наворочено, число ксорят буквально с чем попало: LD BC,#3333 LD HL,#70B2 LD DE,#0666 LD A,R <- L7063 CALL #3D2F XOR B XOR C XOR D XOR E XOR H XOR L XOR (HL) LD (HL),A INC C INC E INC D DEC HL DJNZ L7063 Вот так... Пожалуй, если Вы занимаетесь адаптацией ленточных игрушек на диск, то больших проблем у Вас не должно возни- кать. Наиболее сильномогучие ксорки можно встретить в диско- вых защитах или в настоящих фир- менных версиях игр (заграничных, естественно). Самыми неудобова- римыми обычно получаются ксорки, использующие стек (регистр SP). Вновь обратимся к книжке Н.Роди- онова: LD A,R <-LOOP XOR (HL) На момент подхода к LD (HL),A данной процедурке в LDI стеке было два нуля, DEC SP после - адрес LOOP, DEC SP затем - адрес следу- RET PE ющей ксорки. Предва- DEC SP рительные операции DEC SP выставили значения RET PO регистров R,HL,DE,BC. При выполнении DEC SP; DEC SP на вершине стека окажется адрес LOOP, по команде RET PE произой- дет возврат на LOOP, если в ходе выполнения LDI BC не стал равен нулю. Когда BC=0, RET PE проле- тается, выполняется еще два DEC SP и команда RET PO отправляет процессор выполнять следующую ксорку. Для раскрытия этого бе- зобразия можно внести в стек ад- рес входа в монитор после LOOP (не забыв зафиксировать то зна- чение, которое было там до это- го). После выхода вновь произ- вести подмену адресов и раскру- тить следующую ксорку и т.д. Для извлечения и помещения числа об- ратно в память могут использо- ваться POP и PUSH. Мрачно, прав- да? Ну и, пожалуй, последнее, - так называемые недокументирован- ные команды - команды, которые не понимает монитор - отладчик (STS и shadow monitor понимают практически все команды). Прог- раммки с таким извратом просто трудно посмотреть, но нет ника- ких препятствий, чтобы прогнать их в реальном времени (т.е. так, как было здесь описано). ________________ Все, вводный курс закончен. Желаю Вам успехов в практике. Помните, что если программа во- обще работает, то ее можно вскрыть. P.S. В защитах часто бывают ловушки, будьте внимательны - всегда подумайте, что может сот- ворить программа, если ее запус- тить. Если Вы используете тене- вик Скорпиона или STS, следите, чтобы не произошло "наезда" на их "резидент". Практически, при вскрытии ксорок всегда очень по- могают аппаратные средства, - например, "тормоз" или все та же MAGIC.