Низкоуровневое программирование для Дzenствующих

Вид материалаДокументы

Содержание


4. Изменения в реестре
DOS и появится знакомое нам приглашение вставить чистую дискету в дисковод А
Низкоуровневое программирование для Дzenствующих #36
Бредисловие от WASM GROUP
Гарри Поттер и девайс маглов(серия 3)
Чугайнов Н.Г.
В.Юрова "Ассемблер: учебный курс"
Итак, установка флажков переноса и переполнения производится по следующим правилам
"Положительное число + отрицательное число"
"Два отрицательных числа,сумма которых не меньше -128"
Переполнение без переноса
Перенос с переполнением
Отсутствие переноса и переполнения
Истинная таблица установки флагов переноса и переполнения для сложения
Истинная таблица установки флагов переноса и переполнения для вычитания
RNBOsproRead(packet, address, *data)
33C0 xor eax, eax ; Обнуляем eax (SP_SUCCESS)00435D11 5F
Низкоуровневое программирование для Дzenствующих #37
Бредисловие от WASM GROUP
Гарри Поттер и девайс маглов
...
Полное содержание
Подобный материал:
1   2   3   4   5   6   7   8   9   ...   42

4. Изменения в реестре


Если все работает нормально, можно несколько повысить для себя уровень сервиса при работе с этими программами. Для начала разместим wb.com в каталоге Windows (например, C:\WINDOWS). Теперь wb можно набирать, как обычную команду операционной системы, и она будет работать независимо от каталога, в котором мы находимся. Чтобы еще больше облегчить себе работу, создадим ассоциацию bot-файлов с программой wb.com; для этого придется написать соответствующий reg-файл.
Откройте “Блокнот” Windows и наберите в нем следующий текст:

REGEDIT4


[HKEY_CLASSES_ROOT\.bot]

@="botfile"


[HKEY_CLASSES_ROOT\botfile\Shell]

@=""


[HKEY_CLASSES_ROOT\botfile\Shell\open]

@=""


[HKEY_CLASSES_ROOT\botfile\Shell\open\command]

@="C:\\WINDOWS\\wb.com %1"

В последней строке вы должны указать каталог Windows на своей машине, например, C:\\Win98\\wb.com, если у вас Windows размещена в каталоге Win98. Обратите внимание, что обратная косая черта должна быть продублирована. Еще раз тщательно проверьте правильность всех данных и сохраните файл с расширением .reg, например, “bot.reg”. Из проводника Windows дважды щелкните на названии этого файла; появится запрос на подтверждение изменений в реестре. Щелкните “OK”.

Теперь, если не было сделано ошибок, при двойном щелчке на имени файла с расширением .bot откроется окно DOS и появится знакомое нам приглашение вставить чистую дискету в дисковод А:. Вставив дискету и нажав любую клавишу, мы получим загрузочную дискету. Желающие могут создать таким образом даже собственную операционную систему – причем это можно сделать на компьютере без специальных средств программирования, с использованием одного лишь отладчика debug. Остается только пожелать успеха в ваших экспериментах с загрузочным сектором.

 



- Я знаю, Грейнджер, что вы все знаете! - усмехнулся Снегг. - А вот Поттер меня огорчает. Подготовте мне к экзамену, Поттер, реферат по OpenGL. Перед сессией выступите и расскажете нам, что это такое! На сегодня все свободны.

(Далi буде...)


И да пребудет с вами сила!

PS: если могут быть проблемы с Поттер (R), заменяем по всему тексту Поттер на Портер, "Рон Уизли" на "Ром Уизки", "Гермиона Грейнджер" на "Героину Гранжер", ну и так далее :))

Низкоуровневое программирование для Дzenствующих #36

###########################################################################
#Бредисловие

Сорванные башни
(часть 3)


 

Люди смогут найти имя лишь тому, о чём думают...

(с) anonymous

 

#Бредисловие от WASM GROUP


<00E>: Слушай, а зачем ты Малфрою БИОС накрыл?
<00F>: Да придурок он, не люблю таких!
<00E>: А Поттер у тебя почему такой чайник?
<00F>: Да халявщик он, не люблю...
<00E>: а кого же любишь? :)))
"00F" меняет имя на "Наталья Березовец"
<Наталья Березовец>: А Боба Джонсона с RusFAQ люблю - гарный хлопец, и даже "Овод" читал.
<00E>: Ловко :)) То же что ли попробовать... На какую-нибудь Снегурочку :)
<00A>: Прекращаем собрание трансвеститов :))
"00E" меняет имя на "IceGirl"
: Ой, кто здесь? Стучаться надо, молодой человек!

Кстати, как я - тени не смазались? ;)
"00A" меняет имя на "RedHat"
: Теперь ок? Пора пирожки печь. :)) Намек поняли?
<Наталья Березовец>: А знаешь, почему 00А такой серьезный?

Я его на осень с кандидатским по философии оставил :)
: ... Валентин Петрович?? :О
"Наталья Березовец" меняет имя на "Цвирко В.П., д.ф., зав. каф."
<Цвирко В.П., д.ф., зав. каф.>: Ну что, студент, готов к пересдаче? ;))) Шутка!
: Так и до инфаркта... :) Ты с фамилией не угадал, а во вторых - я по IP вижу,

что ты из другого города!
"Цвирко В.П., д.ф., зав. каф." меняет имя на "00F"
<00F>: Шок - это по нашему! Жаль, за рекламу нам не отстегнут ;))

Вот кстати и муза посетила - сейчас все будет, и про ники, и про IP!
"IceGirl" меняет имя на "00E"
<00E>: К кому муза приходит обнаженная и с арфой,

а к кому - и в красной шапке с корзинкой ;)
: Ну ладно хоть никто меня про номер версии не спросил :)


Гарри Поттер и девайс маглов
(серия 3)


- Гарри, как тебе это удалось? - спросила Гермиона после семинара.
- Не знаю, я просто набрал текст... - задумчиво произнес он. - Но при чем здесь Тот?
- Все знают, что Тот, Кого Нельзя Называть мог писать программы сразу в машинном коде! - Рон смотрел на Гарри с опаской. - Говорят, что все свои вирусы он писал только так - или на ассемблере, и никогда не учил ВижуалБейсик. Теперь наверняка будут говорить, что в тебя вселился его дух, или что он на самом деле - твой родственник. К тому же ты не слышал - кто-то повесил наш сервер, Дамблдор уже второй день ходит сам не свой, теперь еще и гексы какие-то бормочет, сам слышал - "CD EB FF FF"...

