«Hello world» в машинных кодах

Дата публикации 29 мар 2019 | Редактировалось 17 май 2019
Всем привет. Как известно большинство из нас создают программы используя языки высокого уровня, некоторые также используют ассемблер. Сегодня мы с вами напишем программу используя только HEX редактор. Подразумевается что читатель знает строение исполняемых файлов хотя бы поверхностно, поэтому я не буду углубляться в детали, к тому же я уже приводил небольшой обзор загрузчика EXE файлов на VB6. Итак поехали...
Для начала определимся с функциональностью приложения и используемыми инструментами. Для простоты создадим 64-битное приложение которое показывает сообщение "Hello World!" и завершает свою работу. В качестве HEX - редактора будем использовать 010 Editor.
Для начала создадим схему чтобы определить все смещения и размеры внутри PE файла. Для начала определимся с количеством секций. Т.к. наше приложение будет вызывать внешние API функции, то нам нужна будет таблица импорта (вариант с получением через PEB я не рассматриваю). Для показа сообщения мы будем использовать функцию MessageBoxA, а для завершения приложения ExitProcess, т.е. нам уже нужно 2 библиотеки - kernel32.dll и user32.dll. Давайте подсчитаем размер таблицы импорта. Для 2-х библиотек нужно разместить 3 структуры IMAGE_IMPORT_DESCRIPTOR (две с данными и одну забитую нулями), получаем 0x14 * 3 = 0x3C. Также нужно место для размещения имен библиотек в формате ASCIIZ: 0x3C + sizeof("kernel32.dll") + sizeof("user32.dll") = 0x54. Далее нужно расчитать размеры таблиц имен и таблиц адресов, по одной функции из каждой библиотеки получается 0x54 + sizeof(IMAGE_THUNK_DATA) * 4 + sizeof(IMAGE_THUNK_DATA) * 2 = 0x84. Теперь прибавляем размер имен функций: 0x84 + sizeof("MessageBoxA") + 2 + sizeof("ExitProcess") + 2 = 0xA0. Итак таблица импорта занимает у нас 0xA0 байт. Первую секцию разместим по первому доступному RVA выровненному на размер страницы, т.е. 0x1000. Таблицу импорта разместим в самом начале секции (не забывая что данные должны быть в little-endian формате (младший байт по младшему адресу)):
Код (Text):
  1. +-----------------+----------+------------------------+---------------------------------------------+
  2. | метка           | смещение |         данные         |               описание                      |
  3. +-----------------+----------+------------------------+---------------------------------------------+
  4. | таблица импорта |   0x00   | 0x00001054             | OriginalFirstThunk -----------------------+ |
  5. |                 |   0x04   | 0x00000000             | TimeDateStamp                             | |
  6. |                 |   0x08   | 0x00000000             | ForwarderChain                            | |
  7. |                 |   0x0c   | 0x0000103c             | Name ------------------+                  | |
  8. |                 |   0x10   | 0x00001074             | FirstThunk ------------+---------------+  | |
  9. |                 |   0x14   | 0x00001064             | OriginalFirstThunk ----+--------------+|  | |
  10. |                 |   0x18   | 0x00000000             | TimeDateStamp          |              ||  | |
  11. |                 |   0x1c   | 0x00000000             | ForwarderChain         |              ||  | |
  12. |                 |   0x20   | 0x00001049             | Name ----------------+ |              ||  | |
  13. |                 |   0x24   | 0x0000107c             | FirstThunk ----------+-+-----------+  ||  | |
  14. |                 |   0x28   | 0x00000000             | OriginalFirstThunk   | |           |  ||  | |
  15. |                 |   0x2c   | 0x00000000             | TimeDateStamp        | |           |  ||  | |
  16. |                 |   0x30   | 0x00000000             | ForwarderChain       | |           |  ||  | |
  17. |                 |   0x34   | 0x00000000             | Name                 | |           |  ||  | |
  18. |                 |   0x38   | 0x00000000             | FirstThunk           | |           |  ||  | |
  19. | имена библиотек |   0x3c   | kernel32.dll, 0        |                 <----+-+           |  ||  | |
  20. |                 |   0x49   | user32.dll, 0          |                 <----+             |  ||  | |
  21. | таблица имен 1  |   0x54   | 0x0000000000001084     | IMAGE_THUNK_DATA ---------------+  |  ||<-+ |
  22. |                 |   0x5c   | 0x0000000000000000     | IMAGE_THUNK_DATA завершающая    |  |  ||    |
  23. | таблица имен 2  |   0x64   | 0x0000000000001092     | IMAGE_THUNK_DATA ------------+  |  |<-+|    |
  24. |                 |   0x6c   | 0x0000000000000000     | IMAGE_THUNK_DATA завершающая |  |  |   |    |
  25. | таблица адресов |   0x74   | 0x0000000000001084     | IMAGE_THUNK_DATA -+          |  |  |<--+    |
  26. |                 |   0x7c   | 0x0000000000001092     | IMAGE_THUNK_DATA  |--+       |  |<-+        |
  27. |      имя 1      |   0x84   | 0x0000, ExitProcess, 0 |                 <-+  |       |<-+           |
  28. |      имя 2      |   0x92   | 0x0000, MessageBoxA, 0 |                 <----+     <-+              |
  29. +-----------------+----------+------------------------+---------------------------------------------+
