Из газеты Move #02, Минск, 4.02.1997 XOR'EM ALL ------------------------------------------ (c) Ars В этот раз я не смог найти себе более глупого занятия, чем написать про ксорки. Правда, сначала я хотел сказать что-нибудь о, так сказать, приемах программирования, типа мультиколора или скроллах по бордеру, но потом передумал. Загрузите уж лучше са- ми STS'ку и посмотрите сами то, что Вас интересует. Хотя, честно говоря, сегодня уже ни одной программы не найти, в которой можно было бы спокойно покопаться. Всюду поработали хакеры, понаставив ксорок и декранчингов. Ну с decrunching'ами уж ладно, тут все понятно - полезная штука: то же что и рас- паковщик, но гораздо круче и тормознее. Не всегда можно дождаться запуска программы, так и хочется надавить Reset ( особенно, когда нет индикатора прогресса, как в дем- ке FastCode). Однако, память экономится немеряно. Взять вот к примеру Lemming'ов (by PSG), втиснутых в 128Кб(!): а ведь раньше целый диск занимали. Ну, ладно, можно и подождать немного, раз такие дела. А вот xor'ки, как раз наоборот, засоря- ют память, причем как в прямом, так и в переносном смыслах. В зависимости от сте- пени изврата они пожирают от десятков байт до десятков секторов. И не лень же кому-то все заксоривать?! Понятно, что если не лень, то значит это зачем-то необходимо. В принципе, надо понимать, ксорка является одним из способов защиты информации и ав- торских прав, хоть и очень примитивным. Непонятно только одно: от кого же все защищаются? От юзеров? Ну не для всех ведь людей слово "монитор" ассоциируется с вы- ражениями "STS" или "кнопка NMI". От хаке- ров? - разве можно защититься от хакеров? Возможно лишь только приостановить процесс взлома на несколько секунд (часов), и все равно ведь до цели доберутся. Так что, хо- чу сказать: если Вы собираетесь защитить свой продукт, то не надейтесь на ксорки! Лучше уж поставьте где-нибудь в середине кода какую-нибудь извратскую проверку, например: RLC E,(IX+#13) RET C INC SP SRL E RET PO Найти в 128 килобайтах памяти подобную процедурку и въехать зачем она нужна всег- да гораздо сложнее, чем раскрутить даже самую изощренную ксорку. А вообще-то, по моему мнению, если уж и ставить ксорку, то только такую, которую самому будет сложно взломать, даже зная, как она работает. Но возможно ли это? В заключении этого, надо полагать, не- шуточного бреда, приведу несколько самых ярких творений компьютерной мысли и спосо- бы борьбы с ними: IMP PROTECTION SYSTEM'95. Весь Mortal Combat в свое время поголовно защищался почему-то именно этой ксоркой. А некоторые люди, такие как Andy2 и Warlock, даже что- то там пытались в ней дорабатывать (пос- ледний добавил "убивалку монитора"). Сразу после запуска (#5D74) ксорка перекидывает- ся в очищенный экран и получает управле- ние. Ее начало выглядит достаточно бредо- во: пересылки между регистрами, обращения к ПЗУшке, какие-то расчеты на калькулято- ре... Думаю, что трассировать ксорку и разбираться что зачем не имеет никакого смысла. Гораздо эффективным в данном слу- чае является поиск более-менее "нормально- го кода". По адресу #40C6 обнаруживаем следующее: #40C3 JP PO,#40CA #40C6 LD A,R XOR (HL) LD (HL),A #40CA LDI RET PO DEC SP DEC SP LD L,L RET PE А это и есть стандартная стековая ксорка. Установив на этот адрес точку останова, получим следующие значения регистров: HL=#40D3 ;источник - заксоренный код DE=#44CC ;назначение - выполнимый код BC=#00FF ;длина блока Обратим внимание также на стек, а точнее на его содержимое: SP=#402F (SP)=#44CB (SP-2)=#40C3 То есть: пока BC не равно 0, адрес выхода #44CB пропускается в стеке и управление по команде RET PE передается на адрес #40C3. Как только, после очередного LDI, регистр BC станет нулем, срабатывает RET PO и осу- ществляется выход из цикла. Прокрутим раза три цикл ксорки в мониторе и далее поста- вив точку останова на адрес #44CB, мы по- падем на загрузчик. В ячейке #40DE сохра- няется адрес загрузки блока, а в #40E0-его длина. Остается добавить, что после того как мигнет синий border и начнется загруз- ка с диска, управление по стеку передается на адрес #412E. GOLDEN EAGLE PROTECTION SYSTEM. Защита ставилась на loader'ы Silicon Brains. Ос- нована на оригинальной идее использования стека в теле ксорки. Работа с памятью идет только с помощью PUSH'ей и POP'ов. Я видел несколько вариантов защиты, но они отлича- лись только несколькими командами: #5DC5 DI | EXX LD SP,#5DFB | LD A,R LD BC,#005F | XOR L LD A,#28 | LD L,A LD R,A | LD A,R #5DD0 POP DE | XOR H POP HL | LD H,A EXX | PUSH HL POP HL | LD A,R POP DE | XOR E LD A,R | LD E,A XOR E | LD A,R LD E,A | XOR D LD A,R | LD D,A XOR D | PUSH DE LD D,A | #5DFA POP DE PUSH DE | #5DFB POP HL LD A,R | POP DE XOR L | POP HL LD L,A | DEC BC LD A,R | LD A,B XOR H | OR C LD H,A | JR NZ,#5DD0 PUSH HL | #5E03 .... Разумеется, что первоначально ничего по- добного на цикл не наблюдается (здесь по- казан уже расксоренный блок), а начиная с адреса #5DFB (сюда устанавливается стек при запуске) идет невразумительный бред. Первым делом ксорка восстанавливает свои последние 8 байт (4 раза POP и 4 PUSHа), и дойдя до адреса #5DFA она обретает свой "естественный" вид. Ну a дальше с помощью 4-х POP'ов стек смещается на 8 байт вверх, т.е. на адрес #5E03, и круг замыкается... (maybe to be continued...) Из газеты Move #03, Минск, 16.03.1997 КСОРКИ ------------------------------------------ (c) Mastsoft Привет всем! В этой статье я решил про- должить тему про ксорки, которую в преды- дущем номере начал обсуждать ARS. И в этой статье я просто внесу некоторые дополнения и расскажу о некоторых новых приемах защи- ты. Итак, поехали! Первый, и пожалуй самый интересный при- ем связан со всем известной командой LDIR. Начну с особенностей этой команды. Что де- лает процессор когда встречает команду LDIR? 1. Процессор считывает код команды. 2. Из регистра HL берется байт. 3. Байт записывается в регистр DE. 4. Увеличивается регистр HL (HL=HL+1) 5. Увеличивается регистр DE (DE=DE+1) 6. Уменьшается регистр BC (BC=BC-1) Так продолжается до того, как BC станет равен 0. Самое главное в этой последовательности команд то, что ПРОЦЕССОР ПОСТОЯННО СЧИТЫ- ВАЕТ КОД КОМАНДЫ LDIR. Что же произойдет если HL залезет на код команды LDIR ?. Я думаю, что вы намек поняли. Поэкспериментировав с этой коман- дой, можно добиться интересных результа- тов. Теперь я расскажу о примитивной привяз- ке ксорки к определенной области памяти. Вот, например, примитивная ксорка: JR START STACK POP DE PUSH DE RET START XOR A LD R,A LD HL,BEG_DATA LD BC,длина в байтах. LOOP LD A,R XOR (HL) XOR H XOR L CALL STACK XOR E XOR D LD (HL),A INC HL DEC BC LD A,B OR C JR NZ,LOOP BEG_DATA............... Когда выполняется комманда CALL на стек устанавливается тот адрес, который шел не- посредственно за CALL. Процедура STACK снимает этот адрес в DE. После комманды CALL стоит XOR E, XOR D. Получается, что если взломщик перенесет ксорку в другое место в регистре DE будет другое значение и раскрутка ксорки произойдет неправильно. ОБРАТНЫЕ КСОРКИ. В последнее время появилось много так называемых ОБРАТНЫХ КСОРОК. Отличие обрат- ной ксорки от простой в том, что расксори- вание начинается не с начала расксоривае- мого блока а с конца. Например: START DI XOR A LD R,A LD HL,END_DATA LD BC,длина в байтах. LOOP LD A,R XOR (HL) XOR H XOR L LD (HL),A DEC HL DEC BC LD A,B OR C JR NZ,LOOP *** END_DATA............... Преимущество такой ксорки перед простой в том, что никак нельзя поставить точку останова (стандартными средствами). Прихо- дится трассировать ксорку от начала до конца. Согласитесь, довольно утомительное занятие. И напоследок я приведу оригинальную об- ратную ксорку : DI XOR A LD R,A LD IX,END_DATA LD HL,LOOP LOOP LD A,R XOR (IX+0) LD (IX+0),A DEC IX JP (HL) *** END_DATA.............. Не правда ли красиво? я думаю дога- даться как она работает не составит больмого труда. Из газеты Move #05, Минск, 19.05.1997 XOR'EM ALL (Продолжение) ------------------------------------------ (c) Ars MDM 249-9753 Одним из наиболее извращенных способов защиты загрузчиков являются мультиксорки. Они появились достаточно давно, когда ши- роко использовались различные ленточные протекты, типа Alcatraz'а и SpeedLock'а. Основное их назначение состояло в том, чтобы получше упрятать какой-либо нестан- дартный loader, не позволявший осуществить копирование программы обычными средствами. Защита дисковых программ также не обошлась без вложенных ксорок. Так в 1995 году фир- мой SoftLand был выпущен хит сезона - игра "Поле Чудес". Поскольку он был написан на языке Basic и, учитывая большой спрос на столь популярную продукцию, игрушка была сурово защищена - "размазана" по всему диску и слегка заксорена. Это самое "слег- ка" занимало порядка 40(!) секторов. Дру- гим ярким примером подобного кодирования является всеми (особенно Sanalex'ом) горя- чо любимая штучка под названием Multi- Protect (автор-MastSoft). Защита ставилась поверху MicroProtect'а и включала в себя стартовый Basic-блок и мультиксорку на 11 секторов. Следует сказать, что DeadLock (так назывался MultiProtect MastSoft'a), выполнил свою задачу - воровство программ для многих было остановлено на достаточ- но большой срок - до того момента, когда стали распространены дисковые копировщики типа McDonald'а. Интересно отметить, что данная защита видимо понравилась не только trader'ам Минска, но и других городов. На- пример, в игрушке SquareHead от OutLand'а использован данный протект. Что же представляет собой мультипротект ? Это последовательность примитивных ксорок типа: DI LD A,par1 LD R,A LD HL,address-1 LD DE,par2 LD BC,length cycle LD A,R XOR (HL) XOR D XOR E LD (HL),A INC HL DEC BC LD A,B OR C JR NZ,cycle address ... Последующие ксорки могут иметь точно та- кой же вид (с другими значениями парамет- ров) либо немного отличаться, например: использовать для организации цикла коман- ду DJNZ, не использовать регистров DE, и т.п. Отдельные ксорки сами по себе эле- ментарны, однако их огромное количество, измеряемое секторами, вынуждает сразу от- казаться от мысли раскрутить их вручную. Тем более, что на момент появления подоб- ных защит еще не существовало STS и от- лавливать изменение регистра R приходи- лось самостоятельно. Большим недостатком мультипротекта (в отличие от того же Alcatraz'а) являлось то, что он был очень уж примитивен в том плане, что состоял из практически одинаковых ксорок, в которых не было ничего оригинального. Т.е. защита должна была по задумке авторов, попросту говоря, взять измором незадачливого хаке- ра. Несложно было предполжить, что уста- новка защиты осуществлялась с помощью не- которой програмки, а следовательно, и процесс взлома возможно легко автоматизи- ровать. Для этого необходимо было учесть следующие обстоятельства: 1. на первом шаге цикла ксорка восстанав- ливает адрес условного перехода (ячейка address-1); 2. значение регистра R, заданное в ксор- ке, может использоваться в качестве на- чального параметра в последующих ксорках; 3. размер ксорок последовательно изменя- ется в зависимости от их типа; 4. ксорка может быть неперемещаемой. Предлагаю свой способ решения данной задачки: ;DEXORING SYSTEM ;Written by Ars 1995 st_code EQU #9EC1 ;начало ксорки len_code EQU #14E7 ;длина ксорки zapas EQU #0500 ;нужен "на всякий случай", чтобы послед- ;няя ксорка не запортила кусок кода dopusk EQU #0020 ;max возможный размер ксорки: именно по ;этому признаку осуществляется останов, то ;есть на том месте где кончаются ксорки и ;начинается loader, ради которого все и ;делалось... double EQU st_code+len_code+zapas ;копия исходного кода ксорки START EQU double+len_code ;адрес начала рабочей области ORG #9C40 DI LD HL,st_code ;Текущий адрес- LD (curr),HL ;начало ксорки LD BC,len_code ;Делаем копию кода LD DE,double ;всей ксорки LDIR NEWXOR LD A,#77 ;Поиск LD (HL),A CALL SEAR_B ;см. замечание 1 CALL WORK CALL COPY CALL START ;Расксориваем 1 LD (dexor),A ;байт - для JR NZ LD A,#20 ;Поиск JR NZ CALL SEAR_B INC DE LD A,(dexor) ;Записываем верный LD (DE),A ;адрес перехода INC DE LD (curr),DE ;Теперь раскручи- CALL WORK ;ваем всю ксорку CALL COPY CALL START JR NEWXOR ;и т.д. SEAR_B LD (byte+1),A LD HL,(curr) PUSH HL CP #20 JR Z,metka LD DE,#0006 ;Отступ для того JR plus ;чтобы пропустить metka LD DE,#0001 ;возможную коман- plus ADD HL,DE ;ду LD DE,par EX DE,HL ;где в par может POP HL ;быть код #77 BNF LD A,(DE) byte CP 0 ;Выход, если ко- RET Z ;манда найдена INC DE PUSH HL PUSH DE EX DE,HL XOR A SBC HL,DE XOR A LD BC,dopusk SBC HL,BC POP DE POP HL ;Цикл, если ко- JR C,BNF ;манда не найдена POP HL ;Полный выход, EI ;ли код не найден RET ;на длине dopusk WORK XOR A ;Копируем код EX DE,HL ;ксорок в буффер SBC HL,DE PUSH HL POP BC EX DE,HL LD DE,(buffer) LDIR LD (buffer),DE LD A,#C9 ;Установка точки LD (DE),A ;останова LD (curr),HL ;Сохраняем теку- RET ;щий адрес COPY LD HL,double LD DE,st_code ;Восстанавливаем LD BC,len_code ;"оригинал" LDIR RET curr DW 0 buffer DW START dexor DB 0 Не могу гарантировать, что это оптималь- ное решение, однако, идея, по-моему, ясна.