...В столовой ректор попросил внимания и объявил:
- С сегодняшнего дня строжайше запрещаются любые прогулки после 9 вечера. Речь идет о вашей безопасности, поверьте! После обеда я жду старост - надо установить дежурства по комнатам. Профессора заговорят Духов и Демонов. Да, Гарри Поттера прошу подойти ко мне вечером.

- Ну и дела! - сказал Рон. - Чего он от тебя хочет? Наверняка думает, что это ты ему сервак повесил...
- Нет, тут другое, - начал Гарри, - У Снегга какой-то электронный философ сбежал, я сам слышал, - и Гарри рассказал об услышанном разговоре. - Наверное, и предупреждение из-за этого... Хотя чем может быть опасен философ, хоть и электронный? Гермиона, ты не знаешь, кто такой Эвклид?
- Кажется, тоже философ... только древний, греческий. Еще до нашей эры жил.
- Тогда это не тот, - уверенно сказал Рон. - Тогда из кремния только топоры делали!
- Кстати, Рон, а что говорил Дамблдор... ну, когда ты в лазарет угодил?
Рон, как мог, воспроизвел слова ректора, но даже Гермиона перевести это не смогла. В любом случае, к философам эти слова не имели никакого отношения!

Пока Гермиона искала, кто же такой Эвклид, Гарри решил почитать. Заклинание он помнил, и вот уже на экране новости WASM.RU. Самой свежей была статья "Перенос и переполнение - что они представляют собой на самом деле?", и Гарри погрузился в чтение.


Чугайнов Н.Г.

Перенос и переполнение - что они представляют собой на самом деле?


Данная статья ни в коем случае не претендует на полноту описания, и представляет собой лишь краткое дополнение к тем солидным учебным пособиям и справочникам, которые должны быть под рукой у каждого программиста. Просто мне не удалось найти ни в одном из подобных изданий тех элементарных сведений, которые будут изложены ниже. Видимо, авторам этот вопрос кажется настолько тривиальным и очевидным, что они не заостряют на нем внимания, полагая, что двух - трех строк достаточно для полного понимания. Однако это далеко не так - вопрос выходит далеко за те рамки, в которые его пытаются загнать авторы. А дело вот в чем.

Любой начинающий работать на языке Ассемблера программист рано или поздно в своей деятельности доходит до изучения команд, изменяющих флаги переноса и переполнения в соответствии с определенными правилами. К таковым относятся, например, команды сложения, вычитания, умножения, логических и арифметических сдвигов. Естественно, работа с этими командами требует четкого понимания понятий переноса и переполнения. (Если быть более точным, следует осознавать, каким образом знаковые или беззнаковые числа, сочетаясь в арифметических командах, дают различные комбинации флагов переноса и переполнения. Это - азбука начинающего программиста, и без ее освоения дальнейшая работа невозможна).

Раскроем любой учебник по языку Ассемблера, например, очень хороший учебник В.Юрова "Ассемблер: учебный курс". Какую информацию он содержит по нашему вопросу?

В таблице "Флаги состояния" находим следующие сведения:
"... Флаг переноса CF ... устанавливается в 1, если арифметическая операция произвела перенос из старшего бита результата. Старшим является 7, 15 или 31-й бит в зависимости от размерности операнда."
"... Флаг переполнения OF ... устанавливается в 1, если в результате операции происходит перенос (заем) в(из) старшего, знакового бита результата (биты 7, 15 или 31 для 8, 16 или 32-разрядных операндов соответственно)."

Это интересно. Получается, что автор учебника предлагает нам согласиться с тем, что:

1) Перенос происходит тогда, когда единица выносится за пределы разрядной сетки (при операции сложения) или занимается из этих пределов (при операции вычитания);

2) Переполнение происходит тогда, когда единица выносится в последний разряд числа (при операции сложения) или занимается из этого разряда (при операции вычитания).

Проверим, так ли это на самом деле. Сложим в программе два числа и проанализируем получившийся код отладчиком, обращая особое внимание на состояние флагов OF (переполнения) и CF (переноса) до и после выполнения команды. Например:

mov al, 10000000b ;//Произошел вынос единицы ТОЛЬКО за
mov bl, 10000000b ;//пределы разрядной сетки, однако...
add al, bl ;//.есть и переполнение (OF=1),

;//и перенос (CF=1)

mov al, 11111111b ;//Имели место выносы единицы КАК за
mov bl, 00000001b ;//пределы разрядной сетки, так и в старший
add al, bl ;//бит, однако перенос есть, а переполнения нет

Налицо явное противоречие теории, изложенной в учебнике, и действительности, открывшейся после манипуляций с отладчиком. Что же, продолжим изучение теории. Что утверждают в своем учебнике "Язык Ассемблера и организация ЭВМ" В.Сорокин и В.Сарычев?
"... Флаг переноса CF устанавливается в единицу, если произошел перенос из самого старшего разряда числа при команде сложения или если требуется заем для самого старшего разряда уменьшаемого при вычитании."
"... Флаг переполнения OF используется как индикатор переполнения при работе с числами со знаком. Он устанавливается в 1, если результат операции над числами со знаком выйдет за пределы допустимого диапазона результата и устанавливается в 0 в противном случае."

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