Вставляем эти данные в новый файл - это будет у нас таблица импорта:
Код (Text):
  1. 54 10 00 00 00 00 00 00 00 00 00 00 3C 10 00 00  T...........<...
  2. 74 10 00 00 64 10 00 00 00 00 00 00 00 00 00 00  t...d...........
  3. 49 10 00 00 7C 10 00 00 00 00 00 00 00 00 00 00  I...|...........
  4. 00 00 00 00 00 00 00 00 00 00 00 00 6B 65 72 6E  ............kern
  5. 65 6C 33 32 2E 64 6C 6C 00 75 73 65 72 33 32 2E  el32.dll.user32.
  6. 64 6C 6C 00 84 10 00 00 00 00 00 00 00 00 00 00  dll.„...........
  7. 00 00 00 00 92 10 00 00 00 00 00 00 00 00 00 00  ....’...........
  8. 00 00 00 00 84 10 00 00 00 00 00 00 92 10 00 00  ....„.......’...
  9. 00 00 00 00 00 00 45 78 69 74 50 72 6F 63 65 73  ......ExitProces
  10. 73 00 00 00 4D 65 73 73 61 67 65 42 6F 78 41 00  s...MessageBoxA.
  11.  
Для отображения сообщения нужно само сообщение где-то хранить. Будем хранить его непосредственно за таблицей импорта т.е. по смещению 0xA0:
Код (Text):
  1. 00A0h: 48 65 6C 6C 6F 20 77 6F 72 6C 64 21 00  Hello world!.
Сам код у нас будет начинаться сразу после данного сообщения, то есть, по смещению 0xA0 + sizeof("Hello world!") = 0xAD. Все API функции в x64 используют одноименное соглашение: первые 4 параметра передаются в регистрах RCX, RDX, R8, R9, остальные в стеке, также в стеке выделяется 32 байта теневой области. Также стек должен быть выровнен на 16 байтовую границу. Теперь используя относительное смещение напишем код на ассемблере, который далее мы переведем непосредственно в машинный код:
Код (ASM):
  1. MSG db "Hello world!", 0
  2.  
  3. sub RSP, 0x28           ; Резервируем теневую область
  4. mov R9, 0x00000040      ; MB_ICONINFORMATION
  5. xor R8, R8              ; lpCaption = NULL
  6. lea RDX, [MSG]          ; lpText = 'Hello world!'
  7. xor RCX, RCX            ; HWND = NULL
  8. Call MessageBoxA
  9. xor RCX, RCX
  10. Call ExitProcess
Так как в x64 используется RIP адресация (все смещения считаются относительно адреса следующей команды) то немного перепишем код с использованием меток:
Код (ASM):
  1. MSG db "Hello world!", 0
  2.  
  3. sub RSP, 0x28                   ; Резервируем теневую область
  4. mov R9, 0x00000040              ; MB_ICONINFORMATION
  5. xor R8, R8                      ; lpCaption = NULL
  6. lea RDX, [RIP + (MSG - L1)]     ; lpText = 'Hello world!'
  7. L1: xor RCX, RCX                ; HWND = NULL
  8. Call [RIP + (MessageBoxA - L2)]
  9. L2: xor RCX, RCX
  10. Call [RIP + (ExitProcess - L3)]
  11. L3:
