5.9.4. Полурезидентные программы

■ Полурезидентные программы - это программы, которые загружают и Выпол­няют другую программу, оставаясь при этом в памяти, а затем, после того как за­груженная программа заканчивается, они трже заканчиваются обычным образом.

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

В качестве примера напишем простой загрузчик для игры «Tie кото­рый устранит ввод пароля, требующийся при каждом запуске игры. Разумеется, это условный пример, поскольку игра никак не шифрует свои файлы, и того же эффекта можно было достигнуть, изменив всего два байта в файле front.ovl. Един­ственное преимущество нашего загрузчика будет заключаться в том, что он под­ходит для всех версий игры (от X-Wingflo Tie Fighter: Defender of the Empire).

tieload.asm

Пример полурезидентной программы -для игр компании Lucasarts: X-Wing, X-Wing: Imperial Pursuit, B-Wing, Tie Fighter,  Tie Fighter:  Defender of the

m

загрузчик, устраняющий проверку пароля

Empire

.model tiny .code .386

org 100h start:

; Освободить память после конца программы (+ стек).

mov sp,length_of_program

mov ah,4Ah

mov bx,par_length

int 21h

Для команды СОМ-программа.

Перенести стек.

Функция DOS 4Ah.

Размер в параграфах. Изменить размер выделенной памяти.

Заполнить поля ЕРВ,  содержащие сегментные адреса. mov ax.cs mov       word ptr EPB+4,ax mov       word ptr EPB+8,ax mov       word ptr EPB+OCh,ax

Загрузить программу без выполнения.

 

mov

bx, offset EPB

;   ES:BX - EPB

mov

dx, offset filenamel

;  DS:DX - имя файла (TIE.EXE).

mov

ax,4B01h

; Функция DOS 4B01h.

int

21h

; Загрузить без выполнения.

jnc

program_loaded

; Если TIE.EXE не найден,

mov

byte ptr XWING.1

; установить флаг для find_passwd ф

mov

ax,4B01h

 

mov

filename2

и попробовать

int

21h

 

jnc

program_loaded

: Если он не найден,

mov

ax,4B01h

 

mov

dx,offset filename3

; попробовать XWING.EXE.

int

21b

 

jc

error_exit

; Если и он не найден (или не загружается

 

; по какой-нибудь другой причине) -; выйти с сообщением об ошибке.

program_loaded:

Процедура проверки пароля не находится непосредственно в исполняемом файле tie.exe,. bwing.exe или xwing.exe, а подгружается позже из оверлея front.ovl, bfront.ovl или frontend.ovl соответственно. Найти команды, выполняющие чтение из этого оверлея, и установить на них наш обработчик find_passwd. eld

push cs

pop ax

add ax,par_length mov ds.axхог       эМ!     ; 05:51 - первый параграф после конца нашей программы :   (то есть начало области,   в которую была загружена ; модифицируемая программа).

mov

mov

call

jc

Заменить 6

mov mov mov mov

di,offset read_file_code cx,rf_code_l find string

error exit2

ES:DI - код для сравнения. CX - его длина. Поиск кода.

Если он не найден - выйти ;  с сообщением об ошибке. байт из найденного кода командами call find.passwd и пор. byte ptr  [si],  9Abi ; ' САРР (дальний),

word ptr  [si+1], offset find.passwd word ptr [si+3], cs byte ptr [si+5],  90h      ; NOP.

Запустить загруженную программу.

Надо записать правильные начальные значения в регистры для ЕХЕ-программы и заполнить некоторые поля ее PSP.

mov

ah,51ri

 

; Функция DOS 51h.

int

21h

 

; BX = PSP-сегмент загруженной программ

mov

ds, bx

 

Поместить его в DS

mov

es, bx

 

; и ES.  Заполнить также поля PSP:

mov

word ptr ds:[0Ah],offset exit_without_msg

mov

word ptr. ds:[0Ch],cs       ;   "адрес возврата"

mov

word ptr ds:[16h],cs       ; и  "адрес PSP предка".

lss

sp.dword ptr cs:EPB_SSSP ; Загрузитв SS:SP

jmp

dword

ptr  cs:EPB_CSIP         и передать управление на

 

 

 

точку входа программы.

XWING

db

с

тип защиты

ЕРВ *

dw

с

Запускаемый файл         среду DOS от

 

 

 

tieload.com,

 

dw

0080h,?

'и командную строку,

 

dw

005Ch,?

и первый FCB,

 

dw

006Ch,?

и второй FCB.

EPB_SSSP

dd

7

Начальный SS:SP - заполняется DOS.

EPB_CSIP

dd

9

Начальный          - заполняется DOS.

filenamel

db

"tie.exe'

,0        ;  Сначала пробуем запустити этот файл,

filename2

db

"bwing.exe",0       ;   потом этот,

ШепатеЗ

db

"xwing.exe",0      ;  а затем этот.

; Сообщения

об

 

 

errorjnsg

db

"Ошибка:

не найден ни один из файлов

 

db

"BWING.EXE,  XWING. EXE", ODh, OAh, '$'

error_msg2

db

"Ошибка:

участок кода не

; Команды, выполняющие

чтение оверлейного файла в

read_file_code:

 

 

 

db

33h,0D2h

; xor

 

db

OB4h,3Fh

; mov

 

db

OCDh,21h

; int 21h

72h

rf_code_l = $-read_file_code

разный адрес в xwing и tie)

Команды, вызывающие процедуру проверки пароля.