На уровне машинных команд между этими двумя видами чисел нет никакой разницы. Находящийся в памяти или в одном из регистров операнд представляет собой (в зависимости от используемой модели адресации) 8-,16- или 32-разрядное число, все разряды которого абсолютно равноправны. Понятие знака введено исключительно для возможности манипулирования (на логическом уровне) с отрицательными числами - для процессора все числа одинаковы, а для программиста они отличаются тем, что для одних высший разряд выступает в качестве информации о знаке числа (знаковые числа), а для других все разряды несут информации о самом числе (беззнаковые числа). Естественно, выделение одного разряда под знак приводит к уменьшению возможной величины знакового числа вдвое 1; так, максимальное значение беззнакового 8-разрядного числа равно 11111111b, или 255, максимальное же (минимальное) значение аналогичного знакового числа равно соответственно 01111111b, или 127 (-128, или 10000000b). Если старший разряд знакового числа равен 1, число считается отрицательным, если 0 - положительным. Чтобы определить величину знакового числа, следует обратить в нем все биты (изменить их значения с 0 на 1 и наоборот), и приписать к полученному модулю (он считается беззнаковым) знак (-), если старший бит искомого числа был равен 1 2. Исходя из этого, становится понятным различие на 1 в диапазонах для положительных и отрицательных величин (127,-128) - для последних может использоваться старший бит, который и дает единичную прибавку. Легко видеть, что больше 127 (меньше -128) знаковое число быть не может, поскольку для этих величин все информационные разряды уже взведены (сброшены), и дальнейшее увеличение (уменьшение) числа приведет к переносу в знаковый разряд (заему из него) и, соответственно, изменению знака числа...
... а это и есть пересказ иными словами того, что написано по поводу флага переполнения в учебнике "Язык Ассемблера и организация ЭВМ". То есть и здесь авторы не сообщили нам ничего нового - речь идет все о том же пресловутом переносе в знаковый бит (старший разряд). А это, как мы уже убедились, не соответствует действительности.

Популярные учебники не могут помочь нам в выяснении того, когда при выполнении арифметических команд возникает перенос, а когда - переполнение. Остается выяснить это самостоятельно, складывая между собой различные числа во всевозможных комбинациях, и анализируя состояние флагов OF и CF. При этом каждая пара чисел будет интерпретироваться дважды - сперва как две знаковых, затем как две беззнаковых величины.

mov al, 00111111b ;//Нет ни переполнения,ни переноса
mov bl, 00000001b ;//7-й бит: стал равен 0

; перенос в 7-й бит: нет
add al, bl ;//Вынос за разрядную сетку - нет

mov al, 11111101b ;//Перенос есть,переполнения нет
mov bl, 00000101b ;//7-й бит: стал равен 0

; перенос в 7-й бит: есть
add al, bl ;//Вынос за разрядную сетку - есть
;// 253 + 5 = 2 (неверно)

; ИЛИ -3 + 5 = 2 (верно)

mov al, 11111100b ;//Перенос есть,переполнения нет
mov bl, 00000101b ;//7-й бит: стал равен 0

; перенос в 7-й бит: есть
add al, bl ;//Вынос за разрядную сетку - есть
;// 252 + 5 = 1 (неверно) ИЛИ -4 + 5 = 1 (верно)

mov al, 01000000b ;//Перенос есть,переполнения нет
mov bl, 11000000b ;//7-й бит: стал равен 0

; перенос в 7-й бит: есть
add al, bl ;//Вынос за разрядную сетку - есть
;// 64 + 192 = 0 (неверно) ИЛИ 64 - 64 = 0 (верно)

mov al, 11100000b ;//Перенос есть,переполнения нет
mov bl, 01100000b ;//7-й бит: стал равен 0

; перенос в 7-й бит: есть
add al, bl ;//Вынос за разрядную сетку - есть
;// 224 + 96 = 64 (неверно) ИЛИ -32 + 96 = 64 (верно)

mov al, 01100000b ;//Перенос есть,переполнения нет
mov bl, 11100000b ;//7-й бит: стал равен 0

; перенос в 7-й бит: есть
add al, bl ;//Вынос за разрядную сетку - есть
;// 96 + 224 = 64 (неверно) ИЛИ 96 - 32 = 64 (верно)

mov al, 11100000b ;//Перенос есть,переполнения нет
mov bl, 11100000b ;//7-й бит: стал равен 1; перенос в 7-й бит:есть
add al, bl ;//Вынос за разрядную сетку - есть
;// 224 + 224 = 192 (неверно) ИЛИ -32 - 32 = -64(верно)

mov al, 11000000b ;//Перенос есть,переполнения нет
mov bl, 11000000b ;//7-й

бит: стал равен 1

; перенос в 7-й бит: есть
add al, bl ;//Вынос за разрядную сетку - есть
;// 192 + 192 = 128 (неверно) ИЛИ -64 - 64 = -128(верно)

mov al, 11111111b ;//Перенос есть,переполнения нет
mov bl, 00000001b ;//7-й бит: стал равен 0

; перенос в 7-й бит: есть
add al, bl ;//Вынос за разрядную сетку - есть
;// 255 + 1 = 0 (неверно) ИЛИ -1 + 1 = 0 (верно)

mov al, 11111111b ;//Перенос есть,переполнения нет
mov bl, 10000001b ;//7-й бит: стал равен 1

; перенос в 7-й бит: есть
add al, bl ;//Вынос за разрядную сетку - есть
;// 255 + 129 = 128 (неверно) ИЛИ -1 - 127 = -128 (верно)

mov al, 11111111b ;//Перенос есть,переполнения нет
mov bl, 11000001b ;//7-й бит: стал равен 1; перенос в 7-й бит: есть
add al, bl ;//Вынос за разрядную сетку - есть
;// 255 + 193 = 192 (неверно) ИЛИ -1 - 63 = -64 (верно)

mov al, 11111111b ;//Перенос есть,переполнения нет
mov bl, 01000001b ;//7-й бит: стал равен 0; перенос в 7-й бит: есть
add al, bl ;//Вынос за разрядную сетку - есть
;// 255 + 65 = 64 (неверно) ИЛИ -1 + 65 = 64 (верно)

mov al, 01000000b ;//Переполнение есть,переноса нет
mov bl, 01000000b ;//7-й бит: стал равен 1; перенос в 7-й бит: есть
add al, bl ;//Вынос за разрядную сетку - нет
;// 64 + 64 = 128 (верно) ИЛИ +64 + +64 = -128(неверно)

mov al, 01100000b ;//Переполнение есть,переноса нет
mov bl,

01100000b ;//7-й бит: стал равен 1; перенос в 7-й бит: есть
add al, bl ;//Вынос за разрядную сетку - нет
;// 96 + 96 = 192 (верно) ИЛИ +96 + +96 = -64 (неверно)