Теперь приступим непосредственно к трансляции в машинный код. Для этого я буду использовать вот эту таблицу.

Первая инструкция sub RSP, 0x28 оперирует с 64 битным регистром RSP поэтому опкод должен содержать префикс REX.W(0x48), далее смотрим по списку инструкцию SUB чтобы первым операндом был 64 битный регистр, а вторым непосредственное однобайтовое значение и это - 0x83. теперь нужно определится с mod/rm байтом. Так как мы используем непосредственно регистр RSP то поле mod будет равно 0b11, а поле r/m будет равно 0b100 что соответствует регистрам AH/SP/ESP/RSP. В таблице указано что для нашей команды поле Register/ Opcode Field должно быть равно 5 (0b101 в двоичной форме). Собираем все вместе, и получаем 0b11-101-100 = 0xEC. Непосредственный операнд идет сразу же после mod/rm байта, в итоге полный код команды 48 83 EC 28.

Следующая инструкция mov R9, 0x40 также имеет REX префикс, поскольку использует регистр недоступный в 32 битном режиме, а именно комбинацию REX.W и REX.B = 0x49. Префикс REX.B говорит о том что наша инструкция имеет расширенное поле rm. В 32 битном режиме мы могли бы использовать однобайтовую 0xB8 + r, в 64-битном нам придется использовать 0xC7. Также определяем поле mod/rm, так как у нас операнд непосредственный регистр, то mod = 0b11, а rm = 0b001 что соответствует регистру R9. По таблице поле Register/ Opcode Field должно быть равно 0, собирая все вместе получим 0b11-000-001 = 0xC1. Непосредственный операнд размещается за mod/rm полем. В итоге получаем полный код команды = 49 C7 C1 40 00 00 00.

Третья инструкция работает с двумя расширенными регистрами поэтому она содержит расширенный префикс с комбинацией REX.W, REX.B и REX.R = 0x4D. Префикс REX.R говорит о том что поле reg байта mod/rm также является расширенным. Далее ищем опкод команды XOR, здесь мы можем выбрать любой из двух либо 0x31 либо 0x33, я возьму первое. Также определяемся с полем mod/rm. Опять-таки т.к. мы используем непосредственно регистры то поле mod будет равно 0b11, по таблице регистров смотрим что расширеное поле для регистра R8 = 0b000. Собираем все вместе - 0b11-000-000 = 0xC0, а полный код команды - 4D 31 C0.

Далее инструкция lea RDX, [RIP + (MSG - L1)], второй операнд у нас является непосредственным значением, так как мы работаем в 64 битном режиме и адресация у нас идет относительно адреса следующей команды. Нам нужна инструкция вида lea reg64, imm32, но сначала определимся с префиксом. Так как команда работает с 64 битным регистром то префикс будет REX.W(0x48). Опкод команды LEA - 0x8D. В качестве mod/rm у нас должно быть mod = 0b000, а rm = 0b101 что соответствует [RIP + disp32]. Для регистра RDX номер равен 0b010. Компонуем вместе - 0b00-010-101 = 0x15. После идет 4-байтное смещение. Теперь давайте посчитаем смещение до нашей строки относительно следующей команды:
disp = -(sizeof("Hello world!") + sizeof({48 83 EC 28}) + sizeof({49 C7 C1 40 00 00 00}) + sizeof({4D 31 C0}) + sizeof({48 8D 15 00 00 00 00})) = 0xFFFFFFDE
То есть полный код будет тогда = 48 8D 15 DE FF FF FF.

