Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Взлом ПО.docx
Скачиваний:
115
Добавлен:
23.11.2018
Размер:
3.85 Mб
Скачать

Как обмануть отладчик и дизассемблер

Что может помешать дизассемблеру4:

  • непонятные вызовы функций, например, call [ebp+022h];

  • зашифрованные куски кода.

Что может помешать отладчику:

  • изменение работы программы в случае ее выполнения в отладчике;

  • определение отладчика до запуска программы с последующим завершением. Функция IsDebuggerPresent вернет в регистре EAX значение 0FFFFFFFFh, если в системе нет отладчика – такую проверку можно осуществить несколько раз.

Использование виртуальной машины. В саму программу внедряются специальные команды, которые могут обрабатываться только специальным интерпретатором – виртуальной машиной. Отладчик и дизассемблер не знают специализированных команд.

Приложение 1. Ассемблер в Windows

Создадим новый консольный проект в Visual Studio 2010.

Рис. Создание консольного приложения в Visual Studio 2010

Рис. Выбор параметров консольного приложения в Visual Studio 2010

Рис. Создание нового файла в проекте

Рис. Создание файла на языке С++

Листинг 1:

#include <stdio.h>

int a;

void main()

{

a=10;

__asm {

add a,10

sub a,2

}

printf("%d ",a);

}

Запускаем программу на выполнение.

Рис. Результат выполнения программы

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

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

Листинг 2:

#include <stdio.h>

#include <Windows.h>

//пересылка данных

//переменные

DWORD a,b,c,d,e,f,g,h;

void main()

{

f=200;

__asm {

//непосредственная передача

mov a,100

mov eax,100

mov b,eax

//использование косвенной адресации

lea ebx,c

mov dword ptr [ebx],eax

//использование стека

//содержимое eax оказывается в e, число 100 в d

push eax

push 100

pop d

pop e

//команда xchg (обмен содержимым операндов),

//содержимое f переносится в g

xchg eax,f

xchg g,eax

//сложение с предварительным обменом операндов

mov ebx,50

mov eax,20

xadd eax,ebx

mov dword ptr h,ebx

//теперь сумма в eax, а число 20 в h

}

printf("%u %u %u %u %u %u %u %u\n", a,b,c,d,e,f,g,h);

}

Рис. Результат работы программы

Рассмотрим Листинг 2. Заголовочный файл windows.h содержит определение типов переменных, в частности, там содержится определение типа DWORD, которое сводится просто к unsigned int.

В ассемблерных командах мы используем переменные, определенные средствами языка С, т.к. встроенный в С ассемблер не позволяет осуществлять резервирование памяти. Адресация памяти с помощью переменных – прямая адресация.

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

В программе используется косвенная адресация. Если адрес ячейки памяти содержится в регистре, например, в EDX, то, для того чтобы послать туда число, нужно записать MOV BYTE PTR [EDX],100. BYTE PTR означает, что в операции участвует однобайтовая ячейка памяти (WORD PTR – слово, DWORD PTR – для двойного слова).

Команда PUSH помещает в стек четырехбайтовое число, команда POP достает число оттуда. Стек построен по принципу «первым пришел – последним ушел», т.е. в переменной e окажется число из EAX, а в d – число 100.

Команда LEA используется, чтобы получить адрес переменной.

Листинг 3:

#include <stdio.h>

#include <Windows.h>

BYTE ar[6] = {1,12,128,50,200,10};

BYTE a,b,c,d;

WORD e;

DWORD f;

void main()

{

__asm {

mov al,byte ptr ar

mov a,al

lea ebx,ar

mov al,byte ptr [ebx]

mov b,al

mov al,byte ptr [ebx]+3

mov c,al

mov edx,1

mov al,byte ptr [ebx][edx]+2

mov d,al

mov ax,word ptr [ebx]+2

mov e,ax

mov eax,dword ptr [ebx]+2

mov f,eax

};

printf("%u %u %u %u %u %u\n",a,b,c,d,e,f);

}

Рис. Результат работы программы

Листинг 3 посвящен способам адресации, пример построен на косвенной адресации: [EBX]+2, т.е. результирующий адрес получается путем сложения адреса, хранящегося в регистре EBX, и числа 2.

В случае [EBX][EDX]+2 (или [EBX + EDX + 2]) результирующий адрес получается путем сложения содержимого регистра EBX, регистра EDX и числа 2. Это называется адресацией по базе с индексированием и со сдвигом.