mov al, 01111111b ;//Переполнение есть,переноса нет
mov bl, 00000001b ;//7-й бит: стал равен 1; перенос в 7-й бит: есть
add al, bl ;//Вынос за разрядную сетку - нет
;// 127 + 1 = 128 (верно) ИЛИ +127 + +1 = -128 (неверно)

mov al, 10000000b ;//Есть и перенос,и переполнение
mov

bl, 10000000b ;//7-й бит: стал равен 0; перенос в 7-й бит: нет
add al, bl ;//Вынос за разрядную сетку - есть
;// 128 + 128 = 0 (неверно) ИЛИ -128 - 128 = 0 (неверно)

Итак, установка флажков переноса и переполнения производится по следующим правилам:


ПЕРЕНОС БЕЗ ПЕРЕПОЛНЕНИЯ (CF=1, OF=0) - тогда,когда производится перенос единицы в знаковый разряд (7,15,31-й) и перенос единицы из разрядной сетки (из 7,15 или 31-го разрядов в 8,16,32, несуществующие для регистра указанной размерности).

Сложение БЕЗЗНАКОВЫХ чисел при возникновении переноса протекает неправильно (ТОЛЬКО из-за переноса из разрядной сетки - перенос в знаковый разряд роли не играет). При интерпретации слагаемых как беззнаковых чисел перенос из разрядной сетки приводит к потере старших разрядов числа, и результат оказывается неверным.

Сложение ЗНАКОВЫХ чисел при возникновении переноса протекает правильно, так как при такой интерпретации слагаемые представляют собой ЛИБО пару "ПОЛОЖИТЕЛЬНОЕ ЧИСЛО + ОТРИЦАТЕЛЬНОЕ ЧИСЛО" (старший бит одного слагаемого равен 0, а второго - 1, и перенос из шестого (четырнадцатого, тридцатого) бита приводит к переносу в старший и переносу из разрядной сетки), и результат такого сложения не может быть неправильным - он будет находиться в пределах -128 - +127; ЛИБО пару "ДВА ОТРИЦАТЕЛЬНЫХ ЧИСЛА,СУММА КОТОРЫХ НЕ МЕНЬШЕ -128" (это означает, что сочетания единичных битов первого и второго слагаемых ОБЯЗАТЕЛЬНО приведут к переносу в старший разряд в то время,как будет произведен перенос из разрядной сетки, и знаковый бит не будет потерян; для этого и налагается условие на сумму - -127 - 1, -120 - 8, -64 - 64, НО НЕ - -127 - 2, -64 - 65). В последних случаях возникает перенос с переполнением, так как производится только перенос из разрядной сетки.

ПЕРЕПОЛНЕНИЕ БЕЗ ПЕРЕНОСА (OF=1, CF=0) - тогда, когда производится ТОЛЬКО перенос единицы в знаковый разряд.

Сложение ЗНАКОВЫХ чисел при возникновении переполнения протекает неправильно, так как слагаемые могут представлять собой ТОЛЬКО беззнаковые числа (иначе при переносе единицы из шестого бита наличие единицы в знаковом разряде приведет к переносу из разрядной сетки; в результате переполнения не будет,а будет перенос). Поэтому перенос единицы в знаковый разряд приводит к появлению знакового (отрицательного) числа, что неправильно - сложение двух положительных чисел может иметь результатом только положительное число.

Сложение БЕЗЗНАКОВЫХ чисел в данном случае протекает правильно,так как для этих чисел 7-й бит не играет особой роли и представляет собой лишь добавочный разряд; перенос в него не приводит к ошибке.

ПЕРЕНОС С ПЕРЕПОЛНЕНИЕМ (CF=1,OF=1) - тогда,когда производится ТОЛЬКО перенос единицы из разрядной сетки.

Сложение БЕЗЗНАКОВЫХ чисел в данном случае протекает неправильно, так как перенос единицы из разрядной сетки приводит к потере старшего разряда.

Сложение ЗНАКОВЫХ чисел ТОЖЕ протекает неправильно, так как в результате переноса из разрядной сетки теряется знаковый бит,и сумма двух отрицательных чисел (а перенос с переполнением возможен только при сложении двух отрицательных чисел,т.к. для переноса единицы из разрядной сетки без переноса в знаковый бит необходимы единицы в старших разрядах обоих слагаемых) превращается в положительное число,что неправильно.

ОТСУТСТВИЕ ПЕРЕНОСА И ПЕРЕПОЛНЕНИЯ - тогда, когда нет переносов ни в знаковый разряд, ни из разрядной сетки.

На основании всего вышеизложенного может быть составлена следующая
Истинная таблица установки флагов переноса и переполнения для сложения:

Перенос из разрядной сетки

Перенос в знаковый бит

Флаги

Есть

Есть

CF=1, OF=0

Есть

Нет

CF=1, OF=1

Нет

Есть

CF=0, OF=1

Нет

Нет

CF=0, OF=0

Совершенно аналогично операциям сложения можно произвести ряд операций вычитания над знаковыми и беззнаковыми числами, отслеживая зависимость флагов OF и CF от наличия заемов из старшего и из "запредельного" разрядов.

mov al, 11100000b ;//Нет ни переполнения,ни переноса
mov bl, 00100000b ;//Заем в 7-й бит: нет; заем из 7-го бита: нет
sub al, bl

mov al, 00111111b ;//Перенос есть,переполнения нет
mov bl, 11111111b ;//Заем в 7-й бит: есть; заем из 7-го бита: есть
sub al, bl

mov al, 10000011b ;//Перенос есть,переполнения нет
mov bl, 10011010b ;//Заем в 7-й бит: есть; заем из 7-го бита: есть
sub al,

bl

mov al, 10000000b ;//Перенос есть,переполнения нет
mov bl, 10000001b ;//Заем в 7-й бит: есть; заем из 7-го бита: есть
sub al, bl

mov al, 10000000b ;//Перенос есть,переполнения нет
mov bl, 11000000b ;//Заем в 7-й бит: есть; заем из 7-го бита: есть
sub al, bl

mov al, 10001010b ;//Перенос есть,переполнения нет
mov bl, 10100101b ;//Заем в 7-й бит: есть; заем из 7-го бита: есть
sub