Следующий XOR рассчитывается также, как и предыдущий: REX.W + 0x31 + 0b11-001-001 = 48 31 C9.
Дальше у нас идет вызов из таблицы импорта, поэтому нужно посчитать смещение относительно следующей команды до 2-го элемента таблицы адресов (там у нас содержится адрес функции MessageBoxA), которое равно в данном случае -79 (0xFFFFFFB1). Теперь нам нужно найти опкод инструкции CALL которая позволяет вызывать по адресу расположенному в памяти. По таблице находим FF, Register/ Opcode Field должно быть равно 2. Теперь также посчитаем mod/rm байт. 0b00-010-101 = 0x15. Полный код команды = FF 15 B1 FF FF FF. Код следующей команды нам уже известен, поэтому переходим к последнему опкоду - CALL. Опять считаем смещение, оно равно -96 0xFFFFFFA0, подставляем и получаем опкод команды FF 15 A0 FF FF FF. Все! Ничего сложного, только очень кропотливо. Давайте соберем все данные секции вместе:
Код (Text):
  1. 0000h: 54 10 00 00 00 00 00 00 00 00 00 00 3C 10 00 00  T...........<...
  2. 0010h: 74 10 00 00 64 10 00 00 00 00 00 00 00 00 00 00  t...d...........
  3. 0020h: 49 10 00 00 7C 10 00 00 00 00 00 00 00 00 00 00  I...|...........
  4. 0030h: 00 00 00 00 00 00 00 00 00 00 00 00 6B 65 72 6E  ............kern
  5. 0040h: 65 6C 33 32 2E 64 6C 6C 00 75 73 65 72 33 32 2E  el32.dll.user32.
  6. 0050h: 64 6C 6C 00 84 10 00 00 00 00 00 00 00 00 00 00  dll.„...........
  7. 0060h: 00 00 00 00 92 10 00 00 00 00 00 00 00 00 00 00  ....’...........
  8. 0070h: 00 00 00 00 84 10 00 00 00 00 00 00 92 10 00 00  ....„.......’...
  9. 0080h: 00 00 00 00 00 00 45 78 69 74 50 72 6F 63 65 73  ......ExitProces
  10. 0090h: 73 00 00 00 4D 65 73 73 61 67 65 42 6F 78 41 00  s...MessageBoxA.
  11. 00A0h: 48 65 6C 6C 6F 20 77 6F 72 6C 64 21 00 48 83 EC  Hello world!.Hƒì
  12. 00B0h: 28 49 C7 C1 40 00 00 00 4D 31 C0 48 8D 15 DE FF  (IÇÁ@...M1ÀH
  13. 00C0h: FF FF 48 31 C9 FF 15 B1 FF FF FF 48 31 C9 FF 15  ÿÿH1Éÿ.±ÿÿÿH1Éÿ.
  14. 00D0h: A0 FF FF FF                                       ÿÿÿ
Итоговый размер секции у нас занимает 0xD4 байт. Точка входа у нас равна 0x10AD.
Теперь приступим к непосредственному созданию EXE файла. В самом начале любого PE файла располагается IMAGE_DOS_HEADER заголовок:
Код (C++):
  1. typedef struct _IMAGE_DOS_HEADER
  2. {
  3.      WORD e_magic;
  4.      WORD e_cblp;
  5.      WORD e_cp;
  6.      WORD e_crlc;
  7.      WORD e_cparhdr;
  8.      WORD e_minalloc;
  9.      WORD e_maxalloc;
  10.      WORD e_ss;
  11.      WORD e_sp;
  12.      WORD e_csum;
  13.      WORD e_ip;
  14.      WORD e_cs;
  15.      WORD e_lfarlc;
  16.      WORD e_ovno;
  17.      WORD e_res[4];
  18.      WORD e_oemid;
  19.      WORD e_oeminfo;
  20.      WORD e_res2[10];
  21.      DWORD e_lfanew;
  22. } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
В этой структуре нас интересуют только поля e_magic и e_lfanew, находящихся по смещениям 0x00 и 0x3C соответственно. Первое поле содержит сигнатуру MZ, а второе смещение на NT заголовки. Так как мы не используем заглушку DOS, мы расположим NT заголовки сразу за ней, то есть смещение будет равно 0x40. Это очень удобно поскольку NT заголовки должны быть выровнены на 8 байтовую границу, а структура IMAGE_DOS_HEADER имеет размер 0x40 байт. Итак создаем новый файл и вписываем наши данные:
Код (Text):
  1. 0000h: 4D 5A 00 00 00 00 00 00 00 00 00 00 00 00 00 00  MZ..............
  2. 0010h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  3. 0020h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  4. 0030h: 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00  ............@...
Далее вставляем структуру
IMAGE_NT_HEADERS:
Код (C++):
  1. typedef struct _IMAGE_NT_HEADERS
  2. {
  3.      DWORD Signature;
  4.      IMAGE_FILE_HEADER FileHeader;
  5.      IMAGE_OPTIONAL_HEADER64 OptionalHeader;
  6. } IMAGE_NT_HEADERS;
  7. typedef struct _IMAGE_FILE_HEADER
  8. {
  9.      WORD Machine;
  10.      WORD NumberOfSections;
  11.      DWORD TimeDateStamp;
  12.      DWORD PointerToSymbolTable;
  13.      DWORD NumberOfSymbols;
  14.      WORD SizeOfOptionalHeader;
  15.      WORD Characteristics;
  16. } IMAGE_FILE_HEADER;
  17. typedef struct _IMAGE_OPTIONAL_HEADER64
  18. {
  19.      WORD Magic;
  20.      UCHAR MajorLinkerVersion;
  21.      UCHAR MinorLinkerVersion;
  22.      DWORD SizeOfCode;
  23.      DWORD SizeOfInitializedData;
  24.      DWORD SizeOfUninitializedData;
  25.      DWORD AddressOfEntryPoint;
  26.      DWORD BaseOfCode;
  27.      DWORD64 ImageBase;
  28.      DWORD SectionAlignment;
  29.      DWORD FileAlignment;
  30.      WORD MajorOperatingSystemVersion;
  31.      WORD MinorOperatingSystemVersion;
  32.      WORD MajorImageVersion;
  33.      WORD MinorImageVersion;
  34.      WORD MajorSubsystemVersion;
  35.      WORD MinorSubsystemVersion;
  36.      DWORD Win32VersionValue;
  37.      DWORD SizeOfImage;
  38.      DWORD SizeOfHeaders;
  39.      DWORD CheckSum;
  40.      WORD Subsystem;
  41.      WORD DllCharacteristics;
  42.      DWORD64 SizeOfStackReserve;
  43.      DWORD64 SizeOfStackCommit;
  44.      DWORD64 SizeOfHeapReserve;
  45.      DWORD64 SizeOfHeapCommit;
  46.      DWORD LoaderFlags;
  47.      DWORD NumberOfRvaAndSizes;
  48.      IMAGE_DATA_DIRECTORY DataDirectory[16];
  49. } IMAGE_OPTIONAL_HEADER64;
В качестве Signature вставляем строку из 4-х символов PE\0\0. Т.к. у нас 64 битное приложение то в качестве Machine устанавливаем значение IMAGE_FILE_MACHINE_AMD64 равное 0x8664. В качестве NumberOfSections укажем 1, т.к. у нас одна секция. Три следующих поля нам не нужны, поэтому забиваем их нулями. Размер необязательного заголовка установим в IMAGE_SIZEOF_NT_OPTIONAL64_HEADER (0x00F0). Для Characteristics зададим комбинацию флагов IMAGE_FILE_EXECUTABLE_IMAGE и IMAGE_FILE_LARGE_ADDRESS_AWARE (0x0022). Далее начнем заполнять необязательный заголовок. В качестве Magic указываем IMAGE_NT_OPTIONAL_HDR64_MAGIC (0x020B). Версия линкера нам не нужна, поэтому забиваем туда нули. Размер кода указываем равным 0x1000, потому что тут указывается выровненный размер данных на размер одной страницы. Размер инициализированных и неинициализированных данных забиваем нулями. Как мы выше вычислили, точка входа у нас равна 0x10AD, в BaseOfCode забиваем RVA нашей секции, т.к. она содержит код. В качестве ImageBase задаем 0x0000000000400000 - это наш базовый адрес, тут можно в принципе указать любое значение, т.к. наш модуль не содержит абсолютных ссылок. В качестве SectionAlignment указываем 0x1000 - размер одной страницы памяти, а в качестве FileAlignment - 0x200 (стандартное значение для PE файлов). Версии операционной системы и образа мы не используем, а вот в качестве MajorSubsystemVersion и MinorSubsystemVersion укажем 0x0005 и 0x0002 (аналогично /SUBSYSTEM[,major[.minor]] ключу линкера). В качестве SizeOfImage укажем значение 0x2000, поскольку наш файл будет располагаться на двух страницах памяти (заголовки и одна секция). Значение SizeOfHeaders нужно посчитать сложением всех заголовков и выравниванием на границу FileAlignment:
align(sizeof(IMAGE_DOS_HEADER) + sizeof(IMAGE_NT_HEADERS) + sizeof(IMAGE_SECTION_HEADER), 0x200) = 0x200
Контрольную сумму также оставляем без внимания, а вот в качестве Subsystem вбиваем IMAGE_SUBSYSTEM_WINDOWS_GUI (0x0002). В поле DllCharacteristics забиваем комбинацию флагов IMAGE_DLLCHARACTERISTICS_NO_SEH и IMAGE_DLLCHARACTERISTICS_NO_BIND = 0x0C00. Размер резервируемой памяти стека оставим по умолчанию 0x100000 байт, тоже самое и с начальным размером - 0x1000 байт. Те же самые значения забьем и для кучи. LoaderFlags - устаревшее поле и нас не интересует. NumberOfRvaAndSizes - забиваем 0x10. В каталоге директорий нам понадобится только таблица импорта под индексом 1. Забиваем туда 0x1000 в качестве виртуального адреса, а размер равен (как мы ранее вычислили) 0xA0. Вот что у нас получилось:
Код (Text):
  1. 0000h: 4D 5A 00 00 00 00 00 00 00 00 00 00 00 00 00 00  MZ..............
  2. 0010h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  3. 0020h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  4. 0030h: 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00  ............@...
  5. 0040h: 50 45 00 00 64 86 01 00 00 00 00 00 00 00 00 00  PE..d†..........
  6. 0050h: 00 00 00 00 F0 00 22 00 0B 02 00 00 00 10 00 00  ....ð.".........
  7. 0060h: 00 00 00 00 00 00 00 00 AD 10 00 00 00 10 00 00  ...............
  8. 0070h: 00 00 40 00 00 00 00 00 00 10 00 00 00 02 00 00  ..@.............
  9. 0080h: 00 00 00 00 00 00 00 00 05 00 02 00 00 00 00 00  ................
  10. 0090h: 00 20 00 00 00 02 00 00 00 00 00 00 02 00 00 0C  . ..............
  11. 00A0h: 00 00 10 00 00 00 00 00 00 10 00 00 00 00 00 00  ................
  12. 00B0h: 00 00 10 00 00 00 00 00 00 10 00 00 00 00 00 00  ................
  13. 00C0h: 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00  ................
  14. 00D0h: 00 10 00 00 A0 00 00 00 00 00 00 00 00 00 00 00  .... ...........
  15. 00E0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  16. 00F0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  17. 0100h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  18. 0110h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  19. 0120h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  20. 0130h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  21. 0140h: 00 00 00 00 00 00 00 00                          ........
Далее следует вставить описатель секции:
Код (C++):
  1. typedef struct _IMAGE_SECTION_HEADER
  2. {
  3.      BYTE Name[8];
  4.      DWORD VirtualSize;
  5.      DWORD VirtualAddress;
  6.      DWORD SizeOfRawData;
  7.      DWORD PointerToRawData;
  8.      DWORD PointerToRelocations;
  9.      DWORD PointerToLinenumbers;
  10.      WORD NumberOfRelocations;
  11.      WORD NumberOfLinenumbers;
  12.      DWORD Characteristics;
  13. } IMAGE_SECTION_HEADER;
  14.  
В качестве имени забиваем стандартное '.text\0\0\0'. VirtualSize устанавливаем равным 0x1000 (округляем на границу выравнивания секций). VirtualAdress как мы в самом начале определили как 0x1000. Поле SizeOfRawData устанавливаем равным 0x200 байт поскольку размер данных секции равен 0xD4 байт, но его нужно округлить на границу FileAlignment, а в оставшееся место секции забить нули или произвольные данные. Поле PointerToRawData у нас равно значению из IMAGE_OPTIONAL_HEADER64.SizeOfHeaders, то есть 0x200. Поля до поля Characteristics забиваем нулями, а вот это поле будет равно комбинации флагов IMAGE_SCN_CNT_CODE, IMAGE_SCN_MEM_EXECUTE и IMAGE_SCN_MEM_READ, то есть 0x60000020. Все, добиваем нулями до границы 512 байт и прикрепляем секцию которую тоже добиваем до 512 байт нулями. В итоге у нас получается вот такой файл:
Код (Text):
  1. 0000h: 4D 5A 00 00 00 00 00 00 00 00 00 00 00 00 00 00  MZ..............
  2. 0010h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  3. 0020h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  4. 0030h: 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00  ............@...
  5. 0040h: 50 45 00 00 64 86 01 00 00 00 00 00 00 00 00 00  PE..d†..........
  6. 0050h: 00 00 00 00 F0 00 22 00 0B 02 00 00 00 10 00 00  ....ð.".........
  7. 0060h: 00 00 00 00 00 00 00 00 AD 10 00 00 00 10 00 00  ...............
  8. 0070h: 00 00 40 00 00 00 00 00 00 10 00 00 00 02 00 00  ..@.............
  9. 0080h: 00 00 00 00 00 00 00 00 05 00 02 00 00 00 00 00  ................
  10. 0090h: 00 20 00 00 00 02 00 00 00 00 00 00 02 00 00 0C  . ..............
  11. 00A0h: 00 00 10 00 00 00 00 00 00 10 00 00 00 00 00 00  ................
  12. 00B0h: 00 00 10 00 00 00 00 00 00 10 00 00 00 00 00 00  ................
  13. 00C0h: 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00  ................
  14. 00D0h: 00 10 00 00 A0 00 00 00 00 00 00 00 00 00 00 00  .... ...........
  15. 00E0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  16. 00F0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  17. 0100h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  18. 0110h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  19. 0120h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  20. 0130h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  21. 0140h: 00 00 00 00 00 00 00 00 2E 74 65 78 74 00 00 00  .........text...
  22. 0150h: 00 10 00 00 00 10 00 00 00 02 00 00 00 02 00 00  ................
  23. 0160h: 00 00 00 00 00 00 00 00 00 00 00 00 20 00 00 60  ............ ..`
  24. 0170h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  25. 0180h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  26. 0190h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  27. 01A0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  28. 01B0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  29. 01C0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  30. 01D0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  31. 01E0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  32. 01F0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  33. 0200h: 54 10 00 00 00 00 00 00 00 00 00 00 3C 10 00 00  T...........<...
  34. 0210h: 74 10 00 00 64 10 00 00 00 00 00 00 00 00 00 00  t...d...........
  35. 0220h: 49 10 00 00 7C 10 00 00 00 00 00 00 00 00 00 00  I...|...........
  36. 0230h: 00 00 00 00 00 00 00 00 00 00 00 00 6B 65 72 6E  ............kern
  37. 0240h: 65 6C 33 32 2E 64 6C 6C 00 75 73 65 72 33 32 2E  el32.dll.user32.
  38. 0250h: 64 6C 6C 00 84 10 00 00 00 00 00 00 00 00 00 00  dll.„...........
  39. 0260h: 00 00 00 00 92 10 00 00 00 00 00 00 00 00 00 00  ....’...........
  40. 0270h: 00 00 00 00 84 10 00 00 00 00 00 00 92 10 00 00  ....„.......’...
  41. 0280h: 00 00 00 00 00 00 45 78 69 74 50 72 6F 63 65 73  ......ExitProces
  42. 0290h: 73 00 00 00 4D 65 73 73 61 67 65 42 6F 78 41 00  s...MessageBoxA.
  43. 02A0h: 48 65 6C 6C 6F 20 77 6F 72 6C 64 21 00 48 83 EC  Hello world!.Hƒì
  44. 02B0h: 28 49 C7 C1 40 00 00 00 4D 31 C0 48 8D 15 DE FF  (IÇÁ@...M1ÀH
  45. 02C0h: FF FF 48 31 C9 FF 15 B1 FF FF FF 48 31 C9 FF 15  ÿÿH1Éÿ.±ÿÿÿH1Éÿ.
  46. 02D0h: A0 FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00   ÿÿÿ............
  47. 02E0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  48. 02F0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  49. 0300h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  50. 0310h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  51. 0320h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  52. 0330h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  53. 0340h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  54. 0350h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  55. 0360h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  56. 0370h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  57. 0380h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  58. 0390h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  59. 03A0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  60. 03B0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  61. 03C0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  62. 03D0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  63. 03E0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  64. 03F0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
  65.  
Теперь если попробовать запустить его, то у нас появится сообщение, как мы и ожидали :) . Также можно поиграться с параметром FileAlignment дабы уменьшить размер файла.
[​IMG]


Надеюсь вам было интересно, спасибо за внимание!
С уважением,
Кривоус Анатолий (The trick).

0 10.576
Thetrik

Thetrik
UA6527P

Регистрация:
25 июл 2011
Публикаций:
0