07-assembly (1238882)
Текст из файла
АССЕМБЛЕРВведение в ассемблер и ассемблирование. Кооперация языка C иассемблера целевой архитектурыК. Владимиров, Intel, 2019mail-to: konstantin.vladimirov@gmail.comНемного о работе компьютеров•••Дедушкой любого компьютера является электронноеарифметически-логическое устройство, то естькалькуляторMOVI D, i????????ADD rx, rs????????Представим гипотетический целочисленныйкалькулятор PseudoMK, имеющий внутри четыререгистра A, B, C, D на 8 бит каждыйSUB rx, rs????????MUL rx, rs????????Как закодировать команды PseudoMK, чтобыподавать их на вход в двоичном виде?DIV rx, rs????????IN rd????????OUT rs????????...
0100110 ...ProgrammScreenPseudoMKKeyboardПредлагаемая кодировка•Предложена следующая кодировка•Регистры A, B, C, D кодируются от 00 до 11•Каждая команда кодируется опкодом от 0 до 6 икаждое из четырёх сочетаний операндов ещё двумябитамиMOVI D, i0IIIIIIIADD rx, rs1000RRRRSUB rx, rs1001RRRRMUL rx, rs1010RRRR•Прочитайте команды: 0x1F, 0xC3, 0x92, 0xBEDIV rx, rs1011RRRR•Приведите пример некорректной командыIN rd110000RR•Это не единственная возможная кодировкаOUT rs110001RR•Понимаете ли вы почему здесь выбрана именно она?•Можете ли вы предложить лучший вариант?Немного о работе компьютеров•Теперь можно считать простые формулы(x / 3 + 5) * y – 2110000000000001110110011000001011000001111000001101000010000001010010011•//////////////////IN AMOVI D, 3DIV A, DMOVI D, 5ADD A, DIN BMUL A, BMOVI D, 2SUB A, DMOVI D, i0IIIIIIIADD rx, rs1000RRRRSUB rx, rs1001RRRRMUL rx, rs1010RRRRDIV rx, rs1011RRRRIN rd110000RROUT rs110001RRСлева от // у нас перфокарта в виде машинных кодов.
Справа язык ассемблера.Одна из многих программ•Если использовать 16-ричные числа вместо двоичных, каждая команда займётдва разряда. Вот типичная программа для PseudoMK в машинном коде0x5f0x8a0x830x810xc30x990x810xb20x960xc10xc50xc40xc20x9e0x640x850xc40x8b0xc10xc70xc50xb70x870x850xae0x830x830x830x8b0x900xbc0xc60xbe0xbb0xab0x8f0xc10x4d0x4d0x090xb80x050x9d0x830x830xc40xb30xc60xb90x990xae0x9f0x820xc10xc60x020xc30x810x820x840x870xbe0xa00x8f0xc20xc70xc40xa50x8e0xc10xc20xc00xc30xc60x8d0x820xbe0x930xa10xc40xc60xc60xc40xc40xc00x830x830xc20x830xc30xa90xb70x810xad0x900xc50xa20x160xc30x0b0x6b0x970x830xb60xc10x830xc50xc70x810x830x990x830xb30xc30x6c0xb40xc40xc40x860xc50xc30xc50x6a0xc20xa70xc70x8f0x830xa80xa30xad0x8d0x810x830x8a0x050x830xa30x7d0x5d0x3b0x950xa90x800x100xc10x830x090x9f0xb90xc70x830x8b0x940x880x830xbc0x030xc40xaa0xaa0xc10xc3Problem MK – эмулятор калькулятора•Напишите на языке C эмулятор для этого микрокалькулятора.
Вход: файлпрограммы с последовательностью машинных команд и файл ввода с stdin•Эмулятор должен при обработке каждой команды IN запрашивать ввод с входногопотока и выдавать вывод при каждой команде OUT•Пример:001.enc: 0x70 0xc7 0xc1 0x87 0x27 0xc5 0x8d 0xc1 0x87 0x6f 0xc5 0xc7001.in: 104 64> problem_mk 001.enc < 001.in112 216 63 111Problem AS – кодировщик калькулятора•>>>>•Напишите на языке C кодек (encoder/decoder), то есть программу, берущую навход последовательность ассемблерных инструкций рассмотренногомикрокалькулятора и выдающую машинные коды или наоборотcodec –d 00000011MOVDI D, 3codec –c "MOVDI D, 3"00000011Кодировщик должен поддерживать аргументы позволяющие закодироватьцелый файл> codec –c –f file.asm –o file.binАссемблер x86: регистры•Разумеется, современные микропроцессоры куда сложнее игрушечногокалькулятора, рассмотренного ранее•Регистры общего назначения в современном x86 64-битные но у них естьотдельные имена для нижних частейrax / rsi / r8eax / esi / r8dax / si / r8wahal / sil / r8bАссемблер x86: регистры•Многие регистры имеют задокументированное специальное назначениеИмяСпециальное значениеИмяСпециальное значениеraxаккумуляторr8 – r15просто регистрыrbxуказатель на данные в ds*eflagsрегистр флаговrcxсчётчик цикла или операцииeipуказатель на инструкциюrdxуказатель на I/O*csсегмент кодаrbpуказатель на фреймssсегмент стекаrspуказатель на стекds, es, fs, gsсегменты данныхrsiоперанд в строковых операцияхcr0, dr0, ...системная частьrdiрезультат в строковых операцияхmm0, xmm0, ...расширения* в реальности такое назначение не прижилосьОбсуждение•Реалистичные микропроцессоры обычно имеют кроме регистров память иинструкции для работы с ней•Также они обычно поддерживают отдельные флаговые регистры и условныепереходы в зависимости от состояния флаговых регистров•Это делает ассемблерную программу похожей на сишную программу,активно использующую goto•Вот и настало время поговорить о gotoЯзык C: использование goto•Нормальная программаint fact(int x) {int acc = 1;if (x < 2)return x;while (x > 0) {acc = acc * x;x -= 1;}return acc;}•Программа, близкая к ассемблеруint fact(int x) {int acc = x;x -= 1;if (x < 2) goto ret;loop:acc = acc * x;x -= 1;if (x > 0) goto loop;ret:return acc;}Структура ассемблерного файла (AT&T)•Секции••fact:.cfi_startprocmovl4(%esp), %edxmovl%edx, %eaxcmpl$1, %edx// if (x == 1)jleL1//goto L1;movl$1, %eaxНапример директива globl этовнешняя видимостьМетки••Например секция text это кодДирективы••.text.globl factИспользуются для вызова функций(метка fact) и условных переходовИнструкции••L3:арифметика, логика и переходысм.
для полного спискаimullsubljne%edx, %eax$1, %edxL3L1:ret.cfi_endprocСтруктура ассемблерного файла (Intel)•Секции••fact:.cfi_startprocmovedx, DWORD PTR [esp+4]moveax, edxcmpedx, 1// if (x == 1)jleL1//goto L1;moveax, 1Например директива globl этовнешняя видимостьМетки••Например секция text это кодДирективы••.text.globl factИспользуются для вызова функций(метка fact) и условных переходовИнструкции••L3:арифметика, логика и переходысм. для полного спискаimulsubjneeax, edxedx, 1L3L1:ret.cfi_endprocОбсуждение•Какой синтаксис вам больше нравится для edx = edx – 1?1.AT&T: subl $1, %edx2.Intel: sub edx, 1•Какой синтаксис вам больше нравится для edx = MEM[esp+4]?1.AT&T: movl 4(%esp), %edx2.Intel: mov edx, DWORD PTR [esp+4]•Если вам больше нравится интеловский синтаксис, подавайте -masm=intelдля gcc и clangАссемблер x86: условные переходы•Условный переход происходит какпосле явного сравненияcmpjle•Так и после обычной арифметикиsubjne•edx, 1 // if (x <= 1)L1//goto L1;edx, 1 // x -= 1;L3// if (x != 0)//goto L3;Почти каждая арифметическаяоперация выставляет флагиJE, JZif zero == if equalZF == 1JB, JNAE if less unsignedCF == 1JL, JNGE if less signedSF != OFJOif overflowOF == 1JSif signSF == 1JP, JPEif parityPF == 1JGE, JNL if not less signedSF == OFJLE, JNG if not greater signedZF == 1 ||SF != PFJBE, JNA if not greater unsignedCF == 1 ||ZF == 1JCXZif cx iz zero%CX == 0Упражнение•Что делает следующий код?somefunc:movmovL3:movcmpjnbmovmovL2:xordivmovtestjnereteax, DWORD PTR [esp+4]edx, DWORD PTR [esp+8]ecx,eax,L2ecx,eax,// somefunc(x, y):// mov eax, x// mov edx, yedxedxeaxedxedx, edxecxeax, ecxedx, edxL3// return eaxАссемблер x86: кодировка•В дизассемблере вы можете видеть строчки с указанием кодировкиадрес4015c6:•кодировка83 ec 20инструкцияsubоперандыesp,0x20Как кодируется sub? Посмотрите файл subs.s с разными видами вычитаний$ gcc -c -masm=intel subs.s$ objdump -d –M intel subs.o > subs.dis•Что вы можете сказать в результате эксперимента?кодировка = опкод + операнды•Попробуйте вычитать большие константы, как изменится опкод инструкции?Таблица опкодов: http://sparksandflames.com/files/x86InstructionChart.htmlАссемблер x86: кодировка•Продолжим исследование файла subs.o•Теперь откроем сам файл любым hex-редактором (можно :%!xxd и далее:%!xxd -r в vim, но лучше WinHex, hiew, dhex, bless или любые иные)00000090: eb04 83ea 0883 ec0c 83ef 1083 e814 83eb000000a0: 1883 ea1c 83ec 2083 ef24 9090 2e66 696c•Нет ли тут смутно знакомых последовательностей байт?•И ключевой вопрос: что будет если мы прямо в исполняемом файле чтонибудь поменяем? Например в дизассемблере программы fact видим:401609:40160d:•83 7d 08 017f 13cmpjgDWORD PTR [ebp+0x8],0x1401622 <_fact+0x26>Если мы теперь прямо внутри исполняемой программы сменим jg на,скажем, jnge, это изменит логику программы?Главная проблема редактирования кода•В машинном коде все смещения посчитаны и проставленыmovmovcmpjlemovedx,DWORD PTR [esp+0x4]eax,edxedx,0x1L1eax,0x10:4:6:9:b:imulsubjneeax,edxedx,0x1L38b89837eb854 24 04d0fa 010d01 00 00 00movmovcmpjlemovedx,DWORD PTR [esp+0x4]eax,edxedx,0x1+13 byteseax,0x110: 0f af c213: 83 ea 0116: 75 f8imulsubjneeax,edxedx,0x1-8 bytes18: c3retL3:L1:ret•Если вы измените размер инструкции или вставите новую, вам предстоитвручную менять смещения для всех затронутых переходовProblem CM: crackme #0•Используйте файлы crackme.elf для Linux и crackme.exe для Windows изфайлов к семинару (см.
zip-архив)•Вам необходимо дизассемблировать файл, изучить его, после чего используянапример vim в hex-режиме или любой другой hex-редактор, "сломать" его"защиту". Вывод при успешной модификации файла:> ./cm.out> Access granted!•Legal disclaimer: УК РФ, статьи 272, 273, 274 явно запрещают нелегальныйдоступ к компьютерной информации, а также злонамеренную модификациюпрограммного обеспечения. Это не относится к учебным примерам этогосеминара, но вы должны иметь это в виду в обычной жизниГлобальные данные•Ассемблерные файлы разделены на секции (кода, данных и т.д.)•Любые глобальные данные размещаются в секции данных#include <stdio.h>intmain(){puts("Hello, world!");}•.section .rdata,"dr"LC0:.ascii "Hello, world!\0"// .... и так далее.text// .... тут много кодаmov DWORD PTR [esp], OFFSET FLAT:LC0Видно, что глобальная переменная на уровне ассемблера это меткаВызов функций и ABI•На уровне ассемблера никаких функций не существует, только переходы•Поэтому мы должны договориться куда складывать параметрыint x =4015ce:4015d5:4015da:fact(5);c7 04 24 05 00 00 00 move8 22 00 00 00call89 44 24 1cmovDWORD PTR [esp], 0x54015fc <fact>DWORD PTR [esp+0x1c], eax•В этом фрагменте из fact.gds видно, что передача в 32-битном режимепроисходит через стек•Инструкция call сохраняет на стек адрес возврата и делает переходКонвенции вызова: https://en.wikipedia.org/wiki/X86_calling_conventionsApplication binary interface•Регламентирует как именно раскладываются по регистрам и стеку аргументы икак приходит возвращаемое значение•Поэкспериментируйте с функциейlong long sumall(char a, short b, int c, long d, long long e) {asm("");return a + b + c + d + e;}•Вызовите её из main и посмотрите как легли в ассемблер аргументыint res = sumall(50, 1500, 18800, (1l << 23), (1ll << 46));Problem KG: keygen #0•Используйте файлы crackme.elf для Linux и crackme.exe для Windows изфайлов к семинару (см.
Характеристики
Тип файла PDF
PDF-формат наиболее широко используется для просмотра любого типа файлов на любом устройстве. В него можно сохранить документ, таблицы, презентацию, текст, чертежи, вычисления, графики и всё остальное, что можно показать на экране любого устройства. Именно его лучше всего использовать для печати.
Например, если Вам нужно распечатать чертёж из автокада, Вы сохраните чертёж на флешку, но будет ли автокад в пункте печати? А если будет, то нужная версия с нужными библиотеками? Именно для этого и нужен формат PDF - в нём точно будет показано верно вне зависимости от того, в какой программе создали PDF-файл и есть ли нужная программа для его просмотра.