Аналогичный набор команд, встречается и в других местах, поэтому Пг^_ра5Б\«1 будет выполнятв дополнителвные проверки. раэзм^_с^е:

db

89h,46h,OFCh

mov

[bp-4],ax

db

• 89h,56h,OFEh

mov

[bp-2],dx

db

52h

push

dx

db

50h

push

ax

db

9Ah

call

far

passwd_l = $-passwd_code

error_exit:

mov jmp

error_exit2:

mov

exit_with_msg:

mov int

exit_without_msg:

mov int

dx,offset errorjnsg

short

dx,offset error_msg2

Вывод сообщения об ошибке 1.

Вывод сообщения об ошибке 2.

ah,9

21h

ah,4Ch

21h

Функция DOS 09h:

вывести строку на экран.

Сюда также передается управление после

завершения загруженной программы (этот адрес был

вписан в поле PSP "адрес возврата"). Функция DOS 4Ch: конец программы.

; Эту процедуру вызывает программа каждый раз, когда

; она выполняет чтение из оверлейного файла.

find_passwd proc far

; Выполнитв три команды,   которые мы заменили на call find.passwd.

xor dx.dx

mov ah,3Fh ;  Функция DOS 3Fh:

int 21л ; чтение из файла или устройства.

deactivation_point:

pushf

push push

pusha

push

pop mov

mov dec

search_for_pwd:

ds

es

cs

es

si, dx di,offset

si

По этому адресу мы запишем код команды ПЕТР, когда наша задача будет выполнена. Сохраним флаги и регистры.

ПБгБХ - начало только что прочитанного участка ; оверлейного файла. разз1д?с1_сос1е       ;  Е5:и1 - код для сравнения.

Очень скоро мы его увеличим обратно. В этом цикле найденные вхождения эталонного кода проверяются на точное соответствие коду проверки ; пароля.

С

mov

call

jc

;

; процедуры -cmp jne cmp jne cmp jne jmp

check_for_tie: cmp jne

pwd_found:

mov mov mov

pwd_not_found:

popa

pop

pop

popf ret

find_passwd

si

Процедура find.s't ring возвращает DS:SI указывающим на начало найденного кода - чтобы' искать дальше,  надо увеличить SI хотя бы на 1. Длина эталонного кода. [ Поиск его в памяти. Если он не найден - выйти, нашла очередное вхождение нашего эталонного кода вызова : проверим,  точно ли это вызов процедуры проверки пароля. byte ptr [si+10] ,00h search_for_pwd byte ptr cs:XWING,1

cx,passwd_l

find_string pwd_not_found

check_for_tie

word ptr [si+53],0774h

search_for_pwd

short pwd_found

Этот байт должен быть 00. В случае X-wing/B-wing

je

команда

должна быть здесь,

;

а в случае Tie Fighter

здесь.

word ptr [si+42],0774h search_for_pwd

;   Итак,   вызов процедуры проверки пароля найден word ptr ds:[si+8],9090h ; NOP NOP word ptr ds:[si+10],9090h ;  NOP NOP byte ptr ds:[si+12],90h     ; NOP ;   и дезактивизировать нашу процедуру byte ptr cs:deactivation_point,OCBh ; RETF

отключить его

es ds

endp

Восстановить регистры

и флаги

и вернуть управление в программу.

Выполняет поиск строки от заданного адреса до конца всей общей памяти. Вход:  ЕЭ:01 - адрес эталонной строки.

;          СХ -

ее

длина

 

 

; DS:SI

-

адрес, с

которого начинать

тоиск

;  Выход:  CF =

1,

если строка не найдена,

 

;  иначе:  CF =

0

и DS:SI

- адрес,  с которого

начинается найденная строка.

find_string

 

proc

near

 

push

 

ax

 

 

push

 

bx

 

 

push

 

dx

 

Сохранить регистры.

do_cmp: mov

 

dx,1000b

 

Поиск блоками по ЮООИ (4096

cmp_loop:

 

 

 

 

push

 

di

 

 

push

 

si

 

 

push

 

cx

 

 

mov

!

Резидентные программы

repe

cmpsb

 

; Сравнить 05:51 со строкой.

pop

cx

 

 

pop

si

 

 

pop

di .

 

 

je

found_code

 

; Если совпадение - выйти с С¥ =

inc

si

 

; Иначе - увеличитв ОБ:БІ на 1,

dec

dx

 

; уменьшить счетчик в DX

jne

cmp_loop

 

; и,  если он не ноль, продолжить.

; Пройден очередной

блок.

 

sub

si,1000h

 

; Уменьшить SI на ЮООй

mov

ax, ds

 

 

inc

ah

 

; и увеличить DS на 1.

mov

ds, ax

 

 

cmp

ax;9O00h

 

; Если мы добралисв до

jb

do_cmp

 

: сегментного адреса 9000І1 -

pop

dx

 

; восстановить регистры.

pop

bx

 

 

pop

ax

 

 

stc

 

 

; Установить СР = 1

ret

 

 

;  и выйти.

; Сюда передается управление, если

строка

найдена.

found_code:

 

 

 

pop

dx

 

; Восстановить регистры.

pop

bx

 

 

pop

ax

 

 

clc

 

 

; Установить СР = О

ret

 

 

и выйти.

find_string

endp

 

 

end_of_program:

length_of_program = $-start+100h+100h        ;   Длина программы в байтах, parjength - length_of_program + OFh

par_length = par_length/16 ; Длина программы в параграфах,

end start