al, bl

mov al, 10000000b ;//Переполнение есть,переноса нет
mov bl, 01000000b ;//Заем в 7-й бит: нет; заем из 7-го бита: есть
sub al, bl

mov al, 10000000b ;//Переполнение есть,переноса нет
mov bl, 00000001b ;//Заем в 7-й бит: нет; заем из 7-го бита: есть
sub al, bl

mov al, 01000000b ;//Есть и переполнение,и перенос
mov bl, 11000000b ;//Заем в 7-й бит: есть; заем из 7-го бита: нет
sub

al, bl

mov al, 01100000b ;//Есть и переполнение,и перенос
mov bl, 10100000b ;//Заем в 7-й бит: есть; заем из 7-го бита: нет
sub al, bl

mov al, 01111111b ;//Есть и переполнение,и перенос
mov bl, 11111111b ;//Заем в 7-й бит: есть; заем из 7-го бита: нет
sub al, bl

mov al, 01110011b ;//Есть и переполнение,и перенос
mov bl, 10110111b ;//Заем в 7-й бит: есть; заем из 7-го бита: нет
sub

al, bl

Правила установки флагов переноса и переполнения для команды вычитания аналогичны тем, что уже излагались для команды сложения; единственное различие - вместо словосочетания "перенос в..." всюду следует подставить словосочетание "заем из...". А
Истинная таблица установки флагов переноса и переполнения для вычитания

Заем в 7-й(старший) бит

Заем из 7-го(знакового) бита

Флаги

Есть

Есть

CF=1, OF=0

Есть

Нет

CF=1, OF=1

Нет

Есть

CF=0, OF=1

Нет

Нет

CF=0, OF=0

Итак, мы на собственном опыте убедились, как на деле сложен тот вопрос, от которого авторы популярных учебников отделались парой абзацев. Надеюсь, что данная статья поможет всем начинающим программистам быстро освоить этот непростой материал.

(c) 2003, Чугайнов Н.Г.



1 Видимо автор имел ввиду беззнаковое число. (прим. ред.)

2 Такое преобразование над числом так же называется дополнением до двух. А само представление отрицательных чисел - дополнительным кодом. (прим. ред.)


Quantum

SentinelLM!WlscGen_CRK_1


Это первая часть последней главы из цикла о SentinelLM, но уже после её прочтения вы должны быть в состоянии "зарегистрировать" и/или отучить от заглушки в порту (aka донгл) некоторые простенькие программы, продавшие душу Rainbow Tech.

Итак, на данный момент имеем установленный SentinelLM SDK 7.1, эксклюзивно настроенный на наш таргет, т.е. в нём жёстко прописан VId нашей жертвы. Для того, чтобы изменить этот VId можно просто переустановить SDK или найти и пропатчить эти значения в бинарниках, что вовсе не тривиально. После нескольких неудачных попыток поменять VId, я решил всегда переустанавливать SDK и вам советую так поступать.

Пока я усердно работал над этой главой, вы уже прочитали объёмные PDF'ы из документации и узнали, что генератор лицензий SLM (он же WlscGen.exe) так просто нас не наградит халявными лицензиями для нашей жертвы. Оказывается, что он сам защищён SLM и требует наличия донгла! Смешно и обидно... Но не отчаивайтесь -- сегодняшний практикум многому вас научит и поможет устранить защиту SLM даже в патологически сложных случаях, в которых кроме ратификации лицензионного файла программа активно использует EEPROM-память донгла. У меня даже есть готовый патч для "исправления" WlscGen, но я настаиваю на необходимости хотя бы один раз поработать над этим вручную. Чем не ритуал посвящения в Sentinel? :-)

Кроме двух PDF'ов, входящих в комплект поставки SDK, вам нужно прочитать ещё один ОЧЕНЬ важный документ: "SentinelSuperPro 6.0 Developers Guide" (6,4 Мб), который можно скачать на сайте www.rainbow.com. Документ посвящён API Sentinel SuperPro, с помощью которой SLM "общается" с донглами семейства SuperPro. Особого внимания заслуживает глава 14: "API Function Reference".

Перед штурмом WlscGen, хочу добавить пару слов о принципе работы этой программы (особенно для тех лентяев, которые -- как и я в своё время -- не прочитали документацию ;-) Маркетинговая политика радужной компании основана вовсе не на продаже CD с SentinelLM SDK в красивых упаковках. Эти капиталисты взимают дань со своих клиентов за КАЖДУЮ выпущенную лицензию. Справедливости ради стоит заметить, что многие другие компании тоже так поступают... В общем, вместе с SDK компания выдаёт (вроде, первый раз бесплатно) своеобразный электронный счётчик, который автодекрементируется при каждом употреблении. При создании постоянных лицензий для одного PC, счётчик уменьшается на определённое количество единиц; при выпуске корпоративных лицензий для нескольких PC -- теряется соответственно большее количество единиц. Всё зависит от типа лицензии, срока годности и т.д. Эти единицы теряются безвозвратно, даже если пользователь по ошибке создаст бракованную лицензию. При полном истощении счётчика, приходится идти к Rainbow и покупать новый. Вам это не напоминает картриджи для принтеров HP? Так вот, счётчик этот реализован в виде нескольких ячеек памяти в ранее упомянутом донгле и WlscGen "видит" эти ячейки через API, которая общается с донглом через драйвер.

На следующем изображении упрощённо показана зависимость WlscGen от донгла. На большее у нас с Paint'ом не хватило воображения :-)



Обратите внимание на ячейку "Vendor Id" (или "Developer Id") -- это тот самый VId!!! Таким образом, каждый лицензионный донгл "привязан" к своему хозяину и отказывается работать на "чужих" владельцев. Так, по крайней мере, считают в Rainbow. Ячейка "Уникальный S/N" -- это вовсе не то, о чём вы сразу подумали. Нам данный S/N абсолютно безразличен (не путать с серийником для SDK). Область "N/A" не доступна приложениям и, в основном, представляет собой зарезервированные ячейки. В области "Произвольные данные" находится, например, вышеупомянутый счётчик.

