МІНІСТЕРСТВО ОСВІТИ ТА НАУКИ УКРАЇНИ
НАЦІОНАЛЬНИЙ ТЕХНІЧНИЙ УНІВЕРСИТЕТ
«ХАРКІВСЬКИЙ ПОЛІТЕХНІЧНИЙ ІНСТИТУТ»
О.М. Рисований
РЕВЕРСНЕ ПРОГРАМУВАННЯ
ЗАХИСТ КОДУ
Середовище програмування masm64
Навчально-методичний посібник
для студентів спеціальності 123 - "Комп'ютерна інженерія"
всіх форм навчання
Затверджено
редакційно-видавничим
порадою університету,
протокол №2 від 27.06.2024
Харків
2024
ББК 32.973-018.1
УДК 004.42
Р54
Рецензенти:
Н.Ю. Любченко, канд. техн. наук, доцент кафедри системного аналізу
та інформаційно-аналітичних технологій НТУ ХПІ
Р.А. Гамзаєв, канд. техн. наук, віце-президент „Української асоціації
спеціалістів інформаційних технологій“
Рисований О.М.
Р54 Реверсне програмування. Захист коду. Середовище програмування
masm64: навчально-методичний посібник для студентів спеціальності 123
"Комп'ютерна інженерія" всіх форм навчання [електронне видання] /
О.М. Рисований. – Харків : НТУ «ХПІ», 2024. – 214 с.
Основну увагу приділено захисту програм у ОС Windows 11 під час
програмування мовою Асемблер серед masm64.
У роботі розглянуто питання: розміщення даних у секції коду; процедури із
параметрами; перетворення логічних операцій; виклики функцій; самомодифікація
коду; перевірка дати та часу; приховування пароля; зворотне шифрування;
кодування файлів; хешування за алгоритмом SHA-1; обчислення CRC; шифрування
повідомлень шляхом заміни бітових уявлень. Наведено лабораторні роботи із
завданнями та прикладами виконання у середовищі masm64.
Наведено літературу, яка використовується при вивченні матеріалу, що
розглядається.
Призначений для студентів спеціальності 123 – «Комп'ютерна інженерія».
Іл. 54. Бібліогр. 11 назв.
УДК 004.42
ББК 32.973-018.1
© О.М. Рисований, 2024
3
ЗМІСТ
ВСТУП ..................................................................................................... 6
1. РОЗМІЩЕННЯ ДАНИХ У СЕКЦІЇ КОДУ ...................................... 8
1.1. Розміщення даних у секції коду .................................................. 8
1.2. Лабораторна робота «Розміщення даних у секції коду» .......... 12
Контрольні питання для перевірки знань .......................................... 23
2. ЗАСТОСУВАННЯ ПРОЦЕДУР З ПАРАМЕТРАМИ .................... 24
2.1. Передача параметрів за замовчуванням ...................................... 24
2.2. Передача параметрів процедури через стек ............................... 27
2.3. Лабораторна робота «Процедури з параметрами» .................... 30
Контрольні питання для перевірки знань .......................................... 35
3. ПЕРЕТВОРЕННЯ ЛОГІЧНИХ ОПЕРАЦІЙ ..................................... 36
3.1. Заміна команди xor ....................................................................... 36
3.2. Заміна арифметичних операцій логічними ................................. 39
3.3. Лабораторна робота «Перетворення логічних
операцій» ............................................................................................. 45
Контрольні питання для перевірки знань .......................................... 46
4. ПЕРЕКРИТТЯ КОДУ ......................................................................... 47
4.1. Загальні відомості про перекриття коду .................................... 47
4.2. Перекриття коду з переходом назад за кодом програми ........... 49
4.3. Перекриття коду з переходом уперед за кодом програми ......... 53
4.4. Лабораторна робота «Перекриття коду» ................................... 60
Контрольні питання для перевірки знань .......................................... 62
5. ВИКЛИКИ ФУНКЦІЙ ....................................................................... 63
5.1. Виклик функцій без використання директиви invoke ............... 63
5.2. Організація переходу з використанням команди повернення .. 64
5.3. Організація переходу з використанням команди call та
перекриттям коду .................................................................................... 67
5.4. Лабораторна робота «Організація переходів» ........................... 71
Контрольні питання для перевірки знань .......................................... 72
6. САМОМОДИФИКАЦИЯ КОДА ПРОГРАММЫ ........................... 73
6.1. Загальні відомості про самодифікацію коду .............................. 73
4
6.2. Організація переходу з використанням команди повернення .. 74
6.3. Алгоритм самодифікації коду ...................................................... 77
6.4. Самодифікуюча діалогова програма
з кількома діалоговими вікнами ......................................................... 81
6.5. Лабораторна робота «Самомодифікація коду» ......................... 87
Контрольні питання для перевірки знань .......................................... 90
7. ПЕРЕВІРКА ДАТИ І ЧАСУ .............................................................. 91
7.1. Загальні відомості про фіксовану кількість запусків ................ 91
7.2. Перевірка дати закінчення запуску програми ........................... 91
7.3. Запис до файлу кількості запусків програми ............................. 95
7.4. Обмеження спроб введення пароля ............................................ 97
7.5. Запис до реєстру кількості запусків програми .......................... 99
7.6. Лабораторна робота «Перевірка дати та часу» ......................... 111
Контрольні питання для перевірки знань .......................................... 112
8. ШИФРУВАННЯ ПАРОЛЮ ............................................................... 113
8.1. Загальні відомості про шифрування пароля .............................. 113
8.2. Шифрування пароля окремою програмою ................................ 113
8.3. Вилучення частини пароля з великої послідовності ................. 115
8.4. Лабораторна робота «Приховування пароля» ........................... 120
Контрольні питання для перевірки знань .......................................... 121
9. ШИФРУВАННЯ ДАНИХ .................................................................. 122
9.1. Поворотне шифрування ............................................................... 122
9.2. Операція підсумовування за модулем 3 ..................................... 124
9.3. Шифрування даних з інкрементованим ключем ....................... 125
9.4. Лабораторна робота «Зворотне шифрування» .......................... 127
Контрольні питання для перевірки знань .......................................... 129
10. Кодування .......................................................................................... 130
10.1. Загальні відомості про кодування ............................................ 130
10.2. Отримання випадкової послідовності ...................................... 130
10.3. Алгоритм отримання псевдовипадкової послідовності .......... 140
10.4. Поліноміальне кодування .......................................................... 144
10.5. Лабораторна робота «Кодування файлів» ............................... 163
Контрольні питання для перевірки знань .......................................... 163
11. ХЕШУВАННЯ .................................................................................. 165
11.1. Загальні відомості про хешування ............................................ 165
11.2. Алгоритм хешування SHA-1 ...................................................... 166
5
11.3. Лабораторна робота «Хешування за алгоритмом SHA-1» ..... 168
Контрольні питання для перевірки знань .......................................... 169
12. КОНТРОЛЬ ЦИКЛІЧНИМ НАДЛИШНИМ КОДОМ ................. 170
12.1. Загальні відомості про поліноми .............................................. 170
12.2. Арифметика CRC ....................................................................... 171
12.3. Прямий алгоритм обчислення CRC .......................................... 173
12.4. Стандартний табличний алгоритм ............................................ 175
12.5. Лабораторна робота «Обчислення CRC» ................................. 176
Контрольні питання для перевірки знань ......................................... 176
13. ШИФРУВАННЯ ПОВІДОМЛЕНЬ МЕТОДОМ ЗАМІНИ
БИТОВИХ ПРЕДСТАВ ........................................................................ 177
13.1. Метод заміни бітових уявлень .................................................. 177
13.2. Лабораторна робота «Шифрування повідомлень методом
заміни бітових уявлень» ..................................................................... 187
Контрольні питання для перевірки знань ......................................... 188
14. ІНШІ МЕТОДИ ЗАХИСТУ КОДУ ................................................ 189
14.1. Змішування коду ........................................................................ 189
14.2. Застосування команд jmp .......................................................... 189
14.3. Розбиття рядків на частини ....................................................... 189
14.4. Приховування змісту програми ................................................ 189
14.5. Позбавлення адресних констант ................................................ 189
Додаток А. Поліноми degP(x)=4 у GF(2) та їх періоди ...................... 190
Додаток Б. Поліноми degP(x)=5 у GF(2) та їх періоди ....................... 191
Додаток В. Поліноми degP(x)=4 у GF(3) та їх періоди ....................... 193
Додаток Г. Поліноми degP(x)=5 у GF(3) та їх періоди ....................... 205
Додаток Д. Поліноми degP(x)=6 у GF(3) та їх періоди ...................... 207
6
ВСТУП
Досконалого захисту не існує. Тому вибору методу захисту
вихідного коду програми треба приділяти найсерйознішу увагу.
Якісний захист повинен забезпечити такий рівень, щоб на розтин
захисту потрібно було витратити зусилля, які можна порівняти з
написанням самої програми. У такому разі залишається лише
«спортивний» інтерес злому.
Захист повинен бути багаторівневим і перекривається (тобто рівні
повинні працювати незалежно).
Відомо, що програма в основному складається із сегментів:
– коду;
– даних;
- Стека.
За промовчанням права доступу на читання, запис та виконання
програми визначені для кожного сегмента. Так, у сегменті коду
дозволено лише виконання, у сегменті даних та стеку – зчитування та
запис. Однак завжди існує можливість зміни цих властивостей.
При захисті програми паролем завжди, яким би складним пароль
не був, можна його обійти, оскільки є код порівняння з стандартом. Для
злому необхідно змінити лише одну команду розгалуження з аналізу
ознаки виконання операції та програма реагуватиме на будь-який пароль
[3, 6-11]. Крім того, програма зберігається в оперативній пам'яті, звідки
може вважатися іншим додатком.
Теоретично захисту вихідного коду виділяють методи:
– приховування алгоритму роботи програми;
- приховування виконуваних інструкцій;
- Приховування даних шляхом шифрування.
Для утруднення пошуку пароля, заплутування коду
використовують поняття обфускації (від лат. Obfuscare - затіняти,
затемняти; і англ. obfuscate - робити неочевидним, заплутаним, збивати
з пантелику). Обфускація - це приведення вихідного тексту або
виконуваного коду програми до виду, що зберігає її функціональність,
але ускладнює аналіз, розуміння алгоритмів роботи та модифікацію при
декомпіляції.
7
При обфускації широко застосовують такі прийоми:
- Запис програми в один рядок (за наявності відповідних макросів);
– Заміна імен змінних та функцій;
- Вставка команд, що нічого не значать;
- Розміщення даних у сторінках коду;
- Перекриття коду;
- Неявний виклик функцій;
- Перетворення логічних операцій;
- Змішування коду;
- Застосування великої кількості команд jmp;
- Розбиття рядків на частини;
- Звільнення від адресних констант;
- Шифрування та ін.
Існують і інші, дуже ефективні, але трохи складні прийоми захисту,
які потребують інших знань та часу на їхнє вивчення [1 - 7].
Розробка будь-якої програми починається із створення алгоритму.
Якщо планується захист програми паролем, то заплутаний алгоритм
виклику процедур не дозволить хакеру визначити логіку роботи. Тому
важливо розробляти алгоритм з урахуванням вимог безпеки.
Логічну структуру алгоритму можна ускладнити за допомогою:
- Розміщення даних у сторінках коду;
– великої кількості викликів підпрограм (процедур);
- Застосуванням рідко використовуваних інструкцій процесора;
- Застосуванням великої кількості констант;
- Застосуванням функцій, які при їх виконанні змінюють код та
інші прийоми.
Реалізація кожного з цих пунктів призводить до заплутування коду,
а, отже, і до підвищення загальної безпеки програми.
8
1. РОЗМІЩЕННЯ ДАНИХ У СЕКЦІЇ КОДУ
1.1. Розміщення даних у секції коду
Хакер майже ніколи не доступний вихідний текст програми. Йому
доступний лише ехе-файл. Застосування даних у секції коду при аналізі
ехе-файла в налагоджувачі дозволяє дуже заплутати дослідження
програми, оскільки дані в коді подаються як команди, які необхідно
ігнорувати. Такий прийом заплутування коду також дозволяє збільшити
час його аналіз.
При класичному написанні програми на асемблері майже завжди в
секцію даних записують дані, а в секцію коду - програмний код. Секція
- це безперервний діапазон адрес, всі дані в яких вважаються з певної
точки зору однорідними. Це з тим, що у секцію даних можна писати дані
у процесі виконання програми, а секцію коду – не можна.
Розглянемо для архітектури х64 програму, в якій дані розміщені у
секції коду, але при цьому в процесі виконання коду її логіка роботи не
порушується. Це відбувається через те, що програма командою jmp
перестрибує дані, що розміщуються в ній.
Програма 1.1. Розміщення даних у секції коду:
include \masm64\include64\masm64rt.inc
.code
entry_point proc
jmp @f
titl:
db "Просто MessageBoxTimeout",0
inf1:
db "Обошлись без секции .data",10,"Ждем 9 секунд",10,10,
"НТУ ХПИ, каф. КИТ",0
@@:
lea rsi,inf1
invoke MessageBoxTimeout,0,rsi,addr titl,MB_ICONINFORMATION,0,
9000
invoke ExitProcess,0
entry_point endp
end
9
У програмі представлено два варіанти застосування параметрів
функції MessageBoxTimeout: один параметр передається через регістр
rsi – адресу розміщення змінної, яка як приклад, вказана міткою inf1,
інша – безпосередньо міткою titl. Чим більше даних розташовано в
секції коду, тим складніше у налагоджувачі проаналізувати код. Це
відбувається тому, що компілятор перетворює дані в коди операцій,
послідовність яких немає логічного сенсу.
Результат виконання програми наведенона рис. 1.1.
Вікно відладчика x64Dbg з програмою, що розглядається,
представлене на рис. 1.2.
Код, який не має особливої логіки, у налагоджувачі підсвічений
червоним кольором. Це і є дані, які розміщені у секції коду, але
Рис. 1.1. Результат выполнения программы
Рис. 1.2. Вікно налагоджувача x64Dbg з розглянутою програмою
10
інтерпретовані як коди операцій. Те, що це дані, теоретично можна
обчислити розташованою перед цими даними командою jmp, за якою
відбувається стрибок на блок коду, який має логічний сенс.
Для закріплення матеріалу розміщення даних у секції коду
наведемо ще один приклад (програма 1.2). Ті змінні, які обчислюються
в програмі або в них буде здійснено запис у процесі виконання
програми, не можна записувати в секцію коду.
Програма 1.2. Обчислення рівняння ab+c/d - sqrt(d) для 5-ти
значень змінної ai {2.,3.,4.,5.,6.}:
include \masm64\include64\masm64rt.inc
.data
len2 equ ($-mas2)/type mas2
res dq 5 DUP(0),0 ;
buf1 dq 0 ; буфер вывода сообщения
.code
entry_point proc
jmp m1
mas1 real8 3.,8.,4. ; b, c, d
m1:
vmovsd xmm2,mas1[0] ; xmm2 - b
vmovsd xmm3,mas1[8] ; xmm3 - c
vmovsd xmm4,mas1[16] ; xmm3 - d
jmp m2
mas2 dq 2.,3.,4.,5.,6. ; массив чисел А
m2:
mov rcx,len2 ; счетчик чисел mas2
jmp m3
tit1 db "masm64. AVX. Результат вычисления уравнения ab+c/d - sqrt(d)", 0
m3:
lea rdx,res ; адрес массива результатов
lea rbx,mas2 ; адрес mas2
jmp m4
ifmt db "masm64. Массив ai = 2.,3.,4.,5.,6.",10,
9,"Числа: b, c, d := 3., 8., 4.",10,
"Результаты вычисления: %d , %d , %d , %d , %d ",10,10,
"Автор: Рысованый А.Н., каф. КИП, НТУ ХПИ",10,
9,"Сайт: http://blogs.kpi.kharkov.ua/v2/asm/",0
m4:
@@:
vmovsd xmm1,qword ptr[rbx] ; xmm0 - a
vmulsd xmm5,xmm2,xmm1 ; ab
11
vdivsd xmm6,xmm3,xmm4 ; c/d
vaddsd xmm7,xmm5,xmm6 ; ab+c/d
vsqrtsd xmm8,xmm4,xmm4 ; sqrt(d)
vsubsd xmm9,xmm7,xmm8 ; ab+c/d - sqrt(d)
vcvttsd2si eax,xmm9 ;
movsxd r15,eax
mov [rdx],eax ; сохранение результата
add rbx,8
add rdx,8
loop @b ; ссылка на предыдущую метку @@ (наверх)
; подготовка данных для вывода
mov r10,res
mov r11,res[8]
mov r12,res[16]
mov r13,res[24]
mov r14,res[32]
; преобразование и вывод
invoke wsprintf,addr buf1,addr ifmt,r10,r11,r12,r13,r14;
invoke MessageBox,0,addr buf1,addr tit1,MB_ICONINFORMATION
invoke ExitProcess,0
entry_point endp
end
Результат виконання програми наведено на рис. 1.3.
Рівняння розраховується для 5-ти значень змінної а. Тому в
програмі виводяться 5 результатів обчислення цього рівняння.
Рис. 1.3. Результат виконання программи
12
Дані, що переносяться з секції data, розміщуються всередині циклу,
який обмежує командою jmp та міткою. Чим більше таких циклів, тим
більше труднощів для дослідника блоків коду в ехе-файлі.
Усі секції програми можна розглянути у налагоджувачі x64Dbg при
виборі кнопки меню Карта памяти (рис. 1.4).
У програмі є секції: секція коду – секції text та секції, на наявність
яких програміст може впливати лише у певних випадках. Але у зв'язку
з тим, що в програмі не всі дані знаходяться в сегменті коду, а деякі – в
сегменті даних, то й у переліку секцій вони також присутні.
1.2. Лабораторна робота «Розміщення даних у секції коду»
Мета заняття:
– отримати практичні навички розміщення даних у секції коду
програми.
У звіті подати:
– назва лабораторної роботи, варіант, прізвище та ініціали, e-mail,
номер групи автора програми;
- текст програми з виведенням назви лабораторної роботи,
варіантом, прізвища та ініціалів, e-mail, номери групи автора програми;
– результат виконання завдання (скриншоти вікон програми та
відладчика).
Завдання 1
Використовувати чистий USB-flash носій, т.к. дані з нього будуть
втрачені.
Написати програму з виконанням дій:
Рис. 1.4. Секції програми
13
- Вибір USB-flash носія;
- записати блок даних зі значеннями 0FFh у кожну комірку пам'яті;
- порахувати дані та порівняти результати;
- підрахувати кількість справних та несправних осередків.
Завдання 2
Написати програму з використанням функцій:
1. Функція FindFirstFileExA - виконує пошук у каталозі файлу або
підкаталогу з ім'ям та атрибутами, що відповідають зазначеним.
Завдання – організувати виведення всіх файлів у файл з однаковим
розширенням.
2. Функція FindFirstFileNameW – створює перерахування всіх
жорстких посилань на вказаний файл.
3. Функція FindNextStreamW – продовжує пошук потоку,
запущений під час попереднього виклику.
4. Функція FindNextVolumeW – продовжує пошук тома, запущений
викликом.
5. Функція GetCompressedFileSize. Витягує фактичну кількість
байтів дискового сховища.
6. Функція GetDiskFreeSpace - отримує відомості про вказаний
диск, включаючи обсяг вільного місця на диску.
7. Функція GetDiskFreeSpaceEx - отримує відомості про обсяг
вільного місця на томі диска, тобто про загальний обсяг вільного місця,
а також про загальний обсяг вільного місця, доступного користувачеві,
пов'язаному з викликаючим потоком.
8. Функція GetDiskSpaceInformation - отримує відомості про
дисковий простір для тома по заданому кореневому шляху.
9. Функція GetDriveType – визначає, чи є диск знімним,
фіксованим, компакт-диском, диском ОЗУ чи мережним диском.
10. Функція GetFileAttributes – витягує атрибути файлової системи
для зазначеного файлу чи каталогу.
11. Функція GetFileAttributesEx – витягує атрибути для зазначеного
файлу чи каталогу.
12. Функція GetFileInformationByHandle - отримує відомості про
файл для зазначеного файлу.
13. Функція GetFileSize – витягує розмір зазначеного файлу в
байтах.
14. Функція GetFinalPathNameByHandle – витягує розмір
зазначеного файлу в байтах.
15. Функція GetFinalPathNameByHandle – заповнює буфер рядками,
що вказують допустимі диски в системі.
14
16. Функція GetLongPathName - перетворює зазначений шлях на
довгу форму.
17. Функція GetTempFileName – створює ім'я для тимчасового
файлу. Якщо створюється унікальне ім'я файлу, створюється порожній
файл та дескриптор для нього звільняється; Інакше створюється лише
ім'я файлу.
18. Функція GetVolumeInformation - витягує відомості про файлову
систему та том, пов'язаний із зазначеним кореневим каталогом.
19. Функція GetVolumeInformationByHandle - витягує відомості про
файлову систему та том, пов'язаний із зазначеним файлом.
20. Функція GetVolumeInformation - витягує відомості про файлову
систему та том, пов'язаний із зазначеним кореневим каталогом.
21. Функція GetVolumeNameForVolumeMountPoint - витягує шлях
GUID тома для тома, пов'язаного із зазначеною точкою підключення
тому (літера диска, шлях GUID тома або підключена папка).
22. Функція GetVolumePathNamesForVolumeName - витягує список
літер дисків та підключених шляхів до папок для зазначеного тома.
23. Функція GetVolumePathName - витягує точку підключення
тому, до якого підключений зазначений шлях.
24. Функція SetFileAttributes - задає атрибути для файлу чи
каталогу.
25. Функція SetFileInformationByHandle - задає інформацію про
файл для зазначеного файла.
Приклади використання функцій
Програма 1.3. Вилучення повного шляху файлу:
title Извлечение полного пути файла; masm64
include \masm64\include64\masm64rt.inc
.data
buf1 db MAX_PATH dup(?);макс. длина пути MAX_PATH - 260(?) символов
tit1 db "GetFullPathName - извлечение полного пути файла",0
.code
entry_point proc
invoke GetFullPathName,chr$("1.asm"),sizeof buf1,addr buf1,0;rsp
invoke MessageBox,0,addr buf1,addr tit1,MB_ICONINFORMATION
invoke ExitProcess,0
entry_point endp
end
15
Програма 1.4. Виведення першого файлу у папці, який відповідає
формату *.bat:
title вывод первого файла в папке, который соответствует формату *.bat
include \masm64\include64\masm64rt.inc
.data
diry db "c:\masm64\bin64\*.bat",0
wfd WIN32_FIND_DATA <>
;t1 FILETIME <>
buf1 dq 5 dup(0)
fmt1 db "Информация о файле:",10,10,"FileAttributes = %d, ",10, "ст.ч.
размер файла = %d, ",10,
"мл.ч. размер файла = %d байтов, ",10,"короткое имя файла = %d",0
titl1 db "Имя 1-го файла в папке с расширением bat",0
titl2 db "WIN32_FIND_DATA <>",0
.code
entry_point proc
invoke FindFirstFile,addr diry,addr wfd; открывает дескриптор поиска
; и возвращает информацию о первом файле, имя которого
; соответствует указанному образцу
invoke MessageBox,0,addr wfd.cFileName,addr titl1,MB_OK
movsxd r10,wfd.dwFileAttributes ; атрибуты файла
movsxd r11,wfd.nFileSizeHigh ; старшая половина размера файла
movsxd r12,wfd.nFileSizeLow ; младшая половина размера файла
movzx r13,wfd.cAlternate ; короткое имя файла
invoke wsprintf, ADDR buf1, ADDR fmt1,r10,r11,r12,r13;
invoke MessageBox,0,ADDR buf1,ADDR titl2,MB_OK
invoke ExitProcess,0 ; возврат управл. ОС и освобождение ресурсов
entry_point endp
end
Програма 1.5. Визначення часу створення файлу:
include \masm64\include64\masm64rt.inc
SYSTEMTIME struc
wYear WORD ? ; Год
wMonth WORD ? ; Месяц
wDayOfWeek dw ?; День недели
wDay WORD ? ; День месяца
wHour WORD ? ; Час
wMinute WORD ? ; Минута
wSecond WORD ? ; Секунда
16
wMilliseconds dw ? ; Миллисекунда
SYSTEMTIME ends
.data
fTime FILETIME <>
sTime SYSTEMTIME <>
buf db 32 dup(?),0
File1 db "25.asm",0;опр. время создания, а не изменения!
hFile HANDLE ?
fmt db "Дата и время создания файла: %d.%d.%d : %d.%d",0
.code
entry_point proc
invoke CreateFile,addr File1,GENERIC_WRITE,0,0,OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,0
mov hFile,rax
invoke GetFileTime,hFile,addr fTime,0,0;
invoke FileTimeToSystemTime,addr fTime,addr sTime
invoke SystemTimeToTzSpecificLocalTime,0,addr fTime,addr sTime
;отформатирование времени для отображения и показа
invoke GetTimeFormat, LOCALE_USER_DEFAULT,
TIME_FORCE24HOURFORMAT or TIME_NOTIMEMARKER, addr sTime,0,
addr buf, sizeof buf
invoke MessageBox,0,ADDR buf,"Время создания файла",MB_OK
; Получить из числа строку
movzx r15,sTime.wYear ; год
movzx r14,sTime.wMonth ; месяц
movzx r13,sTime.wDay ; день месяца
movzx r12,sTime.wHour ; час
movzx r11,sTime.wMinute ; минуты
invoke wsprintf,addr buf,ADDR fmt,r15,r14,r13,r12,r11
invoke MessageBox,0,ADDR buf,"Время создания файла",MB_OK
invoke ExitProcess,0 ; возврат упр. и освобождение ресурсов
entry_point endp
end
Програма 1.6. Встановлення та читання покажчиків файлу:
include \masm64\include64\masm64rt.inc
.data
_file1 db "File-2-1.txt",0 ; имя 1-го файла
17
_file2 db "File-2-2.txt",0 ; имя 2-го файла
hFile01 HANDLE ?
hFile02 HANDLE ?
from_file db 4096 dup(?)
read_by_file dq ?
write_by_file dq ?
file01_size dq ?
file02_size dq ?
title1 db "Добавление одного файла в конец другого",0
msg1 db "Ошибка! Файл 'File-2-1.txt' не доступен!",0
msg2 db "Размер файла 'File-2-2.txt': %d,",10,"Размер файла 'File-2-2.txt':
%d.",10,
"Считано байт: %d, записано байт: %d.",10,10,
"Рысованый А.Н., НТУ ХПИ, каф. КИП",0
buf dq 0
.code
entry_point proc
invoke CreateFile,addr _file1,GENERIC_READ,0,0,OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,0
mov hFile01,rax ; сохранение дескриптора файла
.if hFile01 == INVALID_HANDLE_VALUE ; если CreateFile возвр. ошибку
invoke MessageBox,0,addr msg1,addr title1,0 ; сообщ. об ошибке
.endif
; Открытие второго файла для записи
invoke CreateFile,addr _file2,GENERIC_WRITE,FILE_SHARE_READ,0,
OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,0
mov hFile02,rax ; сохранение дескриптора файла
invoke GetFileSize,hFile01,0 ; получение размера файла 01
mov file01_size,rax
invoke GetFileSize,hFile02,0 ; получение размера файла 02
mov file02_size,rax
; Установка указателя на конец файла
invoke SetFilePointer,hFile02,0,0,FILE_END
; Чтение из файла и запись в from_file
invoke ReadFile,hFile01,addr from_file,file01_size,addr read_by_file,0
; Запись в файл (конец) из from_file
invoke WriteFile,hFile02,addr from_file,read_by_file,addr write_by_file,0
; Преобразование данных и вывод (информация о программе; автор)
18
invoke wsprintf,addr buf,addr msg2,file01_size,file02_size, read_by_file,
write_by_file
invoke MessageBox,0,addr buf,addr title1,MB_ICONINFORMATION
invoke ExitProcess,0
entry_point endp
end
Програма 1.7. Перезапис даних із масиву у файл:
title перезапись данных из массива в файл; masm64
include \masm64\include64\masm64rt.inc
.data
mas1 dq 1,4,6,3ah,3bh
mas2 dq 5 dup(?)
len1 equ ($-mas2)/type mas2
BSIZE1 equ 40 ; количество байтов, которые записываются в файл
fName BYTE "File2-64-2.txt",0 ; имя файла
fHandle dq ? ; дескриптор хранения файлов
cWritten dq ? ; ячейки для адреса символов вывода
fmt db "%d",0 ; задание преобразования символа
szFileName db "c:\masm32\bin64\File2-64-3-sms.exe",0
.code
entry_point proc
mov r11,len1 ; len1=5
lea rsi,mas1 ; занесение адреса начала элементов массива mas1
lea rdi,mas2 ; занесение адреса массива результата mas2
@1: mov r15,[rsi]
push r11 ; сохранение в стеке перед выполнением wsprintf
invoke wsprintf,ADDR [rdi],ADDR fmt,r15
pop r11 ; возврат из стека
add rsi,type mas1
add rdi,type mas2 ;8
dec r11
jnz @1
invoke CreateFile,ADDR fName,GENERIC_WRITE,0,0,
CREATE_ALWAYS, FILE_ATTRIBUTE_ARCHIVE,0
mov fHandle,rax
invoke WriteFile,fHandle,ADDR mas2,BSIZE1,ADDR cWritten,0;
19
;invoke CloseHandle, fHandle ; закрыть дескриптор файла
invoke WinExec,addr szFileName,SW_SHOW ; запуск внешнего файла
invoke ExitProcess, 0
entry_point endp
end
Програма 1.8. Створення файлу, запис у файл даних та перегляд у
блокноті:
title создание файла, запись в файл и просмотр в блокноте; masm64
include \masm64\include64\masm64rt.inc
.data
fName BYTE "File-4.txt",0 ; имя файла
fName2 BYTE "notepad C:\masm64\bin64\File-4.txt",0 ; имя файла
inf1 db "Задача успешно решена",0 ;
titl1 db "Сообщение о завершении",0 ;
BSIZE equ 16 ; размер буфера для вывода чисел
mas1 dq 10,12 ; массив чисел для записи в файл
len1 equ ($-mas1)/type mas1
fmt db "%d",0 ; для преобразования числа перед выводом
cWritten dq ? ;
buf1 dq 2 dup(0) ; буфер для массива при выводе
hFile dq ?,0 ; дескриптор файла
.code
entry_point proc
lea r13,buf1 ; загрузка адреса массива вывода чисел
lea r12,mas1 ; загрузка адреса массива исходных чисел
mov r15,len1 ; загрузка счетчика чисел массива mas1
@1: ; начало цикла преобразования чисел массива mas1
mov r10,[r12] ; загрузка числа из массива mas1
invoke wsprintf,ADDR [r13],ADDR fmt,r10 ; преобразование
add r12,8 ; увеличение адреса mas1
add r13,type buf1 ; увеличение адреса buf1
dec r15 ; уменьшение счетчика на 1
jnz @1 ; перейти на метку, если не ноль
invoke CreateFile,ADDR fName, GENERIC_WRITE, 0,0,
CREATE_ALWAYS, FILE_ATTRIBUTE_ARCHIVE,0
mov hFile,rax ;
invoke WriteFile,hFile,ADDR buf1,BSIZE,ADDR cWritten,0; чтение
invoke CloseHandle,hFile ; закрыть дескриптор файла (обязательно)
20
invoke MessageBoxTimeout,0,addr inf1,addr titl1, MB_OK, 0,1500
invoke WinExec,addr fName2,SW_SHOW ; запуск внешнего файла
invoke ExitProcess, 0
entry_point endp
end
Программа 1.9. Визначення розміру файлу:
include \masm64\include64\masm64rt.inc
.data
BS equ 128 ; задание кол. байтов
Fname BYTE "makeit.bat",0 ; файл для определения размера
ms1 db "Size of file (in bits) " ; сообщение
totalsize dq ? ; ячейка для сохранения размера
;stdout dq ? ; для хранения дескриптора вывода
hFile dq ? ; дескриптор файла
buf db BS dup (?) ; буфер
fmt db "%d",0 ; форматирование числа
ms2 db "Error!!File not found" ; sms
.code
entry_point proc
invoke CreateFile,ADDR Fname,GENERIC_READ,0,NULL,\
OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL ;открытие файла
mov hFile,rax ;сохранение дескриптора
.if hFile==0FFFFFFFFh ;если ошибка
jmp m1 ;перейти на метку m1
.endif
invoke GetFileSizeEx,hFile,addr totalsize ; получение размера файла
;invoke GetStdHandle,STD_OUTPUT_HANDLE
;mov stdout,rax
;invoke WriteConsoleA,stdout,ADDR ms1,24,0,0
invoke wsprintf,addr buf,addr fmt,totalsize,0
invoke MessageBox,0,ADDR buf,ADDR ms1,MB_YESNO
jmp m2
;invoke WriteConsoleA,stdout,ADDR buf,15,0,0
invoke CloseHandle,hFile
jmp m2
m1:
invoke MessageBox,0,ADDR ms2,ADDR ms1,MB_ABORTRETRYIGNORE
21
m2:
invoke ExitProcess,0
entry_point endp
end
Програма 1.10. Перейменування існуючого файлу:
title переименование существующего файла; masm64
include \masm64\include64\masm64rt.inc
.data
File1 db "C:\masm64\bin64\0.asm",0
NewFile2 db "C:\masm64\bin64\0new.asm.asm",0
.code
entry_point proc
invoke MoveFile,addr File1, addr NewFile2 ;файл File1 переименовать
invoke ExitProcess,0
entry_point endp
end
Програма 1.11. Визначення атрибутів файлу:
include \masm64\include64\masm64rt.inc
.data
BS equ 512 ; Number of bytes
Fname BYTE "c:\masm64\bin64\Px4m2.txt",0
ms1 db "Stream attributes:",0
mRead db ' READONLY', 0
mHide db ' HIDDEN', 0
mSys db ' SYSTEM', 0
mArch db ' ARCHIVE', 0
mNorm db ' NORMAL', 0
mDir db ' DIRECTORY', 0
errorBuf db BS dup (?)
INVALID_HANDLE_VALUE equ -1
.code
entry_point proc
invoke CreateFile,ADDR Fname,GENERIC_READ,FILE_SHARE_READ,0,
OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS, NULL
mov rsi, rax
cmp rsi, INVALID_HANDLE_VALUE
22
je file_not_found
; Определяем атрибуты файла
invoke GetFileAttributes, ADDR Fname
mov rcx, rax
; формирование атрибутов файла
test ecx, FILE_ATTRIBUTE_READONLY
jnz display_readonly_file
test ecx, FILE_ATTRIBUTE_HIDDEN ; скрытый файл
jnz display_hidden_file
test ecx, FILE_ATTRIBUTE_SYSTEM ; только для ОС
jnz display_system_file
test ecx, FILE_ATTRIBUTE_ARCHIVE ; большинство файлов
jnz display_archive_file
test ecx, FILE_ATTRIBUTE_NORMAL ; файл без атрибутов
jnz display_normal_file
test ecx, FILE_ATTRIBUTE_DIRECTORY ; каталог вместо файла
jnz display_directory_file
display_readonly_file:
invoke MessageBoxA,0,addr mRead,addr ms1,MB_OK
jmp end_program
display_hidden_file:
invoke MessageBoxA,0,addr mHide,addr ms1,MB_OK
jmp end_program
display_system_file:
invoke MessageBoxA,0,addr mSys,addr ms1,MB_OK
jmp end_program
display_archive_file:
invoke MessageBoxA,0,addr mArch,addr ms1,MB_OK
jmp end_program
display_normal_file:
invoke MessageBoxA,0,addr mNorm,addr ms1,MB_OK
jmp end_program
23
display_directory_file:
invoke MessageBoxA,0,addr mDir,addr ms1,MB_OK
jmp end_program
file_not_found:
invoke GetLastError
invoke FormatMessageA,FORMAT_MESSAGE_FROM_SYSTEM, 0,rax,0,
ADDR errorBuf,BS,NULL
invoke MessageBoxA,0,ADDR errorBuf,addr ms1,MB_OK
end_program:
; Закрываем дескриптор файла перед завершением программы
invoke CloseHandle,rsi
entry_point endp
end
Контрольні питання для перевірки знань
1. Яка інформація зберігається у кожній із секцій?
2. Чи можна написати програму без секції data?
3. За допомогою якої команди дані можна розташувати у секції
коду?
4. Скільки байтів займає команда jmp та у яких випадках?
5. Як переглянути наявність, назву та характеристики секцій
програми?
6. Які ознаки знаходження даних у секції коду під час перегляду у
відладчику?
24
2. ЗАСТОСУВАННЯ ПРОЦЕДУР З ПАРАМЕТРАМИ
Застосування великої кількості процедур при аналізі коду в
налагоджувачі досить сильно ускладнює його аналіз, особливо якщо
параметри процедур передаються через стек. Цей прийом заплутування
коду сприяє збільшенню часу з його аналіз.
Угода про виклики для 64-розрядних систем передбачає передачу
4 перших параметрів через регістри RCX, RDX, R8, R9, а решти – через
стек.
2.1. Передача параметрів процедури за замовчуванням
Передача параметрів через регістри здійснюється, якщо цих
параметрів трохи більше 4-х. Але трохи нижче буде розглянуто, що і
перші 4 параметри те ж можна передавати через комірки стека.
Застосування великої кількості дзвінків підпрограм (процедур)
дозволяє ускладнити код. Причому перші чотири параметри
передаються через регістри RCX, RDX, R8, R9, а інші – через стек, що
також заплутує аналіз коду.
Розглянемо програму 2.1, де виконується умова ab + c/d. Для
простоти будемо використовувати лише дві процедури з передачею
параметрів через перші регістри.
Програма 2.1. Обчислення рівняння ab+c/d з використанням 2-х
процедур:
include \masm64\include64\masm64rt.inc
.data
a1 dq 1
b1 dq 2
c1 dq 19
d1 dq 4
titl1 db "Процедуры. masm64",0
sbuf dq ?,0
inf1 db "Уравнение ab + c/d",10,"a = 1",10,"b = 2",10,
"c = 19",10,"d = 4",10,"Результат: %d",10,10,
"Автор: Рысованый А.Н., каф. КИП, НТУ ХПИ",10,
9,"Сайт: http://blogs.kpi.kharkov.ua/v2/asm/",0
.code ; ab + c/d
25
count1 proc arga:QWORD, argb:QWORD ; ab
mov rax,rcx ; arg a
mul rdx ; arg b ; rdx:rax
mov rsi,rax
ret
count1 endp
count2 proc argc:QWORD,argd:QWORD ; c/d
mov rax,rcx ; arg c
mov r10,rdx
xor rdx,rdx
div r10 ; arg d
mov rdi,rax
ret
count2 endp
entry_point proc
invoke count1,a1,b1 ; ab
invoke count2,c1,d1 ; c/d
add rsi,rdi ; сложение результатов из 2-х процедур ; ab + c/d
invoke wsprintf,ADDR sbuf,ADDR inf1,rsi ; преобразование rsi
invoke MessageBox,0,addr sbuf,addr titl1, MB_ICONINFORMATION
invoke ExitProcess,0
entry_point endp
end
Результат виконання програми наведено на рис. 2.1.
Рис. 2.1. Результат виконання програми
26
Код програми у налагоджувачі x64Dbg представлений на рис. 2.2.
Для того, щоб у відладчику потрапити до процедури та побачити
код процедури необхідно на рядку call натиснути в покроковому режимі
кнопку F7 (рис. 2.3).
Рис. 2.2. Код програми у відладчику x64Dbg
Рис. 2.3. Код процедур у відладчику x64Dbg
27
Аналіз передачі параметрів процедури через регістри перестав
бути складним прийомом роботи з кодом як для програміста при
налагодженні, а й хакеру у його зловмисних діях.
2.2. Передача параметрів процедури через стек
Майже завжди перші 4 параметри процедури послідовно
передаються через регістри: rcx, rdx, r8, r9 (але є можливість і ці
параметри передавати через стек).
При використанні параметрів процедури, починаючи з п'ятого
параметра, дані передаються тільки через стек, що ще більше заплутує
код, оскільки при аналізі коду необхідно переглядати значення цих
осередків. Але можна написати програму з невикористовуваними
першими чотирма параметрами, а застосовувати лише ті, що
передаються через стек (програма 2.2).
Програма 2.2. Обчислення рівняння ab+c/d з використанням 2-х
процедур та з передачею параметрів через стек:
include \masm64\include64\masm64rt.inc
.data
f1 dq 10
a1 dq 1
b1 dq 2
c1 dq 19
d1 dq 4
titl1 db "Процедуры. masm64",0
sbuf dq ?,0
inf1 db "Уравнение ab + c/d",10,"a = 1",10,"b = 2",10,
"c = 19",10,"d = 4",10,"Результат: %d",10,10,
"Автор: Рысованый А.Н., каф. КИП, НТУ ХПИ",0
.code ; ab + c/d
count1 proc arga: DQ,argb: DQ,argc: DQ,argd: DQ, arge: DQ,argf: DQ
mov rax,[rbp+30h] ; arg a
mov r10,[rbp+38h]
mul r10 ; arg b ; на ячейку стека умножать нельзя
mov rsi,rax
ret
count1 endp
count2 proc arga:DQ,argb: DQ,argc: DQ,argd: DQ, arge: DQ,argf: DQ
mov rax,[rbp+30h] ; arg c
28
mov r10,rdx
xor rdx,rdx
mov r10,[rbp+38h]
div r10 ; arg d ; на ячейку стека делить нельзя
mov rdi,rax
ret
count2 endp
entry_point proc
invoke count1,f1,f1,f1,f1,a1,b1
invoke count2,f1,f1,f1,f1,c1,d1
add rsi,rdi
invoke wsprintf,ADDR sbuf,ADDR inf1,rsi
invoke MessageBox,0,addr sbuf,addr titl1, MB_ICONINFORMATION
invoke ExitProcess,0
entry_point endp
end
При виклику процедури, наприклад
invoke count1,f1,f1,f1,f1,a1,b1
перші 4-ті може мати однакові імена, т.к. вони все одно в програмі
не плануються використовувати.
У зв'язку з тим, що кількість параметрів збільшилася, то і код у
налагоджувачі став складнішим. (рис. 2.4).
Рис. 2.4. Код у відладчику x64Dbg
29
При покроковому виконанні кожного рядка коду (кнопка F7) та
натисканні на рядок коду з ім'ям call потрапляємо усередину цієї
процедури.
Але так як у тексті програми ці процедури знаходяться біля один
одного, то й у налагоджувачі вони теж розташовуються разом (рис. 2.5).
Рис. 2.5. Код процедур у відладчику x64Dbg
30
При розкритті коду процедури видно значення зсувів кожного
параметра, що важливо як із написання програми, і під час аналізу коду.
Першим передається параметр процедури через регістр rcx сегмент
стека зі значенням [rbp+10] в 16-річній системі числення.
Другим передається параметр процедури через регістр rdx сегмент
стека зі значенням [rbp+18] в 16-річній системі числення.
Третій передається параметр процедури через регістр r8 сегмент
стека зі значенням [rbp+18h+8h] = [rbp+20h] в 16-річній системі
числення.
Четвертий передається параметр процедури через регістр r9
сегмент стека зі значенням [rbp+28] в 16-річній системі числення.
П'ятий параметр процедури передається через стек із значенням
[rbp+30].
Шостий параметр процедури передається через стек із значенням
[rbp+38].
Через передачу параметрів у процедурах код процедур збільшився.
Але необхідність перегляду вмісту кожної комірки пам'яті збільшує час
аналізу коду. Для цього рекомендується і перші 4 параметри (rcx, rdx, r8,
r9) передавати те ж через зміщення стека.
2.3. Лабораторна робота «Процедури з параметрами»
Мета заняття:
- Отримати практичні навички застосування параметрів процедури.
У звіті подати:
– назва лабораторної роботи, варіант, прізвище та ініціали, e-mail,
номер групи автора програми;
- текст програми з виведенням назви лабораторної роботи,
варіантом, прізвища та ініціалів, e-mail, номери групи автора програми;
– результат виконання завдання (скриншоти вікон програми та
відладчика).
Завдання
Згідно з номером студента у групі вибрати варіант завдання та
написати на асемблері програму обчислення рівняння із застосуванням
кількох процедур. В останній процедурі параметри передати лише через
стек. Отримані результати записати у файл.
31
Варіанти
1. ac + b/d + f/e +1; 15. g/f + e/d — cb/a;
2. f/e — b/d – a/c +2; 16. gf/e + dc/b — a;
3. b/d + f/e — ca +3; 17. gf + e/d/c + ba;
4. db – hc +a/e+f + 4; 18. g + fe/d/cb — a;
5. a/c + bd — efg + 5; 19. gf/e+dc/b + a;
6. a/b/c — d/e + f + 6; 20. g/f + (ed)/c+b/a;
7. a/d + c/b + efg + 7; 21. 2d/a – 21bc+f;
8. ef + d/c — ab + 8; 22. 4b – a/22c + de;
9. a/b — cd/e+f/g + 9; 23. ab/4e – 16cde;
10. a + b/c/d + efg + 10; 24. d/ba – cd/e/f;
11. abc — de/fg; 25. e/8b + acdef;
12. a/b + cd + e/fg; 26. 4d/a – сd+ bef;
13. ab + cd/ef — g; 27. 8a/b + cd – (e/f)g;
14. abcd — ef/g; 28. 4abc – e/f — d,
где a, b, c, d, e, f, g – числа.
Приклад виконання
Програма 2.3. Виконання рівняння ac + b/e + f/d + 5 з передачею
параметрів в останній процедурі лише через стек:
; Уравнение ac + b/e + f/d + 5
include \masm64\include64\masm64rt.inc
.data
a1 dq 1
b1 dq 9
c1 dq 2
e1 dq 3
d1 dq 4
f1 dq 12
const dq 5
titl1 db "Процедуры. masm64",0
sbuf dq ?,0
inf1 db "Уравнение ac + b/e + f/d + 5",10,"a = 1, b = 9",10,
"c = 2, d = 4",10,"e = 3, f = 12",10,"const = 5",10,"Результат: %d",10,10,
"Автор: Рысованый А.Н., каф. КИП, НТУ ХПИ",10,
9,"Сайт: http://blogs.kpi.kharkov.ua/v2/asm/",0
.code ; ac + b/e + f/d + 5
count1 proc arg1:QWORD,arg2:QWORD ; ac
mov rax,rcx ; arg a
32
mul rdx ; arg c ; rdx:rax
mov rsi,rax
ret
count1 endp
count2 proc arg1:QWORD,arg2:QWORD ; b/e
mov rax,rcx ; arg b
mov r10,rdx
xor rdx,rdx
div r10 ; arg e
mov rdi,rax
ret
count2 endp
count3 proc,arg5:DQ,arg6:DQ, arg7:DQ; f/d+5
mov rax,[rbp+30h] ; arg f
mov r10,[rbp+38h] ; arg d
;xor rdx,rdx
div r10 ;
add rax,[rbp+40h] ; arg const
mov rdi,rax
ret
count3 endp
entry_point proc
invoke count1,a1,c1 ; ab
invoke count2,b1,e1 ; b/e
add rsi,rdi ; сложение результатов из 2-х процедур ; ac + b/e
invoke count3,a1,a1,a1,a1,f1,d1,const ;
add rsi,rdi ; ac + b/e + f/d + 5
invoke wsprintf,ADDR sbuf,ADDR inf1,rsi ; преобразование rsi
invoke MessageBox,0,addr sbuf,addr titl1, MB_ICONINFORMATION
invoke ExitProcess,0
entry_point endp
end
Результат виконання програми наведено на рис. 2.6.
33
У програмі використовуються 3 процедури.
Перші дві процедури мають лише по 2 параметри. Ці параметри
передаються через регістри.
У першій процедурі виконується множення значень 2-х змінних та
збереження результату в регістрі rsi.
У другій процедурі виконується операція поділу двох змінних.
Перед виконанням операції розподілу рекомендується ініціалізувати
регістр rdx.
Для цього використано команду
xor rdx,rdx
Результат поділу зберігається у регістрі rdi.
Особливістю 3-ї процедури є те, що необхідні параметри
передаються лише через стек із необхідними зміщеннями. А перші
чотири параметри, які передаються через регістри, у процедурі не
використовуються.
Внутрішні рядки коду процедур зручно аналізувати у відладчику
(рис. 2.7).
Рис. 2.6. Результат виконання рівняння
34
У відладчику зручно переглядати послідовність передачі
параметрів та адрес, за якими передаються вміст регістрів та стека.
Причому в налагоджувачі видно, що значення параметрів можна
передавати не тільки через регістри, але і з використанням зсувів.
Наприклад, перший параметр процедури передається через регістр rcx.
Однак видно, що цей параметр можна передати через використання
стека, як [rbp + 10h].
Рис. 2.7. Внутрішні рядки коду процедур
35
Отже, можна всі параметри передавати через стек, наприклад:
Приклад частини попередньої програми, в якій параметри
передаються тільки через стек, може бути таким:
count1 proc arg1: QWORD, arg2: QWORD; ac
mov rax,[rbp+10h];rcx; arg a
mul rdx; arg c; rdx:rax
mov rsi,rax
ret
count1 endp
count2 proc arg1: QWORD, arg2: QWORD; b/e
mov rax, [rbp + 10h]; rcx arg b
mov r10, [rbp+18h]; rdx
xor rdx,rdx
div r10; arg e
mov rdi,rax
ret
count2 endp
Передача всіх параметрів тільки через комірки стека вносить
труднощі в аналіз коду і автора програми, і хакера.
Контрольні питання для перевірки знань
1. Перелічити послідовність передачі параметрів у процедурі.
2. Чи можна передавати параметри процедури лише через стек?
3. Яка адреса має перший параметр, який передається через стек?
4. Як розраховуються адреси комірок стека?
5. Якщо в першій процедурі першою операцією є поділ, то в чому
полягає особливість цієї операції?
36
3. ПЕРЕТВОРЕННЯ ЛОГІЧНИХ ОПЕРАЦІЙ
Перетворення логічних операцій у менш відомі формули, а також
застосування логічних операцій (де це можливо) замість арифметичних
дозволяє заплутувати (ускладнювати) логіку роботи програми, а отже, і
витрачати додатковий час на її аналіз.
3.1. Заміна команди xor
Команда xor – це операція додавання по mod2. Фактично це
операція розподілу результату підсумовування на модуль числа (у разі -
число два) і взяття залишку від розподілу як результату операції.
Програма 3.1 отримує залишок від розподілу числа на число два і є
еквівалентною операцією додавання mod2.
Програма 3.1. Отримання результату за модулем два:include
\masm64\include64\masm64rt.inc
.data
a1 dq 1
b1 dq 4
const dq 2
mySg1 segment READ WRITE EXECUTE alias("mySeg")
;.code
entry_point proc
mov rax,a1 ; занесение a1
add rax,b1 ;
mov rdx,0 ; подготовка к делению
div const ;
mov r10,rdx ; a1 mod2 b1
invoke ExitProcess,0
entry_point endp
mySg1 ends
end
У програмі наведено приклад отримання модуля 2 і
перейменування секції коду в нове ім'я mySeg.
37
При отриманні модуля 2 береться не результат цілого розподілу з
регістра rax, а залишок від поділу, який зберігається в регістрі rdx.
У наступному рядку коду значення цього регістру rdx переноситься
в регістр r10:
mov r10,rdx
Нова назва секції коду та характеристики секцій видно при виборі
у налагоджувачі x64Dbg кнопки меню Карта памяти (рис. 3.1).
Ця програма показує класичний приклад отримання результату за
модулем два при застосуванні арифметичної операції поділу. У програмі
не відбуваються логічні перетворення.
Основою перетворення логічних функцій є заміна логічного
висловлювання на формули перетворень із законів булевої алгебри. Їх
застосування дещо збільшує код, але зовсім не порівнянно з часом
пошуку пароля.
Наприклад, функція додавання по mod2 - функція, яка визначається
наступним чином:
х1 х2 = 2121 хххх + = (х1 + х2)( 21 хх + ).
Функція додавання по mod2 має такі характеристики:
- Комутативність (закон переміщення):
х1 х2 = х2 х1;
– асоціативності (сполучний закон):
х1 (х2 х3) = (х1 х2) х3;
– дистрибутивності (розділовий закон):
х1 (х2 х3) = (х1х2) (х1х3).
Для цієї функції справедливі аксіоми:
х х = 0; х 1= х ;
Рис. 3.1. Характеристики секцій програми
38
х х = 1; х 0 = х.
На підставі аксіом і властивостей можна вивести правила
перетворень функцій І, АБО, НЕ через функцію додавання по mod2:
х 1 = х1 1;
x1 + x2 = x1 x2 x1x2;
x1x2 = (x1 x2) (x1 + x2)
Розглянемо програму додавання по mod2, яка замінює команду xor
(програма 3.2).
Програма 3.2. Заміна команди xor на еквівалентну операцію
𝑎1𝑏1 + 𝑎1𝑏1:
include \masm64\include64\masm64rt.inc
.data
a1 dq 2
b1 dq 3
.code
entry_point proc
mov rax,a1 ; a1
mov rbx,b1 ; b1
mov r14,rax ; a1
mov r15,rbx ; b1
not r14 ; ⌐a1
not r15 ; ⌐b1
and rax,r15 ;
and r14,rbx ;
or rax,r14 ; a1 mod1 b1
invoke ExitProcess,0
entry_point endp
end
Операція інверсії не завжди викликає певну настороженість. Її
краще замінити на еквівалентну операцію отримання інверсії х 1 = х
. І тут алгоритм отримання операції mod2 ще більше зміниться.
Розглянемо приклад отримання операції mod2 за формулою
(х1 + х2)( 21 хх + ) (программа 3.3).
39
Програма 3.3. Заміна команди xor на еквівалентну операцію
(х1 + х2)( 21 хх + ):
include \masm64\include64\masm64rt.inc
.data
a1 dq 1
b1 dq 1
.code
entry_point proc
mov rax,a1 ; a1
mov r10,rax ;
mov rbx,b1 ; b1
mov r11,rbx ;
or rax,rbx ; a1 v b1
mov r15,rax ;
xor r10,1 ; ⌐a1
xor r11,1 ; ⌐b1
or r10,r11 ; ⌐a1 v ⌐b1
and r15,r10 ; a1 mod2 b1
invoke ExitProcess,0
entry_point endp
end
Наведена програма не однозначно свідчить про операції mod2. А
при додаванні до цієї формули логічних виразів, які не впливають на
правильність результату, а лише ускладнюють їх аналіз, це ще більше
заплутує аналіз коду.
3.2. Заміна арифметичних операцій логічними
Розглянемо програму з використанням макросу, що виконує
множення на число. Причому якщо це число є ступенем двійки і не
перевищує 16, то множення виконується за швидкою схемою з
використанням зрушень.
Програма 3.4. Застосування зсувів при множенні, якщо число є
ступенем двійки:
include \masm64\include64\masm64rt.inc; библиотеки
mMulD macro digit ; макрос с именем mMulD
40
.if digit == 2 ;; если digit = 2, то
shl eax,1 ;; умножение на 2 - сдвиг влево на 1 разряд
.elseif digit == 4 ;; если digit = 4, то
shl eax,2 ;; умножение на 4 - сдвиг влево на 2 разряда
.elseif digit == 8 ;; если digit = 8, то
shl eax,3 ;; умножение на 8 - сдвиг влево на 3 разряда
.elseif digit == 16 ;; если digit = 16, то
shl eax,4 ;; умножение на 16 - сдвиг влево на 4 разряда
.else ;; иначе
mov ebx, digit
mul ebx ;; eax, edx = eax*ebx – обычное умножение
.endif
endm ;; окончание макроса
.data
digit dd 6 ; запись в 32-разрядную ячейку с именем digit числа 6
titl db " Ускоренное умножение ",0 ; название окна
st2 dw ?,0 ; буфер вывода сообщения
ifmt db "Исходное число = %d", 10, "%d x %d", 10,
"Результат умножения = %d", 10,10, ; преобразование символа
"Автор программы: Рысованый А.Н., НТУ ХПИ",0;
.code
entry_point proc
mov eax,digit ; занесение в еах из ячейки памяти с именем digit
mMulD [digit] ; вызов макроса
invoke wsprintf,ADDR st2,ADDR ifmt,digit,digit,digit,eax ;
invoke MessageBox,0,addr st2,addr titl,MB_ICONWARNING
invoke ExitProcess,0
entry_point endp
end
У програмі для прискореного множення застосовується макрос.
Хоча можна оформити програму без нього.
Результат виконання програми наведено на рис. 3.2.
41
Код програми у налагоджувачі x64Dbg представлений на рис. 3.3,
на якому видно коди команд та переходи між ними залежно від умов.
Рис. 3.2. Результат выполнения программы
Рис. 3.3. Код програми у відладчику x64Dbg
42
У програмі 3.5 розглядається операція поділу альтернативним
способом - командами зсуву. Але такі операції можливі, якщо числа є
ступенем двійки.
Програма 3.5. Рішення рівняння a/c + b/e для конкретних даних:
include \masm64\include64\masm64rt.inc
.data
a1 dq 16
b1 dq 8
c1 dq 4
d1 dq 2
titl1 db "Решение уравнения. Процедуры. masm64",0
sbuf dq ?,0
inf1 db "Уравнение a/c + b/e",10,"a = 16, b = 8",10,
"c = 4, d = 2",10,10,"Результат: %d",10,10,
"Автор: Рысованый А.Н., НТУ ХПИ",10,
9,"Сайт: http://blogs.kpi.kharkov.ua/v2/asm/",0
.code ; a/c + b/e
count1 proc arg1:DQ,arg2:DQ,arg3:DQ,arg4:DQ ;
mov r10,[rbp+10h] ; arg b
shl r10,3 ;
mov r11,[rbp+20h] ; arg c
shl r11,1 ;
add r10,r11
ret
count1 endp
entry_point proc ; a1 = 16, b1 = 8, c1 = 4, d1 = 2
invoke count1,a1,b1,c1,d1 ; a/c + b/e
invoke wsprintf,ADDR sbuf,ADDR inf1,r11 ; преобразование r11
invoke MessageBox,0,addr sbuf,addr titl1, MB_ICONINFORMATION
invoke ExitProcess,0
entry_point endp
end
У програмі 3.6 розглядається операція поділу як командами зсуву
(якщо число є ступенем двійки та звичайним поділом в іншому
випадку).
43
Програма 3.6. Застосування зрушень при розподілі, якщо число є
ступенем двійки:
include \masm64\include64\masm64rt.inc; библиотеки
.data
a1 dq 16
b1 dq 8
c1 dq 4
d1 dq 2
titl1 db "Решение уравнения. Процедуры. masm64",0
sbuf dq ?,0
inf1 db "Уравнение a/b + c/d",10,"a = 16, b = 8",10,
"c = 4, d = 2",10,10,"Результат: %d",10,10,
"Автор: Рысованый А.Н., НТУ ХПИ",10,
9,"Сайт: http://blogs.kpi.kharkov.ua/v2/asm/",0
.code
count1 proc arg1:DQ,arg2:DQ ; a/b
mov rax,rcx
mov r10,rdx
.if r10 == 2 ; если digit = 2, то
shr rax,1 ; деление на 2 - сдвиг влево на 1 разряд
.elseif r10 == 4 ; если = 4, то
shr rax,2 ; деление на 4 - сдвиг влево на 2 разряда
.elseif r10 == 8 ; если = 8, то
shr rax,3 ; деление на 8 - сдвиг влево на 3 разряда
.elseif r10 == 16 ; если 16, то
shr rax,4 ; деление на 16 - сдвиг влево на 4 разряда
.else ; иначе
div r10 ; rax,rdx – обычное деление
mov r14,rax
.endif
mov r14,rax
ret
count1 endp
count2 proc arg1:DQ,arg2:DQ ; c/d
mov rax,rcx
mov r10,rdx
.if r10 == 2 ; если digit = 2, то
shr rax,1 ; деление на 2 - сдвиг влево на 1 разряд
.elseif r10 == 4 ; если = 4, то
shr rax,2 ; деление на 4 - сдвиг влево на 2 разряда
44
.elseif r10 == 8 ; если = 8, то
shr rax,3 ; деление на 8 - сдвиг влево на 3 разряда
.elseif r10 == 16 ; если = 16, то
shr rax,4 ; деление на 16 - сдвиг влево на 4 разряда
.else ; иначе
div r10 ; rax,rdx – обычное деление
mov r11,rax
.endif
mov r11,rax
ret
count2 endp
entry_point proc
invoke count1,a1,b1 ; a/b
invoke count2,c1,d1 ; c/d
add r14,r11
invoke wsprintf,ADDR sbuf,ADDR inf1,r14 ; преобразование
invoke MessageBox,0,addr sbuf,addr titl1,MB_ICONINFORMATION
invoke ExitProcess,0
entry_point endp
end
Результат виконання програми представлений на рис. 3.4.
Рис. 3.4. Результат виконання програми
45
3.3. Лабораторна робота «Перетворення логічних операцій»
Мета заняття:
– отримати практичні навички застосування логічних операцій та
операції додавання за модулем.
У звіті подати:
– назва лабораторної роботи, варіант, прізвище та ініціали, e-mail,
номер групи автора програми;
– текст програми з виведенням назви лабораторної роботи,
варіантом, прізвища та ініціалів, e-mail, номери групи автора програми;
– результат виконання завдання (скриншоти вікон програми та
відладчика).
Завдання
Згідно з номером студента у групі вибрати варіант завдання та
написати на асемблері програму обчислення рівняння. Числа підібрати
таким чином, щоб можна було застосувати операції зсуву. Одну з
операцій замінити на операцію додавання по модулю 2, причому
застосувати альтернативне додавання по модулю.
Отримані результати записати у файл.
Варіанти
1. a/c – e/f – ad; 16. a/b-cd/e+fg;
2. a/b + c/d – eg; 17. fe - b/d - a/c;
3. a/b + cd - f/(ge); 18. g/f + e/dc + ba;
4. d/a – сd+ bef; 19. g/e+d/b+a;
5. g/f+(ed)/c+b/a; 20. g + f/d + cb – a;
6. e/b + a/c – def; 21. g/f/e + dc/b – a;
7. ab + cd/e + f – g; 22. g/f + e/d - c/a;
8. a/b + cd + e/f + g; 23. a/d + f/e – ca;
9. d/b/a – cd+/e/f; 24. ab – gc +a/e + f;
10. abc - d + e / f; 25. a/c + b/d – efg;
11. a+b/e – cde; 26. a/b/c-de + f;
12. b - a/c + de; 27. a/d + c/b +e+ fg;
13. d/a - bc + f; 28. af + d/c – ab;
14. a + b/cd + efg; 29. a/b + c/d + ef;
15. ac + b/d + f/e; 30 abc + d+ef,
де a, b, c, d, e, f, g – числа, показники ступеня 2.
46
Контрольні питання для перевірки знань
1. Якому результату дорівнює одне зрушення вліво чи вправо?
2. Яку дію виконує операція за модулем 2?
3. Яку дію виконує операція за модулем 3?
4. Яка з операцій – додавання, множення, розподіл та зсув
виконується довше?
5. Яка з операцій – додавання, множення, розподіл та зсув
виконується за менший час?
47
4. ПЕРЕКРИТТЯ КОДУ
Програміст, який використовує Асемблер і вміє використовувати
прийом "перекриття коду", вже близький до професіонала. Залишилося
до вже вивченого освоїти прийоми приховування виклику функцій,
самодифікації коду, виконання коду в стеку (шкода, що під х64
можливості вже немає), шифрування коду або його частини,
впровадження свого коду в чужий процес і ще трохи - і ви професіонал
або програміст-фокусник!
4.1. Загальні відомості про перекриття коду
Суть методу перекриття коду у тому, що частина однієї машинної
команди може бути іншою командою. Наприклад, команда mov може
завантажити в регістр число, яке є кодом операції іншої команди.
Потім, іншою командою необхідно в команді mov необхідно початок
виконання коду поставити на потрібний байт даних, які вважати кодом
операції. При цьому необхідно врахувати, що числа в пам'яті
розташовуються в такому порядку: спочатку молодші частини з
меншими адресами, а потім старші частини зі старшими (великими)
адресами (у тексті програми навпаки).
В асемблерній програмі можна задавати не абсолютні адреси, а
зміщення щодо поточної адреси:
jmp $ + 25; перехід на 25h байт "вперед";
jmp $-15; перехід на 15h байт "назад".
Ідентифікатор $ – це значення поточного лічильника адреси рядка
коду, в якому міститься цей символ. А вираз «$-» позначає
арифметичну різницю між адресою рядка коду, в якій знаходиться цей
символ і того значення, яке вказано за ним (або іншої операції, яке
застосовано до ідентифікатора $. У пам'яті як дані, так і рядки коду
розташовуються, починаючи з менших адрес.
Наприклад
mas1 DD 20 dup(1,2,4,6); резервування осередків пам'яті для mas1
dd 16 dup(1); 80 +16 = 96
len1 equ ($-mas1); число байтів у mas1
позначає, що змінної len1 буде присвоєно число, яке
вираховується як різниця між поточною адресою, за якою
48
розташовується змінна $ (велике значення адреси) та значення адреси
змінної з ім'ям mas1 (менше значення адреси). А т.к. кожен байт
адресується своєю адресою, то практично змінна len1 дорівнює числу
байтів, які відводяться для зберігання масиву mas1.
Якщо після рядків
mas1 DD 20 dup(1,2,4,6); резервування осередків пам'яті для mas1
dd 16 dup(1)
і перед рядком
len1 equ ($-mas1)
розташувати один або кілька рядків іншого коду, то ідентифікатор
вважатиме результуюче число байтів весь блок коду.
Розглянемо блок коду:
mov ax,05EBh
jmp $-2
У пам'яті команда mov ax, 05EBh запишеться машинним кодом:
66: B8 EB05 (видно у відладчику). Причому значення 05EBh
помінялися місцями. На згадку про програми числа записуються за
правилом «молодший байт – за молодшою адресою».
Також необхідно пам'ятати, що кожен байт у машинному коді має
адресу і до будь-якого байта на їхню адресу можна звернутися.
Отже, команда jmp$-2 позначає, що з адреси рядка, в якому
вказано ідентифікатор $, буде відраховано 2 байти. Це означає, що
буде пропущено 2 байти попереднього рядка коду 66:B8 EB05 і
виконається команда з кодом операції EB та операндом 05.
Перекриття коду застосовують до вже готової програми при
відкритті її ехе-файлу у відладчику.
Алгоритм перекриття коду полягає в наступному:
1. Відкривається ехе-файл програми у налагоджувачі (у разі
відладчик x64Dbg);
2. Аналізується код у відладчику щодо пошуку місць застосування
перекриття коду. Закривається відладчик;
3. Відкривається текст програми у редакторі середовища masm64.
Вставляється команда jmp$ з негативним або позитивним збільшенням
відповідно до кількості байтів сусідніх команд. У цьому випадку стає
доречним застосування «сміттєвого» коду;
4. Компілюється програма та перевіряється правильність
застосування перекриття коду;
49
5. Повернення до пункту 2, доки не виконаються вимоги до
програми.
4.2. Перекриття коду з переходом назад за кодом програми
При розгляді програми, в якому застосована технологія
перекриття коду, необхідно з початку відкрити налагоджувач, т.к.
тільки в ньому наведено всі коди операцій та дані в машинному
поданні. У програмі 4.1 застосовано технологію перекриття коду з
переходом назад за кодом програми.
Програма 4.1. Перекриття коду з переходом назад:
include \masm64\include64\masm64rt.inc
.code
entry_point proc ;
mov ax,05EBh
jmp $ - 2 ; пропуск 2 байтов EB 05 и остановка на EB
; EB 05 – это jmp на 5 байтов вперед с учетом своих 2-х байтов
dec r9 ; пропускаем, 3 байта: 49:FFC9
inc r10 ; выполняем с этой команды
mov r8,1
mov eax,06EB0000h
jmp $ - 2 ; пропуск 2 байтов 06 и EB и остановка на EB
; EB 06 – это jmp на 6 байтов вперед с учетом своих 2-х байтов
dec cl ; пропускаем, 2 байта: FE C9
dec al ; пропускаем, 2 байта: FE C8
dec dl ; выполняем с этой команды
nop
mov rax,09EB000000000000h
jmp $ - 2 ; пропуск 2 байтов EB 09 и остановка на EB
; EB 09 – это jmp на 9 байтов вперед с учетом своих 2-х байтов
mov r15,1 ; пропускаем, 7 байтов: 49:C7C7 01000000
nop ; выполняем с этой команды
invoke ExitProcess,0
entry_point endp
end
У програмі наведено 3 команди jmp з різною кількістю байтів, що
пропускаються.
50
Скомпілюємо програму та відкриємо її ехе-файл у відладчику
x64Dbg.
На початку програми наведено блок коду:
mov ax,05EBh
jmp $-2
У цьому випадку застосований 16-розрядний регістр ах, т.к. у
налагоджувачі код операції має префікс 66.
Команда mov знаходиться в пам'яті як
66:B8 EB05 mov ax,05EB
Перший байт із вмістом 66 – це префікс заміни розміру операнда
(16-бітовий регістр ах); B8 – код команди mov; EB 05 – константа 05EBh,
записана за правилом «молодший байт – на молодшу адресу» (рис. 4.1).
Графічними ознаками переходів у відладчику є червоні стрілки в
лівому його полі.
Запам'ятовуємо, що код операції команди jmp – ЄВ.
Команда jmp$-2 змушує мікропроцесор пропустити 2 байти з
попереднього рядка (знак мінус) коду 66:B8 EB05, зупинитися на коді
операції EB (команда jmp) і виконати байти EB 05, що вже означає
команду jmp$+5, тобто . перехід на 5h байт вперед за програмним кодом.
І це з'ясовується лише у відладчику.
Якщо виконати команду jmp$-1, то буде здійснено перехід на байт
із вмістом 05, а він інтерпретується командою
add eax,FF49FDEB,
що в нашому випадку не має (поки що) жодного сенсу.
Рис. 4.1. Результат виконання програми
51
Рядок jmp 00.7FF7F028100A передає керування на адресу
00.7FF7F028100A. На початку адреси вказано ім'я файлу – 00.ехе. У
відладчику в полі адрес можна порахувати байт, на який буде передано
управління. Після виконання аналізованої команди jmp
00.7FF7F028100A вміст відладчика матиме вигляд (рис. 4.2).
нтерес представляє лише верхній рядок
jmp 00.7FF7F0281011
З цього рядка червона лінія вказує перехід на рядок із командою inc
r10.
Підходимо до аналізу наступного блоку коду:
inc r10; виконуємо з цієї команди
mov r8,1
mov eax,06EB0000h
jmp $-2;
Для покрокового виконання програми у налагоджувачі x64Dbg
послідовно натискаємо F7 або F8. І після натискання F7 на рядку
00007FF7F0281020 EB FC jmp 00.7FF7F028101E
цей рядок виконається та перетвориться (рис. 4.3).
Рис. 4.2. Вміст відладчика після виконання команди jmp
00.7FF7F028100A
52
Розглянемо аналогічну ситуацію. Команда EB – це код операції
jmp, а 06 – число байт, якими команда здійснить перехід. Знову слід
звернути увагу тому факту, що на цю адресу в налагоджувачі вказують
стрілочки переходів зліва, а також у самій команді jmp записана ця
адреса.
У програмі не можна записувати безпосередньо адресу переходу,
але при налагодженні заздалегідь можна командою jmp $ - підібрати цю
адресу.
У цьому блоці коду застосовано 32-розрядний регістр. Тому і запис
у нього відбувається 32-розрядним числом і спочатку записані молодші
числа, а потім старші. Але префікс розмірності перед кодом операції
немає.
Розглянемо наступні рядки, у яких здійснюється перекриття коду
mov rax,09EB000000000000h
jmp $-2
У цьому блоці коду застосовано 64-розрядний регістр. Тому й запис
до нього відбувається 64-розрядним числом і спочатку записані молодші
числа, а потім – старші (48:B8 000000000000EB09). Префікс розмірності
дорівнює 48.
Кожен байт у машинному коді має адресу і до будь-якого байта на
їхню адресу можна звернутися.
Після виконання команди jmp$-2 відбудеться перехід усередину
команди mov (48:B8 000000000000EB09) на байти ЕВ06 (рис. 4.4).
Рис. 4.3. Результат виконання команди jmp 00.7FF7F028101E
53
Після розгляду перекриття коду з переходом назад за кодом
програми можна зробити висновок: слід застосовувати цей спосіб
досить обережно і остерігатися зациклювання коду. Цей спосіб добре
підходить для неявного, але перестрибування непотрібного коду або
даних в секції коду.
4.3. Перекриття коду з переходом уперед за кодом програми
При розгляді технології перекриття коду з переходом уперед за
кодом програми виконується за допомогою команди jmp$+.
Розглянемо програму 4.2, у якій застосовано технологію
перекриття коду, але з переходом уперед за кодом програми.
Програма 4.2. Перекриття коду з переходом уперед за кодом
програми:
include \masm64\include64\masm64rt.inc
.code
entry_point proc ;
mov ax,05EBh
jmp $ + 5 ; перепрыгивает свои 2 байта и 3 байта dec r9
dec r9 ; 49:FFC0
inc r10 ; выполняем с этой команды
mov r8,1
mov eax,06EB0000h
jmp $ + 6 ; перепрыгивает свои 2 байта и следующие 4
dec cl ; FEC9
dec al ; FEC8
dec dl ; FECA; выполняем с этой команды
nop
mov rax,09EB000000000000h
jmp $ + 9 ; перепрыгивает свои 2 байта и следующие 7
mov r15,1 ; 49:C7C7 0100 0000
Рис. 4.4. Переход назад во внутрь команды mov rax,09EB000000000000h
54
nop ; выполняем с этой команды
invoke ExitProcess,0
entry_point endp
end
У наведеній програмі застосовується рядковий ідентифікатор $ з
різними позитивними збільшеннями. Так зроблено у тому, щоб
розглянути особливості переходів через регістри з різною розрядною
сіткою.
У першому блоці коду, що нас цікавить
mov ax,05EBh
jmp $ + 5; перестрибує свої 2 байти та 3 байти dec r9
dec r9; 49:FFC0
inc r10; виконуємо з цієї команди
команда mov ax, 05EBh ні на що не впливає.
Значення має команда jmp$+5, яка займає в пам'яті 2 байти: EB03.
За результатами виконання цієї команди відбувається перехід через свої
2 байти та 3 байти, розташованих за нею рядки коду. Усього вийшло
зміщення на 5 байтів. Для простоти розгляду застосовано команду dec
r9 з кодом операції 49:FFC0, яка має розмірність 3 байти. Але якщо є
логічний зміст і задум програміста, то можна вказати інше зміщення
адреси і увійти всередину цієї команди і виконати зовсім інший код
операції.
Наступні блоки коду зі зміщеннями +6 та +9 мають аналогічний
зміст, і ці блоки добре прокоментовані.
Розглянемо застосування позитивних зсувів у рядковому
ідентифікаторі $ (програма 4.3).
Програма 4.3.
include \masm64\include64\masm64rt.inc
.data
a1 db 1
b1 db 2
c1 db 4
d1 db 3
.code
entry_point proc ;
; блок1 : ab + c/d
55
mov al,a1
mul b1
mov cl,al
mov al,c1
div d1
add al,cl
nop
; блок2 : ab + c/d
mov al,a1 ; 6 байтов: 8A05 D61F0000
jmp $+4 ; 2 байта: EB 02
nop ;
nop ;
mul b1 ; 6 байтов: F625 CD1F0000
jmp $+5 ; 2 байта: EB 03
dec dx ; 3 байта: 66:FFCA
mov cl,al ;
jmp $+9 ; 2 байта: EB 07
mov r15,1 ; 7 байтов: 49:C7C7 01000000
mov al,c1 ;
jmp $+7 ; 2 байта: EB 05
mov esi,1234 ; 5 байтов: BE D2040000
div d1 ;
add al,cl ;
invoke ExitProcess,0
entry_point endp
end
Програма складається з двох частин, які виконують обчислення
одного і того ж цілісного виразу: ab + c/d.
У блоці коду 1 відсутні будь-які заплутування коду. А в блоці 2
обчислюється теж вираз, але із застосуванням рядкового ідентифікатора
для невеликого утруднення аналізу. Для простоти аналізу в блоці 2
відсутні входження всередину машинного коду команд, що є суттєвим
недоліком цієї програми. Але навіть таке застосування ускладнює аналіз
цього коду.
Перед тим, як застосувати перекриття коду, розглянемо звичайну
програму пересилання цілісного масиву з одного місця пам'яті до
іншого за допомогою команд SSE (програма 4.4).
Програма 4.4.
include \masm64\include64\masm64rt.inc
56
.data
mas1 DD 20 dup(1,2,4,6) ; резервирование ячеек памяти для mas1
dd 16 dup(1) ; 80+16=96
len1 equ ($-mas1)/type mas1
mas2 DD len1 dup(0) ; резервирование ячеек памяти для mas2
ifmt db "… masm64",10,
"…",0
titl1 db "Пересылка целых чисел, SSE",0
.code
entry_point proc ;
mov rcx,len1/4 ; количество блоков массива mas1
lea rsi,mas1 ; адрес начала массива mas1
lea rdi,mas2 ; адрес начала массива mas2
@@: movups xmm0,dword ptr [rsi] ; пересылка 4-x 32-разр. целых чисел
movups dword ptr [rdi],xmm0
add rsi,16;
add rdi,16;
loop @b
invoke MessageBox,0,addr ifmt,addr titl1,MB_ICONINFORMATION
invoke ExitProcess,0
entry_point endp
end
Для утруднення аналізу цієї програми внесемо до неї незначні
зміни шляхом внесення даних до секції коду. Дані можна переносити
лише ті, які під час виконання програми не вимагають запису (змін) до
секції коду (надалі буде розглянуто таку можливість за допомогою змін
атрибутів секції) (програма 4.5).
Програма 4.5. Паралельна передача 32-розр. цілих чисел:
include \masm64\include64\masm64rt.inc
.data
mas1 DD 20 dup(1,2,4,6) ; резервирование ячеек памяти для mas1
dd 16 dup(1) ; 80+16=96
len1 equ ($-mas1)/type mas1
mas2 DD len1 dup(0) ; резервирование ячеек памяти для mas2
.code
entry_point proc ;
mov rcx,len1/4 ; количество блоков массива mas1
lea rsi,mas1 ; адрес начала массива mas1
lea rdi,mas2 ; адрес начала массива mas2
jmp m2
ifmt db "Проверка перекрытия кода на masm64",10,
57
"Рысованый А.Н., каф. КИП, НТУ ХПИ",0
m2:
@@:
movups xmm0,dword ptr [rsi] ; пересылка 4-x 32-разр. целых чисел
movups dword ptr [rdi],xmm0
add rsi,16;
jmp m1
titl1 db "Пересылка целых чисел, SSE",0
m1:
add rdi,16;
loop @b
invoke MessageBox,0,addr ifmt,addr titl1,MB_ICONINFORMATION
invoke ExitProcess,0
entry_point endp
end
Відладчик намагається байти даних подати як коди операцій з
наступними операндами. Але йому це не виходить. І ці рядки
відзначаються червоним кольором (не розпізнані байти).
Наступним кроком зміни першої програми є застосування
перекриття коду. У навчальних цілях простіше це робити на командах
jmp тому, що в інших командах застосування перекриття призводить до
зациклювання цієї частини програми (програма 4.6).
Програма 4.6. Паралельна передача 32-розр. цілих чисел із
перекриттям коду:
include \masm64\include64\masm64rt.inc
.data
mas1 DD 20 dup(1,2,4,6) ; резервирование ячеек памяти для mas1
dd 16 dup(1) ; 80+16=96
len1 equ ($-mas1)/type mas1
mas2 DD len1 dup(0) ; резервирование ячеек памяти для mas2
mySg1 segment READ WRITE EXECUTE alias("mySeg")
;.code
entry_point proc ;
mov rcx,len1/4 ; количество блоков массива mas1
lea rsi,mas1 ; адрес начала массива mas1
lea rdi,mas2 ; адрес начала массива mas2
jmp m2
ifmt db "Проверка перекрытия кода на masm64",10,10,
"Рысованый А.Н., каф. КИП, НТУ ХПИ",10,
9,"Сайт: http://blogs.kpi.kharkov.ua/v2/asm/",0
58
m2:
@@: movups xmm0,dword ptr [rsi] ; пересылка 4-x 32-разр. целых чисел
movups dword ptr [rdi],xmm0
add rsi,16;
mov ax,1debh
jmp $-2
; jmp m1
titl1 db "Пересылка целых чисел, SSE",0
; m1:
add rdi,16;
loop @b
invoke MessageBox,0,addr ifmt,addr titl1,MB_ICONINFORMATION
invoke ExitProcess,0
entry_point endp
mySg1 ends
end
У програмі для утруднення аналізу дані, які в процесі виконання
не змінюються, розміщені в секції коду і ця секція перейменована
керуючим словом segment в нове ім'я mySeg. Дані обрамлені командою
jmp та відповідною міткою.
Результат виконання програми наведено на рис. 4.5.
Команда jmp замінена на рядки коду
mov ax,1debh
jmp $-2
У регістр ax заноситься код операції jmp – значення ebh та усунення
– 1dh.
Вміст вікна налагоджувача перед виконанням команди jmp
00.7FF7F8DD30A0 наведено на рис. 4.6.
Рис. 4.5. Результат виконання програми
59
Вміст вікна відладчика вже після виконання команди jmp
00.7FF7F8DD30A0 наведено на рис. 4.7.
В останньому вікні можна однозначно визначити лише параметри
функції MessageBox.
Після виконання рядка
00007FF7F8DD30A0 EB 1D jmp 00.7FF7F8DD30BF
Рис. 4.6. Вміст вікна відладчика перед виконанням команди jmp
Рис. 4.7. Вміст вікна відладчика після виконання команди jmp
60
Відкривається нове вікно відладчика на завершення трасування
коду (рис. 4.8).
Безпосередній результат пересилання цілих даних можна
подивитися в дампі пам'яті відладчика x64Dbg.
4.4. Лабораторна робота "Перекриття коду"
Мета заняття: придбати практичні навички написання та
застосування програм перевірки пароля з розміщенням даних у
сторінках коду та з перекриттям коду.
У звіті подати:
– назва лабораторної роботи, варіант, прізвище та ініціали, e-mail,
номер групи автора програми;
– текст програми з виведенням назви лабораторної роботи,
варіантом, прізвища та ініціалів, e-mail, номери групи автора програми;
– результат виконання завдання (скриншоти вікон програми та
відладчика).
Завдання
1. Написати програму в середовищі masm64 відповідно до варіанта
завдання з використанням максимально можливої кількості прийомів
перекриття коду.
2. Використовувати процедуру перевірки пароля.
3. Використовувати перевірку на підтримку команд AVX, яку
оформити як виклик окремого ехе-файла. Якщо команди AVX
мікропроцесором не підтримуються, то використовувати команди SSE.
За допомогою команд AVX виконати рівняння, де змінна приймає
п'ять значень і задана масивом. Числа, що залишилися, також задані в
Рис. 4.8. Вміст вікна налагоджувача на завершення трасування коду
61
масиві {b, c, d, e}. Числа задані у масивах. Застосувати максимально
можливу кількість прийомів із перекриттям коду.
Отримані результати записати у файл.
Варіанти
1. (√a) b/c – de; 11. √(ab) + cd + √e;
2. (√/b) c + ad√c; 12. √a – cd – √(eb);
3. (√(bc) a – e√d; 13. √(ce) + a + b/d;
4. (√a/b) c + d/e; 14. a/b/c + √d – e);
5. ab + √(bc) + de; 15. a√(b/c) + cd + e;
6. √(ab) + c/d/e; 16. a√(ce) – b/d;
7. √(ab) + cd√e; 17. bd/c + √(ae);
8. √(edc) – a/b; 18. a√b + c/d + e;
9. √(ac) + b/c + d/e; 19. ab√c + de;
10. √(de) + cd + a; 20. a√e + bc/d,
где a, b, c, d ,e – числа, числа а є{a1, a2, a3, a4, a5} заданы массивом.
Програма 4.7. Перевірка пароля
include \masm64\include64\masm64rt.inc
.data
Password db "12345" ; проверка первых пяти символов
len1 equ $-Password
Buf dq 5 ;
Err1 dq 0
Msg1 db "Пароль совпал",0
Msg2 db "Пароль не корректен",0
Title1 db "Проверка пароля",0
stdout1 dq 0 ;
stdin1 dq 0 ;
cRead dq 0 ;
cWritten dq 0 ;
Msg db "Please enter your password, 5 characters",10,10,0;
.code
Pas1 proc
lea rsi,Password ;адрес первого элемента строки
lea rdi,Buf ;адрес второго элемента строки
mov rcx,len1
repe cmpsb ;побайтно проверяется len раз
jz m2 ;
inc Err1 ; счетчик несовпадений
m2:
ret
62
Pas1 endp
entry_point proc
invoke GetStdHandle,STD_OUTPUT_HANDLE
mov stdout1,rax
invoke GetStdHandle,STD_INPUT_HANDLE
mov stdin1,rax
invoke WriteConsole,stdout1,ADDR Msg,sizeof Msg,ADDR cWritten,0
invoke ReadConsole,stdin1,ADDR Buf,5,ADDR cRead,0
invoke Pas1
.if (Err1==0);
invoke MessageBox,0,addr Msg1,"Проверка пароля",
MB_ICONINFORMATION
.else
invoke MessageBox,0,addr Msg2,"Проверка пароля",MB_OK
.endif
invoke ExitProcess,0
entry_point endp
end
Контрольні питання для перевірки знань
1. У чому полягає суть методу перекриття коду із переходом назад за
кодом програми?
2. У чому полягає суть методу перекриття коду з переходом уперед за
кодом програми?
3. Чому дорівнює код операції команди jmp?
4. Чи можна зробити перехід на будь-який байт команди?
5. У якому разі можливе зациклювання коду програми?
63
5. ВИКЛИКИ ФУНКЦІЙ
У директиві invoke параметри між собою не пов'язані. Тому якщо
між ними вставити код або сміття, то програма стає досить заплутаною.
5.1. Виклик функцій без використання директиви invoke
При написанні програм часто користуються директивою invoke.
При використанні директиви invoke текст програми стає компактним.
Але директива invoke складається з команди call і параметрів.
Наприклад, у програмі, яка виводить повідомлення Hello World!,
параметри функції MessageBox передаються окремими командами і не
використовується директива invoke (програма 5.1).
Програма 5.1. Виведення повідомлення 'Hello World!' із передачею
параметрів функції MessageBox окремими командами:
include \masm64\include64\masm64rt.inc
.data
msg db 'Hello World!', 0
ttl db "Название окна",0
.code
entry_point proc
; invoke MessageBox,0,addr msg,addr ttl,MB_ICONINFORMATION
xor rcx,rcx
lea rdx,msg
lea r8,ttl
mov r9d,64
call MessageBox
invoke ExitProcess,0
entry_point endp
end
Такий запис змінюється транслятором masm64 на послідовність
команд:
xor ecx,ecx
lea rdx,qword ptr ds:[7FF7CF043006]
lea r8,qword ptr ds:[7FF7CF04304D]
mov r9d,40
call qword ptr ds:[<&MessageBoxA>]
64
З цього запису випливає, що рядки коду один від одного не
залежать. Тому цілком логічно не скрізь користуватися директивою
invoke, а тільки в тих блоках коду, які планується внести заплутування
коду. І обов'язково між ними вставляти будь-які інші команди, які на
даний момент не заважають логіці програми (програма 5.2).
Програма 5.2. Виведення повідомлення 'Hello World!' зі вставками
між параметрами функції інших команд:
include \masm64\include64\masm64rt.inc
.data
msg db 'Hello World!', 0
ttl db "Название окна",0
.code
entry_point proc
; invoke MessageBox,0,addr msg,addr ttl,MB_ICONINFORMATION
xor rcx,rcx
mov r15,1 ; “мусор”
lea rdx,inf1
nop ; “мусор”
lea r8,titl
add r15,-1 ; “мусор”
mov r9d,40h
xor r14,14 ; “мусор”
call MessageBox
invoke ExitProcess,0
entry_point endp
end
Кількість рядків коду, які вставляються між параметрами, може
бути більшою. Доцільно вставляти великі шматки коду, кожен з яких
має пов'язаний зміст, але ні на що не впливають і не псують основну
програму (сміттєвий код).
5.2. Організація переходу з використанням команди повернення
Виклик процедури виконується командою call, а повернення із неї
– командою RET. Команда call передає керування ближньою чи далекою
процедурою із запам'ятовуванням у стеку адреси точки повернення.
Команда ret повертає управління з процедури викликаючої програмі,
адреса повернення отримує з стека.
65
Команда CALL аналогічна команді JMP і підтримує самі способи
адресації:
CALL зміщення;
CALL регістр;
CALL qword ptr [змінна];
CALL qword ptr [64-бітний регістр].
Відмінність CALL від JMP у цьому, що CALL зберігає у стеку
адресу повернення, т. е. адресу наступної інструкції. Цю адресу
використовує команда RET, яку прийнято називати командою
повернення з підпрограми. Насправді це назва умовна, т.к. команду RET
можна використовувати і для виклику підпрограм, і для переходів. Дія
команди RET формально можна записати так:
rip ← ss:[rsp]
add rsp, 8
Тобто. верхні 8 байта стека завантажуються в регістр-покажчик
команд, після чого покажчик стека коригується.
Але перед виконанням команди ret компілятор вставляє команду
leave. Для повернення з процедури це правильно, а при переході на
адресу – ні. Тому потрібна корекція. Назад для leave є команда enter 0,0.
Команда ENTER створює кадр стека. Перший операнд задає
кількість байтів пам'яті, що виділяється в стеку при вході в процедуру.
Другий операнд задає рівень вкладеності процедури у вихідному коді.
Він визначає кількість покажчиків кадру стека, що копіюються в новий
кадр стека з попереднього.
Команда LEAVE має дію, протилежну команді ENTER. Фактично,
команда LEAVE тільки копіює вміст RBP в RSP, тим самим викидаючи
зі стека весь кадр, створений командою ENTER, і зчитує зі стека
значення регістра RBP для попередньої процедури.
Значить, команду
call rax
можна замінити командами
push rax
enter 0,0; 0h - кількість байтів у пам'яті, 0 - рівень вкладення
ret
66
У rах попередньо має бути завантажена необхідна адреса переходу.
У програмі 5.3 повинна виконуватися операція ab + a/c, але через
розгляд переходу перша частина рівняння не виконується, а виконається
тільки операція a/c.
Програма 5.3. Використання команди ret під час виконання
обчислень:
title Использование команды ret
include \masm64\include64\masm64rt.inc
.data
a1 dq 6 ;
b1 dq 2 ;
c1 dq 3
titl db "Вывод результата",0;
buf1 dq 1 dup(0),0 ; буфер вывода сообщения
fmt1 db "Результат: "," %d",0
.code ;
entry_point proc
lea rax,[m1] ; адрес метки
push rax
enter 0,0; 0h - число байтов в памяти, 0 - уровень вложения
ret
;m1:
mov rax,a1 ;
imul rax,b1 ; a1 x b1
mov r11,rax ;
m1:
xor rdx,rdx
mov rax,a1
div c1 ; a1/c1
add rax,r11
invoke wsprintf, ADDR buf1, ADDR fmt1,rax;
invoke MessageBox,0,addr buf1,addr titl, MB_ICONINFORMATION;
invoke ExitProcess, 0
entry_point endp
end
На рис. 5.1 наведено вікно відладчика.
67
У цьому вікні видно, що компілятор при звичайному використанні
команди ret вставляє команду leave. Саме тому в програму і треба
вставляти для команди leave команду enter.
5.3. Організація переходу з використанням команди call та
перекриттям коду
Якщо при вставці в програму команд з використанням перекриття
застосовується код команди ret з метою переходу на іншу гілку
програми, компілятор не ідентифікує цю команду і не вставляє
додаткову команду leave. У такому разі і в програму не вставляється
команда корекції – enter.
Розглянемо консольну програму перевірки пароля із заміною
команди call командами push та ret із застосуванням технології
перекриття коду (програма 5.4).
Програма 5.4. Перевірка пароля з перекриттям коду:
include \masm64\include64\masm64rt.inc
.data
Password db "12345" ; проверка только первых пяти символов
len1 equ ($-Password)/type Password
Buf dq 5 ;
Err1 dq 0
stdout1 dq 0 ;
stdin1 dq 0 ;
cRead dq 0 ;
cWritten dq 0 ;
Msg db "Please enter your password, 5 characters",10,10,0 ;
Msg1 db "Поздравляем! Пароль совпал",0
Msg2 db "Сожалеем! Пароль не корректен",0
Рис. 5.1. Використання команд ret і enter
68
Title1 db "Проверка пароля",0
.code
entry_point proc
mov rcx,STD_OUTPUT_HANDLE
call GetStdHandle
mov stdout1,rax
mov rcx,STD_INPUT_HANDLE
call GetStdHandle
mov stdin1,rax
lea rax,[m1]
mov ebx,0C350D8FAh ; 50 - push eax, C3 - ret
jmp $ - 2 ; на предыдущий код
m1: ; адрес возврата – на продолжение
invoke WriteConsole,stdout1,ADDR Msg,sizeof Msg,ADDR cWritten,0
invoke ReadConsole,stdin1,ADDR Buf,5,ADDR cRead,0
lea rsi,Password ; адрес первого элемента строки
lea rdi,Buf ; адрес второго элемента строки
mov rcx,len1
repe cmpsb ; побайтно проверяется len раз
jz m2 ;
inc Err1 ; счетчик несовпадений
m2:
.if (Err1==0);
invoke MessageBox,0,addr Msg1,addr Title1,MB_ICONINFORMATION
.else
invoke MessageBox,0,addr Msg2,addr Title1,MB_ICONERROR
.endif
invoke ExitProcess,0
entry_point endp
end
На рис. 5.2 представлено консольне вікно з виведенням запрошення
та введенням пароля. Повідомлення при успішному збігу пароля
показано на рис. 5.3.
69
3
У програмі представлений блок коду, який показує технологію
перекриття коду та використання команд push та ret для здійснення
переходу на необхідну ділянку коду.
Застосування команди call явно свідчить про виклик процедури. А
застосування зв'язки команд push та ret дозволяє ускладнити аналіз коду
та зробити виклик процедури (або переходу) не явним.
У цій програмі не показано процес застосування виклику
процедури (переходу) із застосуванням зміщення на велику кількість
байтів.
Блок програми, в якому відбувається перекриття коду та перехід на
іншу адресу представляє наступну послідовність команд:
lea rax,[m1]
mov ebx,0C350D8FAh; 50 - push eax, C3 - ret
jmp $-2; на попередній код
m1:; адреса повернення – на продовження
У команді mov ebx,0C350D8FAh значення D8FAh - будь-які
заповнення формату регістру.
Для порівняння змін послідовності виконання рядків коду у
налагоджувачі наведено приклад до виконання команди jmp $ - 2 (рис.
5.4).
Рис. 5.2. Консольне вікно введення пароля
Рис. 5.3. Повідомлення при успішному збігу пароля
70
Блок коду після виконання команди jmp$-2 представлений на
рис. 5.5.
При виконанні команди ret за адресою регістра rax відбувається
перехід на новий рядок коду.
Тобто для здійснення переходу можна використовувати зв'язок
команд push і ret, яку можна спробувати сховати ще й застосуванням
технології перекриття коду.
Програма має великий недолік: значення пароля прописано в самій
програмі секції даних. Наприклад, при запиті програми введення пароля
вводимо значення 99999. А значення пароля у цьому прикладі 12345.
Рис. 5.4. Блок коду до виконання команди jmp $ - 2
Рис. 5.5. Блок коду після виконання команди jmp $ - 2
71
Відкриваємо відладчик x64Dbg і в покроковому режимі при
багаторазовому натисканні на клавішу F8 аналізуємо повідомлення
програми. Шукаємо введені значення 99999. І через деякий час
з'являються рядки коду, які наведені на рис. 5.6.
У верхньому рядку в полі коментарів у першій частині видно
правильний пароль і в другій частині – ті значення, які були введені
(99999).
Тому найпростіший варіант це якось виправити – сховати пароль у
рядках коду. Для цього, як було розглянуто раніше, потрібно
використати команду jmp.
5.4. Лабораторна робота «Організація переходів»
Мета заняття: набути практичних навичок написання та
застосування програм з використанням команди повернення RET.
У звіті подати:
– назва лабораторної роботи, варіант, прізвище та ініціали, e-mail,
номер групи автора програми;
– у тексті програми організувати виведення назви лабораторної
роботи, варіант, прізвище та ініціали, e-mail, номер групи автора
програми;
– результат виконання завдання (скриншоти вікон програми та
відладчика).
Рис. 5.6. Вікно з паролями
72
Завдання
За допомогою команд AVX виконати рівняння, де змінна приймає
п'ять значень і задана масивом. Числа, що залишилися, також задані в
масиві {b, c, d, e}. Застосувати організацію 2-х типів переходу:
- зв'язок команд push та ret;
- Перекриття коду.
Отримані результати записати у файл.
Варіанти
1. a√(bc) – df/e; 11. ab/cd + f√e; 21. ab/c + df√e;
2. a/b + df√c; 12. a/cd – √e + fb; 22. a/bc + f√(de);
3. bc/d – ef√a; 13. ce + √a + bdf; 23. abc√d – e√f;
4. a/b/c + f√(de); 14. a/b/c + f√(de); 24. ab√cd) – f/e;
5. a + bc – df√e; 15. √(ab) + cf/d – e; 25. de√c + bcf/a,
6. ab + c/d – f√e; 16. af√(ce) – bd;
7. (a/b) + cdf√e; 17. bd/c + √a – fe;
8. ed/c – af√b; 18. c√e + a/b + df;
9. √a + √b + cdf/e; 19. de√b + cf/a;
10. c√(de) + df/a; 20. a/e + bf√cd,
де a, b, c, d ,e, f – числа, числа а є{a1,a2,a3,a4} задані масивом.
Контрольні питання для перевірки знань
1. Навіщо під час використання команди ret необхідна корекція у
програмі?
2. Які дії формально виконує команда CALL?
3. Чому при виконанні команд CALL та RET не потрібна корекція
у програмі?
4. Що таке кадр стека і коли він формується?
5. Чому під час перекриття коду з використанням зв'язки команд
push і ret не потрібна корекція в програмі?
73
6. САМОМОДИФІКАЦІЯ КОДУ ПРОГРАМИ
При налагодженні програми в налагоджувачі хакер не завжди і не
відразу перевіряє кожен рядок коду на логіку її виконання. А
застосування самодифікації коду дозволяє вже при виконанні змінювати
логіку програми. Такий прийом ускладнює процес аналізу програми.
6.1. Загальні відомості про самодифікацію коду
Для передачі керування з однієї ділянки коду на інший зазвичай
використовуються такі команди:
• безперечний перехід JMP;
• умовні переходи Jcc;
• виклик підпрограми CALL;
• "повернення з підпрограми" RET;
• команда циклу LOOP.
При зламі програми завжди шукають команди test, cmp, jz, jnz, які
у відладчику одразу впадають у вічі. Достатньо змінити jz на jnz або
взагалі "вбити" виклик процедури порівняння паролів - і програма почне
приймати будь-які дані як правильний пароль. При цьому не потрібно
навіть пізнавати правильний пароль.
Завдання – приховати логіку захисту.
Необхідно записати в коді довільне сміття, а потім уже в процесі
виконання програми змінювати його на потрібні команди. Тут виникає
проблема – запис даних у сторінки коду заборонено. Але й така
проблема так само вирішувана.
Перш ніж змінювати jz або jnz, спочатку розглянемо коди операцій.
Мета - аналіз кодів операцій. Для цього розглянемо програму 6.1.
Програма 6.1. Застосування команд розгалуження:
.code
entry_point proc
jmp L1
jmp L2
jz L1
jnz L1
jb L1
74
jnb L1
jg L1
jng L1
L1:
mov al,bl
L2:
invoke ExitProcess,0
На рис. 6.1 наведено вікно відладника x64Dbg з отриманим ехе-
файлом.
Усі команди ближнього переходу – двобайтові. Перший байт – код
команди, другий – усунення щодо поточної команди до потрібної
адреси.
Команди ближнього переходу дозволяють перейти на -128/127 байт
щодо поточної інструкції. Відомо, що команди далекого переходу
п'ятибайтові.
Слід звернути увагу, що код операції jmp дорівнює ЕВh.
6.2. Самомодифікація команди переходу
При перевірці пароля завжди відбувається порівняння чисел
(символів) та подальший перехід, як правило, за командою jnz.
Тому в тексті програми необхідно замість команди jnz застосувати
іншу команду, наприклад, команду jc.
А вже при виконанні ехе-файлу потрібно команду jnz поміняти на
команду jc. Такий прийом однозначно збиває хакера під час аналізу
коду.
Рис. 6.1. Вікно налагоджувача x64Dbg з отриманим ехе-файлом
75
Зміна коду операції здійснюється за допомогою функції
WriteProcessMemory.
Параметри функції WriteProcessMemory:
- дескриптор процесу (до якого здійснюватиметься запис):
- адреса, за якою здійснюватиметься запис;
- адреса буфера, з якого здійснюватиметься запис;
- кількість байтів, що необхідно записати;
- Покажчик на змінну, в яку буде записано кількість скопійованих
байт. Якщо він дорівнює нулю, запис ігнорується.
Програма 6.2. Консольне введення пароля:
include \masm64\include64\masm64rt.inc
.data
Password db "12345" ; пароль
len1 equ $-Password
Buf dq 5 ;
Err1 dq 0
Msg1 db "Пароль совпал",0
Msg2 db "Пароль не корректен",0
Title1 db "Проверка пароля",0
stdout1 dq 0 ;
stdin1 dq 0 ;
cRead dq 0 ;
cWritten dq 0 ;
Msg db "Введите пароль, 5 символов",10,0 ;
Msg10 db "*****",10,0 ;
opc db 075h ; КОП JNZ
.code
entry_point proc
invoke GetStdHandle,STD_OUTPUT_HANDLE
mov stdout1,rax
invoke GetStdHandle,STD_INPUT_HANDLE
mov stdin1,rax
invoke SetConsoleCP,1251;уст. кодовой страницы win 1251 в поток ввода
invoke SetConsoleOutputCP,1251;уст. кодовой страницы win1251 вывода
invoke WriteConsole,stdout1,ADDR Msg,sizeof Msg,ADDR cWritten,0
invoke WriteConsole,stdout1,ADDR Msg10,sizeof Msg10,ADDR cWritten,0
invoke ReadConsole,stdin1,ADDR Buf,5,ADDR cRead,0
invoke GetCurrentProcessId
76
invoke OpenProcess,PROCESS_VM_OPERATION or
PROCESS_VM_WRITE, 1, rax
lea rdi,_toWrite ; записать адрес метки, т.е. команды jc m1
invoke WriteProcessMemory,rax,rdi,addr opc,1,0 ; в rdi opc=75h
lea rsi,Password ; загрузка адреса нахождения Password
lea rdi,Buf ; загрузка адреса буфера введенных символов
mov rcx,len1 ; счетчик символов
m1:
mov al,[rsi] ; загрузка числа по адресу из rsi
mov bl,[rdi] ;
cmp al,bl ; сравнение символов
jz m2 ; если совпали символы
inc Err1 ; счетчик несовпадений
m2:
add rsi,1 ; inc адреса
add rdi,1 ;
dec rcx
_toWrite:
jc m1
.if (Err1==0);
invoke MessageBox,0,addr Msg1,addr Title1,MB_ICONINFORMATION
.else
invoke MessageBox,0,addr Msg2,addr Title1,MB_OK
.endif
invoke ExitProcess,0
entry_point endp
end
Під час виконання функції WriteProcessMemory команда jс
змінюється на команду jnz.
У секції даних програми записано лише один байт – код команди
jnz, але в разі потреби таким чином можна копіювати цілі функції.
6.3. Алгоритм самодифікації коду
Алгоритм написання програми, що самодифікується, може бути
таким:
77
1. Пишеться програма без самодифікації, компілюється та
перевіряється правильність її роботи (наприклад, за повідомленнями
програми).
2. Вибираються рядки програми, яких можна застосувати
самомодифікацію. На першому етапі для простоти це можуть бути
команди, а чи не функції. Причому самодифікацію простіше проводити
по одному рядку коду (по одній команді).
3. У відладчику відкривається ехе-файл і на аркуш паперу (або в
блокноті) записуються побайтно коди операції та операнди, але у
зворотній послідовності – молодші значення байтів записуються
правіше, а старші – лівіше.
4. Резервується місце для команди, яка вставлятиметься. Для цього
на місці того рядка, який модифікується, ставиться мітка і пишеться
будь-яка команда або команди загальною розмірністю, що дорівнює
команді, яка буде вставлятися.
Після внесених змін необхідно перевіряти працездатність
програми. Потім застосовувати самодифікацію до наступного рядка та
постійно перевіряти працездатність програми.
Програма 6.3. Самомодифікуюча програма перевірки пароля із
заміною кількох команд:
include \masm64\include64\masm64rt.inc
.data
Password db "12345" ; пароль
len1 equ ($-Password)
Buf dq 5 ;
Err1 dq 0
Msg1 db "Пароль совпал",0
Msg2 db "Пароль не корректен",0
Title1 db "Проверка пароля",0
stdout1 dq 0 ;
stdin1 dq 0 ;
cRead dq 0 ;
cWritten dq 0 ;
Msg db "Введите пароль, 5 символов",10,0 ;
Msg10 db "*****",10,0 ;
opc db 075h ; код операции (КОП) JNZ
opc1 dq 0068Ah ; mov al,[rsi]
78
h1 dq ? ; идентификатор процесса
opc2 dq 01F8Ah ; mov bl,[rdi]
opc3 dq 0C33Ah ; cmp al,bl
opc4 dq 01C68348h ; add rsi,1
.code
entry_point proc
invoke GetStdHandle,STD_OUTPUT_HANDLE
mov stdout1,rax
invoke GetStdHandle,STD_INPUT_HANDLE
mov stdin1,rax
invoke SetConsoleCP,1251;уст. кодовой стран. win 1251 в поток ввода
invoke SetConsoleOutputCP,1251;уст. код. стр. win1251 в поток вывода
invoke WriteConsole,stdout1,ADDR Msg,sizeof Msg,ADDR cWritten,0
invoke WriteConsole,stdout1,ADDR Msg10,sizeof Msg10,ADDR cWritten,0
invoke ReadConsole,stdin1,ADDR Buf,5,ADDR cRead,0
invoke GetCurrentProcessId
invoke OpenProcess,PROCESS_VM_OPERATION or
PROCESS_VM_WRITE,1,rax
mov h1,rax ; идентификатор процесса
lea rdi,_toWrite
invoke WriteProcessMemory,rax,rdi,addr opc,1,0
lea r15,m1
invoke WriteProcessMemory,h1,r15,addr opc1,2,0
lea r15,mm10
invoke WriteProcessMemory,h1,r15,addr opc2,2,0
lea r15,mm11
invoke WriteProcessMemory,h1,r15,addr opc3,2,0
lea r15,m2
invoke WriteProcessMemory,h1,r15,addr opc4,4,0
lea rsi,Password ; загрузка адреса нахождения Password
lea rdi,Buf ; загрузка адреса буфера введенных символов
mov rcx,len1 ; счетчик символов, 10 байтов не вмещается в dq
; в эти места будут записываться новые команды из секции данных
m1: add al,10 ; любая команда на 2 байта (mov al,[rsi])
mm10: add al,11 ; любая команда на 2 байта (mov bl,[rdi])
mm11: add al,12 ; любая команда на 2 байта (cmp al,bl)
79
;mov al,[rsi] ; загрузка числа по адресу из rsi
;mov bl,[rdi] ;
;cmp al,bl ; сравнение символов
jz m2 ; если совпали символы
inc Err1 ; счетчик несовпадений
m2: sub rsp,60 ; 4 байта (add rsi,1)
;add rsi,1 ; inc адреса, 4 байта
add rdi,1 ;
dec rcx
_toWrite:
jc m1
.if (Err1==0);
invoke MessageBox,0,addr Msg1,addr Title1,MB_ICONINFORMATION
.else
invoke MessageBox,0,addr Msg2,addr Title1,MB_OK
.endif
invoke ExitProcess,0
entry_point endp
end
На рис. 6.2 наведено вікно налагоджувача x64Dbg до виконання
самодифікації коду. Звернути увагу необхідно на рядки коду внизу
вікна:
add al,A
add al,B
add al,C
Результат виконання самодифікації із заповненими рядками до
рядка, позначеного сірим кольором, показаний на рис. 6.3.
80
Рис. 6.3. Результат виконання самодифікації
Рис. 6.2. Вікно налагоджувача x64Dbg до виконання самодифікації коду
81
Недоліки цього підходу – відкритість (виклик функції
WriteProcessMemory привертає увагу) і трудомісткість (якщо йдеться
про складні функції).
6.4. Самодифікуюча діалогова програма з кількома діалоговими
вікнами
Процес створення діалогового вікна складається з етапів:
1. Створення файлу ресурсів;
2. Створення діалогової програми;
3. Переналаштування (створення) командного (пакетного) файлу.
Для створення ресурсів (наприклад, вставка іконки, JPG-файлу та
інше) будемо використовувати програму ResEd. Послідовність
створення файлу ресурсів може бути такою:
1. У програмі ResEd створюємо новий файл ресурсів (File - New
Project і вводимо ім'я). У правій верхній панелі з'являється піктограма
папки та ім'я файлу.
2. Натискаємо правою кнопкою миші на піктограму папки та
вибираємо «Add Dialog».
3. Виставляємо характеристики вікна:
- Виставляємо мишкою необхідний розмір вікна;
- у полі властивостей вікна Caption змінюємо назву діалогового
вікна.
4. Для розміщення картинки (у нашому випадку іконки) вибираємо
кнопку та перетягуємо її мишкою на діалогове вікно.
5. Для розміщення кнопки вибираємо в полі інструментів кнопку із
зображенням ОК та перетягуємо її мишкою на вибране місце. У полі
Caption вводимо назву кнопки.
6. Для написання тексту на вікні вибираємо в полі інструментів
кнопку із зображенням літери «А» та перетягуємо її мишкою на вибране
місце. У полі Caption вводимо текст.
7. Для створення рамки (якщо необхідно) вибираємо поле із
зображенням рамки. У полі Caption вводимо назву рамки.
8. Додаємо файл ресурсів.
Додавання файлу констант. Для цього натискаємо правою кнопкою
миші по значку папки, вибираємо "Include file", потім "Add". Вибираємо
у вікні програми три точки і вводимо шлях, наприклад C:
masm64include64 RESOURCE.H.
9. Зберігаємо програму.
82
10. Відкриваємо створений rc-файл і додаємо рядок із ресурсом
курсору:
10 ICON DISCARDABLE " sent.ico"
У цьому рядку число 10 означає цифровий ідентифікатор іконки
(ресурс). Він може мати будь-яке значення, але і в rc-і asm-файлах він
повинен бути одним і тим же.
11. Для створення чергового вікна натискаємо правою кнопкою
миші на піктограму папки та вибираємо «Add Dialog». Інші дії над
створенням елементів вікна повторюються.
12. Створити у текстовому редакторі маніфест додатка із вмістом,
як наведено у програмі 6.4.
У зв'язку з тим, що програма створення ресурсів ResEd вже давно
не оновлюється, вона неправильно вносить рядки директив, які
відносяться до вмісту файлу маніфесту в ОС Win64. Тому рядки коду
файлу ресурсів, які відносяться до маніфесту, повинні бути такими:
#define MANIFEST 1 //
1 24 "MsgD.manifest.xml"
Програма 6.4. Маніфест програми:
Диал. прог.
83
13. До файлу ресурсів дописати структури визначення версії:
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,0,0
PRODUCTVERSION 1,0,0,0
FILEOS 0x00000000
FILETYPE 0x00000000
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "041904B0"
BEGIN
VALUE "CompanyName", "каф. КІП\000\0"
VALUE "FileDescription", "Рысованый А.Н. \000\0"
VALUE "FileVersion", "1.0\000\0"
VALUE "InternalName", " MsgD \000\0"
VALUE "OriginalFilename", " MsgD.exe\000\0"
VALUE "LegalCopyright", "\251 2024, Рысованый А.Н. \000\0"
VALUE "ProductName", " MsgD \000\0"
VALUE "ProductVersion", "1.0\000\0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x0419, 0x04B0
END
END
В результаті будуть створені вікна, зображення яких наведено на
рис. 6.4.
Рис. 6.4. Діалогові вікна програми
84
Програма 6.5. Діалогова програма проекту:
include \masm64\include64\masm64rt.inc
.data?
hInstance dq ?
hIcon dq ?
hIcon3 dq ?
hImg1 dq ?
hImg3 dq ?;
tEdit dq ?
buffer db 8 dup(?); BYTE 64 dup(?);;;
.data
szTit1e104 db «Общ. сведения",0
szInf104 db "masm64... ",0
pbuf dq buffer,0 ;;;
szPas db "12345",0 ; пароль
szStr1 db "Вы ввели корректный пароль. Поздравляем!",0
szStr2 db "Вы ввели неправильный пароль.",0
titl db "программа проверки пароля",0
szRun db "RP-Xor-64-sam.exe",0
.code
entry_point proc
mov hInstance, rvcall(GetModuleHandle,0)
mov hIcon,
rv(LoadImage,hInstance,10,IMAGE_ICON,256,256,LR_DEFAULTCOLOR)
invoke DialogBoxParam,hInstance,100,0,ADDR main,hIcon
.exit
entry_point endp
main proc hWin:QWORD,uMsg:QWORD,wParam:QWORD,
lParam:QWORD
.switch uMsg
.case WM_INITDIALOG
rcall SendMessage,hWin,WM_SETICON,1,lParam ; установить иконку в
строке заголовка
mov hImg1, rvcall(GetDlgItem,hWin,102)
rcall SendMessage,hImg1,STM_SETIMAGE,IMAGE_ICON,lParam ; иконка
в клиентской области
.case WM_COMMAND
.switch wParam
.case 103 ; кнопка <Ввод текста>
mov hIcon,rv(LoadImage,hInstance,11,IMAGE_ICON,256,256,
LR_DEFAULTCOLOR)
85
invoke DialogBoxParam,hInstance, 200,0, ADDR GetUserText,hIcon
test rax,rax ; нажата ли кнопка отмены
jz notext
rcall MessageBox,hWin,pbuf,"Пользовательский текст",
MB_ICONQUESTION
lea r14,pbuf; для того, чтобы убрать лишний служебный символ
mov r15,[r14]
invoke lstrcmpi,addr szPas,r15 ;addr pbuf ; сравнение строк символов
.if rax==0
invoke MessageBox,0,addr szStr1,addr titl,MB_ICONINFORMATION
.else
invoke MessageBox,0,addr szStr2,addr titl,MB_ICONERROR
jmp exit_dialog
.endif
mov
hIcon3,rv(LoadImage,hInstance,12,IMAGE_ICON,256,256,LR_DEFAULTCO
LOR)
invoke DialogBoxParam,hInstance,300,0,ADDR Dial3,hIcon3
notext:
.case 105 ; кнопка
jmp exit_dialog
.case 104 ; кнопка <Общ. сведения>
invoke MsgboxI,0,ADDR szInf104,ADDR szTit1e104,MB_OK,10
.endsw
.case WM_CLOSE
exit_dialog:
rcall EndDialog,hWin,0
.endsw
xor rax, rax
ret
main endp
GetUserText proc hWin:QWORD,uMsg:QWORD,wParam:QWORD,
lParam:QWORD
.switch uMsg
.case WM_INITDIALOG
rcall SendMessage,hWin,WM_SETICON,1,lParam ; иконка в строке
заголовка
mov hImg1, rvcall(GetDlgItem,hWin,205); извлекает дескриптор
86
rcall SendMessage,hImg1,STM_SETIMAGE,IMAGE_ICON,lParam ; иконка
в клиентской области
mov tEdit,rvcall(GetDlgItem,hWin,201)
invoke SetFocus,tEdit ; установка курсора в поле ввода
.case WM_COMMAND
.switch wParam
.case 202 ; кнопка ОК
rcall GetWindowText,tEdit,pbuf,sizeof buffer; записать текст по адресу
буфера
.if rax == 0
rcall MessageBox,hWin,"Введите текст или нажмите Cancel","Текст
отсутствует", MB_ICONWARNING
rcall SetFocus,tEdit ; установка фокуса на окно Edit
.else
rcall EndDialog,hWin,1
.endif
.case 203 ;
jmp exit_dialog
.endsw
.case WM_CLOSE
exit_dialog:
rcall EndDialog,hWin,0
.endsw
xor rax, rax
ret
GetUserText endp
Dial3 proc hWin:QWORD,uMsg:QWORD,wParam:QWORD,
lParam:QWORD
.switch uMsg
.case WM_INITDIALOG
rcall SendMessage,hWin,WM_SETICON,1,lParam ; установить иконку
в строке заголовка
mov hImg3,rvcall(GetDlgItem,hWin,302)
rcall SendMessage,hImg3,STM_SETIMAGE,IMAGE_ICON,lParam ;
иконка в клиентской области
.case WM_COMMAND
.switch wParam
.case 304 ; кн. Автор
invoke MsgboxI,0,"Рысованый А.Н., каф. КИП","Автор",MB_OK,13
.case 306 ; кн. Функционал
invoke WinExec,ADDR szRun,SW_HIDE
.case 305 ; кн. Exit
87
jmp exit_dialog3
.endsw
.case WM_CLOSE
exit_dialog3:
rcall EndDialog,hWin,0
.endsw
xor rax, rax
ret
Dial3 endp
end
Діалогова програма викликає ехе-файл перевірки пароля (програма
5.4, яка розглянута раніше).
6.5. Лабораторна робота «Самомодифікація коду»
Мета заняття: набути практичних навичок застосування
самодифікації коду.
У звіті подати:
– назва лабораторної роботи, варіант, прізвище та ініціали, e-mail,
номер групи автора програми;
– представити дві програми: без діалогового вікна та проект з
діалоговими вікнами;
– у тексті програми організувати виведення назви лабораторної
роботи, варіант, прізвище та ініціали, e-mail, номер групи автора
програми;
– результат виконання завдання (скриншоти вікон програми та
відладчика).
Завдання
Відповідно до номера студента у групі вибрати варіант завдання та
написати в середовищі masm64 на асемблері програму обчислення
одного з виразів.
Отримані результати записати у файл.
Варіанти
1. Помножити матрицю [2 х 2] на матрицю [2 х 2].
2. Помножити матрицю [2 х 2] на матрицю [2 х 2] mod2.
3. Помножити матрицю [2 х 2] на матрицю [2 х 2] за mod3.
88
4. Помножити матрицю [3 х 3] на матрицю [3 х 1].
5. Помножити матрицю [3 х 3] на матрицю [3 х 1] mod2.
6. Помножити матрицю [3 х 3] на матрицю [3 х 1] mod3.
7. Помножити матрицю [3 х 3] на матрицю [3 х 3].
8. Помножити матрицю [3 х 3] на матрицю [3 х 3] mod2.
9. Помножити матрицю [3 х 3] на матрицю [3 х 3] mod3.
10. Помножити матрицю [4 х 4] на матрицю [4 х 1].
11. Помножити матрицю [4 х 4] на матрицю [4 х 1] mod2.
12. Помножити матрицю [4 х 4] на матрицю [4 х 1] mod3.
13. Помножити матрицю [4 х 4] на матрицю [4 х 4].
14. Помножити матрицю [4 х 4] на матрицю [4 х 4] mod2.
15. Помножити матрицю [4 х 4] на матрицю [4 х 4] mod3.
16. Помножити матрицю [5 х 5] на матрицю [5 х 1].
17. Помножити матрицю [5 х 5] на матрицю [5 х 1] mod2.
18. Помножити матрицю [5 х 5] на матрицю [5 х 1] mod3.
19. Помножити матрицю [5 х 5] на матрицю [5 х 5].
20. Помножити матрицю [5 х 5] на матрицю [5 х 5] mod3.
21. Помножити матрицю [6 х 6] на матрицю [6 х 6].
22. Помножити матрицю [6 х 6] на матрицю [6 х 6] по mod3.
23. Помножити матрицю [7 х 7] на матрицю [7 х 7].
24. Помножити матрицю [7 х 7] на матрицю [7 х 7] mod2.
25. Помножити матрицю [7 х 7] на матрицю [7 х 7] mod3.
26. Помножити матрицю [8 х 8] на матрицю [8 х 8].
Програма 6.6. Розмноження матриці [3 х 3] на матрицю [3 х 1]:
include \masm64\include64\masm64rt.inc ;
.data
mas1 dd 1,2,3 ; a1, b1, c1
mas2 dd 4,5,6 ; a2, b2, c2
mas3 dd 3,2,1 ; a3, b3, c3
mas4 dd 10,; d1
11,; d2
12 ; d3
buf1 dq 3 dup(0); буфер
fmt1 db "masm64.",10,10,
"|1 2 3| |10|",10,"|4 5 6| x |11|", 10,"|3 2 1| |12|",10,10,
"Результат = |%d %d %d|T",10,10,
"Автор: Рысованый А.Н., каф. КИП, НТУ ХПИ",0
titl1 db "Перемножение матриц 3х3 на 3х1.",0
.code ;
entry_point proc
89
;;;; Умножить матрицу [3 х 3] на матрицу [3 х 1]
vmovd xmm1,mas1[0] ; a1 [3x3]
vmovd xmm2,mas1[4] ; b1
vmovd xmm3,mas1[8] ; c1
vmovd xmm4,mas4[0] ; d1
vmovd xmm5,mas4[4] ; d2
vmovd xmm6,mas4[8] ; d3
vpmulld xmm10,xmm1,xmm4 ;[a1xd1]
vpmulld xmm11,xmm2,xmm5 ;[b1xd1]
vpmulld xmm12,xmm3,xmm6 ;[c1xd3]
vaddsd xmm10,xmm10,xmm11
vaddsd xmm10,xmm10,xmm12
vmovd r10d,xmm10
movsxd r10,r10d ; [3x1] result
vmovd xmm1,mas2[0] ; a2 [3x3]
vmovd xmm2,mas2[4] ; b2
vmovd xmm3,mas2[8] ; c2
vpmulld xmm7,xmm1,xmm4 ;[a2xd1]
vpmulld xmm8,xmm2,xmm5 ;[b2xd2]
vpmulld xmm9,xmm3,xmm6 ;[c3xd3]
vaddsd xmm11,xmm7,xmm8 ;
vaddsd xmm11,xmm11,xmm9 ;
vmovd r11d,xmm11
movsxd r11,r11d ;a2 [3x1] result
vmovd xmm1,mas3[0] ; a3 [3x3]
vmovd xmm2,mas3[4] ; b3
vmovd xmm3,mas3[8] ; c3
vpmulld xmm1,xmm1,xmm4 ;[a3xd1]
vpmulld xmm2,xmm2,xmm5 ;[b3xd2]
vpmulld xmm3,xmm3,xmm6 ;[c3xd3]
vaddsd xmm12,xmm1,xmm2
vaddsd xmm12,xmm12,xmm3
vmovd r12d,xmm12
movsxd r12,r12d ;a3 [3x1] result
invoke wsprintf,addr buf1,ADDR fmt1,r10,r11,r12
invoke MessageBox,0,addr buf1,addr titl1,MB_OK
invoke ExitProcess,0
entry_point endp
end
90
Контрольні питання для перевірки знань
1. Наведіть особливості формування коду операцій команд
переходу.
2. Яка розмірність команд ближнього та далекого переходу?
3. Опишіть послідовність зміни коду операції.
4. Опишіть послідовність перевірки пароля.
5. Опишіть алгоритм написання програми, що самодифікується.
91
7. ПЕРЕВІРКА ДАТИ І ЧАСУ
7.1. Загальні відомості про фіксовану кількість запусків
Обхід захисту програми за датою та часом (як і будь-який інший
простий захист) для звичайного користувача є непереборною дією. Це
можна стверджувати і для звичайного програміста. Для хакера це дуже
легко (якщо він хакер). Для будь-якого злому необхідні специфічні
знання, робота з особливим програмним забезпеченням та досвід, який
напрацьовується на простих методах захисту.
Фіксовану кількість запусків програми можна реалізувати кількома
способами в залежності від конкретних вимог та мови програмування.
Можна організувати обмеження запусків програми за такими
подіями:
- по даті;
= запис дати першого запуску та перевірка з поточною датою;
= Порівняння поточної дати з датою створення.
- за часом використання;
- за кількістю запусків програми;
- за кількістю записів у файл та ін.
Лічильники подій можна розмістити:
- у реєстрі;
- у ключовому файлі;
- в оперативній пам'яті та ін.
7.2. Перевірка дати закінчення запуску програми
У програмі 7.1 розглядається перевірка дати закінчення її запуску
за рахунок порівняння з елементами структури. У цій структурі
наведено дату, з якою порівнюється з поточною датою. І за перевищення
поточної дати виконується перехід закінчення роботи програми.
Програма 7.1. Перевірка дати закінчення запуску:
include \masm64\include64\masm64rt.inc ;
; ограничение запуска по установленной дате
; консольный ввод
SYSTEMTIME1 STRUCT
wYear dw ? ; год
92
wMonth dw ? ; месяц
wDayOfWeek dw ? ; день недели
wDay dw ? ; день месяца 0-31
wHour dw ? ; час 0-23
wMinute dw ? ; минута 0-59
wSecond dw ? ; секунда 0-59
wMilliseconds dw ? ; миллисекунда 0-999
SYSTEMTIME1 ENDS
.data ;
today SYSTEMTIME1 >
date_final SYSTEMTIME1 <2024,6,?,15,?,?,?,?> ; установленная дата
Password db "12345" ; пароль
len1 equ $-Password ; число байтов
Buf dq 3 dup(0),0 ;
Err1 dq 3 dup(0),0
Msg1 db "Пароль совпал",0
Msg2 db "Пароль не корректен",0
Title1 db "Проверка пароля",0
out1 HANDLE 0 ;
in1 HANDLE 0 ;
cRead dq 3 dup(0),0 ;
cWritten dq 3 dup(0),0 ;
Msg db "Введите пароль, 5 значений",10,0 ;
Msg3 db "*****",10,0 ;
.code ;
entry_point proc ;
invoke GetSystemTime,addr today ; извл. текущую системную дату и
время
movzx r13,today.wYear ; значение текущего года
movzx r14,date_final.wYear ; значение конечного года
cmp r14,r13 ; сравнение годов
JNBE next1 ; если не > и =
movzx r13, today.wMonth ; извлечение значения текущего месяца
movzx r14, date_final.wMonth ; извлеч. конечного значения месяца
cmp r14,r13 ; сравнение значений
jnbe next1 ; если не > и =
movzx r13, today.wDay ; значение текущего дня
movzx r14, date_final.wDay ; значение конечного дня
cmp r14, r13 ; сравнение значений дней
93
jnbe next1 ; если >=
fn MessageBox,0,"Дата запуска программы истекла","Проверка интервала
времени",MB_OK
jmp exit
next1:
fn MessageBox,0,"Дата запуска программы не истекла","Проверка
интервала времени",MB_ICONINFORMATION
invoke GetStdHandle,STD_OUTPUT_HANDLE;
mov out1,rax
invoke GetStdHandle,STD_INPUT_HANDLE
mov in1,rax
invoke SetConsoleCP,1251;устан. кодовой стр. win 1251 в поток ввода
invoke SetConsoleOutputCP,1251;устан. кодовой стр. win 1251 в поток
вывода
invoke WriteConsole,out1,ADDR Msg,sizeof Msg,ADDR cWritten,0
invoke WriteConsole,out1,ADDR Msg3,sizeof Msg3,ADDR cWritten,0
invoke ReadConsole,in1,ADDR Buf,5,ADDR cRead,0
lea rsi,Password ;адрес первого элемента строки
lea rdi,Buf ;адрес второго элемента строки
mov rcx,len1
repe cmpsb ; побайтно проверяется len1 раз
jz m2 ;
inc Err1 ; счетчик несовпадений
jmp exit
m2:
invoke MessageBox,0,addr Msg1,addr Title1,MB_OK
exit:
invoke ExitProcess,0
entry_point endp
end
Розглянута програма консольна. Отже, вона повинна
компілюватися bat-файлом з параметром лінкування
/SUBSYSTEM:CONSOLE.
Під час запуску програми спочатку перевіряються три дати: рік,
місяць та день, до якої дозволено використовувати програму (рис. 7.1).
94
Після натискання на кнопку якого виводиться в консольне вікно
пропозиція про введення пароля (рис. 7.2).
У консольному вікні виведено 2 рядки.
Перший рядок з текстом виводиться функцією з параметрами:
invoke WriteConsole,out1,ADDR Msg,sizeof Msg,ADDR cWritten,0
Другий рядок із символами "*****" виводиться функцією з
параметрами:
invoke WriteConsole,out1,ADDR Msg3,sizeof Msg3,ADDR
cWritten,0
7.3. Запис у файл кількості запусків програми
Розглянемо програму 7.2, у якій окремий файл записується
кількість запусків цієї програми. Для зменшення рядків програми
застосовані макроси середовища masm64.
Рис. 7.1. Перше повідомлення програми
Рис. 7.2. Друге повідомлення програми
95
Програма 7.2. Запис у файл кількості запусків програми:
include \masm64\include64\masm64rt.inc
; Запись количества запусков программы в файл.
; Алгоритм:
; - делается попытка открыть файл,
; - если получилось - записываем 0.
; - при каждой записи инкрементируем значение.
; - иначе – создается новый файл и записывается в него число 0
.code
entry_point proc
LOCAL hFile: QWORD
LOCAL run_count: QWORD
LOCAL buf_ptr: QWORD
mov buf_ptr,ptr$(run_count)
mov hFile,flopen("test3.txt") ; открыть файл
cmp hFile,INVALID_HANDLE_VALUE
je FILE_NOT_EXISTS ; если файл не существует
jmp INC_RUN_COUNT
FILE_NOT_EXISTS:
mov hFile,flcreate("test3.txt"); создать файл
mov run_count,0
jmp WRITE_FILE
INC_RUN_COUNT:
mov rax,flread(hFile,buf_ptr,sizeof run_count); чтение файла
cmp rax,0
je FILE_READ_ERROR
mov rax, flseek(hFile,0,0); установить указатель файла. См. API
SetFilePointer
inc run_count ; увеличение счетчика запуска файла
jmp WRITE_FILE
FILE_READ_ERROR:
flclose hFile ; закрыть открытый файл по дескриптору файла
fn MessageBox,0,LastError$(),"ReadFile: Last Error",MB_OK
.exit
WRITE_FILE: ; запись
mov rax,flwrite(hFile,buf_ptr,sizeof run_count)
cmp rax,0
je FILE_WRITE_ERROR
96
flclose hFile
fn MessageBox,0,str$(run_count),"Количество запусков
программы",MB_OK
.exit
FILE_WRITE_ERROR:
flclose hFile ; закрыть открытый файл по дескриптору файла
fn MessageBox,0,LastError$(),"WriteFile: Last Error", MB_OK
.exit
entry_point endp
end
Макроси середовища наведені у довіднику та деякі з них
представлені на рис. 7.3.
На початку програми створюється файл, який записується
початкове значення 0. При наступних запусках значення кількості
запусків програми інкрементується.
У програмі не аналізується кількість решти запусків файлу і
заборона запуску надалі.
Рис. 7.3. Макроси у довіднику masm64
97
7.4. Обмеження спроб введення пароля
Дуже часто в різних програмах вводиться обмеження кількості
спроб введення пароля. Ціль такого обмеження – зменшення
ймовірності підбору пароля.
У програмі 7.3 розглядається приклад обмеження спроб введення
пароля трохи більше 2 разів. Для простоти довжина неправильного
пароля не повинна перевищувати 8 символів.
Приклад 7.3. Обмеження спроб введення неправильного пароля не
більше 2-х разів:
include \masm64\include64\masm64rt.inc ;
; Ограничение попыток ввода пароля (2 раза)
; в программе ограничение на длину не правильного пароля - не более 8
символов
.data
Password db "12345" ; пароль
len1 equ $-Password ; число байтов
Buf dq 0,0 ;
Err1 dq 0
out1 HANDLE 0 ;
in1 HANDLE 0 ;
cRead dq 0,0 ;
cWritten dq 0,0 ;
Msg db "Введите пароль, 5 значений",10,0 ;
Msg3 db "*****",10,0 ;
.code ;
entry_point proc ;
invoke GetStdHandle,STD_OUTPUT_HANDLE;
mov out1,rax
invoke GetStdHandle,STD_INPUT_HANDLE
mov in1,rax
invoke SetConsoleCP,1251;уст. кодовой страницы win 1251 в поток ввода
invoke SetConsoleOutputCP,1251;уст. кодовой стр. win 1251 для вывода
m10:
invoke WriteConsole,out1,ADDR Msg,sizeof Msg,ADDR cWritten,0
invoke WriteConsole,out1,ADDR Msg3,sizeof Msg3,ADDR cWritten,0
invoke ReadConsole,in1,ADDR Buf,5,ADDR cRead,0
98
lea rsi,Password ;адрес первого элемента строки
lea rdi,Buf ;адрес второго элемента строки
mov rcx,len1
repe cmpsb ; побайтно проверяется len1 раз; [RDI] – [RSI], пока RСХ / ? 0
jz m2 ;
inc Err1 ; счетчик кол. проходов
jmp exit
m2:
.if (Err1==0);
fn MessageBox,0,"Пароль совпал","Проверка пароля",
MB_ICONINFORMATION
jmp exit1
.else
exit:
fn MessageBox,0,"Пароль не корректен","Проверка пароля",
MB_ICONERROR
invoke ReadConsole,in1,ADDR Buf,5,ADDR cRead,0
.endif
inc Err1 ; увеличение счетчика повторения программы
.if Err1==2 ;
mov Err1,0; при вводе правильного пароля 2-й раз
jmp m10 ; на новый запуск программы
.endif
exit1:
invoke ExitProcess,0
entry_point endp
end
Лічильник кількості неправильно введених паролів організований
змінної Err1, нульове значення якого аналізується тоді, коли значення
збіглися.
На рис. 7.4 наведено приклад 2-х спроб введення пароля.
99
7.5. Запис до реєстру кількості запусків програми
Windows фіксує кожне звернення користувача до тієї чи іншої
програми і формує на основі зібраної статистики список програм, що
часто використовуються. До реєстру також можна записувати різну
інформацію, у тому числі кількість запусків вибраної програми. У
Windows 11 процес запису в реєстр розробники ОС зробили лише з
правами адміністратора, що певною мірою ускладнює використання
такого прийому.
При написанні програми роботи з реєстром необхідно враховувати,
що функції API, що відповідають за використання реєстру, знаходяться
в бібліотеці advapi32. Тому цю бібліотеку треба приєднувати примусово
на початку програми або доповнити файл masm64rt.inc цими рядками
бібліотеки.
Програма 7.4. Запис до реєстру кількості запусків програми:
include \masm64\include64\masm64rt.inc
include \masm64\include64\advapi32.inc
includelib \masm64\lib64\advapi32.lib
.data
szTestKey db 'Software\Microsoft\Windows\CurrentVersion\Policies',0
szREGSZ db 'REG_DWORD',0
hKey dd ?
lpdwDisp dd ?
szValueName1 db "Timer",0; новая запись с именем
setValue dq "8",0
buf1 LPDWORD 128,0
getKol LPBYTE "8",0 ; максимальное количество запусков
buf3 LPDWORD 128,0
error dd ?,0
ertit db "Описание ошибки",0
ook db "Ключ успешно создан",0
Рис. 7.4. Приклад 2-х спроб введення пароля
100
bed db "Ключ не создан",0
kk db "Реестр",0
kol dd 0 ; для максимального числа первой строки
titl db "Результат программы",0
buf dd 0,0
ifmt db "Условие: Ограничение количества запусков программы ",10,10,\
"Осталось количество запусков: %c",0
.code
entry_point proc
; СОЗДАЕМ РАЗДЕЛ
invoke RegCreateKeyEx,HKEY_CURRENT_USER,ADDR szTestKey, 0,
ADDR szREGSZ, REG_OPTION_VOLATILE,KEY_ALL_ACCESS,0,ADDR
hKey,ADDR lpdwDisp;
cmp rax,0 ;Раздел создан успешно ?
jne m1
; ПРОВЕРЯЕМ РАЗДЕЛ
cmp lpdwDisp,REG_OPENED_EXISTING_KEY
je m2
; СОЗДАЕМ КЛЮЧ И ЗАПИСЫВАЕМ ДАННЫЕ
invoke RegSetValueEx,hKey,addr szValueName1,0,REG_SZ, addr
setValue,1 ; размер ключа в байтах
cmp rax,0 ;ПРОВЕРКА КЛЮЧА НА СОЗДАНИЕ
jne m1
invoke MessageBox,0,addr ook,addr kk,MB_ICONINFORMATION
jmp m3
m2:
; ОТКРЫВАЕМ КЛЮЧ СЧИТЫВАЕМ ДАННЫЕ И ЗАПИСЫВАЕМ НОВЫЕ
invoke RegQueryValueEx,hKey,addr szValueName1,0,addr buf1,addr
getKol, addr buf3 ;
cmp getKol,"0"
je ex
dec getKol
invoke RegSetValueEx,hKey,addr szValueName1,0,REG_SZ,addr getKol,1 ;
;размер ключа в байтах
m3:
; ЗАКРЫВАЕМ РАЗДЕЛ
101
invoke RegCloseKey,hKey ; идентификация открытого ключа для
закрытия
jmp next
m1:
; ВЫВОДИМ СООБЩЕНИЕ ОБ ОШИБКЕ
invoke FormatMessage, FORMAT_MESSAGE_FROM_SYSTEM,0,rax,0,
addr error,100,0
invoke MessageBox,0,addr error,addr bed,MB_ICONINFORMATION
jmp ex
next:
invoke wsprintf, ADDR buf, ADDR ifmt,getKol
invoke MessageBox,0,addr buf,addr titl,MB_ICONEXCLAMATION
ex:
invoke ExitProcess,0
entry_point endp
end
Результат запису в реєстр з кількістю запусків, що залишилися,
наведено на рис. 7.5.
Повідомлення про можливу помилку вводиться функцією
FormatMessage, яка, окрім закладених у ній можливостей щодо
форматування рядків, може використовуватися для отримання
текстового опису помилки за її кодом.
Рис. 7.5. Результат запису в реєстр з кількістю запусків, що залишилися
102
Розглянемо діалогову програму встановлення та видалення ключів
у реєстр. Програма встановлює та видаляє ключі у гілки реєстру, а також
створює у реєстрі розділ та підрозділ.
При створенні проекту з діалоговим вікном спочатку визначаються
з інтерфейсом вікна: наявністю інформації, що виводиться, кількістю
кнопок, якістю та інформаційністю іконки.
Для створення інтерфейсу використано програму ResEd. Зовнішній
вигляд створеного діалогового вікна наведено на рис. 7.6.
Програма 7.5. Файл ресурсів:
#define IDI_ICON 1001
#define IDD_DLG1 100
#define IDC_CREATEKEY 1001
#define IDC_DELETEKEY 1003
#define IDC_STC1 1013
#define IDC_STC2 1004
#define IDC_GRP1 1005
#define IDC_BTN1 103
#define IDC_BTN2 101
#define IDC_IMG1 102
#include "C:/masm64/include64/Resource.h"
10 ICON DISCARDABLE "user.ico"
IDD_DLG1 DIALOGEX 12,6,294,171
CAPTION "Запись и удаление ключей в реестре"
FONT 8,"MS Sans Serif",0,0,0
STYLE WS_VISIBLE|WS_OVERLAPPEDWINDOW
BEGIN
Рис. 7.6. Зовнішній вигляд діалогового вікна
103
CONTROL "Создать ключи",IDC_CREATEKEY,"Button",
WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP,15,27,102,21
CONTROL "Удалить ключи",IDC_DELETEKEY,"Button",
WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP,174,27,96,21
CONTROL "https://blogs.kpi.kharkov.ua/v2/asm/",IDC_STC1,
"Static",WS_CHILDWINDOW|WS_VISIBLE,156,153,132,12
CONTROL "НТУ ХПИ",IDC_STC2,"Static",
WS_CHILDWINDOW|WS_VISIBLE|SS_CENTER,186,132,69,9
CONTROL "Управление реестром",IDC_GRP1,"Button",
WS_CHILDWINDOW|WS_VISIBLE|BS_GROUPBOX,6,9,279,45
CONTROL "Выход",IDC_BTN1,"Button",
WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP,174,96,96,21
CONTROL "Инф. о ветвях реестра",IDC_BTN2,"Button",
WS_CHILDWINDOW|WS_VISIBLE|WS_TABSTOP,174,66,96,21
CONTROL "",IDC_IMG1,"Static",
WS_CHILDWINDOW|WS_VISIBLE|SS_CENTERIMAGE|SS_ICON,30,69,87,75
END
VS_VERSION_INFO VERSIONINFO
FILEVERSION 1,0,0,0
PRODUCTVERSION 1,0,0,0
FILEOS 0x00000000
FILETYPE 0x00000000
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "041904B0"
BEGIN
VALUE "CompanyName", "HTU KhPI\000\0"
VALUE "FileDescription", "Рысованый А.Н.\000\0"
VALUE "FileVersion", "1.0\000\0"
VALUE "InternalName", "Reg64KeyDial-01\000\0"
VALUE "OriginalFilename", "Reg64KeyDial-01.exe\000\0"
VALUE "LegalCopyright", "\251 2024 Рысованый А.Н.\000\0"
VALUE "ProductName", "Reg64KeyDial-01\000\0"
VALUE "ProductVersion", "1.0\000\0"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x0419, 0x04B0
END
END
// 0x0419 язык русский, 0x0409 англ.
// 0x04B0 страница кодировки
104
/* английский язык (0x409) в кодовой странице Windows ANSI (1252). */
/*VALUE "Translation", 0x409, 1252*/
Наприкінці файлу ресурсів вставлені рядки коду, які відповідають
формування властивостей файла.
Після отримання ехе-файлу ці рядки дозволяють вивести
властивості файлу (рис. 7.7).
Програма 7.6. Файл ресурсів:
include \masm64\include64\masm64rt.inc
include \masm64\include64\advapi32.inc
includelib \masm64\lib64\advapi32.lib
; уст. ключей и раздела в реестр
.data?
hInstance dq ?
hIcon dq ?
hBmp dq ?
hStatic dq ?
hKey dd ?
lpdwDisp dd ?
.data
szREGSZ db 'REG_SZ',0
Рис. 7.7. Властивості файлу
105
setValue db "10",0
ValSize1 db 4,0
buf1 LPDWORD 128,0 ;
getKol LPBYTE "9",0 ;
buf3 LPDWORD 128,0 ;
error dd ?,0 ;
res1 dq 0 ;
key1 db "SYSTEM\ControlSet001\
Services\W32Time\TimeProviders\NtpClient8",0
valueName1 db "SpecialPollInterval ",0
key2 db "SOFTWARE\Microsoft\Windows\CurrentVersion\
DateTime\Servers8",0
valueName2 db "sTimeFormat ",0
key3 db 'Control Panel\International2',0 ; уст. Раздела
valueName3 db "sTimeFormat ",0
buf dq 12 dup(0),0
.code
entry_point proc
mov hInstance,rvcall(GetModuleHandle,0)
mov hIcon,rv(LoadImage,hInstance,10,IMAGE_ICON,128,128,
LR_DEFAULTCOLOR)
invoke DialogBoxParam,hInstance,100,0,ADDR main,hIcon
invoke ExitProcess,0
ret
entry_point endp
main proc hWin:QWORD,uMsg:QWORD,wParam:QWORD,lParam:QWORD
.switch uMsg
.case WM_INITDIALOG ; сообщение о создании диал. окна
invoke SendMessage,hWin,WM_SETICON,1,lParam ; отправляет смс окну
invoke SendMessage,rv(GetDlgItem,hWin,102),\ ; сообщение окну по
дескриптору органа управления
STM_SETIMAGE,IMAGE_ICON,lParam
.return TRUE
.case WM_COMMAND ; сообщение от меню или кнопки
.switch wParam
106
.case 101 ; если выбран вывод информации о задании
.data
txt2 db "Создание и удаление ключей реестра по адресам:",
10,10,"Ветки:"," HKLM\SYSTEM\ControlSet001\Services\
W32Time\TimeProviders\NtpClient",
10,"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\
DateTime\Servers",
10,"HKCU\Control Panel\International",
10,10,"Ключи: SpecialPollInterval, sTimeFormat.",0
titl2 db "Информация о задании",0
.code
invoke MsgboxI,hWin,ADDR txt2,ADDR titl2,MB_OK,10
.case 103 ;
.data
msg db "Выход из программы.",0 ; вывод уведомления о выходе
.code
invoke MsgboxI,hWin,ptr$(msg),"Выход",MB_OK,10
rcall SendMessage,hWin,WM_SYSCOMMAND,SC_CLOSE,0 ;
уничтожение окна
.case 1001 ; Создание ключа в реестре
.code
; создание раздела
invoke RegCreateKeyEx,HKEY_LOCAL_MACHINE,ADDR key1,0,ADDR
szREGSZ,REG_OPTION_VOLATILE,KEY_ALL_ACCESS,0,ADDR
hKey,ADDR lpdwDisp;
cmp rax,0 ; проверка создан ли раздел
jne m11
cmp lpdwDisp,REG_OPENED_EXISTING_KEY ; проверяем раздел
je m21
; создание ключа и записывание данных
invoke RegSetValueEx,hKey,addr valueName1,0,REG_SZ,addr setValue,1
; размер ключа в байтах
cmp rax,0 ; проверка создался ли ключ
jne m11
invoke MessageBox,0,chr$("Ключ 1 создан"),chr$("Создание
ключа"),MB_ICONINFORMATION
jmp m31
m21:
107
invoke RegQueryValueEx,\ ; откр. ключа, считывание и записывание новых
hKey,addr valueName1,0,addr buf1,addr getKol,addr buf3 ;
cmp getKol,"0"
je part2
dec getKol
invoke RegSetValueEx,hKey, addr valueName1,0, REG_SZ,addr getKol,1 ;
;размер ключа в байтах
m31: ; закрытие раздела
invoke RegCloseKey,hKey ; идентификация открытого ключа для закрытия
jmp part2
m11: ; вывод сообщения об ошибке
invoke FormatMessage,FORMAT_MESSAGE_FROM_SYSTEM,\
NULL,rax,NULL,addr error,100,NULL
invoke MessageBox,0,addr error,chr$("Ошибка"),\
MB_ICONINFORMATION
jmp _end
;===========================
part2:
invoke RegCreateKeyEx,\ ; создание раздела
HKEY_LOCAL_MACHINE,ADDR key2,0,ADDR
szREGSZ,REG_OPTION_VOLATILE,KEY_ALL_ACCESS,0,ADDR
hKey,ADDR lpdwDisp;
cmp rax,0 ; проверка создан ли раздел
jne m12
cmp lpdwDisp,REG_OPENED_EXISTING_KEY ; проверяем раздел
je m22
invoke RegSetValueEx,\ ; создание ключа и записывание данных
hKey,addr valueName2,0,REG_SZ,addr setValue,1 ;размер ключа в байтах
cmp rax,0 ; проверка создался ли ключ
jne m12
invoke MessageBox,0,chr$("Ключ 2 создан"),chr$("Создание ключа"),
MB_ICONINFORMATION
jmp m32
108
m22:
; откр. ключа, считывание и записывание новых
invoke RegQueryValueEx,hKey,addr valueName2,0,addr buf1,addr getKol, addr
buf3 ;
cmp getKol,"0"
je _end
dec getKol
; размер ключа в байтах
invoke RegSetValueEx,hKey,addr valueName2,0,REG_SZ,addr getKol,1
m32: ; закрытие раздела
invoke RegCloseKey,hKey ; идентификация открытого ключа для закрытия
jmp part3
m12: ; вывод сообщения об ошибке
invoke FormatMessage,FORMAT_MESSAGE_FROM_SYSTEM,\
NULL,rax,NULL,addr error,100,NULL
invoke MessageBox,0,addr error,chr$("Ошибка"),\
MB_ICONINFORMATION
jmp _end
;=======================
part3: ; создание раздела
invoke RegCreateKeyEx, HKEY_CURRENT_USER,ADDR key3, 0,ADDR
szREGSZ, REG_OPTION_VOLATILE,KEY_ALL_ACCESS,0,ADDR
hKey,ADDR lpdwDisp;
cmp rax,0 ; проверка создан ли раздел
jne m13
cmp lpdwDisp,REG_OPENED_EXISTING_KEY ; проверяем раздел
je m23
invoke RegSetValueEx,\ ; создание ключа и записывание данных
hKey,addr valueName2,0,REG_SZ,addr setValue,1;размер ключа в байтах
cmp rax,0 ; проверка создался ли ключ
109
jne m13
invoke MessageBox,0,chr$("Ключ 3 создан"),chr$("Создание ключа"),
MB_ICONINFORMATION
jmp m33
m23: ; открытие ключа, считывание и записывание новых
invoke RegQueryValueEx,hKey,addr valueName2,0,addr buf1,addr
getKol,addr buf3 ;
cmp getKol,"0"
je _end
dec getKol
invoke RegSetValueEx,\
hKey,addr valueName2,0,REG_SZ,addr getKol,1 ; размер ключа в байтах
m33: ; закрытие раздела
invoke RegCloseKey,hKey ; идентификация открытого ключа для
закрытия
jmp part3
m13: ; вывод сообщения об ошибке
invoke FormatMessage,FORMAT_MESSAGE_FROM_SYSTEM,\
NULL,rax,NULL,addr error,100,NULL
invoke MessageBox,0,addr error,chr$("Ошибка"),\
MB_ICONINFORMATION
_end:
.case 1003 ; Удаление ключа реестра
invoke RegDeleteKey, HKEY_LOCAL_MACHINE,
chr$("SYSTEM\ControlSet001\ Services\W32Time\TimeProviders\NtpClient8")
.if eax == ERROR_SUCCESS ; ключ создан успешно ?
invoke RegCloseKey,addr hKey ;закр. дескриптора ключа
invoke MessageBox,0,chr$("Ключ 1 успешно
удалён"),chr$("Реестр"),MB_ICONINFORMATION
.else
invoke MessageBox,0,chr$("Ключ 1 не удалён"),chr$("Ошибка"),
MB_ICONINFORMATION
110
.endif
invoke RegDeleteKey,HKEY_LOCAL_MACHINE,
chr$("SOFTWARE\Microsoft\Windows\CurrentVersion\DateTime\Servers8")
.if eax == ERROR_SUCCESS ; ключ создан успешно ?
invoke RegCloseKey,addr hKey ;закрытие дескриптора ключа в
системном реестре
invoke MessageBox,0,chr$("Ключ 2 успешно удалён"),chr$("Реестр"),
MB_ICONINFORMATION
.else
invoke MessageBox,0,chr$("Ключ 2 не удалён"),chr$("Ошибка"),
MB_ICONINFORMATION
.endif
invoke RegDeleteKey,HKEY_CURRENT_USER,chr$("Control
Panel\International2")
.if eax == ERROR_SUCCESS ; ключ создан успешно ?
invoke RegCloseKey,addr hKey ;закрытие дескриптора ключа
invoke MessageBox,0,chr$("Ключ 3 успешно удалён"),
chr$("Реестр"),MB_ICONINFORMATION
.else
invoke MessageBox,0,chr$("Ключ 3 не удалён"),chr$("Ошибка"),
MB_ICONINFORMATION
.endif
.endsw
.case WM_CLOSE ; если есть сообщение о закрытии окна
invoke RegDeleteKey,HKEY_LOCAL_MACHINE, chr$("SYSTEM\
ControlSet001\ Services\W32Time\TimeProviders\NtpClient8")
invoke RegDeleteKey,HKEY_LOCAL_MACHINE,
chr$("SOFTWARE\Microsoft\Windows\CurrentVersion\DateTime\Servers8")
invoke RegDeleteKey,HKEY_CURRENT_USER,chr$("Control Panel\
International8")
invoke EndDialog,hWin,0 ;
.endsw
xor rax, rax
ret
main endp
111
end
Результат додавання каталогу до реєстру показано на рис. 7.7.
7.6. Лабораторна робота
«Перевірка дати та часу»
Мета заняття: придбати практичні навички написання та
застосування програм фіксованої кількості запусків та виправлення у
ехе-файлах у середовищі masm64.
У звіті подати:
– номер, назва лабораторної роботи та прізвище виконавця;
- Завдання;
– текст програми перевірки пароля з розміщенням даних у
сторінках коду із двома блоками: без перекриття коду та з перекриттям.
Привести коментарі до кожного рядка цих програм;
– у тексті програми організувати виведення назви лабораторної
роботи, варіант, прізвище та ініціали, e-mail, номер групи автора
програми;
– результати виконання програм (скриншоти спрощеного вікна
(MessageBox) та відладчика);
– загальний алгоритм програми із частиною коду перевірки пароля;
– скріншоти пошуку пароля.
Рис. 7.8. Результат додавання каталогу до Реєструр
112
Постановка задачі
1. Написати програму в середовищі masm64 відповідно до варіанта
завдання.
2. Вивести результати виконання програми. Програму та
результати навести у звіті.
3. Навести скріншоти послідовності пошуку пароля.
Завдання
Вибрати варіант відповідно до завдання. Студенти другого та
третього десятків за списком обирають аналогічні завдання, тобто.
студент із 21 номером за списком обирає 1-й номер варіанта:
1. Обмежити запуск програми, залежно від дати першого запуску.
2. Обмежити запуск програми, залежно від поточної дати.
3. Обмежити запуск програми в залежності від дати створення.
4. Обмежити запуск програми в залежності від дати та часу
останньої операції запису у файл.
5. Обмежити запуск програми за часом використання.
6. Обмежити кількість запусків програми.
7. Запис у файл кількості запусків програми без використання
макросів.
8. Запис у файл кількості запусків програми та перевірка цієї
кількості.
9-10. Обмеження спроб введення пароля з виведенням
попереджувальних повідомлень.
* Інший спосіб обмеження.
Контрольні питання для перевірки знань
1. Яка основна програма використовується для зламування коду?
2. У яких місцях можна організувати лічильники подій?
3. У яких місцях програми можна розмістити дату закінчення
роботи програми?
4. В яких місцях можна заховати пароль?
5. Які особливості програми роботи з реєстром?
113
8. ШИФРУВАННЯ ПАРОЛЮ
8.1. Загальні відомості про шифрування пароля
Шифрування пароля дозволяє трохи збільшити безпеку програми,
т.к. у ехе-файлі знаходиться не відкритий пароль. Це допоможе не довго
збільшити час злому парольної програми. Вся справа в тому, що якщо
хакер досліджує програму і знає, що вона має парольний вхід, то він
шукає команду порівняння і наступну за нею команду переходу, як
правило, команду jnz. Потім змінює її, наприклад, команду jz. І це
дозволить реагувати програмі на будь-який пароль. Але в навчальних
цілях застосування парольного захисту дає змогу отримати навички
дослідження таких простих програм.
Можна виділити різні прийоми шифрування пароля, наприклад:
- шифрування пароля окремою програмою;
- шифрування пароля у самій програмі;
- шифрування та розкид елементів пароля в різні частини програми;
- шифрування та приховування пароля.
Для шифрування пароля переважно застосовують зворотне
шифрування. Наприклад, під час передачі пароля його попередньо
складають по модулю 2 з ключем. А на приймальні - отриманий
оброблений пароль складають з тим же ключем і пароль буде
розшифровано. Ключ відомий лише обмеженому колу людей. Це
робиться, щоб у разі перехоплення пароля зловмисник не зміг
скористатися ним відразу. До зворотної операції можна також віднести
операцію зсув вправо, але в приймальні - зрушення вліво та інші
аналогічні прості дії.
8.2. Шифрування пароля окремою програмою
Написання програми з розміщенням пароля у секції даних є
найбільшим недоліком таких програм, т.к. пароль відразу ж видно у
відладчику. Пароль у програмі необхідно приховувати. І найпростішим
способом приховування пароля – це розміщення пароля у секції коду.
Але у навчальних цілях необхідно починати із найпростіших способів.
Для шифрування пароля часто використовують дві програми:
- Для шифрування пароля;
114
– для використання зашифрованого пароля.
Алгоритм шифрування пароля може бути таким:
1. Зашифровуємо пароль.
Для цього використовуємо програму шифрування - у програму
перевірки пароля з використанням базових команд вставляється рядок
коду
xor al, key
Запам'ятовуємо зашифрований пароль.
(Крім операції mod2 можна використовувати будь-які інші – для
яких є дії.)
2. Вставляємо в програму 2 в секцію data зашифрований пароль, а
також рядок розшифрування
xor al, key
Програма 8.1 призначена для шифрування пароля та майже нічим
не відрізняється від розглянутої раніше.
Програма 8.1. Шифрування пароля:
; программа шифрования пароля по модулю 2
; поразрядное mod2: txt mod2 key
include \masm64\include64\masm64rt.inc ;
.data
rez db 16 DUP (0)
buff db 16 DUP (0)
txt db "Enter code/Введите код для преобразования по txt mod2 1:", 10,0
TXTSIZE equ $ - txt ; число символов, выведенных на экран
stdin1 dq 0 ; для дескриптора ввода
stdout1 dq 0 ; для дескриптора вывода
wrn dq 0 ; число записанных символов
rdn dq 0 ; число прочитанных символов
key db 1 ; первоначальное значение ключа
.code
entry_point proc
invoke GetStdHandle,STD_INPUT_HANDLE ;извлекает дескриптор
mov stdin1,rax
invoke GetStdHandle,STD_OUTPUT_HANDLE ;извлекает дескриптор
mov stdout1,rax
invoke SetConsoleCP,1251;уст. кодовой страницы win 1251 в поток ввода
invoke SetConsoleOutputCP,1251;уст. страницы. win 1251 в поток вывода
115
invoke WriteConsoleA,stdout1,addr txt,TXTSIZE,addr wrn,0;вывод смс
invoke ReadConsole,stdin1,addr buff,16,addr rdn,0;чтение символов
;16 - число символов для чтения
; ReadConsole записала по адр. rdn +2 символа
lea rsi, buff ; загрузка адреса буфера
lea rdi, rez ; загрузка адреса ячейки результата
mov rcx, rdn ; запись количества введенных символов (rdn-2)
sub rcx, 2 ; минус служебные символы
_cycle:
mov al, byte ptr [rsi];
xor al, key ;
mov byte ptr [rdi],al ;
inc key ; изменение ключа +1 ключа
inc rsi ;
inc rdi ;
loop _cycle
invoke WriteConsoleA,stdout1,addr rez,14,addr wrn,0; вывод только 14
символов
invoke ReadConsole,stdin1,addr buff,16,addr rdn,0;вывод на 2 символа
меньше (16-2=14)
invoke ExitProcess,0
entry_point endp
end
Программа шифрует только 14 символов. Значение ключа
изменяется на 1 относительно предыдущего значения.
8.3. Вилучення частини пароля з великої послідовності
У програмі пароль складається з 2-х частин. У першій частині
відбувається звичайний аналіз пароля, що вводиться. У другій частині
відбувається порівняння лише з частиною введеного пароля.
Перший пароль дорівнює 1234.
Другий пароль дорівнює 567, але у відладчику видно пароль
012345678567. Звичайно, хакеру важко здогадатися, що перевіряється
тільки якась частина.
116
Для невеликого заплутування процесу злому програма складається
з 2-х вікон: діалогового та консольного. Перший пароль вводиться у
діалогове вікно, а другий (пароль 567) у консольне вікно.
Програма 8.2. Перевірка пароля з 2-х частин:
include \masm64\include64\masm64rt.inc
.data?
hInstance dq ?
hIcon dq ?
hImg1 dq ?
tEdit dq ?
tStat dq ?
pbuf dq ?
.data
Password db "1234" ; пароль, часть 1
len1 equ $-Password
Password2 db "012345678567" ; пароль 567, часть 2
len2 equ $-Password2
Buf2 dq 0 ;
hOut dq 0 ;
hIn dq 0 ;
cRead dq 0 ;
cWritten dq 0 ;
Msg4 db "Enter password, part 2",10,10,0 ;Введите пароль, часть 2
.code
entry_point proc
mov hInstance, rvcall(GetModuleHandle,0)
mov hIcon, rv(LoadImage,hInstance,10,IMAGE_ICON, 128,128,
LR_DEFAULTCOLOR)
invoke DialogBoxParam,hInstance,200,0,ADDR GetUserText,hIcon
.exit
entry_point endp
GetUserText proc hWin:QWORD,uMsg:QWORD,wParam:QWORD,
lParam:QWORD
LOCAL buffer[260]:BYTE
.switch uMsg
.case WM_INITDIALOG
invoke SendMessage,hWin,WM_SETICON,1,lParam ; установить значок
invoke SendMessage,rv(GetDlgItem,hWin,205),\ ; значок в клиентской обл.
STM_SETIMAGE,IMAGE_ICON,lParam
117
mov tEdit, rvcall(GetDlgItem,hWin,201)
invoke SetFocus, tEdit ; установка курсора в поле ввода
mov pbuf, ptr$(buffer) ; символьный тип данных
.case WM_COMMAND
.switch wParam
.case 202
invoke GetWindowText,tEdit,pbuf,sizeof buffer; записать текст в буфер
.if rax == 0
rcall MessageBox,hWin,"Введите пароль или нажмите Cancel","Пароль не
введен", MB_ICONINFORMATION
rcall SetFocus,tEdit ; установка курсора в поле ввода
.else
invoke szCmp,pbuf,ADDR Password
cmp rax, len1
jne WRONG_PASSWORD
invoke MessageBox,0,"1-я часть пароля правильная","Проверка пароля",
MB_OK
jmp m100
WRONG_PASSWORD:
invoke MessageBox,0,cfm$("Пароль был введен неправильно! \n
Попробуйте, пожалуйста, снова"),\"Вход в программу",MB_OK
jmp exit_dialog
m100:
invoke GetStdHandle,STD_OUTPUT_HANDLE
mov hOut,rax
invoke GetStdHandle,STD_INPUT_HANDLE
mov hIn,rax
invoke WriteConsole,hOut,ADDR Msg4,sizeof Msg4,ADDR cWritten,0
invoke ReadConsole,hIn,ADDR Buf2,len2+2,ADDR cRead,0
lea rsi,Password2 ; загрузка адреса нахождения Password2
lea rdi,Buf2 ; загрузка адреса буфера введенных символов
add rsi,9 ; сдвиг на 3 байта
mov rcx,3 ; счетчик символов
xor r14,r14
m4:
mov al,[rsi] ; загрузка числа по адресу из rsi
mov bl,[rdi] ;
cmp al,bl ; сравнение символов
jz m3 ; если совпали символы
118
inc r14 ; счетчик несовпадений
m3:
add rsi,1 ; inc адреса
add rdi,1 ;
dec rcx
jnz m4
.if r14==0;
invoke MessageBox,0,"Пароль совпал","Проверка пароля",
MB_ICONINFORMATION
.else
invoke MessageBox,0,"Пароль не корректен","Проверка пароля",MB_OK
.endif
jmp exit_dialog
.endif
.case 203
jmp exit_dialog
.endsw
.case WM_CLOSE
exit_dialog:
rcall EndDialog,hWin,0
.endsw
xor rax, rax
ret
GetUserText endp
end
При запуску ехе-файлу програми спочатку виводиться діалогове
вікно із запитом пароля (рис. 8.1).
Якщо пароль збігся, виводиться вікно повідомлення (рис. 8.2).
Рис. 8.1. Діалогове вікно із запитом пароля
119
Друга частина пароля вводиться у консольне вікно (рис. 8.3).
Спрощене вікно про підтвердження збігу 2 частини пароля
представлено на рис. 8.4.
Рис. 8.2. Вікно з підтвердженням про збіг першої частини пароля
Рис. 8.3. Консольне вікно введення пароля
Рис. 8.4. Вікно з підтвердженням про збіг другої частини пароля
120
В этой программе при просмотре в отладчике части пароля видны
в отладчике (рис. 8.5).
У вікні відладника видно значення пароля, але не визначено його
частини. Тому для того, щоб знайти точні значення пароля, ехе-файл
необхідно покроково трасувати і вже детально розбиратися в коді
програми.
8.4. Лабораторна робота «Приховування пароля»
Мета заняття: набути практичних навичок застосування
приховування пароля в програмі.
У звіті подати:
– назва лабораторної роботи, варіант, прізвище та ініціали, e-mail,
номер групи автора програми;
– представити дві програми: без діалогового вікна та проект з
діалоговим вікном;
– у тексті програми організувати виведення назви лабораторної
роботи, варіант, прізвище та ініціали, e-mail, номер групи автора
програми;
– результат виконання завдання (скриншоти вікон програми та
відладчика).
Завдання
Пароль розбити на частини та до кожної частини застосувати
окремий спосіб приховування.
Рис. 8.5. Вікно відладчика з видимим паролем
121
Можна застосувати обробку пароля, отримання пароля з відомих
значень програми, використовувати стек, запис даних секцію коду та
інших.
Контрольні питання для перевірки знань
1. Що необхідно зробити у налагоджувачі з ехе-файлом, щоб
програма реагувала на будь-який пароль як на правильний?
2. Які шляхи утруднення пошуку пароля?
3. Які операції зворотного шифрування?
4. Яка послідовність розміщення пароля у секції коду?
5. Які операції можна здійснювати із паролем?
122
9. ШИФРОВАНИЕ ДАННЫХ
Шифрование пароля и шифрование данных – это один и тот же
процесс. Разница только в том, что данные имеют намного большую
длину, например, файл.
Существует очень большое количество алгоритмов шифрования. В
общем случае можно разделить на такие подгруппы:
– возвратное шифрование (xor, сдвиг и т. д.);
– хеширование (CRC, контрольная сумма, MD5 и т.д.);
– кодирование (полиномы и т.д.).
Хеширование - подсчет суммы кода, а при проверке используют
не сам код, а его сумму.
9.1. Возвратное шифрование
Основным свойством алгоритмов возвратного шифрования
является их способность как шифровать, так и расшифровывать данные
без принципиального изменения шифровального алгоритма.
Простейшими алгоритмами считаются сдвиг и xor, т.к. основная
операция этих групп является коммутативной, и порядок операндов
значения не имеет. Такими командами могут быть:
xor eax, ebx
или:
add r15,7 ; шифрование
sub r15,7 ; дешифровка
Внедрение этих простых алгоритмов позволяет быстро и надежно
решить проблему шифрования данных. А при применении двух и более
простых операций шифрования узнать алгоритм расшифрования
становится невыполнимой задачей.
Рассмотрим консольную программу 9.1, которая применяет
внутренний макрос среды masm64 для шифрования исключительно
текста. Ключ шифрования имеет имя padd размерностью 60 значений.
Текст, который шифруется - "Реверсное программирование".
Программа 9.1. Шифрование текста с применением внутренних
макросов среды masm64:
; консольная программа
123
; применение макросов для шифрования текста по мод2
include \masm64\include64\masm64rt.inc
.data ; шифрование сообщения 60 символов
padd db "1234567890123456789012345678901234567890123456789
01234567890",0
blen dq SIZEOF padd
ppad dq padd
.code
entry_point proc
LOCAL st1 :QWORD
LOCAL slen :QWORD
invoke SetConsoleCP,1251;уст. кодовой страницы win 1251 в поток ввода
invoke SetConsoleOutputCP,1251;установка кодовой страницы win 1251 в
поток вывода
mrm st1,"Реверсное программирование" ; шифруется только текст
mov slen,len(st1)
sub blen,1
invoke xor_data,st1,slen,ppad,blen ; строка st1 для шифрования
conout "Зашифрованный текст = ",st1,lf ; показать зашифр. результат
invoke xor_data,st1,slen,ppad,blen ; xor строка для расшифровки
conout "Исходный текст = ",st1,lf ; отображение расшифров. данных
waitkey ; ожидание
invoke ExitProcess,0
entry_point endp
end
На рис. 9.1 показано консольне вікно з виведенням результату
шифрування.
Рис. 9.1. Консольне вікно з виведенням результату шифрування
124
9.2. Операція додавання за модулем 3
Операція підсумовування за модулем кінцевого поля 3 (mod3) не
зовсім відноситься до зворотного шифрування, тим більше якщо
використовувати 2 логічних стан 0 і 1 (поле числа 2). При використанні
трьох логічних станів (0, 1, 2) використовується mod3. Різниця при
шифруванні між mod2 і mod3 в тому, що при mod2 необхідно один раз
скласти дані з ключем, а при mod3 - дві однакові додавання з ключем.
Але такий спосіб кодування вносить деяку частку складності під час
розкодування інформації.
При цьому необхідно або на стороні, що передає, або на
приймальній стороні (залежно від прийнятого правила) здійснити
необхідне додавання з ключем.
Правила складання та множення у кінцевому полі
GF(3) = (А, 3, 3),
де А={0,1,2} представлені на рис. 9.2.
3 0 1 2 3 0 1 2
0 0 0 0 0 0 1 2
1 0 1 2 1 1 2 0
2 0 2 1 2 2 0 1
Результат операції за модулем визначається як залишок від
розподілу отриманого результату на основу модуля. У цьому випадку,
це – розподіл на 3 і отримання залишку. Наприклад, 2 3 2 = 4; 4/3 = 1 –
залишок. Цілий результат під час операції отримання модуля не
враховується.
Якщо необхідно обробляти трійкові сигнали, кодування станів
елементів з трьома станами здійснюється за правилом.:
0 → 00,
1 → 01,
2 → 10.
У обчислювальній техніці три стани мають достатню велику
кількість пристроїв:
- шинні формувачі;
- Контролери шин;
Рис. 9.2. Правила складання та множення у кінцевому полі GF(3)
125
- контролери пристроїв (клавіатури, мишки, ОЗУ, ПЗУ, HDD, SSD,
відеокарти та ін);
- Пристрої, що запам'ятовують.
Отримання mod3 числа наведено у програмі 9.2.
Програма 9.2. Отримання mod3:
include \masm64\include64\masm64rt.inc
.data ;
a1 dq 5 ; число
b1 dq 3 ; основание модуля
buf1 dq 0,0 ; буфер
.code
entry_point proc
xor rdx,rdx
mov rax,a1
div b1
mov r10,rdx : сохранение rdx перед функцией с параметрами
invoke wsprintf,addr buf1, "mod3 = %d",r10
invoke MessageBox,0,addr buf1,chr$(" Операция mod3 "), 0
invoke mov r10,rdx : ExitProcess,0
entry_point endp
end
Після операції розподілу залишок залишається у регістрі rdx. Але в
наступному рядку після операції розподілу виконується функція
wsprintf, параметри якої передаються через регістри rcx, rdx, r8, r9. У
регістр rdx запише значення "mod3 = %d". Тому rdx зберігається в r10:
mov r10,rdx
9.3. Шифрування даних із інкрементованим ключем
Розглянемо шифрування даних, які вводяться у консольне вікно та
шифруються за допомогою ключа. Причому початкове значення ключа
дорівнює 1, а наступні значення виходять шляхом збільшення
(інкрементації) на 1 попереднього значення.
Програма 9.3. Шифрування mod2 з інкрементуванням ключа:
; поразрядное mod2: txt mod2 key
include \masm64\include64\masm64rt.inc ;
126
.data
rez db 128 DUP (0)
buff db 128 DUP (0)
txt db "Введите код для преобразования",10,0
TXTSIZE equ $ - txt ; число символов, выведенных на экран
txt2 db "txt mod2 key:",10,0
stdin1 dq 0 ; для дескриптора ввода
stdout1 dq 0 ; для дескриптора вывода
wrn dq 0 ; число записанных символов
rdn dq 0 ; число прочитанных символов
key db 1; ключ для сложения по mod2
.code
entry_point proc
invoke GetStdHandle,STD_INPUT_HANDLE ;извлекает дескриптор
mov stdin1,rax
invoke GetStdHandle,STD_OUTPUT_HANDLE ;извлекает дескриптор
mov stdout1,rax
invoke SetConsoleCP,1251;уст. кодовой страницы win 1251 в поток ввода
invoke SetConsoleOutputCP,1251;уст. код. стр. win 1251 в поток вывода
invoke WriteConsoleA,stdout1,addr txt,TXTSIZE,addr wrn,0
invoke WriteConsoleA,stdout1,addr txt2,14,addr wrn,0
invoke ReadConsole,stdin1,addr buff,128,addr rdn,0
; ReadConsole записала по адр. rdn +2 символа
lea rsi, buff ; загрузка адреса буфера
lea rdi, rez ; загрузка адреса ячейки результата
mov rcx, rdn ; запись символов
sub rcx, 2 ; минус служебные символы
_cycle:
mov al, byte ptr [rsi];
xor al, key ;
mov byte ptr [rdi],al ;
inc rsi ;
inc rdi ;
inc key ; изменение ключа на +1
127
loop _cycle
invoke WriteConsoleA,stdout1,addr rez,128,addr wrn,0
invoke ReadConsole,stdin1,addr buff,130,addr rdn,0
invoke ExitProcess,0
entry_point endp
end
Кількість символів, які можна закодувати в консольному вікні
програми, дорівнює 128. Хоча цю кількість можна змінити на досить
велике значення.
Як ключ для шифрування наступного символу можна
використовувати певну задану послідовність дій над попереднім
значенням, так і розрахунок наступного значення за формулою.
9.4. Лабораторна робота «Зворотне шифрування»
Мета заняття: набути практичних навичок застосування операцій
зворотного шифрування в програмі.
У звіті подати:
– назва лабораторної роботи, варіант, прізвище та ініціали, e-mail,
номер групи автора програми;
– представити програми: без діалогового вікна та проект з
діалоговим вікном;
– у тексті програми організувати виведення назви лабораторної
роботи, варіант, прізвище та ініціали, e-mail, номер групи автора
програми;
– результат виконання завдання (скриншоти вікон програми та
відладчика).
Завдання
Застосувати парольний вхід до програми та над паролем зробити
перетворення відповідно до варіанта.
Написати програму шифрування файлу (файлів).
У програмі еталонний пароль заховати у секції коду.
128
Варіанти
У варіантах завдання застосовується поняття інкрементованого
ключа – це ключ, у якому кожне наступне значення ключа збільшується
на 1 від попереднього. Декрементований ключ – наступне значення
ключа зменшується на 1 від попереднього.
1. Циклічний зсув ліворуч на 1 розряд і додавання по mod2 з
інкрементованим ключем;
2. Циклічний зсув ліворуч на 1 розряду та додавання по mod3 з
інкрементованим ключем;
3. Циклічний зсув праворуч на 1 розряд і додавання по mod2 з
інкрементованим ключем;
4. Циклічний зсув праворуч на 2 розряди і додавання по mod3 з
інкрементованим ключем;
5. Віднімання інкрементованого ключа та зсув ліворуч на 1 розряд;
6. Віднімання декрементованого ключа та додавання по mod3;
7. Віднімання інкрементованого ключа та зсув праворуч на 1
розряд;
8. Віднімання декрементованого ключа та зсув праворуч на 1
розряд;
9. Додавання інкрементованого ключа та додавання по mod3;
10. Додавання декрементованого ключа і зсув ліворуч на 1 розряд;
11. Додавання інкрементованого ключа та зсув праворуч на 1
розряд;
12. Додавання декрементованого ключа та зсув праворуч на 1
розряд;
13. Додавання по mod2 з ключем, додавання по mod3 з ключем;
14. Додавання по mod2 з ключем, зрушення вліво на 2 розряди,
додавання по mod3 з ключем;
15. Додавання по mod2 з ключем, зсув праворуч на 1 розряду,
додавання по mod3 з ключем;
16. Додавання по mod2 з ключем, зсув праворуч на 2 розряди,
додавання по mod2 з ключем;
17. Циклічний зсув ліворуч на 2 розряди, додавання по mod2 з
інкрементованим ключем, зсув праворуч на 1 розряд;
18. Циклічний зсув вправо на 2 розряди, додавання по mod2 з
інкрементованим ключем, зрушення вліво на 1 розряд;
19. Циклічний зсув вправо на 3 розряди, додавання по mod2 з
інкрементованим ключем, зрушення вліво на 2 розряди;
20*-25*. Власна послідовність обробки пароля, що не зустрічається
в інших випадках завдання.
129
Контрольні питання для перевірки знань
1. Які операції є зворотними?
2. Що таке хешування та де застосовується?
3. Для яких цілей застосовується парольний захист програми?
4. У яких випадках пароль видно у ехе-файлі?
5. Навіщо у програмі застосовується кодова сторінка win 1251?
130
10. Кодування
10.1. Загальні відомості про кодування
Кодування входить у загальне поняття шифрування і часто-густо
ототожнюються друг з одним. Під час кодування повідомлень дані
шифруються за допомогою криптографічних ключів.
Залежно від природи ключів шифрування може ділитися на 2
категорії: симетричне та асиметричне.
Симетричне шифрування: дані шифруються та розшифровуються
за допомогою одного криптографічного ключа. Це означає, що ключ,
який використовується для шифрування, використовується для
розшифровки.
Асиметричне шифрування: використовуються два різні ключі -
один для шифрування, другий для розшифрування. Один ключ
називається публічним, другий таємним.
10.2. Отримання випадкової послідовності
Послідовності випадкових чисел є невід'ємним інструментом
вирішення багатьох математичних завдань. Більшість природних
процесів є випадковими, і, згідно з теорією математичної статистики,
вони підкоряються різним законам розподілу випадкових величин.
Отримання випадкових чисел без дотримання законів розподілу та
критеріїв відбору не є складним завданням для програміста.
При передачі закодованого довгого повідомлення на приймальну
сторону необхідно передавати файл ключа, що не завжди доцільно.
Однак і такий спосіб кодування те саме може застосовуватися.
Розглянемо одержання випадкової послідовності (програма 10.1).
Основою формування випадкової послідовності є значення, що
повертається функцією GetTickCount, над якою згодом проводяться
певні програмістом дії. Ці дії можуть бути будь-якими, як і функції, які
можуть застосовуватись. Але бажано вибирати такі функції, у яких
значення, що повертаються, весь час різні.
131
Програма 10.1. Отримання випадкової послідовності як ключа
шифрування на основі використання функції GetTickCount:
:
include \masm64\include64\masm64rt.inc
.data
fileName db "keyfile.bin", 0 ; Имя файла для сохранения ключа
keyBuffer db 1024 dup(0) ; Буфер для хранения сгенерированного ключа
fileHandle dq 0 ; Дескриптор файла
bytesWritten dq 0 ; Количество записанных байт
.code
entry_point proc
; Получить текущее значение системного таймера для использования в
качестве начального значения
sub rsp, 8
call GetTickCount
mov eax, eax ; Извлекаем 32 бита из rax
mov dword ptr [keyBuffer], eax ; Записываем это значение в первые 4
байта keyBuffer
add rsp, 8
; Настройка регистров для генерации ключа
mov rdi, offset keyBuffer ; Указатель на текущий байт в keyBuffer
mov rcx, 1024 ; Счетчик для 1024 байт
lea rax, [keyBuffer] ; Загрузка начального значения ключа в rax
mov rax, [rax]
generate_key:
; Простая генерация случайного ключа
xor rax, rcx ; Используем XOR для изменения rax
rol rax, cl ; Циклический сдвиг rax на количество бит, указанное в cl
mov byte ptr [rdi], al ; Сохраняем младший байт rax в keyBuffer
inc rdi ; Переход к следующему байту в keyBuffer
dec rcx ; Уменьшение счетчика
jnz generate_key ; Продолжить, пока счетчик не станет равным 0
; Открыть файл для записи сгенерированного ключа
invoke CreateFile, addr fileName, GENERIC_WRITE, 0, NULL,
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL
mov fileHandle, rax ; Сохраняем дескриптор файла
; Проверка на успешное открытие файла
test rax, rax
132
jz exit ; Если файл не открылся, выходим
; Запись ключа в файл
invoke WriteFile, fileHandle, addr keyBuffer, 1024, addr bytesWritten, NULL
; Закрыть файл
invoke CloseHandle, fileHandle
exit:
invoke ExitProcess, 0
entry_point endp
end
В результаті виконання цього ехе-файлу створюється файл з ім'ям
keyfile.bin, в якому записана послідовність довжиною 1024 біта. В різні
моменти часу вміст файлу буде різним. Випадковий вміст отриманого
файлу наведено на рис. 10.1.
.
Але для розшифровки треба застосовувати той самий файл із
ключем з ім'ям keyfile.bin.
Шифрування файлу
Шифрування файлів у директорії можна виконати за допомогою
програми 10.2. Але для шифрування необхідно застосувати ключ,
створений програмою 10.1 та має ім'я keyfile.bin.
Після шифрування розширення файлу змінюється на ім'я cringe.
Рис. 10.1. Випадковий вміст файлу
133
Програма 10.2. Шифрування файлів у директорії ключем із файлу
з ім'ям keyfile.bin:
include \masm64\include64\masm64rt.inc
.data
directoryName db "C:\masm64\bin64\test\*", 0 ; Путь к директории для
шифрования файлов
keyFileName db "keyfile.bin", 0 ; Имя файла с ключом шифрования
findData WIN32_FIND_DATA { } ; Структура для хранения информации
о файлах в директории
; Буферы и переменные для работы с файлами и ключами
keyBuffer db 1024 dup(0) ; Буфер для хранения ключа шифрования
buffer db 10240 dup(0) ; Буфер для чтения/записи данных файла
fullPathFile db 1024 dup(0) ; Полный путь к файлу для шифрования
inputFileNameEnc db 1024 dup(0) ; Имя файла с новым расширением
после шифрования
newExtension db '.cringe',0 ; Новое расширение для зашифрованных
файлов
negBytesRead dq 0 ; Переменная для управления смещением в файле
.code
entry_point proc
; Считать ключ для шифрования
invoke OpenKeyFile
test rax, rax
jz exit
; Шифруем содержимое указанной директории
invoke EncryptDirectory, addr directoryName
exit:
invoke ExitProcess, 0
entry_point endp
; Функция для шифрования содержимого директории
EncryptDirectory proc directoryPath:QWORD
local hFind:QWORD
134
; Начинаем поиск файлов в директории
lea rdx, [findData]
invoke FindFirstFile, directoryPath, rdx
mov hFind, rax
cmp rax, INVALID_HANDLE_VALUE
je end_search ; Завершение, если файлы для поиска отсутствуют
search_loop:
; Шифрование каждого найденного файла
lea rcx, [findData.cFileName]
invoke EncryptFile, rcx, addr keyBuffer
lea rdx, [findData] ; Это нужно для обновления адреса в rdx
invoke FindNextFile, hFind, rdx
cmp rax, 0
jne search_loop ; Повторение поиска, пока есть файлы
invoke FindClose, hFind ; Закрытие поиска файлов
end_search:
ret
EncryptDirectory endp
; Функция для конкатенации пути и имени файла
ConcatenatePath proc
; rcx - адрес directoryName, rdx - адрес fileName
lea rsi, [rcx] ; Указатель на путь к директории
lea rdi, [fullPathFile] ; Указатель на полный путь
; Копирование пути к директории в fullPath
copy_directory:
lodsb ; Загружаем байт из rsi в al
cmp al, '*' ; Проверяем, не является ли это звёздочкой
je copy_file ; Если да, переходим к копированию имени файла
stosb ; Сохраняем байт из al в rdi
test al, al ; Проверяем, не достигли ли мы конца строки
jnz copy_directory ; Если нет, продолжаем копирование
copy_file:
lea rsi, [rdx] ; Указатель на имя файла
; Копирование имени файла в fullPath
repeat_file:
lodsb ; Загружаем байт из rsi в al
stosb ; Сохраняем байт из al в rdi
135
test al, al ; Проверяем, не достигли ли мы конца строки
jnz repeat_file ; Если нет, продолжаем копирование
ret
ConcatenatePath endp
; Функция для шифрования отдельного файла
EncryptFile proc filePath:QWORD, keyBuffer1:QWORD
local hFile:QWORD
local bytesRead:QWORD
local bytesWritten:DWORD
; Подготовка пути и имени файла для шифрования
lea rcx, [directoryName] ; Путь к директории
mov rdx, filePath ; Имя файла
call ConcatenatePath
; Изменение расширения файла
lea rsi, [fullPathFile] ;
lea rdi, [inputFileNameEnc]
call ChangeExtension
; Открыть файл для чтения и записи
invoke CreateFile, addr fullPathFile, GENERIC_READ OR
GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL
mov hFile, rax
cmp rax, INVALID_HANDLE_VALUE
je encrypt_exit
; Чтение, шифрование и запись данных файла
read_loop:
invoke ReadFile, hFile, addr buffer, 1024, addr bytesRead, NULL
test rax, rax
jz exit
lea rsi, [buffer]
lea rdx, [keyBuffer]
mov rcx, bytesRead
xor rdi, rdi
; Цикл шифрования
encrypt_loop:
mov al, byte ptr [rsi + rdi]
136
xor al, byte ptr [rdx + rdi]
mov [rsi + rdi], al
inc rdi
dec rcx
jnz encrypt_loop
; Перемещение указателя файла и запись зашифрованных данных
mov rax, bytesRead
neg rax
mov negBytesRead, rax
invoke SetFilePointer, hFile, negBytesRead, NULL, FILE_CURRENT
invoke WriteFile, hFile, addr buffer, bytesRead, addr bytesWritten, 0
cmp bytesRead, 1024
je read_loop ; Повторение чтения, если не достигнут конец файла
exit:
; Закрытие файла и изменение его имени
invoke CloseHandle, hFile
invoke MoveFile, addr fullPathFile, addr inputFileNameEnc
encrypt_exit:
ret
EncryptFile endp
; Функция для открытия файла ключа и чтения данных
OpenKeyFile proc
local hFile:QWORD
local bytesRead:QWORD
; Открыть файл ключа для чтения
invoke CreateFile, addr keyFileName, GENERIC_READ,
FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL
mov hFile, rax
cmp rax, INVALID_HANDLE_VALUE
je openkeyfile_exit
; Читаем содержимое файла ключа в keyBuffer
invoke ReadFile, hFile, addr keyBuffer, 1024, addr bytesRead, NULL
; Закрыть файл ключа
invoke CloseHandle, hFile
openkeyfile_exit:
137
ret
OpenKeyFile endp
; Функция для замены расширения файла
ChangeExtension proc
; Копируем имя файла до точки (если точка есть)
copy_name:
lodsb
cmp al, '.'
je add_new_extension ; Если найдена точка, добавляем новое
расширение
stosb
test al, al
jnz copy_name ; Продолжение копирования, если не достигнут конец
строки
; Добавляем расширение
add_new_extension:
lea rsi, [newExtension]
movsd
movsd
movsd ; Копирование расширения в имя файла
ret
ChangeExtension endp
end
Наведена програма шифрує всі файли у зазначеній директорії
directoryName db "C:\masm64\bin64\test\*", 0
Дешифрація файлу
Розглянемо програму 10.3, яка дешифрує лише один файл, а чи не
всю директорію. Приклад використання директорії показано у програмі
шифрування. Програма 10.3 використовує той самий ключ, що й для
шифрування і ту саму операцію XOR, що дозволяє відновити
оригінальний вміст файлу.
Програма 10.3. Дешифрування файлу:
include \masm64\include64\masm64rt.inc
.data
inputFileName db "C:\masm64\bin64\test\01.cringe", 0 ; Имя
зашифрованного файла для дешифровки
138
inputFileNameDec db 1024 dup(0) ; Буфер для имени файла после
удаления расширения
keyFileName db "keyfile.bin", 0 ; Имя файла, содержащего ключ
шифрования
; Буферы для ключа и данных
keyBuffer db 1024 dup(0) ; Буфер для хранения ключа
дешифрования
buffer db 10240 dup(0) ; Буфер для хранения данных файла
; Переменные для работы с файлом
negBytesRead dq 0 ; Переменная для перемещения указателя файла
inputFileHandle dq 0 ; Дескриптор файла, который нужно дешифровать
keyFileHandle dq 0 ; Дескриптор файла ключа
bytesRead dq 0 ; Количество прочитанных байтов из файла
bytesReadKey dq 0 ; Кол. прочитанных байтов из файла ключа
bytesWritten dq 0 ; Количество записанных байтов в файл
.code
entry_point proc
; Подготовка имени файла без расширения
xor rsi, rsi
xor rdi, rdi
lea rsi, [inputFileName] ; Загружаем адрес зашифрованного файла
lea rdi, [inputFileNameDec] ; Загружаем адрес буфера для имени
файла без расширения
call RemoveExtension ; Удаляем расширение из имени файла
; Открытие файла ключа для чтения
invoke CreateFile, addr keyFileName, GENERIC_READ,
FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL
mov keyFileHandle, rax
test rax, rax
jz exit ; Выходим, если файл ключа не может быть открыт
; Чтение ключа из файла ключа
invoke ReadFile, keyFileHandle, addr keyBuffer, 1024, addr bytesReadKey,0
139
; Открытие зашифрованного файла для чтения и записи
invoke CreateFile, addr inputFileName, GENERIC_READ OR
GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, NULL
mov inputFileHandle, rax
test rax, rax
jz exit ; Выходим, если зашифров. файл не может быть открыт
; Чтение и дешифрование файла
read_loop:
invoke ReadFile, inputFileHandle, addr buffer, 1024, addr bytesRead,0
test rax, rax
jz exit ; Выходим, если достигнут конец файла
; Цикл дешифрования
lea rsi, [buffer]
lea rdx, [keyBuffer]
mov rcx, bytesRead
xor rdi, rdi
decrypt_loop:
mov al, byte ptr [rsi + rdi]
xor al, byte ptr [rdx + rdi]
mov [rsi + rdi], al
inc rdi
dec rcx
jnz decrypt_loop
; Перемещение указателя файла назад и запись дешифрованных
данных
mov rax, bytesRead
neg rax
mov negBytesRead, rax
invoke SetFilePointer, inputFileHandle, negBytesRead,0, FILE_CURRENT
invoke WriteFile,inputFileHandle,addr buffer, bytesRead,addr bytesWritten, 0
cmp bytesRead, 1024
je read_loop ; Читаем следующий блок, если не достигнут конец
файла
exit:
; Закрытие дескрипторов файлов и переименование зашифрованного
файла
invoke CloseHandle, inputFileHandle
140
invoke CloseHandle, keyFileHandle
; Переименовываем файл после дешифрования
invoke MoveFile, addr inputFileName, addr inputFileNameDec
invoke ExitProcess, 0
entry_point endp
; Процедура для удаления расширения из имени файла
RemoveExtension proc
copy_name:
lodsb ; Загружаем один байт из имени файла
cmp al, '.'
je finish_copy ; Если найдена точка, завершаем копирование
stosb ; Сохраняем байт в новое имя файла
test al, al
jnz copy_name ; Продолжаем, если не достигнут конец строки
finish_copy:
mov byte ptr [rdi], 0 ; Добавляем нулевой байт в конец строки
ret
RemoveExtension endp
end
10.3. Алгоритм отримання псевдовипадкової послідовності
Найправильнішим з погляду математичного опису способом
отримання псевдовипадкової послідовності є спосіб, заснований на
застосуванні поліном P(x). І тут застосуємо весь математичний апарат
алгебри, дискретної математики та інших галузей математики. Це
дозволяє математично описувати такі послідовності, виконувати
розрахунки характеристик поліномів та за необхідними критеріями
вибирати оптимальні, проводити математичне моделювання поведінки
таких послідовностей.
Поліном P(x) (він же многочлен), який застосовується при
отриманні псевдовипадкової послідовності має вигляд:
P(x)=xn+an−1xn−1 + an−2xn−2 + … + a1x + a0x0
де знак + - це операція mod2, n – ступінь полінома, ai – коефіцієнти при
відповідних ступенях, a0 = 1.
Операція mod2 застосовується у тому випадку, якщо обробляються 2
стани: 0 та 1.
141
На підставі полінома P(x) будується цифрова схема, основою якої є
зсувний регістр, а зворотні зв'язки на вхід першого тригера через
суматор модуля подаються на основі ступенів обраного полінома.
Наприклад, для полінома
Р(х) = х16 х12 х9 х7 1
цифрова схема матиме вигляд, як представленоцифрова схема матиме
вигляд, як представлено на рис. 10.2.
Усі показані 4-і суматори по модулю два об'єднуються в один
багатовхідний суматор з mod2. Для того щоб така схема генерувала
цифрову послідовність необхідно записати 1 в молодший тригер
регістра і за допомогою синхросигналів зрушувати цю послідовність. На
вхід першого тригера через суматор mod2 подаються стану тих тригерів,
номери яких рівні показниками ступенів полінома.
Природно, що перша послідовність h1 матиме вигляд:
1000000000000000.
Друга послідовність h2 = 0100 0000 0000 0000 (зі зрушенням на 1
розряд у старший бік).
Третя послідовність h3 = 0010 0000 0000 0000 і т.д.
Таким чином формується матриця вихідних станів:
H = h1, h2, h3, h4…hn
Для простоти викладу розглянемо поліном менших ступенів,
наприклад Р(Х) = х4 х3 1, схема з'єднань якого наведена на рис. 10.3.
Рис. 10.2. Цифровая схема генератора псевдослучайной последовательности с
Р(х) = х16 х12 х9 х7 1
142
Матриця вихідних станів Р(Х) = х4 х3 1 має вигляд:
1 0 0 1 1 0 1 0 1 1 1 1 0 0 0 20
0 1 0 0 1 1 0 1 0 1 1 1 1 0 0 21
0 0 1 0 0 1 1 0 1 0 1 1 1 1 0 22
0 0 0 1 0 0 1 1 0 1 0 1 1 1 1 23
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
Верхній рядок – це стан першого тригера. Другий рядок – це стан
другого тригера. І т.д. Тобто, поліном 4-го ступеня має 4 тригери, а,
отже, і 4 рядки вихідних двійкових станів матриці.
Кожен стовпець – це псевдовипадкове число. Наприклад, другий
стовпець – це h2 = 2.
Третій стовпець h3 = 4.
Чотвертий стовпець h4 = 9.
П'ятий стовпець h5 = 3.
Алгоритм отримання псевдовипадкової послідовності може бути
таким:
1. Вибирається поліном. Він повинен мати максимальний період
генерації, Tmax = 2n -1. Мінус 1 означає, що в послідовності немає стовпця
з нульовими станами, інакше регістр почне зрушувати нулі і перестане
генерувати псевдовипадкову послідовність.
2. За показниками ступенів обраного полінома будується схема
генератора із зворотними зв'язками.
H =
D ТT
C 1
D ТT
C 2
C
D ТT
C 3
D ТT
C 4
M2
Рис. 10.3. Схема генератора псевдовипадкової послідовності
с Р(Х) = х4 х3 1
143
3. У перший тригер регістру зсуву записується 1 (якщо
застосовується mod2). Практично – цей стан дорівнює a0 полінома.
Перший стан регістру
h1 = 1000.
Кількість розрядів hі дорівнює максимальному ступеню полінома.
4. Розраховуємо наступний стовпець.
Зробимо це спочатку з прикладу другого стовпець. Для цього в
клітинки другого стовпця робиться косий зсув з першого, а в перший
тригер другого стовпця записується сума по mod2 станів з першого
(попереднього) стовпця, номери яких рівні ступеням обраного полінома.
Наприклад, для Р(Х) = х4 х3 1:
Тг1 1
Тг2 0 1
Тг3 0 0
Тг4 0 0
h1 h2
На другий стовпець в Тг1 записується стан Тг1 Тг2 першого
стовпця. Тобто, необхідно записати 0.
Третій стовпець:
Тг1 1 0
Тг2 0 1 0
Тг3 0 0 1
Тг4 0 0 0
h1 h2 h3
Тобто, необхідно записати 0.
Четвертий стовпець для Р(Х) = х4 х3 1:
Тг1 1 0 0 1
Тг2 0 1 0 0
Тг3 0 0 1 0
Тг4 0 0 0 1
h1 h2 h3 h4
Таким чином формуються всі стовпці матриці псевдовипадкової
послідовності.
5. Після отримання кожного нового стовпця робиться порівняння з
першим стовпцем. Якщо стовпці збігаються, то всі попередні стовпці
144
сформували псевдовипадковий цикл. Розрахунок наступних циклів
потрібно припинити, т.к. значення всіх циклів одного полінома
однакові. А якщо псевдовипадкова послідовність використовується,
наприклад, при тестуванні і не перший цикл генерації, то повністю
порушується математичне обгрунтування пошуку розрядів, якими
з'явився збій.
10.4. Поліноміальне кодування
Для поліномінального кодування необхідні: програма, що генерує
псевдовипадкову послідовність; програма, яка використовує цю
послідовність як ключ. Символи кодової таблиці кодуються байтами.
Отже, і ключ повинен мати розмірність байта. А це 8 розрядів. Тому
можна використовувати псевдовипадкові числа як ключ, отримані
поліномами до 8 ступеня включно (28 = 256 ключів).
Можна застосовувати поліноми і менших ступенів, але в цьому
випадку необхідно використовувати цикли, що повторюються.
Максимальний рівень полінома записується як degP(x). Наприклад,
якщо використовувати degP(x) = 4, то максимальний період генерації
Tmax = 24 – 1 = 15.
Цей цикл дуже короткий і легко розпізнаний.
Практичне використовувати Р(х) з degP(x) = 8 і надалі
застосовувати кілька циклів для збільшення послідовності.
Наприклад, вірус шифрувальник-вимагач, який додає своє
розширення ahtw, кодує 1024 символи. Вірус не змінює (чомусь) перші
5 байтів і дописує до кінця файлу блоки однакового розміру 334 = 14Eh
байтів, у яких зберігається так званий маркет (інформація для
розшифровки на сервері). Ця шкідлива програма використовує "icacls" -
командну утиліту Windows для захисту цього шляху/папки, де
розташований сам вірус. Шкідлива програма використовує API-
інтерфейси ShellExecute з ім'ям runas, щоб спробувати знову запустити
себе з правами адміністратора.
Для отримання псевдовипадкової послідовності розглянемо
програму 10.4. У ній розраховуються всім Р(х) з degP(x) = 4 двійкові
псевдовипадкові числа. Для отримання десяткових чи 16-річних чисел
програму необхідно модифікувати.
Програма 10.4. Отримання псевдовипадкових двійкових чисел
всім Р(х) з degP(x) = 4 полі GF(2):
145
include /masm64/include64/masm64rt.inc
BSIZE equ 32 ; кол. байтов, которые записываются в файл: 15+пробел
.data
Tick1 dq 0 ; ячейка для хранения начального времени
Tick2 dq 0 ; ячейка для хранения полученного времени
Tick11 DQ 0
bufT dq 0,0 ; буфер
ifmtT db "Количество тиков = %d ",10,10,
"Количество тиков находятся с помощью",10,
"API-функции QueryPerformanceCounter",10,10,
"Автор: Рысованый А.Н., https://blogs.kpi.kharkov.ua/v2/asm/ob-avtore/",0
TitlT db "Время выполнения расчетов ",0
szTitle1 db "Время выполнения программы вычисления P(x)=4 c mod2",0
fmt db "%d ",0 ; преобразование символа
szBuf1 db BSIZE dup(0),0 ;
szBuf2 db BSIZE dup(0),0 ;
szBuf3 db BSIZE dup(0),0 ;
szBuf4 db BSIZE dup(0),0 ;
crtf db 10 ; перенос на следующую строку
fName BYTE "Px4m2-64.txt",0 ; имя файла
fHandle DQ ? ; дескриптор
cWritten DQ ? ; для адреса символов вывода
a1 dq 0 ; коэффициент при х1
a2 dq 0 ; коэффициент при х2
a3 dq 0 ; коэффициент при х3
a4 dq 1 ; коэффициент при х4
_h1_1 dq 1 ; начальное значение 1-й яч. 1-го столбца
_h1_2 dq 0 ; начальное значение 2-й яч. 1-го столбца
_h1_3 dq 0 ; начальное значение 3-й яч. 1-го столбца
_h1_4 dq 0 ; начальное значение 4-й яч. 1-го столбца
_m1 dq ? ; рабочее значение 1-й ячейки
_m2 dq ? ; рабочее значение 2-й ячейки
_m3 dq ? ; рабочее значение 3-й ячейки
_m4 dq ? ; рабочее значение 4-й ячейки
_m1_1 dq ? ; текущее значение 1-й ячейки
_m2_1 dq ? ; текущее значение 2-й ячейки
146
_m3_1 dq ? ; текущее значение 3-й ячейки
_m4_1 dq ? ; текущее значение 4-й ячейки
mmm1 dq 0 ; счетчик столбцов
mmm2 dq 15 ; счетчик макс. генерации - от зацикливания при наладке
Hello db "Файл с результатами расчета матриц состояний создан",0
szSt1 db "%dx4+%dx3+%dx2+%dx1+1 ",0 ;!!!
szBufS1 db "%dx4+%dx3+%dx2+%dx1+1",0
szM db " %d ",0 ;!!!
meterLen dq 0 ; счетчик цикла !!!
.code
procPx4m2 proc; процедура
; создание файла
invoke CreateFile,ADDR fName,GENERIC_WRITE,0,0,
CREATE_ALWAYS,FILE_ATTRIBUTE_ARCHIVE,0
mov fHandle,rax ; дескриптор
m1:
inc meterLen ;!!!
mov rdi,0
; запись в буфер значения полинома
invoke wsprintf,ADDR szBufS1, ADDR szSt1,a4,a3,a2,a1
; запись в буфер первого столбца матрицы состояний
invoke wsprintf,ADDR szBuf1[rdi],ADDR fmt,_h1_1
invoke wsprintf,ADDR szBuf2[rdi],ADDR fmt,_h1_2
invoke wsprintf,ADDR szBuf3[rdi],ADDR fmt,_h1_3
invoke wsprintf,ADDR szBuf4[rdi],ADDR fmt,_h1_4
; сохранение первого столбца
mrmq _m1,_h1_1 ; 1
mrmq _m2,_h1_2 ; 0
mrmq _m3,_h1_3 ; 0
mrmq _m4,_h1_4 ; 0
; перезапись первого столбца для вычислений следующих столбцов
mov r11,_h1_1 ;
mov rbx,_h1_2 ;
mov rcx,_h1_3 ;
mov rdx,_h1_4 ;
147
mBegin:
dec mmm2 ; уменьшение счетчика кол. генерации - для останова
cmp mmm2,0 ;
jz m15 ;
and r11,a1 ; выделение состояния 1-й ячейки
and rbx,a2 ; выделение состояния 2-й ячейки
and rcx,a3 ; выделение состояния 3-й ячейки
and rdx,a4 ; выделение состояния 4-й ячейки
; расчет следующего состояния 1-й ячейки
xor r11,rbx ;
xor rcx,rdx ;
xor r11,rcx ; получение следующего состояния 1-й ячейки
mov r10,r11 ; сохранение следующего состояния 1-й ячейки
mrmq _m4_1,_m3
mrmq _m3_1,_m2
mrmq _m2_1,_m1
mov _m1_1,r10
mov r11,_m1_1 ;
mov rbx,_m2_1 ;
mov rcx,_m3_1 ;
mov rdx,_m4_1 ;
mov mmm1,0 ; счетчик совпадения с 1-м столбцом
; сравнение полученного столбца с первым столбцом
cmp r11,qword ptr _h1_1
jnz m11
inc mmm1
m11: cmp rbx,qword ptr _h1_2
jnz m12
inc mmm1
m12: cmp rcx,qword ptr _h1_3
jnz m13
inc mmm1
m13: cmp rdx,qword ptr _h1_4
jnz m14
inc mmm1
m14: cmp qword ptr mmm1,4
jz m15
inc rdi ; вставка пробела перед след. столбцом
inc rdi ; сдвиг на следующую позицию вывода
inc meterLen ;!!!
148
; сохранение в буфер текущего столбца
invoke wsprintf,ADDR szBuf1[rdi],ADDR fmt,_m1_1
invoke wsprintf,ADDR szBuf2[rdi],ADDR fmt,_m2_1
invoke wsprintf,ADDR szBuf3[rdi],ADDR fmt,_m3_1
invoke wsprintf,ADDR szBuf4[rdi],ADDR fmt,_m4_1
invoke wsprintf,ADDR szM,ADDR fmt,meterLen ;!!!
mov r11,_m1_1 ; 1-е значение текущего столбца
mov rbx,_m2_1 ; 2-е значение текущего столбца
mov rcx,_m3_1 ; 3-е значение текущего столбца
mov rdx,_m4_1 ; 4-е значение текущего столбца
; подготовка к вычислению следующего столбца
mrmq _m1,_m1_1
mrmq _m2,_m2_1
mrmq _m3,_m3_1
mrmq _m4,_m4_1
jmp mBegin
m15:
invoke WriteFile,fHandle,ADDR szBufS1,BSIZE,ADDR cWritten,0
invoke WriteFile,fHandle,ADDR crtf,1,ADDR cWritten,0
invoke WriteFile,fHandle,ADDR szBuf1,BSIZE,ADDR cWritten,0
invoke WriteFile,fHandle,ADDR crtf,1,ADDR cWritten,0
invoke WriteFile, fHandle, ADDR szBuf2, BSIZE, ADDR cWritten, 0
invoke WriteFile,fHandle,ADDR crtf,1,ADDR cWritten,0
invoke WriteFile, fHandle, ADDR szBuf3, BSIZE, ADDR cWritten, 0
invoke WriteFile,fHandle,ADDR crtf,1,ADDR cWritten,0
invoke WriteFile, fHandle, ADDR szBuf4, BSIZE, ADDR cWritten, 0
invoke WriteFile,fHandle,ADDR crtf,1,ADDR cWritten,0
invoke WriteFile,fHandle,ADDR crtf,1,ADDR cWritten,0
; очистка буфера
;invoke MemSet, ADDR szBuf1,'0',16
;invoke ZeroMemory,ADDR szBuf2,32
;invoke ZeroMemory,ADDR szBuf3,32
;invoke FlushFileBuffers, szBuf4
mov meterLen,0 ;!!!
mov rcx,BSIZE
mov rsi,0
149
mov r11b,0 ; ;;;
@@: mov szBuf1[rsi],r11b
inc rsi
loop @b
mov rcx,BSIZE
mov rsi,0
mov r11b,0;
@2: mov szBuf2[rsi],r11b
inc rsi
loop @2
mov rcx,BSIZE
mov rsi,0
mov r11b,0;
@3: mov szBuf3[rsi],r11b
inc rsi
loop @3
mov ecx,BSIZE
mov rsi,0
mov r11b,0 ;
@4: mov szBuf4[rsi],r11b
inc rsi
loop @4
; изменение коэффициентов полинома
xor a1,1
cmp a1,1
jz m1
xor a2,1
cmp a2,1
jz m1
xor a3,1
cmp a3,1
jz m1
invoke CloseHandle,fHandle ; закрытие дескриптора файла
ret
procPx4m2 endp
150
entry_point proc
invoke QueryPerformanceCounter,ADDR Tick1; извлечение тиков
invoke procPx4m2
invoke QueryPerformanceCounter,ADDR Tick2; извлечение тиков
finit
fild dword ptr Tick2; загр. последних значений тиков
fild dword ptr Tick1; загр. начальных значений тиков
fsubp st(1),st ; расчет разницы тиков
fistp Tick11 ; сохр. целой части результата тиков
invoke wsprintf,ADDR bufT,ADDR ifmtT,Tick11
invoke MessageBox,0,ADDR bufT,ADDR szTitle1, MB_ICONINFORMATION
invoke ExitProcess, 0
entry_point endp
end
Програма створює файл, у якому записує коефіцієнти полінома і
праворуч від них – довжину циклу кожного Р(х) (рис. 10.4). Довжина
циклу дорівнює кількості стовпців матриці станів Р(х).
Значення лічильника циклу кожного Р(х) записується в змінну
meterLen.
Після кожного формування стовпця значення цього лічильника
збільшується на 1:
inc meterLen
Кожен новий стовпець починаючи з другого порівнюється з
першим. І якщо для degp(x)=4 сталося 4 збіги, це свідчить у тому, що
почався формуватися новий цикл генерації. Після формування циклу
генерування лічильник примусово обнулюється командоюmov
meterLen,0
151
1x4+0x3+0x2+0x1+1 4
1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1
1x4+0x3+0x2+1x1+1 15
1 1 1 1 0 1 0 1 1 0 0 1 0 0 0
0 1 1 1 1 0 1 0 1 1 0 0 1 0 0
0 0 1 1 1 1 0 1 0 1 1 0 0 1 0
0 0 0 1 1 1 1 0 1 0 1 1 0 0 1
1x4+0x3+1x2+0x1+1 6
1 0 1 0 0 0
0 1 0 1 0 0
0 0 1 0 1 0
0 0 0 1 0 1
1x4+0x3+1x2+1x1+1 7
1 1 0 1 0 0 0
0 1 1 0 1 0 0
0 0 1 1 0 1 0
0 0 0 1 1 0 1
1x4+1x3+0x2+0x1+1 15
1 0 0 1 1 0 1 0 1 1 1 1 0 0 0
0 1 0 0 1 1 0 1 0 1 1 1 1 0 0
0 0 1 0 0 1 1 0 1 0 1 1 1 1 0
0 0 0 1 0 0 1 1 0 1 0 1 1 1 1
1x4+1x3+0x2+1x1+1 6
1 1 1 0 0 0
0 1 1 1 0 0
0 0 1 1 1 0
0 0 0 1 1 1
1x4+1x3+1x2+0x1+1 7
1 0 1 1 0 0 0
0 1 0 1 1 0 0
0 0 1 0 1 1 0
0 0 0 1 0 1 1
1x4+1x3+1x2+1x1+1 5
1 1 0 0 0
0 1 1 0 0
0 0 1 1 0
0 0 0 1 1
Рис. 10.4. Вміст вихідного файлу
152
Після завершення розрахунків виводиться повідомлення з
кількістю тиків, яке витрачено на обчислення (рис. 10.5).
Кожен стовпець матриці станів є псевдовипадковим числом.
Як приклад невеликої модифікації попередньої програми
розглянемо процес отримання всіх Р(х) з degP(x) =5, їх вихідних
матриць (матриць станів) та періоду генерування станів кожного з них.
Програма 10.5. Програма отримання всіх Р(х) з degP(x) =5, їх
вихідних матриць (матриць станів) та періоду генерування станів
кожного з них:
include /masm64/include64/masm64rt.inc
BSIZE equ 80 ; кол. байтов, которые записываются в файл: 32+пробелы
.data
Tick1 dq 0 ; ячейка для хранения начального времени
Tick2 dq 0 ; ячейка для хранения полученного времени
Tick11 dq 0
bufT dq 0,0 ; буфер
ifmtT db "Kоличество тиков = %d ",10,10,
"Kоличество тиков находятся с помощью",10,
"API-функции QueryPerformanceCounter",10,10,
"Aвтор: Pысованый A.H., https://blogs.kpi.kharkov.ua/v2/asm/ob-avtore/",0
Рис. 10.5. Повідомлення з кількістю тиків на виконання розрахунків
153
TitlT db "Время выполнения расчетов ",0
szTitle1 db "Время выполнения программы вычисления P(x)=4 c mod2",0
fmt db "%d ",0 ; преобразование символа
szBuf1 db BSIZE dup(0),0 ;
szBuf2 db BSIZE dup(0),0 ;
szBuf3 db BSIZE dup(0),0 ;
szBuf4 db BSIZE dup(0),0 ;
szBuf5 db BSIZE dup(0),0 ;
crtf db 10 ; перенос на следующую строку
fName BYTE "Px5m2-64.txt",0 ; имя файла
fHandle DQ ? ; дескриптор
cWritten DQ ? ; для адреса символов вывода
a1 dq 0 ; коэффициент при х1
a2 dq 0 ; коэффициент при х2
a3 dq 0 ; коэффициент при х3
a4 dq 0 ; коэффициент при х4
a5 dq 1 ; коэффициент при х5
_h1_1 dq 1 ; начальное значение 1-й яч. 1-го столбца
_h1_2 dq 0 ; начальное значение 2-й яч. 1-го столбца
_h1_3 dq 0 ; начальное значение 3-й яч. 1-го столбца
_h1_4 dq 0 ; начальное значение 4-й яч. 1-го столбца
_h1_5 dq 0 ; нач. знач. 5-й яч. 1-го столбца
_m1 dq ? ; рабочее значение 1-й ячейки
_m2 dq ? ; рабочее значение 2-й ячейки
_m3 dq ? ; рабочее значение 3-й ячейки
_m4 dq ? ; рабочее значение 4-й ячейки
_m5 dq ? ; рабочее знач. 5-й яч.
_m1_1 dq ? ; текущее значение 1-й ячейки
_m2_1 dq ? ; текущее значение 2-й ячейки
_m3_1 dq ? ; текущее значение 3-й ячейки
_m4_1 dq ? ; текущее значение 4-й ячейки
_m5_1 dq ? ; текущее значение 5-й ячейки
mmm1 dq 0 ; счетчик совпадений с 1-м столбцом
mmm2 dq 128 ; счетчик макс. генерации - от зацикливания при наладке
Hello db "Файл с результатами расчета матриц состояний
создан",0
154
szSt1 db "%d%d%d%d%d1",0 ;!!! вывод полинома,x0=1
szBufS1 db " %d ",0; значение периода
szM db " %d",0 ;!!!
meterLen dq 0 ; счетчик цикла !!!
.code
procPx5m2 proc ; процедура
; создание файла
invoke CreateFile,ADDR fName,GENERIC_WRITE,0,0,
CREATE_ALWAYS,FILE_ATTRIBUTE_ARCHIVE,0
mov fHandle,rax ; дескриптор
m1:
inc meterLen ;!!!
mov rdi,0
; запись в буфер значения полинома
invoke wsprintf,ADDR szBufS1, ADDR szSt1,a5,a4,a3,a2,a1
; запись в буфер первого столбца матрицы состояний
invoke wsprintf,ADDR szBuf1[rdi],ADDR fmt,_h1_1
invoke wsprintf,ADDR szBuf2[rdi],ADDR fmt,_h1_2
invoke wsprintf,ADDR szBuf3[rdi],ADDR fmt,_h1_3
invoke wsprintf,ADDR szBuf4[rdi],ADDR fmt,_h1_4
invoke wsprintf,ADDR szBuf5[rdi],ADDR fmt,_h1_5
; сохранение первого столбца
mrmq _m1,_h1_1 ; 1
mrmq _m2,_h1_2 ; 0
mrmq _m3,_h1_3 ; 0
mrmq _m4,_h1_4 ; 0
mrmq _m5,_h1_5 ; 0
; перезапись первого столбца для вычислений следующих столбцов
mov r11,_h1_1 ;
mov rbx,_h1_2 ;
mov rcx,_h1_3 ;
mov rdx,_h1_4 ;
mov r12,_h1_5 ;
mBegin:
dec mmm2 ; уменьшение счетчика кол. генерации - для останова
cmp mmm2,0 ;
jz m15 ;
155
and r11,a1 ; выделение состояния 1-й ячейки
and rbx,a2 ; выделение состояния 2-й ячейки
and rcx,a3 ; выделение состояния 3-й ячейки
and rdx,a4 ; выделение состояния 4-й ячейки
and r12,a5 ; выделение состояния 5-й ячейки
; расчет следующего состояния 1-й ячейки
xor r11,rbx ;
xor rcx,rdx ;
xor r11,rcx ; получение следующего состояния 1-й ячейки
xor r11,r12
mov r10,r11 ; сохранение следующего состояния 1-й ячейки
mrmq _m5_1,_m4
mrmq _m4_1,_m3
mrmq _m3_1,_m2
mrmq _m2_1,_m1
mov _m1_1,r10
mov r11,_m1_1 ;
mov rbx,_m2_1 ;
mov rcx,_m3_1 ;
mov rdx,_m4_1 ;
mov r12,_m5_1 ;
mov mmm1,0 ; счетчик совпадения с 1-м столбцом
; сравнение полученного столбца с первым столбцом
cmp r11,qword ptr _h1_1
jnz m11
inc mmm1
m11: cmp rbx,qword ptr _h1_2
jnz m12
inc mmm1
m12: cmp rcx,qword ptr _h1_3
jnz m13
inc mmm1
m13: cmp rdx,qword ptr _h1_4
jnz m14
inc mmm1
m14: cmp r12,qword ptr _h1_5
jnz m15
inc mmm1
m15: cmp qword ptr mmm1,5
156
jz m16
inc rdi ; вставка пробела перед след. столбцом
inc rdi ; сдвиг на следующую позицию вывода
inc meterLen ;!!!
; сохранение в буфер текущего столбца
invoke wsprintf,ADDR szBuf1[rdi],ADDR fmt,_m1_1
invoke wsprintf,ADDR szBuf2[rdi],ADDR fmt,_m2_1
invoke wsprintf,ADDR szBuf3[rdi],ADDR fmt,_m3_1
invoke wsprintf,ADDR szBuf4[rdi],ADDR fmt,_m4_1
invoke wsprintf,ADDR szBuf5[rdi],ADDR fmt,_m5_1
invoke wsprintf,ADDR szM,ADDR fmt,meterLen ;!!!
mov r11,_m1_1 ; 1-е значение текущего столбца
mov rbx,_m2_1 ; 2-е значение текущего столбца
mov rcx,_m3_1 ; 3-е значение текущего столбца
mov rdx,_m4_1 ; 4-е значение текущего столбца
mov r12,_m5_1 ; 5-е значение текущего столбца
; подготовка к вычислению следующего столбца
mrmq _m1,_m1_1
mrmq _m2,_m2_1
mrmq _m3,_m3_1
mrmq _m4,_m4_1
mrmq _m5,_m5_1 ;
jmp mBegin
m16:
invoke WriteFile,fHandle,ADDR szBufS1,BSIZE,ADDR cWritten,0
invoke WriteFile,fHandle,ADDR crtf,1,ADDR cWritten,0
invoke WriteFile,fHandle,ADDR szBuf1,BSIZE,ADDR cWritten,0
invoke WriteFile,fHandle,ADDR crtf,1,ADDR cWritten,0
invoke WriteFile, fHandle, ADDR szBuf2, BSIZE, ADDR cWritten, 0
invoke WriteFile,fHandle,ADDR crtf,1,ADDR cWritten,0
invoke WriteFile, fHandle, ADDR szBuf3, BSIZE, ADDR cWritten, 0
invoke WriteFile,fHandle,ADDR crtf,1,ADDR cWritten,0
invoke WriteFile, fHandle, ADDR szBuf4, BSIZE, ADDR cWritten, 0
invoke WriteFile,fHandle,ADDR crtf,1,ADDR cWritten,0
invoke WriteFile, fHandle, ADDR szBuf5, BSIZE, ADDR cWritten, 0
invoke WriteFile,fHandle,ADDR crtf,1,ADDR cWritten,0
157
invoke WriteFile,fHandle,ADDR crtf,1,ADDR cWritten,0
; очистка буфера
;invoke MemSet, ADDR szBuf1,'0',16
;invoke ZeroMemory,ADDR szBuf2,32
;invoke ZeroMemory,ADDR szBuf3,32
;invoke FlushFileBuffers, szBuf4
mov meterLen,0 ;!!!
mov rcx,BSIZE
mov rsi,0
mov r11b,0 ; ;;;
@@: mov szBuf1[rsi],r11b
inc rsi
loop @b
mov rcx,BSIZE
mov rsi,0
mov r11b,0;
@2: mov szBuf2[rsi],r11b
inc rsi
loop @2
mov rcx,BSIZE
mov rsi,0
mov r11b,0;
@3: mov szBuf3[rsi],r11b
inc rsi
loop @3
mov ecx,BSIZE
mov rsi,0
mov r11b,0 ;
@4: mov szBuf4[rsi],r11b
inc rsi
loop @4
mov ecx,BSIZE
mov rsi,0
mov r11b,0 ;
@5: mov szBuf5[rsi],r11b
inc rsi
loop @5
158
; изменение коэффициентов полинома
xor a1,1
cmp a1,1
jz m1
xor a2,1
cmp a2,1
jz m1
xor a3,1
cmp a3,1
jz m1
xor a4,1
cmp a4,1
jz m1
invoke CloseHandle,fHandle ; закрытие дескриптора файла
ret
procPx5m2 endp
entry_point proc
invoke QueryPerformanceCounter,ADDR Tick1
invoke procPx5m2
invoke QueryPerformanceCounter,ADDR Tick2
finit
fild dword ptr Tick2
fild dword ptr Tick1
fsubp st(1),st
fistp Tick11
invoke wsprintf,ADDR bufT,ADDR ifmtT,Tick11
invoke MessageBox,0,ADDR bufT,ADDR szTitle1, MB_ICONINFORMATION
invoke ExitProcess, 0
entry_point endp
end
159
Поліноми Р(х) з degP(x) =5 (максимальним ступенем) в полі GF(2)
(mod2) генерують послідовність, яку можна для деяких з них
представити у вигляді:
Р(х) = 100101 = х5 2 х2 2 1, Т = 31
1 0 1 0 1 1 1 0 1 1 0 0 0 1 1 1 1 1 0 0 1 1 0 1 0 0 1 0 0 0 0
0 1 0 1 0 1 1 1 0 1 1 0 0 0 1 1 1 1 1 0 0 1 1 0 1 0 0 1 0 0 0
0 0 1 0 1 0 1 1 1 0 1 1 0 0 0 1 1 1 1 1 0 0 1 1 0 1 0 0 1 0 0
0 0 0 1 0 1 0 1 1 1 0 1 1 0 0 0 1 1 1 1 1 0 0 1 1 0 1 0 0 1 0
0 0 0 0 1 0 1 0 1 1 1 0 1 1 0 0 0 1 1 1 1 1 0 0 1 1 0 1 0 0 1
Р(х) = 101001 = х5 2 х3 2 1, Т = 31
1 0 0 1 0 1 1 0 0 1 1 1 1 1 0 0 0 1 1 0 1 1 1 0 1 0 1 0 0 0 0
0 1 0 0 1 0 1 1 0 0 1 1 1 1 1 0 0 0 1 1 0 1 1 1 0 1 0 1 0 0 0
0 0 1 0 0 1 0 1 1 0 0 1 1 1 1 1 0 0 0 1 1 0 1 1 1 0 1 0 1 0 0
0 0 0 1 0 0 1 0 1 1 0 0 1 1 1 1 1 0 0 0 1 1 0 1 1 1 0 1 0 1 0
0 0 0 0 1 0 0 1 0 1 1 0 0 1 1 1 1 1 0 0 0 1 1 0 1 1 1 0 1 0 1
Р(х) = 101111, Т = 31
1 1 0 0 1 0 0 1 1 1 1 1 0 1 1 1 0 0 0 1 0 1 0 1 1 0 1 0 0 0 0
0 1 1 0 0 1 0 0 1 1 1 1 1 0 1 1 1 0 0 0 1 0 1 0 1 1 0 1 0 0 0
0 0 1 1 0 0 1 0 0 1 1 1 1 1 0 1 1 1 0 0 0 1 0 1 0 1 1 0 1 0 0
0 0 0 1 1 0 0 1 0 0 1 1 1 1 1 0 1 1 1 0 0 0 1 0 1 0 1 1 0 1 0
0 0 0 0 1 1 0 0 1 0 0 1 1 1 1 1 0 1 1 1 0 0 0 1 0 1 0 1 1 0 1
Р(х) = 110111, Т = 31
1 1 0 1 0 1 0 0 1 0 0 0 1 0 1 1 1 1 1 0 1 1 0 0 1 1 1 0 0 0 0
0 1 1 0 1 0 1 0 0 1 0 0 0 1 0 1 1 1 1 1 0 1 1 0 0 1 1 1 0 0 0
0 0 1 1 0 1 0 1 0 0 1 0 0 0 1 0 1 1 1 1 1 0 1 1 0 0 1 1 1 0 0
0 0 0 1 1 0 1 0 1 0 0 1 0 0 0 1 0 1 1 1 1 1 0 1 1 0 0 1 1 1 0
0 0 0 0 1 1 0 1 0 1 0 0 1 0 0 0 1 0 1 1 1 1 1 0 1 1 0 0 1 1 1
Р(х) = 111011, Т = 31
1 1 1 0 0 1 1 0 1 1 1 1 1 0 1 0 0 0 1 0 0 1 0 1 0 1 1 0 0 0 0
0 1 1 1 0 0 1 1 0 1 1 1 1 1 0 1 0 0 0 1 0 0 1 0 1 0 1 1 0 0 0
0 0 1 1 1 0 0 1 1 0 1 1 1 1 1 0 1 0 0 0 1 0 0 1 0 1 0 1 1 0 0
0 0 0 1 1 1 0 0 1 1 0 1 1 1 1 1 0 1 0 0 0 1 0 0 1 0 1 0 1 1 0
0 0 0 0 1 1 1 0 0 1 1 0 1 1 1 1 1 0 1 0 0 0 1 0 0 1 0 1 0 1 1
160
Р(х) = 111101, Т = 31
1 0 1 1 0 1 0 1 0 0 0 1 1 1 0 1 1 1 1 1 0 0 1 0 0 1 1 0 0 0 0
0 1 0 1 1 0 1 0 1 0 0 0 1 1 1 0 1 1 1 1 1 0 0 1 0 0 1 1 0 0 0
0 0 1 0 1 1 0 1 0 1 0 0 0 1 1 1 0 1 1 1 1 1 0 0 1 0 0 1 1 0 0
0 0 0 1 0 1 1 0 1 0 1 0 0 0 1 1 1 0 1 1 1 1 1 0 0 1 0 0 1 1 0
0 0 0 0 1 0 1 1 0 1 0 1 0 0 0 1 1 1 0 1 1 1 1 1 0 0 1 0 0 1 1
Кожен стовпець наведених матриць станів є числом, послідовність
яких називається псевдовипадковою. Для деяких з них така
псевдовипадкова послідовність наведена нижче:
- для P(x)=100101:
1,2,5,10,21,11,23,14,29,27,22,12,24,17,3,7,15,31,30,28,25,19,6,13,26,
20,9,18,4,8,16;
- для P(x)= 101001:
1,2,4,9,18,5,11,22,12,25,18,7,15,31,30,28,24,17,3,6,13,27,23,14,29,26,
21,10,20,8,16;
- для P(x)= P(x)=101111:
1,3,6,12,25,18,4,9,19,7,15,31,30,29,27,23,14,28,24,17,2,5,10,21,11,22,
13,26,20,8,16;
- для P(x)= P(x)= 111011:
1,3,7,14,28,25,19,6,13,27,23,15,31,30,29,26,20,8,17,2,4,9,18,5,10,21,1
1,22,12,24,16.
Для отримання псевдовипадкової послідовності з використанням
Р(х) інших ступенів необхідно отримати їх стани матриці і кожен
стовпець перевести в десяткове число.
У програмі 10.6 показано застосування шифрування ключами,
отриманими при використанні Р(Х) = х4 х3 х 1. Для збільшення довжини
зашифрованої послідовності застосовано 8 циклів генерації чисел по 15
чисел у кожному циклі.
Програма 10.6. Шифрування пароля за модулем 2 з використанням
команд набору (технології) AVX2:
; программа шифрования пароля по модулю 2 с использ. ком. AVX2
; поразрядное mod2: txt mod2 key
; key = 120 символов
include \masm64\include64\masm64rt.inc ;
.data
161
rez db 240 DUP(0) ; для 120 символов
buff db 240 DUP(0) ;
txt db "Введите код для преобразования",10,0
TXTSIZE equ $ - txt ; число символов, выведенных на экран
txt2 db "txt mod2 random:",10,0 ;
stdin1 dq 0 ; для дескриптора ввода
stdout1 dq 0 ; для дескриптора вывода
wrn dq 0 ; число записанных символов
rdn dq 0 ; число прочитанных символов
; key db 1 ; ключ нач.знач. для сложения по mod2 (при отладке)
key db 1,2,4,9,3,6,0Dh,0Ah,5,0Bh,7,0Fh,0Eh,0Ch,8 ; 15х8=120
db 1,2,4,9,3,6,0Dh,0Ah,5,0Bh,7,0Fh,0Eh,0Ch,8
db 1,2,4,9,3,6,0Dh,0Ah,5,0Bh,7,0Fh,0Eh,0Ch,8
db 1,2,4,9,3,6,0Dh,0Ah,5,0Bh,7,0Fh,0Eh,0Ch,8
db 1,2,4,9,3,6,0Dh,0Ah,5,0Bh,7,0Fh,0Eh,0Ch,8
db 1,2,4,9,3,6,0Dh,0Ah,5,0Bh,7,0Fh,0Eh,0Ch,8
db 1,2,4,9,3,6,0Dh,0Ah,5,0Bh,7,0Fh,0Eh,0Ch,8
db 1,2,4,9,3,6,0Dh,0Ah,5,0Bh,7,0Fh,0Eh,0Ch,8 ; Р(х)=х4 + х3 + 1
.code ; Р(х)=х4 + х3 + 1
entry_point proc
invoke GetStdHandle,STD_INPUT_HANDLE ;извлекает дескриптор
mov stdin1,rax
invoke GetStdHandle,STD_OUTPUT_HANDLE ;извлекает дескриптор
mov stdout1,rax
invoke SetConsoleCP,1251;уст. кодовой страницы win 1251 в поток ввода
invoke SetConsoleOutputCP,1251;уст. код. стр. win 1251 в поток вывода
invoke WriteConsoleA,stdout1,addr txt,TXTSIZE,addr wrn,0 ; вывод текста
invoke WriteConsoleA,stdout1,addr txt2,17,addr wrn,0 ; вывод текста
invoke ReadConsole,stdin1,addr buff,128,addr rdn,0 ;
; ReadConsole записала по адр. rdn +2 символа
lea rsi,buff ; загрузка адреса буфера
lea rdi,rez ; загрузка адреса ячейки результата
lea r15,key ; загрузка адреса нахождения ключа
mov rcx,rdn ; запись прочитанных символов
sub rcx,2 ; минус служебные символы
cmp rcx,8
jl mL
162
jmp mG
mL:
mov rcx,rdn
@@:
mov al,byte ptr [rsi] ; buff
mov bl,byte ptr [r15] ; key
xor al,bl ; шифрование текста по модулю 2
mov byte ptr [rdi],al ;
inc rsi ;
inc rdi ;
inc r15 ; изменение ключа на +1
loop @b ; dec, jnz
jmp mExit
mG:
mov rax,rdn ; количество чисел
sub rax,2 ; минус служебные символы
mov rbx,8 ; чисел в цикле
xor rdx,rdx ; подготовка к делению
div rbx ; количество циклов
mov rcx,rax ; сохранение количества циклов
lea rsi,buff ; загрузка адреса buff
lea r15,key ; загрузка адреса key
lea rdi,rez ; загрузка адреса rez
m1:
vmovups ymm0,[rsi] ; buff
vmovups ymm1,[r15] ; key
vxorpd ymm2,ymm0,ymm1;
vmovups [rdi],ymm2 ; перемещение в память по адресу регистра rdi
add rsi,32 ; buff, 8 бит x 32 числа = 256 разрядов
add r15,32 ; rez, смещение на 256 разряда
add rdi,32 ; результат, смещение на 256 разрядов
loop m1
mExit:
invoke WriteConsoleA,stdout1,addr rez,128,addr wrn,0
invoke ReadConsole,stdin1,addr buff,130,addr rdn,0
invoke ExitProcess,0
entry_point endp
end
163
У програмі в секції даних можна застосувати псевдовипадкову
послідовність, отриману за допомогою будь-якого полінома з degP(x) 8
ступеня.
Програма шифрує 120 символів під час введення символів у
консольному вікні.
10.5. Лабораторна робота «Кодування файлів»
Мета заняття: набути практичних навичок кодування файлів.
У звіті подати:
– назва лабораторної роботи, варіант, прізвище та ініціали, e-mail,
номер групи автора програми;
– представити тексти програм та всі файли проекту;
– у тексті програми організувати виведення назви лабораторної
роботи, варіант, прізвище та ініціали, e-mail, номер групи автора
програми;
– результат виконання завдання (скриншоти вікон програми та
відладчика).
Завдання
Залежно від рівня програмування студента вибрати один чи всі
варіанти завдання.
Варіанти
1. Написати програму розрахунку всіх вихідних матриць із
зазначенням коефіцієнтів для degР(х) = 8, довжину циклів для кожного
Р(х), а для Р(х), які генерують максимальні періоди – в окремих файлах
навести 10-е чи 16- е уявлення цих послідовностей.
2. Написати програму шифрування каталогу із додаванням нового
розширення.
3. Написати програму дешифрування каталогу із відновленням
старого розширення.
Контрольні питання для перевірки знань
1. Навести приклади API-функцій, які можна використовувати для
створення випадкових послідовностей.
164
2. Що являє собою процес кодування при передачі даних та
декодування?
3. Які операції застосовуються під час кодування?
4. Навіщо необхідно кодувати дані послідовності з максимальним
періодом?
5. Як формується вихідна матриця станів для псевдовипадкової
послідовності?
165
11. ХЕШУВАННЯ
11.1. Загальні відомості про хешування
Хешування (англ. hashing) – перетворення масиву вхідних даних
довільної довжини на (вихідний) бітовий рядок встановленої довжини,
що виконується певним алгоритмом. Хеш - це число, яке генерується з
тексту за допомогою хеш-алгоритму. Це число менше оригінального
тексту.
Хеш-функції спроектовані так, щоб навіть незначні зміни у
вихідних даних призводили до радикальних змін у хеші, що генерується.
Хеш (hash) – це унікальний цифровий відбиток, який можна
привласнити будь-якому файлу.
Один із популярних варіантів використання хешу – зберігання
паролів на сайті. При вході на який-небудь дані не передаються в базу
даних у відкритому вигляді - щоб уникнути крадіжки хакерами. Під час
авторизації пароль спочатку хешується і потім записується в базу даних.
При наступній спробі входу пароль знову перетворюється на хеш і
порівнюється з хешом на сервері.
У Мережі можна знайти цілі словники, які містять тисячі вкрадених
дехешованих паролів. Для запобігання пошуку за словниками кожному
паролю під час реєстрації додають сіль - тобто випадковий набір
символів. Коли вводиться пароль, алгоритм додає до нього унікальну
сіль, потім все хешується і виходить зовсім новий хеш.
Хеш-функцію можна отримати на основі різних алгоритмів,
наприклад:
1. «Хеш-код» як залишок від розподілу на число всіх можливих
«хешів»;
2. "Хеш-код" як набір коефіцієнтів одержуваного полінома;
3. "Хеш-функції", засновані на комбінованих операціях.
166
11.2. Алгоритм хешування SHA-1
Алгоритма SHA-1 (Secure Hashing Algorithm) – вважається
застарілим та досить простим, що дозволяє починати вивчення
хешування з нього.
Хеш-функція представляє 160-бітове (20 байт) значення, зване
також дайджестом повідомлення, яке зазвичай відображається як
шістнадцяткове число завдовжки 40 цифр.
Для отримання хеш-значення алгоритму SHA-1 вихідне
повідомлення розбивається на блоки по 512 біт у кожному. Останній
блок доповнюється до довжини, кратної 512 біт. Спочатку додається 1
(біт), а потім нулі, щоб довжина блоку стала рівною 512 - 64 = 448 біт.
У 64 біти, що залишилися, записується довжина вихідного повідомлення
в бітах. Якщо останній блок має довжину більше 447, але менше 512 біт,
то доповнення виконується наступним чином: спочатку додається 1
(біт), потім нулі аж до кінця 512-бітного блоку; після цього створюється
ще один 512-бітний блок, який заповнюється аж до 448 біт нулями, після
чого в 64 біти, що залишилися, записується довжина вихідного
повідомлення в бітах. Доповнення останнього блоку здійснюється
завжди, навіть якщо повідомлення має потрібну довжину.
Наприклад, якщо написати текстовий файл із вмістом «Привіт,
світ!», можна вважати, що ця фраза складається з 12 символів
включаючи пробіл. Кожен символ кодується байтом, тому 12 х 8 = 96
біт = 0110 0000.
Кількість байтів у блоці: 512/8=64.
Наприкінці блоку додамо двійковий код, що означає розмір
повідомлення в бітах: 1101000b = 104d. Доповнення останнього блоку
здійснюється завжди, навіть якщо повідомлення має потрібну довжину.
Для отримання хеш-значення використовуються:
- п'ять 32-бітових змінних (A, B, C, D, E);
- чотири константи Kt (1-4);
- чотири нелінійні операції Ft (1-4);
Для перемішування блоку 512 біт використовуються константи:
A = h0 = 0×67452301
B = h1 = 0xEFCDAB89
C = h2 = 0×98BADCFE
D = h3 = 0×10325476
167
E = h4 = 0xC3D2E1F0
Алгоритм дробить вихідне повідомлення на 80 частин і перемішує
з кожною констант. Кожна ітерація циклу оновлює значення h0–h4, доки
не закінчиться вихідне повідомлення.
У результаті п'ять фінальних значень склеюються: h0 h1 h2 h3 h4.
Попередня обробка.
Приєднуємо біт 1 до повідомлення.
Приєднуємо k бітів '0', де k найменше число ≥ 0 таке, що довжина
повідомлення, що вийшло (у бітах) порівнянна за модулем 512 з 448
(length mod 512 = 448).
Додаємо довжину вихідного повідомлення (до попередньої
обробки) як ціле 64-бітове число.
В процесі виконання.
Повідомлення розбивається послідовно 512 біт.
Блок розбивається на 16 частин по 32-біта w[i], 0 <= i <= 15
Ці 16 частин по 32-бітові доповнюються до 80 32-бітових частин:
for i from 16 to 79
w[i] = (w[i-3] xor w[i-8] xor w[i-14] xor w[i-16]) цикліч. зрушення
вліво 1
Відбувається ініціалізація хеш-значень цієї частини:
a = h0
b = h1
c = h2
d = h3
e = h4
Основний цикл має вигляд:
for i from 0 to 79
if 0 ≤ i ≤ 19 then
f = (b and c) or ((not b) and d)
k = 0x5A827999
else if 20 ≤ i ≤ 39 then
f = b xor c xor d
k = 0x6ED9EBA1
else if 40 ≤ i ≤ 59 then
f = (b and c) or (b and d) or (c and d)
168
k = 0x8F1BBCDC
else if 60 ≤ i ≤ 79 then
f = b xor c xor d
k = 0xCA62C1D6
temp = (a leftrotate 5) + f + e + k + w[i]
e = d
d = c
c = b leftrotate 30
b = a
a = temp
Додаємо хеш-значення цієї частини до результату:
h0 = h0 + a
h1 = h1 + b
h2 = h2 + c
h3 = h3 + d
h4 = h4 + e
Підсумкове хеш-значення (h0, h1, h2, h3, h4 має бути перетворене
до виду:
digest = hash = h0 append h1 append h2 append h3 append h4
11.3. Лабораторна робота «Хешування за алгоритмом SHA-1»
Мета заняття: набути практичних навичок хешування файлів за
алгоритмом SHA-1.
У звіті подати:
– назва лабораторної роботи, варіант, прізвище та ініціали, e-mail,
номер групи автора програми;
– у тексті програми організувати виведення назви лабораторної
роботи, варіант, прізвище та ініціали, e-mail, номер групи автора
програми;
– результат виконання завдання (скриншоти вікон програми та
відладчика).
Завдання
Написати програму отримання хеш-функції для своєї оригінальної
169
програми із зазначенням у програмі свого прізвища, номера групи та
призначення програми.
Контрольні питання для перевірки знань
1. Яку розрядність має хеш-функція?
2. Що являє собою хеш-функція?
3. Скільки 32-бітових змінних застосовується при хешуванні?
4. Скільки констант використовується при хешуванні і чого вони
залежать?
5. Скільки нелінійних операцій використовується при хешуванні?
170
12. КОНТРОЛЬ ЦИКЛІЧНИМ НАДЛИШНИМ КОДОМ
12.1. Загальні відомості про поліноми
Контроль циклічно надлишковим кодом - CRC (Cyclical
Redundancy Check) - це потужний і широко використовуваний метод
виявлення помилок передачі інформації. Він забезпечує виявлення
помилок із високою ймовірністю. Крім того, цей метод має низку інших
корисних моментів, які можуть знайти своє застосування у практичних
завданнях.
CRC - це залишок від поділу вхідної послідовності на поліном P(x).
Поліном (від багаточлен) вибирається за певними критеріями.
Приклад запису полінома: Р(х) = х4 2 х3 2 1. Коефіцієнти цього
многочлена записуються як 11001 = 318 = 1916
У Р(х) вільний член а0 = 1.
Для генераторів псевдовипадкових чисел поліноми Р(х) завжди
вибирають ті, що генерують максимальний період, т.к. у цьому періоді
присутні всі стани, а пропущений стан лише один – усі нулі. У цьому
випадку багаточлен застосовні всі математичні методи його обробки та
аналізу.
Вихідна послідовність байтів, якою може бути і великий файл, і
текст розміром кілька слів і навіть символів, є єдиною послідовністю
бітів. Ця послідовність поділяється на деяке фіксоване двійкове число.
Інтерес представляє залишок від поділу, який є значенням CRC.
На приймальній стороні виконується розподіл той самий поліном і
порівняння залишку від розподілу з вихідним значенням CRC. Якщо
вони рівні, то вважається, що вихідне повідомлення не пошкоджене.
Найбільш повно описані поліноми та їх властивості у книзі
«Пітерсон У., Уелдон Е. Коди, що виправляють помилки. 2-ге вид. - М.:
Світ, 1976. - 593 с. ». Користуватись поліномами з інших джерел,
особливо з інтернету, треба з великою обережністю.
Наведені у літературі поліноми немає остаточним вибором і
вимагають постійного дослідження залежно від обраних критеріїв. Не
всі з наведених Р(х) дозволяють отримати псевдовипадкову
послідовність максимальної довжини. Можна припустити, що вибрано
171
зовсім інші критерії і під них отримано певну практичну доцільність їх
застосування. Напевно, отримання залишку від поділу на полином (як
контрольного результату), властивості Р(х) та його можливості не
завжди актуальні.
12.2. Арифметика CRC
Розрахунки CRC ведуться у двійковій системі числення. Природно,
можна застосовувати й інші системи числення, але це вже в галузі
наукових досліджень та областей застосування.
Розрахунки CRC здійснюються в поліноміальній арифметиці за
модулем 2. У операції mod2 переноси відсутні. Операції додавання та
віднімання в арифметиці CRC тотожні і виконуються як додавання за
модулем 2 (XOR).
В алгоритмі обчислення CRC вводиться ще кілька поліномів та
співвідношень між ними:
– породжує поліпом G(x) – обраний за певними критеріями
поліном, який ділиться вихідний поліном повідомлення;
– поліном-приватне Q(x) – поліном, який виходить при розподілі і
є приватним від поділу поліномів D(x)/G(x);
– поліном-залишок R(x) – поліном, що вийшов як залишок від
поділу поліномів D(x)/G(x).
Між переліченими поліномами існують відносини:
D(x) = Q(x)xG(x) + R(x), Q(x) = (D(x) - R(x))/G(x).
Існує кілька різних способів поділу.
На рис. 12.1 наведено схему обчислення двійкового поділу (з
циклічним переносом).
172
На рис. 12.2 наведено схему обчислення CRC-ділення.
Рис. 12.1. Схема обчислення двійкового ділення
(З циклічним перенесенням)
Рис. 12.2. Схема обчислення CRC- ділення
173
Результати звичайного та CRC-поділів відрізняються.
Алгоритм обчислення CRC є одним із можливих алгоритмів
хешування. Розрядність полінома G(x) 16 біт, що породжує, забезпечує
до 216 = 65 536-1 значень хеш-функції (відсутня нульовий стан).
Збільшення розрядності полінома G(x) до 32 бітів призводить до
розширення набору значень хеш-функції вже до 4294967296-1.
12.3. Прямий алгоритм обчислення CRC
Схема обчислення CRC-розподілу, яка наведена на рис.12.2
реалізує прямий алгоритм CRC-розподілу для вихідної послідовності на
стороні, що передає. У CRC арифметиці операції додавання та
віднімання в ній тотожні і виконуються як додавання за модулем 2
(XOR).
Схема обробки отриманої послідовності на приймальній стороні
представлена на рис. 12.3.
Рис. 12.3. Схема обчислення CRC-ділення на приймальній стороні
174
На приймальній стороні вхідна послідовність доповнюється трьома
нулями, т.к. використовувався Р(х) третього ступеня - 1011. При
виконанні CRC-розподілу ці додаткові біти гарантують, що всі біти
вихідної послідовності візьмуть участь у процесі формування значення
CRC.
Довжина значення CRC, що приєднується до вихідної
послідовності, повинна дорівнювати ступеню полінома.
Але практично немає необхідності доповнювати отриману
послідовність нулями. Необхідно виконати CRC-розподіл отриманого
вихідного рядка (доповненого в кінці вихідним значенням CRC) на
поліном і аналізувати залишок. Якщо залишок від цього поділу
нульовий, то вихідна послідовність була порушена під час передачі.
Існує досить багато методів отримання контрольної
характеристики з отриманням різних результатів.
Для зручності та простоти поділу Р(х) необхідно брати кратними
значенню 8. Ступінь полінома визначає розмірність регістрів.
Ділити багаточлени "стовпчиком" зі зрушенням на 1 біт на кожній
ітерації занадто повільно, тому на практиці використовують більш
швидкі алгоритми, що ґрунтуються на властивостях CRC-арифметики.
На рис. 12.4 показаний один з варіантів поділу вихідної
послідовності бітів на многочлен x8 + x2 + x1 + x0, у якому старший
розряд зрушений зарубіжних країн регістру.
При розгляді цього алгоритму прийнято, що старший аргумент
полінома завжди дорівнює 1 і вже зрушений за його межу, але бере
участь в операції XOR.
Алгоритм обчислення контрольної суми CRC:
Рис. 12.4. Приклад поділ вихідної послідовності бітів на багаточлен
x8 + x2 + x1 + x0
175
1. Вихідне повідомлення доповнюється нулями в молодших
розрядах, у кількості, що дорівнює кількості розрядів полінома.
2. У молодший розряд регістру заноситься один старший біт
повідомлення, та якщо з старшого розряду регістру висувається один
біт.
3. Якщо висунутий біт дорівнює "1", то виконується операція XOR,
у тих розрядах регістру, які відповідають одиницям полінома.
4. Якщо у повідомленні ще є біти, переходимо до кроку 2.
5. Коли всі біти повідомлення надійшли в регістр і були оброблені
цим алгоритмом, у регістрі залишається залишок від поділу, який є
контрольною сумою CRC.
12.4. Стандартний табличний алгоритм
Стандартний табличний алгоритм дозволяє зменшити час
отримання залишку від поділу. Для того щоб була можливість
обробляти поліном математичними методами, він повинен генерувати
максимальний період. Суть його в тому, що кожен поліном (див. рис.
10.4) генерує свою псевдовипадкову послідовність.
Для обчислення CRC необхідно кожен розряд вхідної
послідовності (0 або 1) помножити (тобто вибрати) на відповідне
псевдовипадкове число та вибрані значення скласти mod2. Наприклад,
1-й старший розряд множиться на 1-й стовпець матриці станів (1 число
псевдовипадкової послідовності). Другий розряд множиться на 2-й
стовпець і т.д. Потім всі значення складаються mod2.
Таким чином, програму записується псевдовипадкова
послідовність (матриця станів) у вигляді набору псевдовипадкових
чисел, які послідовно перемножуються на розряди вхідної
послідовності. А потім відбувається складання всіх результатів по mod2.
Псевдовипадкову послідовність чисел іноді неправильно
називають таблицею ініціалізації, що не відображає суті перетворень,
що відбуваються.
Такий самий принцип множення матриці станів на вхідну
послідовність застосовується і при отриманні сигнатур.
12.5. Лабораторна робота "Обчислення CRC"
Мета заняття: набути практичних навичок обчислення CRC.
176
У звіті подати:
– назва лабораторної роботи, варіант, прізвище та ініціали, e-mail,
номер групи автора програми;
– у тексті програми організувати виведення назви лабораторної
роботи, варіант, прізвище та ініціали, e-mail, номер групи автора
програми;
– результат виконання завдання (скриншоти вікон програми та
відладчика).
Завдання
Ознайомитись із матеріалами, розташованими за посиланням
https://guildalfa.ru/alsha/node/2.
Написати програму обчислення CRC для своєї оригінальної
програми.
Контрольні питання для перевірки знань
1. Які переваги контролю з використанням поліномів?
2. Переваги поліномів, які мають максимальний період
генерування?
3. Які операції використовує арифметика CRC?
4. Як за допомогою поліномів описати алгоритм розподілу?
5. Опишіть процес надсилання та отримання повідомлення.
177
13. ШИФРУВАННЯ ПОВІДОМЛЕНЬ МЕТОДОМ ЗАМІНИ
БИТОВИХ ПРЕДСТАВ
13.1. Метод заміни бітових уявлень
Шифрування повідомлень методом заміни бітових уявлень є ще
одним з алгоритмів кодування, який заснований на стисканні даних без
втрат.
Стиснення даних без втрат (англ. lossless data compression) – клас
алгоритмів стиснення даних (відео, аудіо, графіки, документів, які у
цифровому вигляді), під час використання яких закодовані дані може
бути повністю відновлені.
У загальних рисах сенс стиснення без втрат такий: у вихідних
даних знаходять якусь закономірність і з урахуванням цієї
закономірності генерують другу послідовність, яка повністю визначає
вихідну.
Наприклад, для кодування двійкових послідовностей, у яких багато
нулів та мало одиниць, можна використовувати таку заміну:
00 → 0
01 → 10
10 → 110
11 → 111
У такому разі шістнадцять бітів
00 01 00 00 11 10 00 00
будуть перетворені на тринадцять бітів
0 10 0 0 111 110 0 0
Більшість алгоритмів стиснення без втрат працюють у дві стадії: на
першій генерується статистична модель для вхідних даних, на другій
проводиться заміна бітових уявлень на нові, використовуючи модель
для отримання «імовірнісних» (тобто часто зустрічаються) даних, які
використовуються частіше, ніж «неймовірні ».
Наведений алгоритм перетворення бітового уявлення (що
відноситься до другої стадії стиснення) реалізовано у програмі 13.1. Під
час введення довільного тексту у програмі немає стиснення обсягу.
Навпаки – обсяг коду після стиску збільшується, т.к. кількість
комбінацій 00 набагато менша, ніж інших комбінацій. Однак така
програма здійснює шифрування повідомлень шляхом заміни бітових
уявлень.
178
Програма 13.1. Шифрування повідомлень методом заміни бітових
уявлень:
include /masm64/include64/masm64rt.inc
.const
; имена фаайлов
input_file db "codingIn.dat", 0 ; исходный файл
output_file db "codingDe.dat", 0 ; файл с закодированной инф.
.data?
hInput dq ?
hOutput dq ?
read_count dq ? ; количество байтов, прочитанных файлом ReadFile
.data
bRead db 0 ; байт, который был прочитан
bToWrite db 0 ; байт для записи
bRemainder db 0 ; оставшиеся биты для записи
nRemainderSize db 0 ; количество битов в остатке
nEncodedSize dq 0 ; количество бит в закодированных данных
.code
entry_point proc
; Открытие входного файла
invoke CreateFileA, addr input_file, GENERIC_READ,
FILE_SHARE_READ, NULL,\
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL
cmp rax, INVALID_HANDLE_VALUE
je exit ; если файл не открываеся file - exit
mov hInput, rax ; сохранение дескриптора входного файла
; Создание выходного файла
invoke CreateFileA, addr output_file, GENERIC_WRITE,
FILE_SHARE_READ, NULL,\
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL
cmp rax, INVALID_HANDLE_VALUE
je exit ; If can't open file - exit
mov hOutput,rax ; Save input file handle
; AX - закодированный результат
; CL - смещение
; BX - loops
; DX - чтение данных во время обработки
179
; Сегменты данных:
; - количество битов в последнем байте
; - закодированные данные
; Резервный байт для сохранения количества оставшихся битов
mov bToWrite, 0
invoke WriteFile, hOutput, addr bToWrite, 1, NULL, NULL
; Основной цикл кодирования - Main encoding loop
m0:
; Чтение байта из файла
invoke ReadFile, hInput, addr bRead, 1, addr read_count, NULL
mov al, bRemainder ; Load reminder into memory
mov bl, nRemainderSize ; установить количество начальных битов
mov nEncodedSize, rbx
; Обработка последнего байта
cmp read_count, 1
je m1 ; если байт прочитан
; иначе - Prepare the remainder, write and exit
mov cl, 8
sub cl, nRemainderSize ; 8 - Rem., size = количество бит для сдвига
shl al, cl ; сдвиг влево
mov bToWrite, al
; запись и выход
invoke WriteFile, hOutput, addr bToWrite, 1, NULL, NULL
; количество битов остатка
invoke SetFilePointer, hOutput, 0, NULL, FILE_BEGIN
; Размер остатка равен 0 или самому размеру (из последней итерации)
invoke WriteFile, hOutput, addr nRemainderSize, 1, NULL, NULL
jmp exit
m1:
; Обработка данных
mov cl, 6 ; shift size (>> 6, >> 4, >> 2, >> 0)
mov bl, 4 ; повторение 4 раза (для каждой пары битов)
; Цикл кодирования
m2:
cmp bl, 0
je m3 ; на окончание кодирования
mov dl, bRead ; данные, которые необходимо обработать
shr dl, cl ; перемещение битов в начало, чтобы их замаскировать
180
and dl, 3 ; маскированные биты для обработки
; Определение битовой последовательности и запись кодир. битов
; 00 -> 0
cmp dl, 0
jne seq1
shl rax, 1 ; добавление 0 к закодированной последовательности
add nEncodedSize,1 ; увеличение размера за счет кол.
закодированных битов
jmp seq_end
; 01 -> 10
seq1:
cmp dl, 1
jne seq2
shl rax, 2 ; добавить 10 к закодированной последовательности
or rax, 2
add nEncodedSize, 2 ; увеличение размера за счет кол.
закодированных битов
jmp seq_end
; 10 -> 110
seq2:
cmp dl, 2
jne seq3
shl rax, 3 ; добавить к закодированной последовательности
or rax, 6
add nEncodedSize, 3 ; увеличение размера за счет кол.
закодированных битов
jmp seq_end
; 11 -> 111
seq3:
; Don't need to compare. This is the last possible case
shl rax, 3 ; добавить к закодированной последовательности
or rax, 7
add nEncodedSize, 3 ; увеличение размера за счет кол.
закодированных битов
; конец условия и цикла
seq_end:
dec bl ; количество повторов
sub cl, 2 ; размер сдвига (перейти к следующей паре)
jmp m2
181
; Конец кодирования
m3:
xor rbx, rbx ; Число циклов записи (0)
mov rcx, nEncodedSize
; Нет записи, если размер < 8. Переход к остатку и повторение цикла
cmp rcx, 8
jge @f
mov bRemainder, al
mov nRemainderSize, cl
jmp m0
; Получить количество циклов записи и размер остатка
@@:
cmp rcx, 8
jl @f
; Size >= 8
inc rbx ; ++ писать циклы
sub rcx, 8 ; -1 записываемый байт из размера
jmp @b
; Size < 8
@@:
mov nRemainderSize, cl ; Сохранение размера остатка для
следующего цикла чтения
; Готовим маску для остатка
xor dl, dl ; 0000 0000
not dl ; 1111 1111
shl dl, cl ; 1111 1000
not dl ; 0000 0111
; Сохранение остатка для следующего цикла чтения.
and dl, al
mov bRemainder, dl
shr rax, cl ; удалить остаток из закодированных данных
mov r12, rax ; Swap rax, r12. Теперь r12 содержит закодированные
данные (поскольку вызов перезапишет rcx-r11)
; Запись байта в цикле
; rax - закодированные данные для обработки
; rbx - кол. циклов
; rcl - shifts count
; r11 - закодированные данные
@@:
182
cmp rbx, 0
je m0 ; на след. байт
mov rax, r12
dec rbx ; -1 количество циклов/сдвигов (в байтах)
mov cl, bl
imul rcx, 8 ; количество сдвигов (в битах)
shr rax, cl ; Переместить байт влево
and rax, 255 ; маска 1 байт
mov bToWrite, al ; Заключительный этап
invoke WriteFile, hOutput, addr bToWrite, 1, NULL, NULL
jmp @b
exit:
invoke CloseHandle, hInput
invoke CloseHandle, hOutput
invoke ExitProcess, 0
entry_point endp
end
В результаті роботи програми файл з ім'ям codingIn.dat кодується
та закодована інформація записується у файл та ім'ям codingDe.dat.
Для розкодування файлу використовується програма 13.2.
Програма 13.2. Розкодування повідомлень методом заміни бітових
уявлень:
include /masm64/include64/masm64rt.inc
.const
; Filenames
input_file db "codingDe.dat", 0
output_file db "codingDe2.dat", 0
.data?
hInput dq ?
hOutput dq ?
read_count dq ? ; Number of bytes ReadFile has read
.data
bRead db 0 ; Byte that were read
mInputSize dq 0 ; Size of an input file in bytes
nLastBitsCount db 0 ; Bits count in the last byte
183
bRemainder dq 0 ; Remainder from bits to write
nRemainderSize db 0 ; Bits count in the remainder
bEncodedData dq 0 ; Encoded data
bDecodedRemainder db 0 ; Remainder from decoded bits
nDecodedRemainderSize db 0 ; Bits count in the decoded remainder
bToWrite db 0 ; Byte to be written
.code
entry_point proc
; Opening an input file
invoke CreateFileA, addr input_file, GENERIC_READ,
FILE_SHARE_READ, NULL,\
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL
cmp rax, INVALID_HANDLE_VALUE
je exit ; If can't open file - exit
mov hInput, rax ; Save input file handle
; Creating an output file
invoke CreateFileA, addr output_file, GENERIC_WRITE,
FILE_SHARE_READ, NULL,\
CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL
cmp rax, INVALID_HANDLE_VALUE
je exit ; If can't open file - exit
mov hOutput, rax ; Save input file handle
; Getting input file size
invoke GetFileSizeEx, hInput, addr mInputSize
dec mInputSize ; 1 byte is reserved for the remainder size. Skip
; Read bits count in the last byte
invoke ReadFile, hInput, addr nLastBitsCount, 1, addr read_count, NULL
; Main decoding loop
m0:
cmp mInputSize, 0 ; Decode while there are bytes to decode
je exit ; End of decoding
mov r12, bRemainder ; Load reminder into memory
xor rbx, rbx
mov bl, nRemainderSize ; Set start bits count
; Read byte from the file
invoke ReadFile, hInput, addr bRead, 1, addr read_count, NULL
cmp read_count, 0
184
je exit ; Nothing to decode
; Process size for the last byte
.if mInputSize == 1 ; If the byte is last
add bl, nLastBitsCount ; Add count of read bits
shl r12, 8
or r12b, bRead ; Place read bytes
mov rcx, 8
sub cl, nLastBitsCount
shr r12, cl ; Remove redundant zeros
.else
add bl, 8 ; Add count of read bits
shl r12, 8 ; Place read bytes
or r12b, bRead
.endif
dec mInputSize ; Decrease the remaining file size
mov bEncodedData, r12 ; Save full encoded data
xor rax, rax
mov al, bDecodedRemainder ; Saving the decoded data from the
previous iteration
xor r9, r9
mov r9b, nDecodedRemainderSize; Load to r9 remainder size
; Don't need this data anymore
mov bRemainder, 0
mov nRemainderSize, 0
m2:
; Shifting and preparing metadata
; rax - decoded bits
; rbx - encoded bits count
; rdx - encoded bits
; r8 - count of bits to take
; r9 - count of encoded bits in rax
cmp rbx, 0 ; If the size of the remaining encoded data <= 0
jle end_decode ; No more data to decode. Exit
cmp rbx, 3
jg @f ; rbx > 3
; rbx - (0; 3]: r8 = rbx
mov r8, rbx ; Take the remaining bits
jmp start_decode
@@:
; rbx > 3
mov r8, 3 ; Take 3 bits
start_decode:
185
; Moving bits
mov rdx, bEncodedData ; Load the encoded data
mov rcx, rbx
sub rcx, r8 ; Size - count of bits to take = shifts count
shr rdx, cl ; Bits are moved to the right border
; Masking bits
mov r10, rdx ; Copy encoded data
mov rcx, r8 ; rcx - count of bits
shr rdx, cl
shl rdx, cl ; erase rcx bits from the right side
xor rdx, r10 ; mask rcx bits
; Process taken bits depending on their count
.if r8 == 3 ; 3 bits
.if rdx == 7 ; 111
shl rax, 2
or rax, 3 ; Save 11
sub rbx, 3 ; Decrease ncoded bits count
add r9, 2 ; Increase decoded bits count
jmp m2 ; Loop
.elseif rdx == 6 ; 110
shl rax, 2
or rax, 2 ; Save 10
sub rbx, 3 ; Decrease encoded bits count
add r9, 2 ; Increase decoded bits count
jmp m2 ; Loop
.else
dec r8 ; Decrease count of bits to take
jmp start_decode ; Take 2 bits instead
.endif
.elseif r8 == 2 ; 2 bits
.if rdx == 2 ; 10
shl rax, 2
or rax, 1 ; Save 01
sub rbx, 2 ; Decrease encoded bits count
add r9, 2 ; Increase decoded bits count
jmp m2 ; Loop
.elseif rdx == 0 ; 00
shl rax, 4 ; Save 0000
sub rbx, 2 ; Decrease encoded bits count
add r9, 4 ; Increase decoded bits count
jmp m2 ; Loop
.elseif rdx == 3 ; 11 - remainder
mov nRemainderSize, 2 ; 2 bits are in the remainder
mov bRemainder, 3 ; Save the remainder
186
jmp end_decode
.else ; 01 or 1 or 0
dec r8 ; Decrease count of bits to take
jmp start_decode ; Take 2 bits instead
.endif
.else ; 1 bit
.if rdx == 0 ; 0
shl rax, 2 ; Save 00
sub rbx, 1 ; Decrease encoded bits count
add r9, 2 ; Increase decoded bits count
jmp m2 ; Loop
.else ; 1
mov nRemainderSize, 1 ; 1 bit is in the remainder
mov bRemainder, 1 ; Save the remainder
jmp end_decode
.endif
.endif
end_decode:
xor rbx, rbx ; Writing loops count (0)
mov rcx, r9 ; Load size of the decoded data
; Can't write if size < 8. Moving to the remainder and repeating loop
cmp rcx, 8
jge @f
mov bDecodedRemainder, al
mov nDecodedRemainderSize, cl
jmp m0
; Get write loops count and remainder size
@@:
cmp rcx, 8
jl @f
; Size >= 8
inc rbx ; ++write_loops
sub rcx, 8 ; -1 writable byte from size
jmp @b
; Size < 8
@@:
mov nDecodedRemainderSize, cl ; Save remainder size for the next
reading loop
; Masking bits of the remainder
mov r10, rax ; Copy encoded data
shr r10, cl
187
shl r10, cl ; erase rcx bits from the right side
xor r10, rax ; mask rcx bits
mov bDecodedRemainder, r10b
shr rax, cl ; Remove remainder from the encoded data
mov r12, rax ; Swap rax, r12. Now r12 contains encoded data
(Because of invoke will rewrite rcx-r11)
@@:
cmp rbx, 0
je m0 ; End. Next byte, please!
mov rax, r12
dec rbx ; -1 loop / shifts count (in bytes)
mov cl, bl
imul rcx, 8 ; shifts count (in bits)
shr rax, cl ; Move the byte to the left
and rax, 255 ; Mask exacly 1 byte
mov bToWrite, al ; Final step
invoke WriteFile, hOutput, addr bToWrite, 1, NULL, NULL
jmp @b
exit:
invoke CloseHandle, hInput
invoke CloseHandle, hOutput
invoke ExitProcess, 0
entry_point endp
end
13.2. Лабораторна робота "Шифрування повідомлень методом
заміни бітових уявлень"
Мета заняття: набути практичних навичок обчислення
шифрування повідомлень методом заміни бітових уявлень.
У звіті подати:
– назва лабораторної роботи, варіант, прізвище та ініціали, e-mail,
номер групи автора програми;
– у тексті програми організувати виведення назви лабораторної
роботи, варіант, прізвище та ініціали, e-mail, номер групи автора
програми;
188
– результат виконання завдання (скриншоти вікон програми та
відладчика).
Завдання
Написати програму шифрування повідомлень методом заміни
бітових уявлень для обраного кодування двійкових послідовностей.
Запропонуйте програму статистичної моделі аналізу вхідних
даних.
Контрольні питання для перевірки знань
1. Описати алгоритм стиснення даних без втрат?
2. Які переваги та недоліки аналізованого методу стиснення?
3. Які комбінації бінарних послідовностей можна застосувати для
стиснення?
4. Які стадії алгоритму стиснення?
5. Запропонуйте варіант статистичної моделі аналізу вхідних
даних.
189
14. ІНШІ МЕТОДИ ЗАХИСТУ КОДУ
14.1. Змішування коду
Змішування коду застосовується, коли деякі частини програми не
залежать один від одного, і їхнє розміщення не впливає на логіку роботи
програми. Такі частини програми ускладнюють аналіз коду.
14.2. Застосування команд jmp
Часте застосування команди jmp сильно ускладнює аналіз коду, а
при досить великій кількості робить такий аналіз практично
неможливим. У випадку, якщо програма невелика, для збільшення
кількості команд jmp, що застосовуються, необхідно додавати
«сміттєвий код». Навіть лінійне виконання програми можна розбити на
блоки, розмістити їх у різних місцях програми та керувати ними за
допомогою команд jmp.
14.3. Розбиття рядків на частини
Розбиття рядків на частини дозволить досліднику збирати всі
частини різних місць програми. А ще актуальніше, якщо ці частини
розташовані у різних файлах, які потім збираються командним bat-
файлом разом.
14.4. Приховування змісту програми
Даний метод заснований на використанні системної функції за
прямим призначенням. Вона має отримувати деякі параметри,
порівнювати їх та повертати певний стан прапорів. А за станом цих
прапорів (ознак) можливе подальше продовження алгоритму.
14.5. Позбавлення адресних констант
Адресні константи, які зустрічаються у програмі, дозволяють
розуміти зміст алгоритму. Тому бажано переписувати в різні регістри
або осередки пам'яті, щоб заплутати дослідника.
190
Додаток А
Поліноми degP(x)=4 в GF(2) та їх періоди
1x4+0x3+0x2+0x1+1 4
1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1
1x4+0x3+0x2+1x1+1 15
1 1 1 1 0 1 0 1 1 0 0 1 0 0 0
0 1 1 1 1 0 1 0 1 1 0 0 1 0 0
0 0 1 1 1 1 0 1 0 1 1 0 0 1 0
0 0 0 1 1 1 1 0 1 0 1 1 0 0 1
1x4+0x3+1x2+0x1+1 6
1 0 1 0 0 0
0 1 0 1 0 0
0 0 1 0 1 0
0 0 0 1 0 1
1x4+0x3+1x2+1x1+1 7
1 1 0 1 0 0 0
0 1 1 0 1 0 0
0 0 1 1 0 1 0
0 0 0 1 1 0 1
1x4+1x3+0x2+0x1+1 15
1 0 0 1 1 0 1 0 1 1 1 1 0 0 0
0 1 0 0 1 1 0 1 0 1 1 1 1 0 0
0 0 1 0 0 1 1 0 1 0 1 1 1 1 0
0 0 0 1 0 0 1 1 0 1 0 1 1 1 1
1x4+1x3+0x2+1x1+1 6
1 1 1 0 0 0
0 1 1 1 0 0
0 0 1 1 1 0
0 0 0 1 1 1
1x4+1x3+1x2+0x1+1 7
1 0 1 1 0 0 0
0 1 0 1 1 0 0
0 0 1 0 1 1 0
0 0 0 1 0 1 1
1x4+1x3+1x2+1x1+1 5
1 1 0 0 0
0 1 1 0 0
0 0 1 1 0
0 0 0 1 1
191
Додаток Б
Поліноми degP(x)=5 у GF(2) та їх періоди
10000 5
1 0 0 0 0
0 1 0 0 0
0 0 1 0 0
0 0 0 1 0
0 0 0 0 1
10001 21
1 1 1 1 1 0 1 0 1 0 0 1 1 0 0 0 1 0 0 0 0
0 1 1 1 1 1 0 1 0 1 0 0 1 1 0 0 0 1 0 0 0
0 0 1 1 1 1 1 0 1 0 1 0 0 1 1 0 0 0 1 0 0
0 0 0 1 1 1 1 1 0 1 0 1 0 0 1 1 0 0 0 1 0
0 0 0 0 1 1 1 1 1 0 1 0 1 0 0 1 1 0 0 0 1
10010 31
1 0 1 0 1 1 1 0 1 1 0 0 0 1 1 1 1 1 0 0 1 1 0 1 0 0 1 0 0 0 0
0 1 0 1 0 1 1 1 0 1 1 0 0 0 1 1 1 1 1 0 0 1 1 0 1 0 0 1 0 0 0
0 0 1 0 1 0 1 1 1 0 1 1 0 0 0 1 1 1 1 1 0 0 1 1 0 1 0 0 1 0 0
0 0 0 1 0 1 0 1 1 1 0 1 1 0 0 0 1 1 1 1 1 0 0 1 1 0 1 0 0 1 0
0 0 0 0 1 0 1 0 1 1 1 0 1 1 0 0 0 1 1 1 1 1 0 0 1 1 0 1 0 0 1
10011 14
1 1 0 1 1 1 1 0 0 1 0 0 0 0
0 1 1 0 1 1 1 1 0 0 1 0 0 0
0 0 1 1 0 1 1 1 1 0 0 1 0 0
0 0 0 1 1 0 1 1 1 1 0 0 1 0
0 0 0 0 1 1 0 1 1 1 1 0 0 1
10100 31
1 0 0 1 0 1 1 0 0 1 1 1 1 1 0 0 0 1 1 0 1 1 1 0 1 0 1 0 0 0 0
0 1 0 0 1 0 1 1 0 0 1 1 1 1 1 0 0 0 1 1 0 1 1 1 0 1 0 1 0 0 0
0 0 1 0 0 1 0 1 1 0 0 1 1 1 1 1 0 0 0 1 1 0 1 1 1 0 1 0 1 0 0
0 0 0 1 0 0 1 0 1 1 0 0 1 1 1 1 1 0 0 0 1 1 0 1 1 1 0 1 0 1 0
0 0 0 0 1 0 0 1 0 1 1 0 0 1 1 1 1 1 0 0 0 1 1 0 1 1 1 0 1 0 1
10101 15
1 1 1 0 1 1 0 0 1 0 1 0 0 0 0
0 1 1 1 0 1 1 0 0 1 0 1 0 0 0
0 0 1 1 1 0 1 1 0 0 1 0 1 0 0
0 0 0 1 1 1 0 1 1 0 0 1 0 1 0
0 0 0 0 1 1 1 0 1 1 0 0 1 0 1
10110 13
1 0 1 1 1 1 0 1 0 0 0 0 0
0 1 0 1 1 1 1 0 1 0 0 0 0
0 0 1 0 1 1 1 1 0 1 0 0 0
0 0 0 1 0 1 1 1 1 0 1 1 0
0 0 0 0 1 0 1 1 1 1 0 0 1
10111 31
1 1 0 0 1 0 0 1 1 1 1 1 0 1 1 1 0 0 0 1 0 1 0 1 1 0 1 0 0 0 0
0 1 1 0 0 1 0 0 1 1 1 1 1 0 1 1 1 0 0 0 1 0 1 0 1 1 0 1 0 0 0
0 0 1 1 0 0 1 0 0 1 1 1 1 1 0 1 1 1 0 0 0 1 0 1 0 1 1 0 1 0 0
0 0 0 1 1 0 0 1 0 0 1 1 1 1 1 0 1 1 1 0 0 0 1 0 1 0 1 1 0 1 0
0 0 0 0 1 1 0 0 1 0 0 1 1 1 1 1 0 1 1 1 0 0 0 1 0 1 0 1 1 0 1
11000 21
192
1 0 0 0 1 1 0 0 1 0 1 0 1 1 1 1 1 0 0 0 0
0 1 0 0 0 1 1 0 0 1 0 1 0 1 1 1 1 1 0 0 0
0 0 1 0 0 0 1 1 0 0 1 0 1 0 1 1 1 1 1 0 0
0 0 0 1 0 0 0 1 1 0 0 1 0 1 0 1 1 1 1 1 0
0 0 0 0 1 0 0 0 1 1 0 0 1 0 1 0 1 1 1 1 1
11001 8
1 1 1 1 0 0 0 0
0 1 1 1 1 0 0 0
0 0 1 1 1 1 0 0
0 0 0 1 1 1 1 0
0 0 0 0 1 1 1 1
11010 15
1 0 1 0 0 1 1 0 1 1 1 0 0 0 0
0 1 0 1 0 0 1 1 0 1 1 1 0 0 0
0 0 1 0 1 0 0 1 1 0 1 1 1 0 0
0 0 0 1 0 1 0 0 1 1 0 1 1 1 0
0 0 0 0 1 0 1 0 0 1 1 0 1 1 1
11011 31
1 1 0 1 0 1 0 0 1 0 0 0 1 0 1 1 1 1 1 0 1 1 0 0 1 1 1 0 0 0 0
0 1 1 0 1 0 1 0 0 1 0 0 0 1 0 1 1 1 1 1 0 1 1 0 0 1 1 1 0 0 0
0 0 1 1 0 1 0 1 0 0 1 0 0 0 1 0 1 1 1 1 1 0 1 1 0 0 1 1 1 0 0
0 0 0 1 1 0 1 0 1 0 0 1 0 0 0 1 0 1 1 1 1 1 0 1 1 0 0 1 1 1 0
0 0 0 0 1 1 0 1 0 1 0 0 1 0 0 0 1 0 1 1 1 1 1 0 1 1 0 0 1 1 1
11100 14
1 0 0 1 1 1 1 0 1 1 0 0 0 0
0 1 0 0 1 1 1 1 0 1 1 0 0 0
0 0 1 0 0 1 1 1 1 0 1 1 0 0
0 0 0 1 0 0 1 1 1 1 0 1 1 0
0 0 0 0 1 0 0 1 1 1 1 0 1 1
11101 31
1 1 1 0 0 1 1 0 1 1 1 1 1 0 1 0 0 0 1 0 0 1 0 1 0 1 1 0 0 0 0
0 1 1 1 0 0 1 1 0 1 1 1 1 1 0 1 0 0 0 1 0 0 1 0 1 0 1 1 0 0 0
0 0 1 1 1 0 0 1 1 0 1 1 1 1 1 0 1 0 0 0 1 0 0 1 0 1 0 1 1 0 0
0 0 0 1 1 1 0 0 1 1 0 1 1 1 1 1 0 1 0 0 0 1 0 0 1 0 1 0 1 1 0
0 0 0 0 1 1 1 0 0 1 1 0 1 1 1 1 1 0 1 0 0 0 1 0 0 1 0 1 0 1 1
11110 31
1 0 1 1 0 1 0 1 0 0 0 1 1 1 0 1 1 1 1 1 0 0 1 0 0 1 1 0 0 0 0
0 1 0 1 1 0 1 0 1 0 0 0 1 1 1 0 1 1 1 1 1 0 0 1 0 0 1 1 0 0 0
0 0 1 0 1 1 0 1 0 1 0 0 0 1 1 1 0 1 1 1 1 1 0 0 1 0 0 1 1 0 0
0 0 0 1 0 1 1 0 1 0 1 0 0 0 1 1 1 0 1 1 1 1 1 0 0 1 0 0 1 1 0
0 0 0 0 1 0 1 1 0 1 0 1 0 0 0 1 1 1 0 1 1 1 1 1 0 0 1 0 0 1 1
11111 6
1 1 0 0 0 0
0 1 1 0 0 0
0 0 1 1 0 0
0 0 0 1 1 0
0 0 0 0 1 1
193
Додаток
Поліноми degP(x)=4 у GF(3) та їх періоди
10001 4
1 0 0 0
0 1 0 0
0 0 1 0
0 0 0 1
10011 80
11112012112120202211020110012220210020002222102122121010112201022002111012001000
01111201211212020221102011001222021002000222210212212101011220102200211101200100
00111120121121202022110201100122202100200022221021221210101122010220021110120010
00011112012112120202211020110012220210020002222102122121010112201022002111012001
10021 80
12122011122220202112010210022120220020002121102221111010122102012001121011001000
01212201112222020211201021002212022002000212110222111101012210201200112101100100
00121220111222202021120102100221202200200021211022211110101221020120011210110010
00012122011122220202112010210022120220020002121102221111010122102012001121011001
10101 16
1 0 1 0 2 0 0 0 2 0 2 0 1 0 0 0
0 1 0 1 0 2 0 0 0 2 0 2 0 1 0 0
0 0 1 0 1 0 2 0 0 0 2 0 2 0 1 0
0 0 0 1 0 1 0 2 0 0 0 2 0 2 0 1
10111 26
1 1 2 0 0 1 0 1 1 0 1 2 1 0 2 1 1 2 2 2 2 0 1 0 0 0
0 1 1 2 0 0 1 0 1 1 0 1 2 1 0 2 1 1 2 2 2 2 0 1 0 0
0 0 1 1 2 0 0 1 0 1 1 0 1 2 1 0 2 1 1 2 2 2 2 0 1 0
0 0 0 1 1 2 0 0 1 0 1 1 0 1 2 1 0 2 1 1 2 2 2 2 0 1
10121 26
1 2 2 0 0 2 0 2 1 0 1 1 1 0 2 2 1 1 2 1 2 0 1 0 0 0
0 1 2 2 0 0 2 0 2 1 0 1 1 1 0 2 2 1 1 2 1 2 0 1 0 0
0 0 1 2 2 0 0 2 0 2 1 0 1 1 1 0 2 2 1 1 2 1 2 0 1 0
0 0 0 1 2 2 0 0 2 0 2 1 0 1 1 1 0 2 2 1 1 2 1 2 0 1
10201 16
1 0 2 0 2 0 0 0 2 0 1 0 1 0 0 0
0 1 0 2 0 2 0 0 0 2 0 1 0 1 0 0
0 0 1 0 2 0 2 0 0 0 2 0 1 0 1 0
0 0 0 1 0 2 0 2 0 0 0 2 0 1 0 1
10211 24
1 1 0 2 0 2 2 2 0 0 2 1 2 1 1 1 2 2 1 0 1 0 0 0
0 1 1 0 2 0 2 2 2 0 0 2 1 2 1 1 1 2 2 1 0 1 0 0
0 0 1 1 0 2 0 2 2 2 0 0 2 1 2 1 1 1 2 2 1 0 1 0
0 0 0 1 1 0 2 0 2 2 2 0 0 2 1 2 1 1 1 2 2 1 0 1
10221 24
1 2 0 1 0 1 2 1 0 0 2 2 2 2 1 2 2 1 1 0 1 0 0 0
0 1 2 0 1 0 1 2 1 0 0 2 2 2 2 1 2 2 1 1 0 1 0 0
0 0 1 2 0 1 0 1 2 1 0 0 2 2 2 2 1 2 2 1 1 0 1 0
0 0 0 1 2 0 1 0 1 2 1 0 0 2 2 2 2 1 2 2 1 1 0 1
194
1100180
10011012110021020122101011112220112120002002202122001201021120202222111022121000
01001101211002102012210101111222011212000200220212200120102112020222211102212100
00100110121100210201221010111122201121200020022021220012010211202022221110221210
00010011012110021020122101011112220112120002002202122001201021120202222111022121
11011 8
1 1 1 2 1 0 0 0
0 1 1 1 2 1 0 0
0 0 1 1 1 2 1 0
0 0 0 1 1 1 2 1
11021 6
1 2 1 0 0 0
0 1 2 1 0 0
0 0 1 2 1 0
0 0 0 1 2 1
11101 24
1 0 1 1 2 2 1 2 2 2 2 0 0 1 2 1 0 1 0 2 1 0 0 0
0 1 0 1 1 2 2 1 2 2 2 2 0 0 1 2 1 0 1 0 2 1 0 0
0 0 1 0 1 1 2 2 1 2 2 2 2 0 0 1 2 1 0 1 0 2 1 0
0 0 0 1 0 1 1 2 2 1 2 2 2 2 0 0 1 2 1 0 1 0 2 1
11111 26
1 1 2 1 2 0 2 2 0 1 2 2 2 1 1 0 1 0 2 0 0 2 1 0 0 0
0 1 1 2 1 2 0 2 2 0 1 2 2 2 1 1 0 1 0 2 0 0 2 1 0 0
0 0 1 1 2 1 2 0 2 2 0 1 2 2 2 1 1 0 1 0 2 0 0 2 1 0
0 0 0 1 1 2 1 2 0 2 2 0 1 2 2 2 1 1 0 1 0 2 0 0 2 1
1112180
12211100220100101022102121101111210120002112220011020020201120121220222212021000
01221110022010010102210212110111121012000211222001102002020112012122022221202100
00122111002201001010221021211011112101200021122200110200202011201212202222120210
00012211100220100101022102121101111210120002112220011020020201120121220222212021
11201 26
1 0 2 1 2 1 1 2 2 0 1 1 1 0 1 2 0 2 0 0 2 2 1 0 0 0
0 1 0 2 1 2 1 1 2 2 0 1 1 1 0 1 2 0 2 0 0 2 2 1 0 0
0 0 1 0 2 1 2 1 1 2 2 0 1 1 1 0 1 2 0 2 0 0 2 2 1 0
0 0 0 1 0 2 1 2 1 1 2 2 0 1 1 1 0 1 2 0 2 0 0 2 2 1
11211 26
1 1 0 0 2 0 1 0 1 2 2 1 2 2 0 1 2 0 2 2 2 2 1 0 0 0
0 1 1 0 0 2 0 1 0 1 2 2 1 2 2 0 1 2 0 2 2 2 2 1 0 0
0 0 1 1 0 0 2 0 1 0 1 2 2 1 2 2 0 1 2 0 2 2 2 2 1 0
0 0 0 1 1 0 0 2 0 1 0 1 2 2 1 2 2 0 1 2 0 2 2 2 2 1
1122180
12021222202212102110202002011002221120002101211110112120122010100102200111221000
01202122220221210211020200201100222112000210121111011212012201010010220011122100
00120212222022121021102020020110022211200021012111101121201220101001022001112210
00012021222202212102110202002011002221120002101211110112120122010100102200111221
1200180
195
10021011120022010221101012122120122220002001202221001102011220202121121021111000
01002101112002201022110101212212012222000200120222100110201122020212112102111100
00100210111200220102211010121221201222200020012022210011020112202021211210211110
00010021011120022010221101012122120122220002001202221001102011220202121121021111
12011 6
1 1 1 0 0 0
0 1 1 1 0 0
0 0 1 1 1 0
0 0 0 1 1 1
12021 8
1 2 1 1 1 0 0 0
0 1 2 1 1 1 0 0
0 0 1 2 1 1 1 0
0 0 0 1 2 1 1 1
12101 24
1 0 1 2 2 1 1 1 2 1 2 0 0 2 2 2 0 2 0 1 1 0 0 0
0 1 0 1 2 2 1 1 1 2 1 2 0 0 2 2 2 0 2 0 1 1 0 0
0 0 1 0 1 2 2 1 1 1 2 1 2 0 0 2 2 2 0 2 0 1 1 0
0 0 0 1 0 1 2 2 1 1 1 2 1 2 0 0 2 2 2 0 2 0 1 1
12111 80
11221200210200101021102222101212220220002211210012010020201220111120212111011000
01122120021020010102110222210121222022000221121001201002020122011112021211101100
00112212002102001010211022221012122202200022112100120100202012201111202121110110
00011221200210200101021102222101212220220002211210012010020201220111120212111011
12121 26
1 2 2 2 2 0 2 1 0 2 2 1 2 2 1 0 1 0 2 0 0 1 1 0 0 0
0 1 2 2 2 2 0 2 1 0 2 2 1 2 2 1 0 1 0 2 0 0 1 1 0 0
0 0 1 2 2 2 2 0 2 1 0 2 2 1 2 2 1 0 1 0 2 0 0 1 1 0
0 0 0 1 2 2 2 2 0 2 1 0 2 2 1 2 2 1 0 1 0 2 0 0 1 1
12201 26
1 0 2 2 2 2 1 1 2 0 1 2 1 0 1 1 0 1 0 0 2 1 1 0 0 0
0 1 0 2 2 2 2 1 1 2 0 1 2 1 0 1 1 0 1 0 0 2 1 1 0 0
0 0 1 0 2 2 2 2 1 1 2 0 1 2 1 0 1 1 0 1 0 0 2 1 1 0
0 0 0 1 0 2 2 2 2 1 1 2 0 1 2 1 0 1 1 0 1 0 0 2 1 1
12211 80
11011121202111102210202001021001211220002202221210122220112010100201200212211000
01101112120211110221020200102100121122000220222121012222011201010020120021221100
00110111212021111022102020010210012112200022022212101222201120101002012002122110
00011011121202111102210202001021001211220002202221210122220112010100201200212211
12221 26
1 2 0 0 2 0 1 0 1 1 2 2 2 1 0 2 2 0 2 1 2 1 1 0 0 0
0 1 2 0 0 2 0 1 0 1 1 2 2 2 1 0 2 2 0 2 1 2 1 1 0 0
0 0 1 2 0 0 2 0 1 0 1 1 2 2 2 1 0 2 2 0 2 1 2 1 1 0
0 0 0 1 2 0 0 2 0 1 0 1 1 2 2 2 1 0 2 2 0 2 1 2 1 1
20001 8
1 0 0 0 2 0 0 0
0 1 0 0 0 2 0 0
0 0 1 0 0 0 2 0
0 0 0 1 0 0 0 2
196
20011 26
1 1 1 1 0 2 1 0 0 1 0 0 0 2 2 2 2 0 1 2 0 0 2 0 0 0
0 1 1 1 1 0 2 1 0 0 1 0 0 0 2 2 2 2 0 1 2 0 0 2 0 0
0 0 1 1 1 1 0 2 1 0 0 1 0 0 0 2 2 2 2 0 1 2 0 0 2 0
0 0 0 1 1 1 1 0 2 1 0 0 1 0 0 0 2 2 2 2 0 1 2 0 0 2
20021 13
1 2 1 2 0 1 1 0 0 2 0 0 0
0 1 2 1 2 0 1 1 0 0 2 0 0
0 0 1 2 1 2 0 1 1 0 0 2 0
0 0 0 1 2 1 2 0 1 1 0 0 2
20101 12
1 0 1 0 0 0 2 0 2 0 0 0
0 1 0 1 0 0 0 2 0 2 0 0
0 0 1 0 1 0 0 0 2 0 2 0
0 0 0 1 0 1 0 0 0 2 0 2
20111 13
1 1 2 0 1 0 2 2 0 2 0 0 0
0 1 1 2 0 1 0 2 2 0 2 0 0
0 0 1 1 2 0 1 0 2 2 0 2 0
0 0 0 1 1 2 0 1 0 2 2 0 2
20121 26
1 2 2 0 1 0 2 1 0 1 0 0 0 2 1 1 0 2 0 1 2 0 2 0 0 0
0 1 2 2 0 1 0 2 1 0 1 0 0 0 2 1 1 0 2 0 1 2 0 2 0 0
0 0 1 2 2 0 1 0 2 1 0 1 0 0 0 2 1 1 0 2 0 1 2 0 2 0
0 0 0 1 2 2 0 1 0 2 1 0 1 0 0 0 2 1 1 0 2 0 1 2 0 2
20201 6
1 0 2 0 0 0
0 1 0 2 0 0
0 0 1 0 2 0
0 0 0 1 0 2
20211 40
1 1 0 2 1 1 0 0 2 1 2 1 0 1 2 0 1 0 0 0 2 2 0 1 2 2 0 0 1 2 1 2 0 2 1 0 2 0 0 0
0 1 1 0 2 1 1 0 0 2 1 2 1 0 1 2 0 1 0 0 0 2 2 0 1 2 2 0 0 1 2 1 2 0 2 1 0 2 0 0
0 0 1 1 0 2 1 1 0 0 2 1 2 1 0 1 2 0 1 0 0 0 2 2 0 1 2 2 0 0 1 2 1 2 0 2 1 0 2 0
0 0 0 1 1 0 2 1 1 0 0 2 1 2 1 0 1 2 0 1 0 0 0 2 2 0 1 2 2 0 0 1 2 1 2 0 2 1 0 2
20221 40
1 2 0 1 1 2 0 0 2 2 2 2 0 2 2 0 1 0 0 0 2 1 0 2 2 1 0 0 1 1 1 1 0 1 1 0 2 0 0 0
0 1 2 0 1 1 2 0 0 2 2 2 2 0 2 2 0 1 0 0 0 2 1 0 2 2 1 0 0 1 1 1 1 0 1 1 0 2 0 0
0 0 1 2 0 1 1 2 0 0 2 2 2 2 0 2 2 0 1 0 0 0 2 1 0 2 2 1 0 0 1 1 1 1 0 1 1 0 2 0
0 0 0 1 2 0 1 1 2 0 0 2 2 2 2 0 2 2 0 1 0 0 0 2 1 0 2 2 1 0 0 1 1 1 1 0 1 1 0 2
21001 26
1 0 0 1 2 0 1 1 1 1 0 0 0 2 0 0 2 1 0 2 2 2 2 0 0 0
0 1 0 0 1 2 0 1 1 1 1 0 0 0 2 0 0 2 1 0 2 2 2 2 0 0
0 0 1 0 0 1 2 0 1 1 1 1 0 0 0 2 0 0 2 1 0 2 2 2 2 0
0 0 0 1 0 0 1 2 0 1 1 1 1 0 0 0 2 0 0 2 1 0 2 2 2 2
21011 9
1 1 1 2 2 2 0 0 0
0 1 1 1 2 2 2 0 0
0 0 1 1 1 2 2 2 0
0 0 0 1 1 1 2 2 2
197
21021 20
1 2 1 0 1 1 1 0 0 0 2 1 2 0 2 2 2 0 0 0
0 1 2 1 0 1 1 1 0 0 0 2 1 2 0 2 2 2 0 0
0 0 1 2 1 0 1 1 1 0 0 0 2 1 2 0 2 2 2 0
0 0 0 1 2 1 0 1 1 1 0 0 0 2 1 2 0 2 2 2
21101 13
1 0 1 1 0 2 0 1 2 2 0 0 0
0 1 0 1 1 0 2 0 1 2 2 0 0
0 0 1 0 1 1 0 2 0 1 2 2 0
0 0 0 1 0 1 1 0 2 0 1 2 2
21111 12
1 1 2 1 0 2 1 2 2 0 0 0
0 1 1 2 1 0 2 1 2 2 0 0
0 0 1 1 2 1 0 2 1 2 2 0
0 0 0 1 1 2 1 0 2 1 2 2
21121 24
1 2 2 1 2 2 2 1 1 0 0 0 2 1 1 2 1 1 1 2 2 0 0 0
0 1 2 2 1 2 2 2 1 1 0 0 0 2 1 1 2 1 1 1 2 2 0 0
0 0 1 2 2 1 2 2 2 1 1 0 0 0 2 1 1 2 1 1 1 2 2 0
0 0 0 1 2 2 1 2 2 2 1 1 0 0 0 2 1 1 2 1 1 1 2 2
21201 40
1 0 2 1 0 1 2 1 2 0 0 1 1 2 0 1 1 0 0 0 2 0 1 2 0 2 1 2 1 0 0 2 2 1 0 2 2 0 0 0
0 1 0 2 1 0 1 2 1 2 0 0 1 1 2 0 1 1 0 0 0 2 0 1 2 0 2 1 2 1 0 0 2 2 1 0 2 2 0 0
0 0 1 0 2 1 0 1 2 1 2 0 0 1 1 2 0 1 1 0 0 0 2 0 1 2 0 2 1 2 1 0 0 2 2 1 0 2 2 0
0 0 0 1 0 2 1 0 1 2 1 2 0 0 1 1 2 0 1 1 0 0 0 2 0 1 2 0 2 1 2 1 0 0 2 2 1 0 2 2
21211 10
1 1 0 0 0 2 2 0 0 0
0 1 1 0 0 0 2 2 0 0
0 0 1 1 0 0 0 2 2 0
0 0 0 1 1 0 0 0 2 2
21221 8
1 2 0 2 2 0 0 0
0 1 2 0 2 2 0 0
0 0 1 2 0 2 2 0
0 0 0 1 2 0 2 2
22001 13
1 0 0 2 2 0 1 2 1 2 0 0 0
0 1 0 0 2 2 0 1 2 1 2 0 0
0 0 1 0 0 2 2 0 1 2 1 2 0
0 0 0 1 0 0 2 2 0 1 2 1 2
22011 20
1 1 1 0 1 2 1 0 0 0 2 2 2 0 2 1 2 0 0 0
0 1 1 1 0 1 2 1 0 0 0 2 2 2 0 2 1 2 0 0
0 0 1 1 1 0 1 2 1 0 0 0 2 2 2 0 2 1 2 0
0 0 0 1 1 1 0 1 2 1 0 0 0 2 2 2 0 2 1 2
22021 18
1 2 1 1 2 1 0 0 0 2 1 2 2 1 2 0 0 0
0 1 2 1 1 2 1 0 0 0 2 1 2 2 1 2 0 0
0 0 1 2 1 1 2 1 0 0 0 2 1 2 2 1 2 0
0 0 0 1 2 1 1 2 1 0 0 0 2 1 2 2 1 2
198
22101 26
1 0 1 2 0 1 0 2 2 1 0 0 0 2 0 2 1 0 2 0 1 1 2 0 0 0
0 1 0 1 2 0 1 0 2 2 1 0 0 0 2 0 2 1 0 2 0 1 1 2 0 0
0 0 1 0 1 2 0 1 0 2 2 1 0 0 0 2 0 2 1 0 2 0 1 1 2 0
0 0 0 1 0 1 2 0 1 0 2 2 1 0 0 0 2 0 2 1 0 2 0 1 1 2
22111 24
1 1 2 2 2 1 2 2 1 0 0 0 2 2 1 1 1 2 1 1 2 0 0 0
0 1 1 2 2 2 1 2 2 1 0 0 0 2 2 1 1 1 2 1 1 2 0 0
0 0 1 1 2 2 2 1 2 2 1 0 0 0 2 2 1 1 1 2 1 1 2 0
0 0 0 1 1 2 2 2 1 2 2 1 0 0 0 2 2 1 1 1 2 1 1 2
22121 12
1 2 2 2 0 1 1 1 2 0 0 0
0 1 2 2 2 0 1 1 1 2 0 0
0 0 1 2 2 2 0 1 1 1 2 0
0 0 0 1 2 2 2 0 1 1 1 2
22201 40
1 0 2 2 0 2 2 2 2 0 0 2 1 1 0 2 1 0 0 0 2 0 1 1 0 1 1 1 1 0 0 1 2 2 0 1 2 0 0 0
0 1 0 2 2 0 2 2 2 2 0 0 2 1 1 0 2 1 0 0 0 2 0 1 1 0 1 1 1 1 0 0 1 2 2 0 1 2 0 0
0 0 1 0 2 2 0 2 2 2 2 0 0 2 1 1 0 2 1 0 0 0 2 0 1 1 0 1 1 1 1 0 0 1 2 2 0 1 2 0
0 0 0 1 0 2 2 0 2 2 2 2 0 0 2 1 1 0 2 1 0 0 0 2 0 1 1 0 1 1 1 1 0 0 1 2 2 0 1 2
22211 8
1 1 0 1 2 0 0 0
0 1 1 0 1 2 0 0
0 0 1 1 0 1 2 0
0 0 0 1 1 0 1 2
22221 5
1 2 0 0 0
0 1 2 0 0
0 0 1 2 0
0 0 0 1 2
10002 4
2 0 0 0
0 2 0 0
0 0 2 0
0 0 0 2
10012 80
22221021221210101122010220021110120010001111201211212020221102011001222021002000
02222102122121010112201022002111012001000111120121121202022110201100122202100200
00222210212212101011220102200211101200100011112012112120202211020110012220210020
00022221021221210101122010220021110120010001111201211212020221102011001222021002
10022 80
21211022211110101221020120011210110010001212201112222020211201021002212022002000
02121102221111010122102012001121011001000121220111222202021120102100221202200200
00212110222111101012210201200112101100100012122011122220202112010210022120220020
00021211022211110101221020120011210110010001212201112222020211201021002212022002
10102 16
2 0 2 0 1 0 0 0 1 0 1 0 2 0 0 0
0 2 0 2 0 1 0 0 0 1 0 1 0 2 0 0
0 0 2 0 2 0 1 0 0 0 1 0 1 0 2 0
0 0 0 2 0 2 0 1 0 0 0 1 0 1 0 2
199
10112 26
2 2 1 0 0 2 0 2 2 0 2 1 2 0 1 2 2 1 1 1 1 0 2 0 0 0
0 2 2 1 0 0 2 0 2 2 0 2 1 2 0 1 2 2 1 1 1 1 0 2 0 0
0 0 2 2 1 0 0 2 0 2 2 0 2 1 2 0 1 2 2 1 1 1 1 0 2 0
0 0 0 2 2 1 0 0 2 0 2 2 0 2 1 2 0 1 2 2 1 1 1 1 0 2
10122 26
2 1 1 0 0 1 0 1 2 0 2 2 2 0 1 1 2 2 1 2 1 0 2 0 0 0
0 2 1 1 0 0 1 0 1 2 0 2 2 2 0 1 1 2 2 1 2 1 0 2 0 0
0 0 2 1 1 0 0 1 0 1 2 0 2 2 2 0 1 1 2 2 1 2 1 0 2 0
0 0 0 2 1 1 0 0 1 0 1 2 0 2 2 2 0 1 1 2 2 1 2 1 0 2
10202 16
2 0 1 0 1 0 0 0 1 0 2 0 2 0 0 0
0 2 0 1 0 1 0 0 0 1 0 2 0 2 0 0
0 0 2 0 1 0 1 0 0 0 1 0 2 0 2 0
0 0 0 2 0 1 0 1 0 0 0 1 0 2 0 2
10212 24
2 2 0 1 0 1 1 1 0 0 1 2 1 2 2 2 1 1 2 0 2 0 0 0
0 2 2 0 1 0 1 1 1 0 0 1 2 1 2 2 2 1 1 2 0 2 0 0
0 0 2 2 0 1 0 1 1 1 0 0 1 2 1 2 2 2 1 1 2 0 2 0
0 0 0 2 2 0 1 0 1 1 1 0 0 1 2 1 2 2 2 1 1 2 0 2
10222 24
2 1 0 2 0 2 1 2 0 0 1 1 1 1 2 1 1 2 2 0 2 0 0 0
0 2 1 0 2 0 2 1 2 0 0 1 1 1 1 2 1 1 2 2 0 2 0 0
0 0 2 1 0 2 0 2 1 2 0 0 1 1 1 1 2 1 1 2 2 0 2 0
0 0 0 2 1 0 2 0 2 1 2 0 0 1 1 1 1 2 1 1 2 2 0 2
11002 80
20022021220012010211202022221110221210001001101211002102012210101111222011212000
02002202122001201021120202222111022121000100110121100210201221010111122201121200
00200220212200120102112020222211102212100010011012110021020122101011112220112120
00020022021220012010211202022221110221210001001101211002102012210101111222011212
11012 8
2 2 2 1 2 0 0 0
0 2 2 2 1 2 0 0
0 0 2 2 2 1 2 0
0 0 0 2 2 2 1 2
11022 6
2 1 2 0 0 0
0 2 1 2 0 0
0 0 2 1 2 0
0 0 0 2 1 2
11102 24
2 0 2 2 1 1 2 1 1 1 1 0 0 2 1 2 0 2 0 1 2 0 0 0
0 2 0 2 2 1 1 2 1 1 1 1 0 0 2 1 2 0 2 0 1 2 0 0
0 0 2 0 2 2 1 1 2 1 1 1 1 0 0 2 1 2 0 2 0 1 2 0
0 0 0 2 0 2 2 1 1 2 1 1 1 1 0 0 2 1 2 0 2 0 1 2
11112 26
200
2 2 1 2 1 0 1 1 0 2 1 1 1 2 2 0 2 0 1 0 0 1 2 0 0 0
0 2 2 1 2 1 0 1 1 0 2 1 1 1 2 2 0 2 0 1 0 0 1 2 0 0
0 0 2 2 1 2 1 0 1 1 0 2 1 1 1 2 2 0 2 0 1 0 0 1 2 0
0 0 0 2 2 1 2 1 0 1 1 0 2 1 1 1 2 2 0 2 0 1 0 0 1 2
11122 80
21122200110200202011201212202222120210001221110022010010102210212110111121012000
02112220011020020201120121220222212021000122111002201001010221021211011112101200
00211222001102002020112012122022221202100012211100220100101022102121101111210120
00021122200110200202011201212202222120210001221110022010010102210212110111121012
11202 26
2 0 1 2 1 2 2 1 1 0 2 2 2 0 2 1 0 1 0 0 1 1 2 0 0 0
0 2 0 1 2 1 2 2 1 1 0 2 2 2 0 2 1 0 1 0 0 1 1 2 0 0
0 0 2 0 1 2 1 2 2 1 1 0 2 2 2 0 2 1 0 1 0 0 1 1 2 0
0 0 0 2 0 1 2 1 2 2 1 1 0 2 2 2 0 2 1 0 1 0 0 1 1 2
11212 26
2 2 0 0 1 0 2 0 2 1 1 2 1 1 0 2 1 0 1 1 1 1 2 0 0 0
0 2 2 0 0 1 0 2 0 2 1 1 2 1 1 0 2 1 0 1 1 1 1 2 0 0
0 0 2 2 0 0 1 0 2 0 2 1 1 2 1 1 0 2 1 0 1 1 1 1 2 0
0 0 0 2 2 0 0 1 0 2 0 2 1 1 2 1 1 0 2 1 0 1 1 1 1 2
11222 80
21012111101121201220101001022001112210001202122220221210211020200201100222112000
02101211110112120122010100102200111221000120212222022121021102020020110022211200
00210121111011212012201010010220011122100012021222202212102110202002011002221120
00021012111101121201220101001022001112210001202122220221210211020200201100222112
12002 80
20012022210011020112202021211210211110001002101112002201022110101212212012222000
02001202221001102011220202121121021111000100210111200220102211010121221201222200
00200120222100110201122020212112102111100010021011120022010221101012122120122220
00020012022210011020112202021211210211110001002101112002201022110101212212012222
12012 6
2 2 2 0 0 0
0 2 2 2 0 0
0 0 2 2 2 0
0 0 0 2 2 2
12022 8
2 1 2 2 2 0 0 0
0 2 1 2 2 2 0 0
0 0 2 1 2 2 2 0
0 0 0 2 1 2 2 2
12102 24
2 0 2 1 1 2 2 2 1 2 1 0 0 1 1 1 0 1 0 2 2 0 0 0
0 2 0 2 1 1 2 2 2 1 2 1 0 0 1 1 1 0 1 0 2 2 0 0
0 0 2 0 2 1 1 2 2 2 1 2 1 0 0 1 1 1 0 1 0 2 2 0
0 0 0 2 0 2 1 1 2 2 2 1 2 1 0 0 1 1 1 0 1 0 2 2
12112 80
22112100120100202012201111202121110110001122120021020010102110222210121222022000
02211210012010020201220111120212111011000112212002102001010211022221012122202200
00221121001201002020122011112021211101100011221200210200101021102222101212220220
00022112100120100202012201111202121110110001122120021020010102110222210121222022
201
12122 26
2 1 1 1 1 0 1 2 0 1 1 2 1 1 2 0 2 0 1 0 0 2 2 0 0 0
0 2 1 1 1 1 0 1 2 0 1 1 2 1 1 2 0 2 0 1 0 0 2 2 0 0
0 0 2 1 1 1 1 0 1 2 0 1 1 2 1 1 2 0 2 0 1 0 0 2 2 0
0 0 0 2 1 1 1 1 0 1 2 0 1 1 2 1 1 2 0 2 0 1 0 0 2 2
12202 26
2 0 1 1 1 1 2 2 1 0 2 1 2 0 2 2 0 2 0 0 1 2 2 0 0 0
0 2 0 1 1 1 1 2 2 1 0 2 1 2 0 2 2 0 2 0 0 1 2 2 0 0
0 0 2 0 1 1 1 1 2 2 1 0 2 1 2 0 2 2 0 2 0 0 1 2 2 0
0 0 0 2 0 1 1 1 1 2 2 1 0 2 1 2 0 2 2 0 2 0 0 1 2 2
12212 80
22022212101222201120101002012002122110001101112120211110221020200102100121122000
02202221210122220112010100201200212211000110111212021111022102020010210012112200
00220222121012222011201010020120021221100011011121202111102210202001021001211220
00022022212101222201120101002012002122110001101112120211110221020200102100121122
12222 26
2 1 0 0 1 0 2 0 2 2 1 1 1 2 0 1 1 0 1 2 1 2 2 0 0 0
0 2 1 0 0 1 0 2 0 2 2 1 1 1 2 0 1 1 0 1 2 1 2 2 0 0
0 0 2 1 0 0 1 0 2 0 2 2 1 1 1 2 0 1 1 0 1 2 1 2 2 0
0 0 0 2 1 0 0 1 0 2 0 2 2 1 1 1 2 0 1 1 0 1 2 1 2 2
20002 8
2 0 0 0 1 0 0 0
0 2 0 0 0 1 0 0
0 0 2 0 0 0 1 0
0 0 0 2 0 0 0 1
20012 26
2 2 2 2 0 1 2 0 0 2 0 0 0 1 1 1 1 0 2 1 0 0 1 0 0 0
0 2 2 2 2 0 1 2 0 0 2 0 0 0 1 1 1 1 0 2 1 0 0 1 0 0
0 0 2 2 2 2 0 1 2 0 0 2 0 0 0 1 1 1 1 0 2 1 0 0 1 0
0 0 0 2 2 2 2 0 1 2 0 0 2 0 0 0 1 1 1 1 0 2 1 0 0 1
20022 13
2 1 2 1 0 2 2 0 0 1 0 0 0
0 2 1 2 1 0 2 2 0 0 1 0 0
0 0 2 1 2 1 0 2 2 0 0 1 0
0 0 0 2 1 2 1 0 2 2 0 0 1
20102 12
2 0 2 0 0 0 1 0 1 0 0 0
0 2 0 2 0 0 0 1 0 1 0 0
0 0 2 0 2 0 0 0 1 0 1 0
0 0 0 2 0 2 0 0 0 1 0 1
20112 13
2 2 1 0 2 0 1 1 0 1 0 0 0
0 2 2 1 0 2 0 1 1 0 1 0 0
0 0 2 2 1 0 2 0 1 1 0 1 0
0 0 0 2 2 1 0 2 0 1 1 0 1
20122 26
202
2 1 1 0 2 0 1 2 0 2 0 0 0 1 2 2 0 1 0 2 1 0 1 0 0 0
0 2 1 1 0 2 0 1 2 0 2 0 0 0 1 2 2 0 1 0 2 1 0 1 0 0
0 0 2 1 1 0 2 0 1 2 0 2 0 0 0 1 2 2 0 1 0 2 1 0 1 0
0 0 0 2 1 1 0 2 0 1 2 0 2 0 0 0 1 2 2 0 1 0 2 1 0 1
20202 6
2 0 1 0 0 0
0 2 0 1 0 0
0 0 2 0 1 0
0 0 0 2 0 1
20212 40
2 2 0 1 2 2 0 0 1 2 1 2 0 2 1 0 2 0 0 0 1 1 0 2 1 1 0 0 2 1 2 1 0 1 2 0 1 0 0 0
0 2 2 0 1 2 2 0 0 1 2 1 2 0 2 1 0 2 0 0 0 1 1 0 2 1 1 0 0 2 1 2 1 0 1 2 0 1 0 0
0 0 2 2 0 1 2 2 0 0 1 2 1 2 0 2 1 0 2 0 0 0 1 1 0 2 1 1 0 0 2 1 2 1 0 1 2 0 1 0
0 0 0 2 2 0 1 2 2 0 0 1 2 1 2 0 2 1 0 2 0 0 0 1 1 0 2 1 1 0 0 2 1 2 1 0 1 2 0 1
20222 40
2 1 0 2 2 1 0 0 1 1 1 1 0 1 1 0 2 0 0 0 1 2 0 1 1 2 0 0 2 2 2 2 0 2 2 0 1 0 0 0
0 2 1 0 2 2 1 0 0 1 1 1 1 0 1 1 0 2 0 0 0 1 2 0 1 1 2 0 0 2 2 2 2 0 2 2 0 1 0 0
0 0 2 1 0 2 2 1 0 0 1 1 1 1 0 1 1 0 2 0 0 0 1 2 0 1 1 2 0 0 2 2 2 2 0 2 2 0 1 0
0 0 0 2 1 0 2 2 1 0 0 1 1 1 1 0 1 1 0 2 0 0 0 1 2 0 1 1 2 0 0 2 2 2 2 0 2 2 0 1
21002 26
2 0 0 2 1 0 2 2 2 2 0 0 0 1 0 0 1 2 0 1 1 1 1 0 0 0
0 2 0 0 2 1 0 2 2 2 2 0 0 0 1 0 0 1 2 0 1 1 1 1 0 0
0 0 2 0 0 2 1 0 2 2 2 2 0 0 0 1 0 0 1 2 0 1 1 1 1 0
0 0 0 2 0 0 2 1 0 2 2 2 2 0 0 0 1 0 0 1 2 0 1 1 1 1
21012 9
2 2 2 1 1 1 0 0 0
0 2 2 2 1 1 1 0 0
0 0 2 2 2 1 1 1 0
0 0 0 2 2 2 1 1 1
21022 20
2 1 2 0 2 2 2 0 0 0 1 2 1 0 1 1 1 0 0 0
0 2 1 2 0 2 2 2 0 0 0 1 2 1 0 1 1 1 0 0
0 0 2 1 2 0 2 2 2 0 0 0 1 2 1 0 1 1 1 0
0 0 0 2 1 2 0 2 2 2 0 0 0 1 2 1 0 1 1 1
21102 13
2 0 2 2 0 1 0 2 1 1 0 0 0
0 2 0 2 2 0 1 0 2 1 1 0 0
0 0 2 0 2 2 0 1 0 2 1 1 0
0 0 0 2 0 2 2 0 1 0 2 1 1
21112 12
2 2 1 2 0 1 2 1 1 0 0 0
0 2 2 1 2 0 1 2 1 1 0 0
0 0 2 2 1 2 0 1 2 1 1 0
0 0 0 2 2 1 2 0 1 2 1 1
21122 24
2 1 1 2 1 1 1 2 2 0 0 0 1 2 2 1 2 2 2 1 1 0 0 0
0 2 1 1 2 1 1 1 2 2 0 0 0 1 2 2 1 2 2 2 1 1 0 0
0 0 2 1 1 2 1 1 1 2 2 0 0 0 1 2 2 1 2 2 2 1 1 0
0 0 0 2 1 1 2 1 1 1 2 2 0 0 0 1 2 2 1 2 2 2 1 1
203
21202 40
2 0 1 2 0 2 1 2 1 0 0 2 2 1 0 2 2 0 0 0 1 0 2 1 0 1 2 1 2 0 0 1 1 2 0 1 1 0 0 0
0 2 0 1 2 0 2 1 2 1 0 0 2 2 1 0 2 2 0 0 0 1 0 2 1 0 1 2 1 2 0 0 1 1 2 0 1 1 0 0
0 0 2 0 1 2 0 2 1 2 1 0 0 2 2 1 0 2 2 0 0 0 1 0 2 1 0 1 2 1 2 0 0 1 1 2 0 1 1 0
0 0 0 2 0 1 2 0 2 1 2 1 0 0 2 2 1 0 2 2 0 0 0 1 0 2 1 0 1 2 1 2 0 0 1 1 2 0 1 1
21212 10
2 2 0 0 0 1 1 0 0 0
0 2 2 0 0 0 1 1 0 0
0 0 2 2 0 0 0 1 1 0
0 0 0 2 2 0 0 0 1 1
21222 8
2 1 0 1 1 0 0 0
0 2 1 0 1 1 0 0
0 0 2 1 0 1 1 0
0 0 0 2 1 0 1 1
22002 13
2 0 0 1 1 0 2 1 2 1 0 0 0
0 2 0 0 1 1 0 2 1 2 1 0 0
0 0 2 0 0 1 1 0 2 1 2 1 0
0 0 0 2 0 0 1 1 0 2 1 2 1
22012 20
2 2 2 0 2 1 2 0 0 0 1 1 1 0 1 2 1 0 0 0
0 2 2 2 0 2 1 2 0 0 0 1 1 1 0 1 2 1 0 0
0 0 2 2 2 0 2 1 2 0 0 0 1 1 1 0 1 2 1 0
0 0 0 2 2 2 0 2 1 2 0 0 0 1 1 1 0 1 2 1
22022 18
2 1 2 2 1 2 0 0 0 1 2 1 1 2 1 0 0 0
0 2 1 2 2 1 2 0 0 0 1 2 1 1 2 1 0 0
0 0 2 1 2 2 1 2 0 0 0 1 2 1 1 2 1 0
0 0 0 2 1 2 2 1 2 0 0 0 1 2 1 1 2 1
22102 26
2 0 2 1 0 2 0 1 1 2 0 0 0 1 0 1 2 0 1 0 2 2 1 0 0 0
0 2 0 2 1 0 2 0 1 1 2 0 0 0 1 0 1 2 0 1 0 2 2 1 0 0
0 0 2 0 2 1 0 2 0 1 1 2 0 0 0 1 0 1 2 0 1 0 2 2 1 0
0 0 0 2 0 2 1 0 2 0 1 1 2 0 0 0 1 0 1 2 0 1 0 2 2 1
22112 24
2 2 1 1 1 2 1 1 2 0 0 0 1 1 2 2 2 1 2 2 1 0 0 0
0 2 2 1 1 1 2 1 1 2 0 0 0 1 1 2 2 2 1 2 2 1 0 0
0 0 2 2 1 1 1 2 1 1 2 0 0 0 1 1 2 2 2 1 2 2 1 0
0 0 0 2 2 1 1 1 2 1 1 2 0 0 0 1 1 2 2 2 1 2 2 1
22122 12
2 1 1 1 0 2 2 2 1 0 0 0
0 2 1 1 1 0 2 2 2 1 0 0
0 0 2 1 1 1 0 2 2 2 1 0
0 0 0 2 1 1 1 0 2 2 2 1
22202 40
204
2011011110012201200010220222200211021000
0201101111001220120001022022220021102100
0020110111100122012000102202222002110210
0002011011110012201200010220222200211021
22212 8
22021000
02202100
00220210
00022021
22222 5
21000
02100
00210
00021
205
Додаток Г
Поліноми degP(x)=5 у GF(3) та їх періоди
100001 5
100011 78
100021 121
100101 104
100111 121
100121 24
100201 80
100211 40
100221 52
101001 80
101011 121
101021 24
101101 121
101111 26
101121 121
101201 12
101211 104
101221 78
102001 104
102011 39
102021 80
102101 18
102111 121
102121 11
102201 121
102211 8
102221 20
110001 121
110011 121
110021 12
110101 80
110111 39
110121 121
110201 24
110211 80
110221 104
111001 52
111011 26
111021 104
111101 20
111111 104
111121 16
111201 78
111211 121
111221 9
112001 24
112011 52
112021 121
112101 11
112111 24
112121 10
112201 121
112211 40
112221 16
120001 78
120011 8
120021 121
120101 39
120111 80
120121 52
120201 121
120211 121
120221 26
121001 40
121011 121
121021 80
121101 8
121111 121
121121 40
121201 104
121211 6
121221 121
122001 121
122011 80
122021 39
122101 121
122111 12
122121 24
122201 26
122211 121
122221 104
200001 10
200011 242
200021 78
200101 104
200111 24
200121 242
200201 80
200211 52
200221 40
201001 104
201011 80
201021 78
201101 18
201111 22
201121 242
201201 242
201211 20
201221 8
202001 80
202011 24
202021 242
202101 242
202111 242
202121 26
202201 12
202211 78
202221 104
210001 242
210011 12
210021 242
210101 80
210111 242
210121 78
210201 24
210211 104
210221 80
211001 24
211011 242
211021 52
211101 22
211111 10
211121 24
211201 242
211211 16
211221 40
212001 52
212011 104
212021 26
212101 20
212111 16
212121 104
212201 78
212211 18
212221 242
220001 78
220011 242
220021 8
220101 78
220111 52
220121 80
220201 242
220211 26
220221 242
221001 242
221011 78
221021 80
221101 242
221111 24
221121 12
221201 26
221211 104
221221 242
222001 40
222011 80
222021 242
222101 8
222111 40
222121 242
222201 104
222211 242
222221 6
100002 5
100012 78
100022 121
100102 104
100112 121
100122 24
100202 80
100212 40
100222 52
101002 80
101012 121
101022 24
101102 121
101112 26
101122 121
101202 12
101212 104
101222 78
102002 104
102012 39
102022 80
102102 18
206
102112 121
102122 11
102202 121
102212 8
102222 20
110002 121
110012 121
110022 12
110102 80
110112 39
110122 121
110202 24
110212 80
110222 104
111002 52
111012 26
111022 104
111102 20
111112 104
111122 16
111202 78
111212 121
111222 9
112002 24
112012 52
112022 121
112102 11
112112 24
112122 10
112202 121
112212 40
112222 16
120002 78
120012 8
120022 121
120102 39
120112 80
120122 52
120202 121
120212 121
120222 26
121002 40
121012 121
121022 80
121102 8
121112 121
121122 40
121202 104
121212 6
121222 121
122002 121
122012 80
122022 39
122102 121
122112 12
122122 24
122202 26
122212 121
122222 104
200002 10
200012 242
200022 78
200102 104
200112 24
200122 242
200202 80
200212 52
200222 40
201002 104
201012 80
201022 78
201102 18
201112 22
201122 242
201202 242
201212 20
201222 8
202002 80
202012 24
202022 242
202102 242
202112 242
202122 26
202202 12
202212 78
202222 104
210002 242
210012 12
210022 242
210102 80
210112 242
210122 78
210202 24
210212 104
210222 80
211002 24
211012 242
211022 52
211102 22
211112 10
211122 24
211202 242
211212 16
211222 40
212002 52
212012 104
212022 26
212102 20
212112 16
212122 104
212202 78
212212 18
212222 242
220002 78
220012 242
220022 8
220102 78
220112 52
220122 80
220202 242
220212 26
220222 242
221002 242
221012 78
221022 80
221102 242
221112 24
221122 12
221202 26
221212 104
221222 242
222002 40
222012 80
222022 242
222102 8
222112 40
222122 242
222202 104
222212 242
222222 6
207
Додаток Д
Поліноми degP(x)=6 у GF(3) та їх періоди
1000211 104
1000221 104
1001001 24
1001011 728
1001021 40
1001101 242
1001111 24
1001121 104
1001201 242
1001211 240
1001221 26
1002001 24
1002011 40
1002021 728
1002101 242
1002111 104
1002121 24
1002201 242
1002211 26
1002221 240
1010001 26
1010011 72
1010021 72
1010101 26
1010111 242
1010121 242
1010201 12
1010211 728
1010221 728
1011001 242
1011011 242
1011021 728
1011101 240
1011111 104
1011121 728
1011201 40
1011211 80
1011221 78
1012001 242
1012011 728
1012021 242
1012101 240
1012111 728
1012121 104
1012201 40
1012211 78
1012221 80
1020001 16
1020011 78
1020021 78
1020101 8;
1020111 728
1020121 728
1020201 26
1020211 242
1020221 242
1021001 242
1021011 52
1021021 40
1021101 56
1021111 728
1021121 78
1021201 240
1021211 242
1021221 40
1022001 242
1022011 40
1022021 52
1022101 56
1022111 78
1022121 728
1022201 240
1022211 40
1022221 242
1100001 728
1100011 56
1100021 10
1100101 78
1100111 22
1100121 80
1100201 72
1100211 242
1100221 40
1101001 728
1101011 24
1101021 26
1101101 52
1101111 728
1101121 104
1101201 242
1101211 728
1101221 242
1102001 40
1102011 40
1102021 26
1102101 40
1102111 52
1102121 48
1102201 728
1102211 242
1102221 240
1110001 104
1110011 242
1110021 40
1110101 242
1110111 78
1110121 728
1110201 728
1110211 26
1110221 12
1111001 240
1111011 728
1111021 240
1111101 242
1111111 728
1111121 104
1111201 80
1111211 24
1111221 728
1112001 26
1112011 242
1112021 242
1112101 40
1112111 240
1112121 242
1112201 78
1112211 24
1112221 728
1120001 242
1120011 22
1120021 80
1120101 728
1120111 24
1120121 18
1120201 242
1120211 78
1120221 728
1121001 24
1121011 728
1121021 48
1121101 728
1121111 20
1121121 104
1121201 104
1121211 728
1121221 242
1122001 104
1122011 52
1122021 104
1122101 78
1122111 26
1122121 104
1122201 728
1122211 240
1122221 104
1200001 728
1200011 10
1200021 56
1200101 78
1200111 80
1200121 22
1200201 72
1200211 40
1200221 242
1201001 40
1201011 26
1201021 40
1201101 40
1201111 48
1201121 52
1201201 728
1201211 240
1201221 242
1202001 728
1202011 26
1202021 24
1202101 52
1202111 104
1202121 728
1202201 242
1202211 242
1202221 728
1210001 104
1210011 40
208
1210021 242
1210101 242
1210111 728
1210121 78
1210201 728
1210211 12
1210221 26
1211001 26
1211011 242
1211021 242
1211101 40
1211111 242
1211121 240
1211201 78
1211211 728
1211221 24
1212001 240
1212011 240
1212021 728
1212101 242
1212111 104
1212121 728
1212201 80
1212211 728
1212221 24
1220001 242
1220011 80
1220021 22
1220101 728
1220111 18
1220121 24
1220201 242
1220211 728
1220221 78
1221001 104
1221011 104
1221021 52
1221101 78
1221111 104
1221121 26
1221201 728
1221211 104
1221221 240
1222001 24
1222011 48
1222021 728
1222101 728
1222111 104
1222121 20
1222201 104
1222211 242
1222221 728
2000001 12
2000011 104
2000021 104
2000101 52
2000111 60
2000121 60
2000201 16
2000211 364
2000221 364
2001001 18
2001011 52
2001021 364
2001101 104
2001111 242
2001121 91
2001201 182
2001211 80
2001221 78
2002001 9;
2002011 364
2002021 52
2002101 104
2002111 182
2002121 121
2002201 91
2002211 78
2002221 80
2010001 52
2010011 121
2010021 242
2010101 12
2010111 80
2010121 80
2010201 52
2010211 242
2010221 121
2011001 104
2011011 78
2011021 364
2011101 13
2011111 40
2011121 80
2011201 242
2011211 24
2011221 182
2012001 104
2012011 364
2012021 39
2012101 26
2012111 80
2012121 40
2012201 121
2012211 91
2012221 24
2020001 16
2020011 26
2020021 13
2020101 52
2020111 120
2020121 120
2020201 8;
2020211 121
2020221 242
2021001 182
2021011 364
2021021 24
2021101 242
2021111 11
2021121 80
2021201 30
2021211 52
2021221 78
2022001 91
2022011 24
2022021 364
2022101 121
2022111 80
2022121 22
2022201 30
2022211 39
2022221 52
2100001 104
2100011 15
2100021 24
2100101 121
2100111 242
2100121 39
2100201 26
2100211 364
2100221 78
2101001 52
2101011 28
2101021 242
2101101 78
2101111 80
2101121 120
2101201 364
2101211 80
2101221 16
2102001 364
2102011 12
2102021 121
2102101 364
2102111 104
2102121 242
2102201 24
2102211 182
2102221 182
2110001 60
2110011 242
2110021 78
2110101 80
2110111 26
2110121 8;
2110201 120
2110211 121
2110221 182
2111001 242
2111011 80
2111021 121
2111101 40
2111111 18
2111121 364
2111201 11
2111211 13
2111221 104
2112001 182
2112011 104
2112021 120
2112101 80
2112111 20
2112121 364
2112201 80
2112211 242
2112221 39
2120001 364
2120011 364
2120021 78
2120101 242
2120111 121
2120121 91
2120201 121
2120211 24
2120221 20
2121001 80
2121011 80
2121021 91
2121101 24
2121111 13
2121121 78
2121201 52
2121211 14
209
2121221 121
2122001 78
2122011 182
2122021 16
2122101 91
2122111 242
2122121 104
2122201 39
2122211 36
2122221 242
2200001 104
2200011 24
2200021 30
2200101 242
2200111 78
2200121 121
2200201 13
2200211 78
2200221 364
2201001 364
2201011 242
2201021 12
2201101 364
2201111 121
2201121 104
2201201 24
2201211 91
2201221 91
2202001 52
2202011 121
2202021 28
2202101 39
2202111 120
2202121 80
2202201 364
2202211 16
2202221 80
2210001 60
2210011 39
2210021 121
2210101 80
2210111 8;
2210121 13
2210201 120
2210211 91
2210221 242
2211001 91
2211011 120
2211021 104
2211101 80
2211111 364
2211121 20
2211201 80
2211211 78
2211221 121
2212001 121
2212011 242
2212021 80
2212101 40
2212111 364
2212121 18
2212201 22
2212211 104
2212221 26
2220001 364
2220011 78
2220021 364
2220101 121
2220111 182
2220121 242
2220201 242
2220211 20
2220221 24
2221001 78
2221011 16
2221021 91
2221101 182
2221111 104
2221121 121
2221201 78
2221211 121
2221221 36
2222001 80
2222011 182
2222021 80
2222101 24
2222111 39
2222121 26
2222201 52
2222211 242
2222221 7;
1000002 6;
1000012 728
1000022 728
1000102 16
1000112 242
1000122 242
1000202 26
1000212 104
1000222 104
1001002 24
1001012 728
1001022 40
1001102 242
1001112 24
1001122 104
1001202 242
1001212 240
1001222 26
1002002 24
1002012 40
1002022 728
1002102 242
1002112 104
1002122 24
1002202 242
1002212 26
1002222 240
1010002 26
1010012 72
1010022 72
1010102 26
1010112 242
1010122 242
1010202 12
1010212 728
1010222 728
1011002 242
1011012 242
1011022 728
1011102 240
1011112 104
1011122 728
1011202 40
1011212 80
1011222 78
1012002 242
1012012 728
1012022 242
1012102 240
1012112 728
1012122 104
1012202 40
1012212 78
1012222 80
1020002 16
1020012 78
1020022 78
1020102 8;
1020112 728
1020122 728
1020202 26
1020212 242
1020222 242
1021002 242
1021012 52
1021022 40
1021102 56
1021112 728
1021122 78
1021202 240
1021212 242
1021222 40
1022002 242
1022012 40
1022022 52
1022102 56
1022112 78
1022122 728
1022202 240
1022212 40
1022222 242
1100002 728
1100012 56
1100022 10
1100102 78
1100112 22
1100122 80
1100202 72
1100212 242
1100222 40
1101002 728
1101012 24
1101022 26
1101102 52
1101112 728
1101122 104
1101202 242
1101212 728
1101222 242
1102002 40
1102012 40
1102022 26
1102102 40
1102112 52
1102122 48
1102202 728
1102212 242
1102222 240
1110002 104
1110012 242
1110022 40
1110102 242
1110112 78
210
1110122 728
1110202 728
1110212 26
1110222 12
1111002 240
1111012 728
1111022 240
1111102 242
1111112 728
1111122 104
1111202 80
1111212 24
1111222 728
1112002 26
1112012 242
1112022 242
1112102 40
1112112 240
1112122 242
1112202 78
1112212 24
1112222 728
1120002 242
1120012 22
1120022 80
1120102 728
1120112 24
1120122 18
1120202 242
1120212 78
1120222 728
1121002 24
1121012 728
1121022 48
1121102 728
1121112 20
1121122 104
1121202 104
1121212 728
1121222 242
1122002 104
1122012 52
1122022 104
1122102 78
1122112 26
1122122 104
1122202 728
1122212 240
1122222 104
1200002 728
1200012 10
1200022 56
1200102 78
1200112 80
1200122 22
1200202 72
1200212 40
1200222 242
1201002 40
1201012 26
1201022 40
1201102 40
1201112 48
1201122 52
1201202 728
1201212 240
1201222 242
1202002 728
1202012 26
1202022 24
1202102 52
1202112 104
1202122 728
1202202 242
1202212 242
1202222 728
1210002 104
1210012 40
1210022 242
1210102 242
1210112 728
1210122 78
1210202 728
1210212 12
1210222 26
1211002 26
1211012 242
1211022 242
1211102 40
1211112 242
1211122 240
1211202 78
1211212 728
1211222 24
1212002 240
1212012 240
1212022 728
1212102 242
1212112 104
1212122 728
1212202 80
1212212 728
1212222 24
1220002 242
1220012 80
1220022 22
1220102 728
1220112 18
1220122 24
1220202 242
1220212 728
1220222 78
1221002 104
1221012 104
1221022 52
1221102 78
1221112 104
1221122 26
1221202 728
1221212 104
1221222 240
1222002 24
1222012 48
1222022 728
1222102 728
1222112 104
1222122 20
1222202 104
1222212 242
1222222 728
2000002 12
2000012 104
2000022 104
2000102 52
2000112 60
2000122 60
2000202 16
2000212 364
2000222 364
2001002 18
2001012 52
2001022 364
2001102 104
2001112 242
2001122 91
2001202 182
2001212 80
2001222 78
2002002 9;
2002012 364
2002022 52
2002102 104
2002112 182
2002122 121
2002202 91
2002212 78
2002222 80
2010002 52
2010012 121
2010022 242
2010102 12
2010112 80
2010122 80
2010202 52
2010212 242
2010222 121
2011002 104
2011012 78
2011022 364
2011102 13
2011112 40
2011122 80
2011202 242
2011212 24
2011222 182
2012002 104
2012012 364
2012022 39
2012102 26
2012112 80
2012122 40
2012202 121
2012212 91
2012222 24
2020002 16
2020012 26
2020022 13
2020102 52
2020112 120
2020122 120
2020202 8;
2020212 121
2020222 242
2021002 182
2021012 364
2021022 24
2021102 242
2021112 11
2021122 80
2021202 30
2021212 52
2021222 78
2022002 91
2022012 24
211
2022022 364
2022102 121
2022112 80
2022122 22
2022202 30
2022212 39
2022222 52
2100002 104
2100012 15
2100022 24
2100102 121
2100112 242
2100122 39
2100202 26
2100212 364
2100222 78
2101002 52
2101012 28
2101022 242
2101102 78
2101112 80
2101122 120
2101202 364
2101212 80
2101222 16
2102002 364
2102012 12
2102022 121
2102102 364
2102112 104
2102122 242
2102202 24
2102212 182
2102222 182
2110002 60
2110012 242
2110022 78
2110102 80
2110112 26
2110122 8;
2110202 120
2110212 121
2110222 182
2111002 242
2111012 80
2111022 121
2111102 40
2111112 18
2111122 364
2111202 11
2111212 13
2111222 104
2112002 182
2112012 104
2112022 120
2112102 80
2112112 20
2112122 364
2112202 80
2112212 242
2112222 39
2120002 364
2120012 364
2120022 78
2120102 242
2120112 121
2120122 91
2120202 121
2120212 24
2120222 20
2121002 80
2121012 80
2121022 91
2121102 24
2121112 13
2121122 78
2121202 52
2121212 14
2121222 121
2122002 78
2122012 182
2122022 16
2122102 91
2122112 242
2122122 104
2122202 39
2122212 36
2122222 242
2200002 104
2200012 24
2200022 30
2200102 242
2200112 78
2200122 121
2200202 13
2200212 78
2200222 364
2201002 364
2201012 242
2201022 12
2201102 364
2201112 121
2201122 104
2201202 24
2201212 91
2201222 91
2202002 52
2202012 121
2202022 28
2202102 39
2202112 120
2202122 80
2202202 364
2202212 16
2202222 80
2210002 60
2210012 39
2210022 121
2210102 80
2210112 8;
2210122 13
2210202 120
2210212 91
2210222 242
2211002 91
2211012 120
2211022 104
2211102 80
2211112 364
2211122 20
2211202 80
2211212 78
2211222 121
2212002 121
2212012 242
2212022 80
2212102 40
2212112 364
2212122 18
2212202 22
2212212 104
2212222 26
2220002 364
2220012 78
2220022 364
2220102 121
2220112 182
2220122 242
2220202 242
2220212 20
2220222 24
2221002 78
2221012 16
2221022 91
2221102 182
2221112 104
2221122 121
2221202 78
2221212 121
2221222 36
2222002 80
2222012 182
2222022 80
2222102 24
2222112 39
2222122 26
2222202 52
2222212 242
2222222 7
212
СПИСОК ЛІТЕРАТУРИ
1. Методичні вказівки для виконання лабораторних робіт з курсу
"Низькорівневе програмування апаратних засобів", "Розробка та
застосування маніфесту додатка Win32. Середовище програмування
masm64" для студентів спеціальності: 123 - "Комп'ютерна інженерія" всіх
форм навчання/упорядник О.М. Рисований. - Х.: НТУ "ХПІ", 2024. - 64 с.
2. Методичні вказівки для виконання практичних та лабораторних
робіт з навчальної дисципліни «Низькорівневе програмування апаратних
засобів» «Управління комп'ютером. Командна оболонка» для студентів
спеціальності: 123–"Комп'ютерна інженерія" всіх форм навчання
[електронне видання] / укладач О.М. Рисований.-Х.: НТУ "ХПІ", 2024. -
74 с.
3. Методичні вказівки для виконання практичних та лабораторних
робіт з курсу «Реверсне програмування. Антиналагоджувальні прийоми
захисту від реверсу. Середовище програмування masm64 для студентів
спеціальності: 123 - "Комп'ютерна інженерія" всіх форм навчання
[електронне видання] / укладач О.М. Рисований. - Х.: НТУ "ХПІ", 2024. -
132 с.
4. Методичні вказівки для виконання практичних та лабораторних
робіт з курсу «Системне програмування. Графічний інтерфейс
користувача (GUI) для студентів спеціальності: 123 – «Комп'ютерна
інженерія» всіх форм навчання [електронне видання] / укладач О.М.
Рисований. - Х.: НТУ "ХПІ", 2024. - Харків - 90 с.
5. Низькорівневе програмування апаратних засобів. Керування
комп'ютером. Командна оболонка. : навчально-методичний посібник для
студентів спеціальності 123 "Комп'ютерна інженерія" всіх форм навчання
[електронне видання] / О.М. Рисований. – Харків: НТУ «ХПІ», 2024. –
74 с.
6. Методичні вказівки до виконання лабораторних робіт з курсу
"Реверсне програмування", Ч.1. «Впровадження коду» для студентів
спеціальностей: 123 – «Комп'ютерна інженерія», 125 – «Кібербезпека» /
укладач А.М. Рисований. – Х.: «Слово», 2019. – 84 с.
7. Методичні вказівки до виконання лабораторних робіт з курсу
«Реверсне програмування», Ч.2 «Крекінг: практика злому простих
програм. Середовище програмування masm64» для студентів
спеціальностей: 123 – «Комп'ютерна інженерія», 125 – «Кібербезпека»
всіх форм навчання/упорядник О.М. Рисований. - Х.: "Слово", 2020. –
213
92 с.
8. Рисований О.М. Системне програмування, Ч. 1. Програмування
серед masm64 : учеб.-метод. посібник/О.М. Рисований. - Харків: «Слово»,
2017. -108с.
9. Рисований О.М. Системне програмування, Ч. 2. Розширені
можливості програмування в середовищі masm64: учеб.-метод.
посібник/О.М. Рисований. – Харків: «Слово», 2017. – 140 с.
10. Рисований О.М. Реверсне програмування. Використання коду.
Середовище програмування masm64: навчальний посібник для студентів
спеціальностей 123 "Комп'ютерна інженерія", 125 "Кібербезпека" / О.М.
Рисований-Харків: "Слово", 2021 - 250с.
11. Рисований О.М. Системне програмування : підручник для
студентів напряму “Комп’ютерна інженерія” вищих навчальних
закладів / О.М. Рисований. – Харків : НТУ “ХПІ”, 2010. – 912с.
Навчальне видання
Рисований Олександр Миколайович
«РЕВЕРСНЕ ПРОГРАМУВАННЯ»
Захист коду.
Середовище розробки masm64
Навчально-методичний посібник
для студентів спеціальності 123 - "Комп'ютерна інженерія"
всіх форм навчання
Роботу до видання рекомендував Микола Заполовський
Відповідальний за випуск Олександр ЗАКОВОРОТНИЙ
В авторській редакції
План 2024, поз. 95
Підгот. до друку 15.07.2024. Формат 60х84 1/16.
Електронне видання. Уч. піч. лист. 11.
Видавничий центр НТУ "ХПІ"
Свідоцтво суб'єкта вид. Справи ДК №5478 від 21.08.2017р.
Вул. Кирпичова, 2, м. Харків, 61002
Електронне видання