Реферат Курсовая Конспект
Простейшие системы шифрования - раздел Компьютеры, История хакерства — Высказана Мысль Или Нет, Она Существует И Имеет Свою Власть,— Сказал Тус...
|
— Высказана мысль или нет, она существует и имеет свою власть,— сказал Туск. — Ты можешь обнаружить однажды, что грань между жизнью и смертью у Свободных, слишком тонка."
Ф. Херберт. "Дюна".
Данная глава является кратким обзором проблемы для неподготовленного читателя. Остальные могут ее смело пропустить.
Неоправданно популярный способ проверки легальности копии:
If (!IsValidUser())
{
Message ("Invalid user! Aborting. ..");
Abort;
}
транслируется компилятором приблизительно в следующий код;
CALL IsValidUser
OR AX,AX
JZ continue
push offset str_invalid_user
CALL Message
CALL Abort
continue: ; нормальное продолжение исполнения программы
и может быть легко взломан хакером изменением всего одного байта. Поменяв выделенную строку JZ continue на JMP continue, злоумышленник получает работоспособную копию программы. Независимо от алгоритма функции lsValid-User — будь то проверка ключевого диска или ввод серийного номера — совершается безусловный переход на ветку нормального продолжения исполнения программы. На языке Си исправленная программа будет выглядеть так:
IsValidUser();
if (!true)
{
Message(“Invalid user! Aborting..,");
Abort;
}
T.e. ветка {...} никогда не получит управления! На самом деле все не так просто, поскольку в исполняемом файле нужно еще найти эту инструкцию перехода. К тому же разработчики защиты это всячески пытаются затруднить. Запутывают алгоритм, используют самомодифицирующийся код, применяют недокументированные вызовы операционной системы... Однако такие препятствия хакера не смущают. Технологии противодействия заметно обгоняют эволюцию систем защиты. А с появлением дизассемблера IDA, отладчика Soft-Ice и распаковщика сир386 копание в чужом коде не только превратилось ц удовольствие, но и стало доступно широкому кругу лиц. Десять лет назад всего выше перечисленного богатства еще не было, процессор работал только в реальном режиме, и не было никакой возможности уберечь отладчик от разрушающего воздействия со стороны изучаемой программы. Хакеры "старого поколения" работали в основном карандашом, листком бумаги и головой. Зачастую код приходилось дизассемблировать в уме, а недокументированные вызовы изучали, погружаясь в недра операционной системы. Это не только требовало высокого профессионализма, но и огромного количества свободного времени, которое было нечем занять.
Россия в этом преуспела. Кадровые специалисты, скучавшие на работе, восприняли защиты как увлекательную головоломку. Так или иначе, с той поры мы настолько привыкли к бесплатному поломанному программному обеспечению, что до сих пор поддаемся соблазну купить пиратский диск, а не платить вдесятеро большую сумму фирме-производителю.
Отсюда и возникло твердое убеждение: как бы разработчик ни защищал свой продукт, все равно сломают. На самом же деле существуют алгоритмы, делающие взлом по меньшей мере неэффективным. Основанные на криптографии, они обеспечивают не только надежную, но и математически обоснованную степень защиты.
Допустим, пароль, введенный пользователем, расшифровывает рабочий код программы. Мне могут возразить, что это не спасает от банальной кражи пароля. Что помешает одному пользователю использовать пароль другого? Но если пароль взят из неочевидных источников, например электронных ключей, взлом становиться трудным делом.
Кроме того, даже использование в качестве пароля ключевого диска или файла требует по крайней мере одной легальной копии для взлома. Пока такая копия попадет к руки хакера и будет нелегально распространена, разработчик успевает продать достаточное число экземпляров продукта. Кроме того, каждый уважающий себя кодокопатель считает долгом чести самостоятельно написать генератор ключей, а не использовать уже существующий. Это позволит какое-то время поддержать объем продаж.
Впрочем, организационные проблемы выходят за рамки данной книги, и мы на этом закончим их рассмотрение. Гораздо интереснее рассмотреть популярные криптосистемы и возможные атаки на них.
Большинство защит сегодня используют шифровку своего кода в целях затруднения анализа и модификации кода. Ключ, используемый в расшифровщике, хранится непосредственно в последнем, поэтому теоретическая криптостой-кость подобной системы равна нулю. Впрочем, это не важно, так как преследуются совсем другие цели. Кроме IDA, ни один известный мне дизассемблер не может работать с шифрованным кодом. Отладчик не сможет функционировать, если декодер использует необходимые ему ресурсы. Наконец, непосредственная модификация кода становится невозможна. При этом сам алгоритм шифра и его криптостойкость не играют никакой роли! Действительно, если пароль, используемый декодером, известен, то использовать криптостойкие алгоритмы бессмысленно!
Поэтому наиболее популярными являются криптосистемы на основе логической операции хог. Одним из ее свойств является зеркальность. Повторное шифрование результата восстановит исходный текст. Шифровщик и дешифров-щик устроены одинаково, что упрощает и сокращает код. Докажем, что
а хог b хог а= b.
Для этого просто перечислим все возможные значения а и b в следующей табличке:
аb | ||
0 хог 0 хог 0 == 0 | 0 хог 1 хог 0 == 1 | |
1 хог 0 хог 1 == 0 | 1 хог 1 хог 1 == 1 |
Заметим, что хог — битовая операция. Аргументы а и b могут иметь только два значения: 0 или 1. Однако никто не запрещает проводить ту же операцию для последовательности битов. Команда процессора XOR word, const на самом деле представляет собой не word хог const, а последовательность операций над каждой парой битов двух переменных.
Теперь обратим внимание, что а хог 0 == а; а хог 1 == !а. Т.е. значащими в маске шифрования являются только единичные биты. Поэтому рекомендуется выбирать такую маску, в которой единичные и нулевые биты равномерно перемешаны. К примеру, 00001111b (OxF) будет плохой маской, так как оставляет неизменными четыре старшие бита в каждом символе шифротекста, что позволяет (как будет показано ниже) успешно атаковать шифр. Маска 01010011 полностью уничтожает вероятностное распределение исходных символов в шифротек-сте, поэтому считается хорошей.
Возможна шифровка двух видов — статическая и динамическая. В первом случае дешифровщик работает только один раз, после чего исходный текст может быть полностью восстановлен. Иными словами, наступает момент, когда не остается ни одного зашифрованного фрагмента. Такой подход имеет очень простую реализацию, но крайне неэффективен. Хакер может снять дамп с памяти в момент окончания работы расшифровщика и записать его на диск. После чего полученный файл можно будет изучать штатными средствами. Это невозможно выполнить для динамической расшифровки, когда ни в какой момент код не будет расшифрован полностью. При вызове процедуры он расшифровывается, а при выходе зашифровывается опять. Технически можно написать декодер, который расшифрует весь код в автономном режиме, но это довольно сложно и требует тщательного анализа защиты.
Покажем это на примере самошифрующейся программы. Традиционно такие программы выполняются на ассемблере, но можно реализовать их на С, Pascal и подобных языках, даже не используя ассемблерных вставок, а работая с памятью через указатели. Рассмотрим простейший пример (file://CD:SOURCE ASM_CCRYPTOOcryptOO.asm).
LEA SI, beginCrypt ; расшифровываем с этого адреса
Repeat:
XOR Byte Ptr [SI],077h ; расшифровать очередной байт
INC SI ; Переместить указатель
СМР SI, offset endCrypt ; ?Конец достигнут
JNA Repeat ; —{SI<=offset endCrypt}—
Чтобы полученная программа оказалась работоспособной, необходимо вручную зашифровать фрагмент [offset beginCrypt, offset endCrypt] по хог 0х77. Для этого можно воспользоваться утилитой HIEW, скриптом IDA или написать процедуру, которая это сделает автоматически.
Теперь сравним два дампа: до и после шифровки. Шифровка исказила исходный дамп до неузнаваемости, исчезла текстовая строка "Hello.World!". Этот прием может использоваться злоумышленником для сокрытия текстовых фрагментов в вирусах, троянских программах и т.д.
Шифровка затруднила к изучение программы. Вот что выдаст дизассемблер в нашем случае.
1AEF:0100 BE0D01 MOV SI,0010D
1AEF:0103 803477 XOR BYTE PTR [SI] ,077
1AEF:0106 46 INC SI
1AEF:0107 81FE2401 CHP SI,0124
1AEF:010B 76F6 JBE 0103
1AEF:010D C3 RET ; < отсюда все зашифровано
1AEF:010E 7ECD JLE 00DD
1AEF:0110 62 DB 62
1AEF:0111 76BA JBE 00CD
1AEF:0113 56 PUSH SI
1AEF:0114 B43F MOV AH,3F
1AEF:0116 121B ADC BL, [BP+DI]
1AEF:0118 1B18 SBB BX, [BX+SI]
1AEF:011A 5В POP BX
1AEF:01lB 57 PUSH DI
1AEF:011C 2018 AND [BX+SI] ,BL
1AEF:011E 051356 ADD AX,5613
1AEF:0121 7A7D JPE 01A0
1AEF:0l23 53 PUSH BX
Как разобраться в этой дикой мешанине кода и данных? Что делать и как с этим жить?
Тут на помощь приходит уникальный дизассемблер IDA, поддерживающий встроенный Си-подобный язык. Следующий скрипт (file;// CD; SOURCE ASM_CCRYPTOOci-yptOO.idc) выполнит все автоматически. Чтобы его запустить на выполнение, нужно дать команду: idax —ScryptOO.idc cryptOO.com
Рассмотрим, как он работает:
for (a=0x10D,a<0xl24;a++) // Цикл дешифровки
{
c=Byte(MK_FP, (0x1000,a)); // Взять байт
с = с ^ 0х77; // Расшифровать
PatchByte (MK_FP(0x1000,a),c); // Записать результат
}
Фактически мы копируем алгоритм расшифровщика, с точностью до реализации. Приведенный код расшифровывает загруженный образ файла, который потом IDA будет в состоянии дизассемблировать. Вот за эту возможность он горячо любим всеми хакерами. В самом деле, не нужно выходить из уютной и привычной среды дизассемблера в агрессивную среду отладчика. Дожидаться окончания расшифровки и записывать дамп на диск (а ведь не всякий отладчик обеспечивает такую возможность). Загружать полученный образ в дизассемблер и, если что-то не ладится, повторять все вновь.
SOURCER, являясь автоматическим пакетным дизассемблером, для этой цели не годится. Однако мы все же можем заставить его работать, если подадим на вход уже расшифрованный файл. Для этого воспользуемся не менее любимой утилитой хакеров HIEW, которая аналогичным образом обеспечивает пошаговую интерпретацию встроенного ассемблер-подобного языка.
Для начала нам потребуется узнать начало и конец зашифрованного фрагмента. Переключим HIEW в режим дизассемблера н обратим внимание на следующие строки:
00000000: BE0D01 mov si,0010D ; <-- начало зашиф. фрагмента
00000003: 803477 xor b, [si],077
00000006: 46 inc si
00000007: 81FE2401 cmp si,00124 ;<-- конец зашиф. фрагмента
0000000В; 76F6 jbe 000000003
Поскольку в com-файле базовое смещение 0х100, то истинным адресом начала будет 0x10D ~ 0х100 = 0xD. Переведем курсор на полученный адрес, введем следующий скрипт XOR AX,77 и начнем расшифровку. Код на глазах "оживет" и, словно феникс из пепла, одна за одной возникнут "родные" инструкции. Теперь файл можно сохранить на диск и обработать любым дизассемблером вплоть до debug.com! Вот только работать он больше не будет. Наша ошибка в том, что мы не удалили дешифровщик, который "не знает", что код уже расшифрован и портит его. Достаточно заменить маску шифрования 0х77 на 0х0, чтобы устранить это упущение.
Однако неограниченные возможности IDA позволяют проделать ту же самую операцию и на ее встроенном языке! Для этого нам необходимо воспользоваться файловым вводом-выводом.
while (1)
{
c=fgetc (hIn) ;
if (c==-l) break;
c=c ^ 0x77;
if (fputc (hOut, c) ,hOut)==-l) break;
}
Полученный дамп можно загрузить в любой дизассемблер (в IDA. например) и продолжить его изучение. Конечно, тот же самый скрипт не хуже будет обрабатываться и обычным компилятором Си (и даже быстрее выполняться), но это потребует компилятора (которого может и не оказаться под рукой), к тому же IDA в этом отношении просто удобнее. Дело в том, что зачастую анализ алгоритма декодера — далеко не тривиальная задача, и он заметно облегчается, когда в IDA перед глазами возникает его дизассемблированный код. Можно даже не вникать в его смысл, а просто покомандно переписать на Си. В этом отношении IDA не имеет равных.
В некоторых случаях ресурсов и быстродействия встроенного языка явно не хватает, н тогда приходится прибегать к помощи MS VC или оптимизированного ассемблера. Но в таких случаях уместнее воспользоваться другими методами.
Выше я назвал использование отладчика "агрессивным" методом. Б каком-то смысле это метод "грубой силы". Никакого вникания в алгоритм декодера не требуется. Достаточно лишь точно определить момент завершения расшифровки и скинуть дамп в файл. Это очень популярный прием, однако необходимо помнить, что жизнь "человеку с отладчиком" испортить очень легко. Возможны самые разнообразные эффекты — от блокирования трассировки до "глухого" завешивания системы. Выход из этого положения только один: использовать хороший отладчик.
Данный пример не содержит антиотладочных приемов, поэтому для его изучения подойдет любой отладчик. Воспользуемся замечательной утилитой trsutil, входящей в комплект антивируса AVP 2.2 PRO. Это очень компактный, но многофункциональный отладчик, который подходит для решения широкого спектра задач. Подробное обсуждение его возможностей впереди, а пока ознакомимся лишь с некоторыми из них.
Пошагово трассируя программу, можно наблюдать за ходом расшифровки. "В живом" виде понять алгоритм декодера несравненно легче, чем в дизассемблере. Дождавшись окончания цикла, записываем дамп. Вся операция отняла меньше минуты, тогда как использование IDA отнимет по меньшей мере десяток минут.
Однако над полученным дампом требуется еще поработать. Если не "убить" дескриптор, как уже было сказано выше, то дескриптор "убьет" код. Использование специализированных средств может ускорить и облегчить эту операцию. Обычно эту задачу возлагают на автоматические распаковщики, которые хорошо с ней справляются. Часто, но не всегда.
Один из мощнейших распаковщиков Сuр386 имеет ручной режим распаковки. По сути это полноценный интегрированный отладчик необычайной мощности. На данном этапе нас это еще не интересует, поэтому выберем простейшую пошаговую трассировку, для чего запустим сир с ключами /I cryptOO.com /d. Как нв первом случае, дожидаемся выхода из цикла (для этого можно подогнать курсор к строке OxlOD и нажать F4). В этот момент весь код расшифрован и может быть немедленно исполнен. Если бы существовал способ "сфотографировать" это состояние и записать, чтобы в любой момент можно было его восстановить, не начиная выполнения программы с самого начала... И сир как раз обеспечивает такой снимок! Он позволяет сохранять значение любых регистров и точку входа и сохранять их в ехе-файле. Для его создания необходимо выбрать пункт меню
"Create executable file" и задать длину сохраняемого фрагмента. В нашем примере она равна OxD. Никакие регистры нам сохранять не нужно, поэтому выбираем "Just create, no preserving" и нажимаем заветную кнопочку "ОК". Мы получим готовый работоспособный файл, который можно запускать, загружать в отладчик и дизассемблер в рекордно короткие сроки — на все действия вполне достаточно пяти-десяти секунд! И это при том самом впечатляющем результате, который мы получили!
Увы, сир не всесилен, и для динамической шифровки уже невозможно получить полностью расшифрованный файл, так как в любой момент будет расшифрована только часть его.
Рассмотрим простой пример динамической шифровки на основе все той же операции xor (file:/ /CD:SOURCEASM_CCRYPT02crypt02.asm).
Давайте перед выводом каждой процедуры сначала ее расшифровывать, а при выходе — вновь зашифровывать. Таким образом в любой момент будет открыта только небольшая часть кода, а остальная — зашифрована.
EXECUTE PROC NEAR
CALL CRYPT ; Расшифровываем процедуру
PUSH ВР ; Сохраняем ВР для вложенных вызовов
CALL Word ptr [ВР+2] ; Запускаем расшифрованную проц.
POP ВР ; Восстанавливаем ВР
CALL CRYPT ; Зашифровываем проц. Обратно
RETH ; —
EHDP
Чтобы данный пример мог работать, необходимо каким-то образом сообщить процедуре CRYPT начало и длину шифруемого фрагмента.
Один из вариантов — перед каждой процедурой расположить блок данных, содержащий все необходимые сведения.
СРВ macro Segin,End,XorMask ; CPM (CRYPT PREDEF BLOCK)
DW offset &End - offset &Begin
DW offset &Begin
DB XorMask
endm
Определим для удобства метод run следующим образом:
RUN macro ProcA
MOV ВР, offset &ProcA-5
CALL EXECUTE
endm
Тогда вызов подпрограммы будет выглядеть как run procl. Рассмотрим дизас-семблированный листинг этого вызова:
start proc near
mov bp, 234h
call sub_0_11A
retn
start endp
Процедура sub_0_11A и есть execute, — чтобы в этом убедиться, достаточно бегло взглянуть на нижеследующий фрагмент:
Sub_0_11A proc near
call sub_0_107
push bp
call word ptr [bp+2]
pop bp
call sub_0_107
Интересующая нас процедура находится по адресу [BP+2] == 0х234 + 0х2 = 0х236; [0х236] == 0х239. Однако дизассемблер не может восстановить код процедуры, так как он еще зашифрован.
seg000:0235 dw 239h
seg000;0239 db 0C9h
seg000:023A db 21h
seg000:023B db 75h
seg000:023C db 0DAh
seg000:023D db 7Ch
seg000:023E db 0B7h
seg000;023F db 3
И невозможно никаким образом снять дамп более чем с одной процедуры одновременно. Вообще-то данный пример при вызове вложенных процедур не зашифровывает родительские (для упрощения понимания), но это нам мало чем помогает.
Дизассемблирование программы становится невозможным. Как с этим бороться? Можно воспользоваться отладчиком, не это не будет полноценной заменой дизассемблированному листингу. Можно поочередно записывать дампы всех процедур по мере их выполнения, но это очень утомительная и бесконечно долгая процедура. И что потом делать с этой кучей дампов? До недавнего времени дизассемблирование динамических защит было сложным и неэффективным занятием, на которое отваживались далеко не все. С появлением IDA все изменилось.
Запустим несложный скрипт на выполнение (file;//CD:SOURCE ASM_CCRYPT02crypt02.idc).
static trн()
{
auto a,p,l,c,mask;
p= ScreenEA(); mask = Byte(p+4); I = Word (p);
for (a-O; a<i; a++)
{
с = Byte(p+a+5);
с - с ^ mask;
PatchByte (p+a+5, c)
}
AnalyseArea (p+5, -1);
}
Наведем курсор на начало блока СРВ и вызовем функцию try. Это еще одна особенность IDA — с помощью своих функций мы безгранично можем расширять ее возможности. Функция try теперь будет доступна из любого выполняющегося скрипта. Или с консоли. Нажмем Shift-F2 и введем try(). Было бы утомительно проделывать это каждый раз, не поддерживай IDA макросы. Можно задать любую удобную для нас горячую клавишу для вызова этой функции. Например, Alt-C.
Однако этот метод грешит тем, что придется проанализировать все функции вручную, а это потребует больших усилий. В самом деле, неудобно работать "ручками" там, где можно использовать автономный скрипт. Попытаемся использовать тот факт, что процедура EXECUTE принимает входной аргумент в регистре ВР, представляющем собой смещение СРВ. Можно предположить, что использовалась конструкция MOV ВР, offset Proc (LEA ВР, Ргос), и таким образом, найдя все вхождения MOV ВР, xxxxCALL EXECUTE мы можем автоматически расшифровать весь файл? В большинстве случаев этот способ безотказно срабатывает. Действительно, поскольку процедура расшифровки одна, то простым контекстным поиском мы можем обнаружить все ссылки на нее. Неужели все так просто? И все наши усилия по созданию динамически шифрующейся программы пропали даром? Другими словами: можно ли от всего этого защититься? Разумеется! Даже не потребуется менять алгоритм. Нужно, чтобы адрес процедуры был задан не в форме константы, а произвольным образом вычислялся. В этом случае контекстный поиск окажется бессильным.
В нашем примере сигнатурный поиск поможет расшифровать только часть процедур, большую часть которых составляют переходники к операционной системе такие как WriteString, ReadString и т.д., не содержащие в себе ни йоты интересного кода. Остальные останутся зашифрованными. Приглядимся повнима-тельнее к тому, как работает функция main:
LEA SI, scenario
Main_repeat:
LODSW
OR AX,AX
JZ main_exit
XCHG BP,AX
SUB ВР, 5
CALL EXECUTE
JMP SHORT Main_repeat
Фактически это встроенный интерпретатор, который последовательно исполняет инструкции из списка scenario. Но содержит ли scenario полный перечень процедур? Быть может, вложенные процедуры также содержат свой локальный интерпретатор?
Но существует простое и элегантное решение, которое зачастую упускают разработчики защит. В большинстве случаев все существующие процедуры расположены вплотную одна за другой. За концом одной процедуры — начало следующей. Эта банальность предельно упрощает расшифровку. Очевидным решением будет помещение между соседними процедурами случайного числа незначащих байт. К сожалению, ни один из известных мне ассемблеров или компиляторов не поддерживал такой особенности. А вручную это делать очень утомительно? Но, допустим, автор защиты пошел на такие затраты времени и все соседние процедуры разнесены от нуля до N байт. Остановит ли это хакеров? Давайте еще раз внимательно посмотрим на СРВ-структуру:
СРВ macro Begin, End,XorMask
DW offset &End - offset &Begin
DW offset &Begin
DB XorMask
endm
Обнаруживаются две закономерности. Поле [2] численно равно смещению заголовка СРВ и offset &End — offset &Begin, как правило, не больше OxFFFF. Этой избыточной информации вполне достаточно для поиска блоков СРВ и расшифровки всех существующих процедур простейшим автоматическим скриптом.
Сражение технологий взлома и защиты не прекращается ни на минуту. Каждый день рождаются все новые хитроумные скрывающие механизмы, чтобы спустя короткое время исчезнуть, освобождая место для новых. Приведенный выше пример оказался нестойким из-за ошибки в программной реализации. Существуют ли программы без ошибок? Хакеры отвечают: "Программ без ошибок не бывает. Бывает — плохо искали". Неизвестно, чего больше в этой шутке — юмора или правды.
Язык ассемблера, однако сегодня непопулярен. Можно ли писать самошифрующиеся программы на языках высокого уровня? Удивительно, но далеко не каждый программист на этот вопрос утвердительно ответит "ДА". Обычно пожимают плечами — зачем это делать? В результате подавляющее большинство программ абсолютно не защищены и легко модифицируются злоумышленниками, число которых угрожающе растет. Доходит до того, что новые версии программ и "ломки" для них появляются практически одновременно, часто их разделяет всего несколько часов.
В России бесполезно надеяться на правовую поддержку. Спасение утопающих остается задачей утопающих, которые упорно не хотят понять, что никто не поможет им кроме них самих. Пираты не будут копировать программы, если их взлом станет невыгодным и коммерчески неокупаемым. Шифровка кода — первый шаг на пути создания защиты, без которого последняя ничего не стоит.
Создание самошифрующихся программ на языках высокого уровня — сложная, но все же разрешимая задача. Для ее решения приходится учитывая специфику конкретного компилятора и операционной системы. Заметим, что в некоторых операционных системах наложен запрет на модификацию кодового сегмента. В таком случае сделать ничего нельзя. Остается либо сменить операци-онку, либо спуститься на один уровень ниже, разрабатывая защиту для работы в нулевом кольце с неограниченными правами доступа.
К счастью, MS-DOS никак не препятствует модификации программой своего собственного кода, и данная процедура будет успешно работать:
void Crypt (char *point, char *EndPoint)
{
while (Point<=EndPoint) Point[0]=(point++)[0] ^ 0х77;
}
Однако при этом будут наложены жесткие ограничения — программа должна компилироваться для TINY модели памяти. Будет очень жаль, если ваш любимый компилятор на это не рассчитан.
Попробуем выяснить, что влияет на выбор модели памяти. TINY — "крошеч-' ная" — размещает в одном сегменте и код, и данные. Следовательно, один и тот же указатель может иметь доступ как к собственному коду, так и к данным, Отметим, что в языке Си нет указателей, работающих с кодом, и только особенность выбранной модели памяти позволяет "дотянуться" до кода. Впрочем некоторые компиляторы могут проверять границы и при выходе за отведенное для мнных пространство генерировать исключение или останавливаться с сообщением об ошибке.
Модель SMALL размещает код и переменные в двух независимых сегментах. Используются только близкие указатели, адресуемые через DS. Сам DS строго указывает на сегмент данных.
Но с переходом к большой (LARGE) модели памяти все вновь меняется. При этом все указатели превращаются в далекие (сегмент: смещение) и могут адресовать как данные, так и код. Эту замечательную новость омрачает тот 'прискорбный факт, что вместе с указателями становятся далекими и вызовы процедур. В момент загрузки файла DOS вычисляет и непосредственно записывает конкретные значения сегментов во всех перемещаемых элементах. Подробнее этот процесс описан в руководстве MS-DOS для программиста: мы же просто примем к сведению, что средствами одного лишь языка высокого уровня, не Используя ассемблерных вставок, работать с перемещаемыми элементами невозможно.
– Конец работы –
Эта тема принадлежит разделу:
На сайте allrefs.net читайте: "История хакерства"
Если Вам нужно дополнительный материал на эту тему, или Вы не нашли то, что искали, рекомендуем воспользоваться поиском по нашей базе работ: Простейшие системы шифрования
Если этот материал оказался полезным ля Вас, Вы можете сохранить его на свою страничку в социальных сетях:
Твитнуть |
Новости и инфо для студентов