SLM API в данном случае реализована статически, т.е. нужные функции внедрены в WlscGen.exe. Наличие lsapiw32.dll не должно сбивать вас с толку. Наша задача -- пропатчить генератор лицензий, вернее пропатчить SLM API для того, чтобы генератор "видел" несуществующий донгл и признавал его своим. Потом мы "заполним" счётчик и получим неистощимый запас лицензий на зависть всем клиентам Rainbow!

Единственный известный мне рабочий метод взлома WlscGen -- это метод описанный в статье CyberHeg "Removing need for dongle in Sentinel LM Wlscgen". Вообще, SentinelLM!WlscGen_CRK_1 можно считать частичным переводом статьи CyberHeg.

Итак, запускаем WlscGen.exe и убеждаемся в его неработоспособности без донгла. Я настоятельно рекомендую вам сделать паузу в чтении этой статьи и помедитировать над кодом программы как в IDA (не забудьте наложить сигнатуру статической SLM API), так и под софтайсом. Можете запомнить текст сообщения об ошибке и попытаться оттрассировать его под отладчиком. Попробуйте угадать какие функции из SLM API могут/должны вызываться для обнаружения донгла.

Сдаётесь? Так быстро? Ладно... в IDA > Names ищем те самые функции из "SentinelSuperPro 6.0 Developer's Guide". При помощи дизассемблера, отладчика и хекс-редактора мы постепенно заставим некоторые из этих функций работать с несуществующим донглом :-) По мере необходимости мы будем заглядывать в SoftIce (как обычно, MAP > SYM > NMS и т.д.)

RNBOsproFindFirstUnit(packet, VendorID)

Первым делом ставим BPX на RNBOsproFindFirstUnit(), так-как эта функция предназначена для поиска донгла с заданным VId. Для большей уверенности можете поставить бряк сразу на все 16 функций из этой API. Наше предположение оказывается верным и SoftIce выскакивает на входе в RNBOsproFindFirstUnit(). Трассируем до RETN и получаем 3 в аккумуляторе (EAX = 3), что означает отсутствие донгла и объясняет сообщение об ошибке. Не теряя времени, идём в IDA и правим это безобразие:

00435B00 _RNBOsproFindFirstUnit@8 proc near
00435B00 push ebx
00435B01 push esi
00435B02 mov eax, [packet]
00435B06 or eax, eax
00435B08 jnz short loc_435B13
00435B0A mov ax, 2
00435B0E pop esi
00435B0F pop ebx
00435B10 retn 8
. . .

При успешном выполнении RNBOsproFindFirstUnit возвращает SP_SUCCESS, т.е. ноль. Блиц-патч:

00435B00 _RNBOsproFindFirstUnit@8 proc near
00435B00 push ebx
00435B01 push esi
00435B02 mov eax, [packet]
00435B06 33C0 xor eax, eax ; Обнуляем eax (SP_SUCCESS)
00435B08 90 nop ; Забиваем переход
00435B09 90 nop
00435B0A 90 nop ; Забиваем mov ax, 2
00435B0B 90 nop
00435B0C 90 nop
00435B0D 90 nop
00435B0E pop esi
00435B0F pop ebx
00435B10 retn 8


. . .

Элементарно, не правда ли? Вместо исправления кода внутри функции RNBOsproFindFirstUnit можно поправить условные переходы после каждого её вызова, но гораздо проще и быстрее поступить вышеописанным образом. По ходу дела, не забывайте осуществлять изменения в самом файле WlscGen.exe при помощи HIEW, WinHex или подобной утилиты.
RNBOsproRead(packet, address, *data)

После успешного "обнаружения" донгла с помощью RNBOsproFindFirstUnit, WlscGen пытается прочитать 16-битные ячейки донгловой памяти через RNBOsproRead. Второй параметр функции задаёт относительное местоположение запрашиваемой ячейки. Полученное значение возвращается через указатель в третьем параметре. Так-как данная функция возвращает принципиально различные значения через указатель, нам её так просто не пропатчить. Опираясь на статьи Goatass и CrackZ, CyberHeg предложил внедрить в конец RNBOsproRead массив из 128 байт для эмуляции памяти донгла. Естественно, код самой функции нужно исправить и заменить вызов драйвера донгла на чтение локального, так сказать, массива. "Правильные" значения ячеек в данном массиве определяются путём долгих мучений с отладчиком. В большинстве случаев, WlscGen проверяет значение считанной ячейки вскоре после возврата из RNBOsproRead и вы можете его перехватить и добавить в массив. Правда, иногда проверка значений происходит иным, менее элементарным образом. Далее представлен исправленный вариант RNBOsproRead:

00435CD0 _RNBOsproRead@12 proc near
00435CD0 push esi
00435CD1 push edi
00435CD2 mov eax, [packet]
00435CD6 or eax, eax
00435CD8 jnz @F
00435CDA mov ax, 2
00435CDE pop edi
00435CDF pop esi
00435CE0 retn 0Ch
00435CE3 @@: push eax
00435CE4 call sub_42F940
00435CE9 mov esi, eax
00435CEB cmp word ptr [esi], 7242h
; Здесь начинаются изменения:
00435CF0 90 nop
00435CF1 90 nop
00435CF2 55 push ebp
00435CF3 E800000000 call $+5
00435CF8 5D pop ebp ; Получить EIP
; (1Eh = 00435D16 - 00435CF8)
00435CF9 8D551E lea edx, [ebp+1Eh] ; Адрес начала
; нашего массива
00435CFC 5D pop ebp ; Восстановить стек
00435CFD 0FB74C2410 movzx ecx, [address]
; Каждая ячейка представляет собой 16-битное слово, т.е. 2 байта
; Поэтому ECX следует умножить на 2
00435D02 D1E1 shl ecx, 1
00435D04 0FB7040A movzx eax, [edx+ecx] ; Помещаем в EAX значение

; считанное из ячейки
00435D08 8B7C2414 mov edi, [*data]
00435D0C 668907 mov [edi], ax ; Сохранить результат
00435D0F 33C0 xor eax, eax ; Обнуляем eax (SP_SUCCESS)
00435D11 5F pop edi
00435D12 5E pop esi
00435D13 C20C00 retn 0000C
; А вот и наш массив:
00435D16 0000 dw 00000h ; №0
00435D18 0000

dw 00000h
00435D1A 0000 dw 00000h
00435D1C 0000 dw 00000h
00435D1E 0000 dw 00000h
00435D20 0000 dw 00000h
00435D22 0000 dw 00000h
00435D24 0000 dw 00000h
00435D26 FFFF dw 0FFFFh ; №8
00435D28 FFFF dw 0FFFFh ; №9
00435D2A 0000 dw 00000h
00435D2C FFFF dw 0FFFFh ; №11
00435D2E

0000 dw 00000h
00435D30 0000 dw 00000h
00435D32 0000 dw 00000h
00435D34 0007 dw 00700h ; №15
00435D36 0000 dw 00000h
. . . ; Забить нулями
00435D5C 0000 dw 00000h
00435D5E FFFF dw 0FFFFh ; №36
00435D60 0000 dw 00000h
. . . ; Забить нулями
00435D94 0000

dw 00000h ; №63

Обратите внимание на 4 ячейки с 0FFFFh и одну с 0700h. Эти значения были получены путём трассирования каждого вызова RNBOsproRead.

Если снова запустить WlscGen, программа должна заметно тормознуть (!) и показать окно с приглашением "Please Login". Эта задержка при запуске служит явным признаком того, что нам ещё рано праздновать. Действительно, пора заняться RNBOsproQuery, RNBOsproFindNextUnit и RNBOsproDecrement. Хотя, стоп!!! Я по себе чувствую, что вы подустали :-) Поэтому оставим эти три API для следующей главы. Я вам даже больше скажу: с RNBOsproFindNextUnit и RNBOsproDecrement вы должны быть в состоянии разобраться сами! Это будет своеобразным домашним заданием :-) Отдыхайте.



Гарри дочитывал статью о SentinelLM!WlscGen_CRK_1, а Рон успел задремать, когда вбежала Гермиона.
- Я задала вопрос на форуме, и мне ответили! - она размахивала распечаткой, - Теперь я знаю, в чем дело!
Все трое склонились над распечаткой и увидели:

Hi, Magic Girl!

> know about Evklid?

Easy! Look here:

-----------------------------------

proc NOD near

;in - AX, BX: unsigned integers

;out - NOD in AX

;(c) Evklid ;)

;

@Up:

cmp AX, BX

jc @Down

xchg AX, BX

@Down:

sub BX, AX

jnz @Up

ret

NOD endp

- И чего? не понял Рон. - Что это за лажа?
- Это не "лажа", а алгоритм Эвклида поиска Наибольшего Общего Делителя! - объяснила Гермиона.
Теперь не поверил Гарри: - И эти ... (он посчитал на пальцах...) 11 байт находят общий делитель? Похоже, над тобой посмеялись! Этого не может быть!
Впрочем, спустя полчаса, исписав тестовыми примерами вторую тетрадь, он начал понимать, что ошибки не было...
- Стоп, - удивился Гарри, - Но это должен быть другой Эвклид! Тот Эвклид не мог придумать такой алгоритм, ведь у него НЕ МОГЛО быть компьютера!
- Элементарно, Гарри! - отозвалась Гермиона, - Он был магом, а значит - все возможно. И именно к этой его машине и подключил Снегг своего...
Тут Рон, рассматривавший распечатку, вскрикнул. "Подпись! Взгляните на подпись!" Все снова склонились над бумагой и Гарри дочитал до конца:

...

ret

NOD endp

-----------------------

Regards!

Anonymus.

- Да это же ник Того, Кого Нельзя Называть! - почти хором выдохнули они...

...В это же самое время на такую же подпись угрюмо смотрел Драко Малфрой. Он тоже зарегистрировался на одном форуме, под крутым ником "Raneon" (а всё потому, что его любимый ник Саурон был занят). И даже поместил несколько сообщений - тоже крутых. Всем сразу должно быть ясно, что это Хакер - с большой буквы X! И что же? Над ним посмеялись. Кто-то с ником Anonymus! Малфрой начал копаться на своем винте - где-то лежали скачанные ранее нюки, которые он приберегал для Поттера. Сейчас этот Анонимус свое получит! Оставалась одна проблема - указать IP-адрес жертвы. Драко набрал в командной строке:

ping anonymus

но адрес не определялся. "Должно быть, он сейчас не в сети...", подумал Малфрой, - "ничего, сейчас вылезет!" И он отправил на форум сообщение "кАзлы позорные! Удалите Ананимуса с форума!" и сел ждать, напевая "Спрячь анонимуса за файерволом - ..." Время шло, рифма не подбиралась, а загадочный Anonymus не появлялся. "Ну тогда занючу весь сайт!" злобно подумал Драко. "Ваш-то IP я знаю!", бормотал он, набивая в окне нюки "195.161.118.107". "Будете знать Драко Малфроя!" - и он уверенно кликнул мышкой по кнопке "NukeIt!"...

... как всегда, продолжение to be... or not to be?

Низкоуровневое программирование для Дzenствующих #37

часть 1

###########################################################################
#Бредисловие

Сорванные башни
(часть 4)


 

Когда я верю в чудо, зная, что его нет, я понимаю, как думает детство.
(с) мечтатель

 

#Бредисловие от WASM GROUP




<00E>: Я тут письмо получил... Только оно в ящик не пролазит :))
<00F>: И что пишут?
<00E>: Да все об одном и том же.
<00F>: Что об одном и том же? в одном письме? Ето как, по несколько раз
повторяют что-ли? :0
<00E>: Ну типа того :) Вот, "Уважаемые HI-TECH" ... ага... вот... "неужели вы
не можете выпускать рассылку без приколов?"
<00F>: мда... можем. Но не хочем :)))
<00E>: не перебивай! Вот дальше: "и почему у вас на форуме какие-то закорючки?
Пусть админ подправит, а то ни в одной кодировке не читается. Парнография
какая-то!"...
<00F>: Это не порнография,

а старорусское народное творчество - ЯТЬ
называется.
<00А>: Какой-то безграмотный тип! ЯТЬ - это суть русской письменности.

SERV: PING, PING user aka <-1>
<-1>: А помоему давно нужно решить этот вопрос об ятях!!! В самом деле,
неудобно и странно...
<00A>: только через труп. Не дам! Ни за что! :))

<00E>: Можно и чере труп, вот я только что муху убил.. :((

Удивительное животное, повернул её голову на 180 градусов....
<00A>: и вообще, подумаешь, ять... никто и не говорил, что все будет просто.
Читать они не могут ... некоторые вон и на ассемблере пишут, а тут ять
прочитать не могут... Будете возмущаться - напишу на японском!
<-1>: нет-нет, яти вполне нормальные буквы, всех устраивает! :))

<00F>: 00E, а зачем на 180?

<00E>: Я хотел, чтобы она вверх ногами летела :(

<00A>: Птичку жалко :((

<00E>: Не хнычь, в следующий раз, я крылья переставлю!

Ничего, трудно в ученьи легко в бою. Скоро перейдём на животных покрупнее.
<00А>: А что там еще? >:E
<00E>: Ну много чего, я ж говорю, все тоже самое повторяется... а, вот в конце
"Вчера слышал в троллейбусе, что сайт WASM.RU будет на первом месте по
посещаемости с чем вас и поздравляю.
С уважением, Артурик из Эстонии"
<00F>: Ну так это хорошо? :)
<00E>: Замечательный парень этот Артурик.
Вот думаю, поеду к нему, подарю БОЛЬШОЙ СЮРПРИЗ
(он ж тут как раз адрес обратный оставил на конверте)
Ведь старался человек, раскрутил наш сайт аж на 10 место!
Ура, Артурику!!! Просто ангелочек!!!

Я слышал у него даже крылышки на спине растут.
<00A>: А что за СЮРПРЫЗ?
<00E>: ЭЭЭ секрет. Говорю же большой. :))
<00F>: Так, пока вы тут письма читали, я вступление написал. :)


Гарри Поттер и девайс маглов


...Проходя мимо надписи на левом крыле Хогвартса "Поттер+Грейнджер=...", Гарри выругался и махнул палочкой. Стена раскрошилась, башня дрогнула. Надпись осталась - она висела в воздухе, поддерживаемая чьим-то заклинанием. На стенах все равно ничего написать было невозможно - рассерженная декан Гриффиндорфа, шепча странные заклинания "Annes-ke! Kutyn-ges-a-Chaleem!", наложила на все стены заклятье Восковой Доски, и после этого никакие надписи на стенах не держались. Даже Гермиона, владевшая всеми иностранными языками в совершенстве, перевести эту фразу не смогла.

До экзаменов осталась три дня. Солнце ярко светило, птицы пели. А у Гермионы как раз был День Рожденья. Правда, она, похоже, о нем забыла, закопавшись в учебники..., но Гарри собирался напомнить.

Ну какая еще может быть сессия - летом, да еще в 16 лет! "Нет, хорошую погоду в учебный день придумали точно садисты!"-подумал Гарри, потом посмотрел на висящую в воздухе надпись, пробормотал "Козлы!" и добавил одно из словечек профессора Дамблдора. Из палочки вырвался ослепительный луч, ударивший в левую башню Хогвартса. Башня задрожала и начала медленно рассыпаться. "Ну, теперь симметрично!" - подумал Поттер. Правая башня развалилась на прошлой неделе, когда группа слизеринцев, по словам Гермионы, попытались "узнать стиль моей одежды". Гермиона тогда тоже добавила к заклинанию одно из словечек Дамблдора. Шестерка слизеринцев до сих пор лежала в отдельной палате. По слухам, они превратились в что-то похожее на одноглазых циклопов с вертикальным ртом и заросли густой шерстью. Гермиона, как непосредственный очевидец, могла рассказать больше, но при воспоминании об этом ее разбирал такой истерический хохот, что друзья решили ни о чем больше не расспрашивать. А башня развалилась - так же, как и эта. "Ну все,"- подумал Гарри, - "если кто-нибудь видел, тысяча штрафных нам обеспечена!". И поспешно, но бесшумно, скрылся в направлении оранжереи...

...Посреди оранжереи угрюмо стоял Хагрид. На вытоптанной земле торчали чудом сохранившиеся несколько веточек. Со вздохом он оборвал их и критически посмотрел на получившийся пучок.
- Привет, Хагрид! - раздался за спиной голос Гарри. - А что... больше ничего нет?
- Да, придется идти в Дикий Лес, - вздохнул великан, - циклопы, они... ну как это сказать... ну им надо много, килограммов по 10 травы каждому!
- Слушай, Хагрид, а тогда не отдашь этот букетик мне? - осторожно осведомился Гарри.
- Да, конечно, бери, о чем разговор! А... для чего тебе? - и он протянул Гарри последние цветы из оранжереи.
- Ну,... для Гермионы... - Гарри слегка покраснел.
- А что с ней? - забеспокоился Хагрид, - надеюсь, ничего серьезного? Может, помочь чем?
- Нет, нет, все в порядке, - поспешил успокоить его Гарри, - мы справимся сами!...
Хагрид еще раз вздохнул и начал собираться за целебными травами в Дикий Лес. Здесь до следующего года ничего ожидать не приходилось.

...Последние консультации Снегга разнообразием не блистали. Он просто давал дополнительные ссылки на статьи, и прочитать все это можно было в любое свободное время. Но совсем не появляться на консультации было опасно. Вопросы по программированию, задаваемые волшебниками, похоже, ставили Снегга в тупик. Каждый вопрос, на который, по мнению Гарри, он не мог ответить сам, Снегг вставлял в билеты или переадресовывал другим, не упуская случая накинуть штрафных баллов. Вот и сейчас он предложил просмотреть статью "Об упаковщиках в последний раз". Гарри делал вид, что что-то читает, и просто пролистывал текст то вверх, то вниз. Мысли были далеко - сегодня вечером Гермиона согласилась прогуляться с ним по опушке леса! Да, после 9 выходить не разрешалось, но Гарри помнил несколько выходов из Хогвартса - ведущих как раз к Бешеной Иве и лесу. Впрочем, Гарри увидел несколько строчек посвящённых защите, и тут представив себя великим крякером, увлёкся за чтением новой статьи...


VOLODYA/HI-TECH
NEOx/UINC.RU

Об упаковщиках в последний раз