На главную
ПРАВИЛА FAQ Помощь Участники Календарь Избранное DigiMania RSS
msm.ru
! Перед отправкой сообщения внимательно прочтите правила раздела!!!
1. Запрещается обсуждать написание вирусов, троянов и других вредоносных программ!
2. Помните, что у нас есть FAQ раздела Assembler и Полезные ссылки. Посмотрите, возможно, там уже имеется решение вашего вопроса.

3. Настоятельно рекомендуем обратить особое внимание на правила форума, которые нарушаются чаще всего:
  3.1. Заголовок темы должен кратко отражать её суть. Темы с заголовками типа "Срочно помогите!" или "Ассемблер" будут отправляться в Корзину для мусора.
  3.2. Исходники программ обязательно выделяйте тегами [code]...[/code] (одиночные инструкции можно не выделять).
  3.3. Нежелательно поднимать старые темы (не обновлявшиеся более года) без веской на то причины.

Не забывайте также про главные Правила форума!

Добро пожаловать и приятного вам общения!!! ;)
 
Модераторы: Jin X, Qraizer
  
> "Hello world" в машинных кодах., Создание 64 битного exe в HEX редакторе.
    Всем привет. Как известно большинство из нас создают программы используя языки высокого уровня, некоторые также используют ассемблер. Сегодня мы с вами напишем программу используя только HEX редактор. Подразумевается что читатель знает строение исполняемых файлов хотя бы поверхностно, поэтому я не буду углубляться в детали, к тому же я уже приводил небольшой обзор загрузчика EXE файлов на VB6. Итак поехали...
    Для начала определимся с функциональностью приложения и используемыми инструментами. Для простоты создадим 64-битное приложение которое показывает сообщение "Hello World!" и завершает свою работу. В качестве HEX - редактора будем использовать 010 Editor.
    Для начала создадим схему чтобы определить все смещения и размеры внутри PE файла. Для начала определимся с количеством секций. Т.к. наше приложение будет вызывать внешние API функции, то нам нужна будет таблица импорта (вариант с получением через PEB я не рассматриваю). Для показа сообщения мы будем использовать функцию MassageBoxA, а для завершения приложения 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 формате (младший байт по младшему адресу)):
    ExpandedWrap disabled
      +-----------------+----------+------------------------+---------------------------------------------+
      | метка           | смещение |         данные         |               описание                      |
      +-----------------+----------+------------------------+---------------------------------------------+
      | таблица импорта |   0x00   | 0x00001054             | OriginalFirstThunk -----------------------+ |
      |                 |   0x04   | 0x00000000             | TimeDateStamp                             | |
      |                 |   0x08   | 0x00000000             | ForwarderChain                            | |
      |                 |   0x0c   | 0x0000103c             | Name ------------------+                  | |
      |                 |   0x10   | 0x00001074             | FirstThunk ------------+---------------+  | |
      |                 |   0x14   | 0x00001064             | OriginalFirstThunk ----+--------------+|  | |
      |                 |   0x18   | 0x00000000             | TimeDateStamp          |              ||  | |
      |                 |   0x1c   | 0x00000000             | ForwarderChain         |              ||  | |
      |                 |   0x20   | 0x00001049             | Name ----------------+ |              ||  | |
      |                 |   0x24   | 0x0000107c             | FirstThunk ----------+-+-----------+  ||  | |
      |                 |   0x28   | 0x00000000             | OriginalFirstThunk   | |           |  ||  | |
      |                 |   0x2c   | 0x00000000             | TimeDateStamp        | |           |  ||  | |
      |                 |   0x30   | 0x00000000             | ForwarderChain       | |           |  ||  | |
      |                 |   0x34   | 0x00000000             | Name                 | |           |  ||  | |
      |                 |   0x38   | 0x00000000             | FirstThunk           | |           |  ||  | |
      | имена библиотек |   0x3c   | kernel32.dll, 0        |                 <----+-+           |  ||  | |
      |                 |   0x49   | user32.dll, 0          |                 <----+             |  ||  | |
      | таблица имен 1  |   0x54   | 0x0000000000001084     | IMAGE_THUNK_DATA ---------------+  |  ||<-+ |
      |                 |   0x5c   | 0x0000000000000000     | IMAGE_THUNK_DATA завершающая    |  |  ||    |
      | таблица имен 2  |   0x64   | 0x0000000000001092     | IMAGE_THUNK_DATA ------------+  |  |<-+|    |
      |                 |   0x6c   | 0x0000000000000000     | IMAGE_THUNK_DATA завершающая |  |  |   |    |
      | таблица адресов |   0x74   | 0x0000000000001084     | IMAGE_THUNK_DATA -+          |  |  |<--+    |
      |                 |   0x7c   | 0x0000000000001092     | IMAGE_THUNK_DATA  |--+       |  |<-+        |
      |      имя 1      |   0x84   | 0x0000, ExitProcess, 0 |                 <-+  |       |<-+           |
      |      имя 2      |   0x92   | 0x0000, MessageBoxA, 0 |                 <----+     <-+              |
      +-----------------+----------+------------------------+---------------------------------------------+

    Вставляем эти данные в новый файл - это будет у нас таблица импорта:
    ExpandedWrap disabled
      54 10 00 00 00 00 00 00 00 00 00 00 3C 10 00 00  T...........<...
      74 10 00 00 64 10 00 00 00 00 00 00 00 00 00 00  t...d...........
      49 10 00 00 7C 10 00 00 00 00 00 00 00 00 00 00  I...|...........
      00 00 00 00 00 00 00 00 00 00 00 00 6B 65 72 6E  ............kern
      65 6C 33 32 2E 64 6C 6C 00 75 73 65 72 33 32 2E  el32.dll.user32.
      64 6C 6C 00 84 10 00 00 00 00 00 00 00 00 00 00  dll.„...........
      00 00 00 00 92 10 00 00 00 00 00 00 00 00 00 00  ....’...........
      00 00 00 00 84 10 00 00 00 00 00 00 92 10 00 00  ....„.......’...
      00 00 00 00 00 00 45 78 69 74 50 72 6F 63 65 73  ......ExitProces
      73 00 00 00 4D 65 73 73 61 67 65 42 6F 78 41 00  s...MessageBoxA.

    Для отображения сообщения нужно само сообщение где-то хранить. Будем хранить его непосредственно за таблицей импорта т.е. по смещению 0xA0:
    ExpandedWrap disabled
      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 байтовую границу. Теперь используя относительное смещение напишем код на ассемблере, который далее мы переведем непосредственно в машинный код:
    ExpandedWrap disabled
      MSG db "Hello world!", 0
          
      sub RSP, 0x28           ; Резервируем теневую область
      mov R9, 0x00000040      ; MB_ICONINFORMATION
      xor R8, R8              ; lpCaption = NULL
      lea RDX, [MSG]          ; lpText = 'Hello world!'
      xor RCX, RCX            ; HWND = NULL
      Call MessageBoxA
      xor RCX, RCX
      Call ExitProcess

    Т.к. в x64 используется RIP адресация (все смещения считаются отнгосительно адреса следующей команды) то немного перепишем код с использованием меток:
    ExpandedWrap disabled
      MSG db "Hello world!", 0
          
      sub RSP, 0x28                   ; Резервируем теневую область
      mov R9, 0x00000040              ; MB_ICONINFORMATION
      xor R8, R8                      ; lpCaption = NULL
      lea RDX, [RIP + (MSG - L1)]     ; lpText = 'Hello world!'
      L1: xor RCX, RCX                ; HWND = NULL
      Call [RIP + (MessageBoxA - L2)]
      L2: xor RCX, RCX
      Call [RIP + (ExitProcess - L3)]
      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, 0x00000040 также имеет 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. Все! Ничего сложного, только очень кропотливо. Давайте соберем все данные секции вместе:
    ExpandedWrap disabled
      0000h: 54 10 00 00 00 00 00 00 00 00 00 00 3C 10 00 00  T...........<...
      0010h: 74 10 00 00 64 10 00 00 00 00 00 00 00 00 00 00  t...d...........
      0020h: 49 10 00 00 7C 10 00 00 00 00 00 00 00 00 00 00  I...|...........
      0030h: 00 00 00 00 00 00 00 00 00 00 00 00 6B 65 72 6E  ............kern
      0040h: 65 6C 33 32 2E 64 6C 6C 00 75 73 65 72 33 32 2E  el32.dll.user32.
      0050h: 64 6C 6C 00 84 10 00 00 00 00 00 00 00 00 00 00  dll.„...........
      0060h: 00 00 00 00 92 10 00 00 00 00 00 00 00 00 00 00  ....’...........
      0070h: 00 00 00 00 84 10 00 00 00 00 00 00 92 10 00 00  ....„.......’...
      0080h: 00 00 00 00 00 00 45 78 69 74 50 72 6F 63 65 73  ......ExitProces
      0090h: 73 00 00 00 4D 65 73 73 61 67 65 42 6F 78 41 00  s...MessageBoxA.
      00A0h: 48 65 6C 6C 6F 20 77 6F 72 6C 64 21 00 48 83 EC  Hello world!.Hƒì
      00B0h: 28 49 C7 C1 40 00 00 00 4D 31 C0 48 8D 15 DE FF  (IÇÁ@...M1ÀH
      00C0h: FF FF 48 31 C9 FF 15 B1 FF FF FF 48 31 C9 FF 15  ÿÿH1Éÿ.±ÿÿÿH1Éÿ.
      00D0h: A0 FF FF FF                                       ÿÿÿ

    Итоговый размер секции у нас занимает 0xD4 байт. Точка входа у нас равна 0x10AD. Теперь приступим к непосредственному созданию EXE файла. В самом начале любого PE файла располагается IMAGE_DOS_HEADER заголовок:
    ExpandedWrap disabled
      typedef struct _IMAGE_DOS_HEADER
      {
           WORD e_magic;
           WORD e_cblp;
           WORD e_cp;
           WORD e_crlc;
           WORD e_cparhdr;
           WORD e_minalloc;
           WORD e_maxalloc;
           WORD e_ss;
           WORD e_sp;
           WORD e_csum;
           WORD e_ip;
           WORD e_cs;
           WORD e_lfarlc;
           WORD e_ovno;
           WORD e_res[4];
           WORD e_oemid;
           WORD e_oeminfo;
           WORD e_res2[10];
           DWORD e_lfanew;
      } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;

    В этой структуре нас интересуют только поля e_magic и e_lfanew, находящихся по смещениям 0x00 и 0x3C соответственно. Первое поле содержит сигнатуру MZ, а второе смещение на NT заголовки. Т.к. мы не используем заглушку DOS, мы расположим NT заголовки сразу за ней, т.е. смещение будет равно 0x40. Это очень удобно поскольку NT заголовки должны быть выровнены на 8 байтовую границу, а структура IMAGE_DOS_HEADER имеет размер 0x40 байт. Итак создаем новый файл и вписываем наши данные:
    ExpandedWrap disabled
      0000h: 4D 5A 00 00 00 00 00 00 00 00 00 00 00 00 00 00  MZ..............
      0010h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
      0020h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
      0030h: 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00  ............@...

    Далее вставляем структуру IMAGE_NT_HEADERS:
    ExpandedWrap disabled
      typedef struct _IMAGE_NT_HEADERS
      {
           DWORD Signature;
           IMAGE_FILE_HEADER FileHeader;
           IMAGE_OPTIONAL_HEADER64 OptionalHeader;
      } IMAGE_NT_HEADERS;
      typedef struct _IMAGE_FILE_HEADER
      {
           WORD Machine;
           WORD NumberOfSections;
           DWORD TimeDateStamp;
           DWORD PointerToSymbolTable;
           DWORD NumberOfSymbols;
           WORD SizeOfOptionalHeader;
           WORD Characteristics;
      } IMAGE_FILE_HEADER;
      typedef struct _IMAGE_OPTIONAL_HEADER64
      {
           WORD Magic;
           UCHAR MajorLinkerVersion;
           UCHAR MinorLinkerVersion;
           DWORD SizeOfCode;
           DWORD SizeOfInitializedData;
           DWORD SizeOfUninitializedData;
           DWORD AddressOfEntryPoint;
           DWORD BaseOfCode;
           DWORD64 ImageBase;
           DWORD SectionAlignment;
           DWORD FileAlignment;
           WORD MajorOperatingSystemVersion;
           WORD MinorOperatingSystemVersion;
           WORD MajorImageVersion;
           WORD MinorImageVersion;
           WORD MajorSubsystemVersion;
           WORD MinorSubsystemVersion;
           DWORD Win32VersionValue;
           DWORD SizeOfImage;
           DWORD SizeOfHeaders;
           DWORD CheckSum;
           WORD Subsystem;
           WORD DllCharacteristics;
           DWORD64 SizeOfStackReserve;
           DWORD64 SizeOfStackCommit;
           DWORD64 SizeOfHeapReserve;
           DWORD64 SizeOfHeapCommit;
           DWORD LoaderFlags;
           DWORD NumberOfRvaAndSizes;
           IMAGE_DATA_DIRECTORY DataDirectory[16];
      } 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. Вот что у нас получилось:
    ExpandedWrap disabled
      0000h: 4D 5A 00 00 00 00 00 00 00 00 00 00 00 00 00 00  MZ..............
      0010h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
      0020h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
      0030h: 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00  ............@...
      0040h: 50 45 00 00 64 86 01 00 00 00 00 00 00 00 00 00  PE..d†..........
      0050h: 00 00 00 00 F0 00 22 00 0B 02 00 00 00 10 00 00  ....ð.".........
      0060h: 00 00 00 00 00 00 00 00 AD 10 00 00 00 10 00 00  ........­.......
      0070h: 00 00 40 00 00 00 00 00 00 10 00 00 00 02 00 00  ..@.............
      0080h: 00 00 00 00 00 00 00 00 05 00 02 00 00 00 00 00  ................
      0090h: 00 20 00 00 00 02 00 00 00 00 00 00 02 00 00 0C  . ..............
      00A0h: 00 00 10 00 00 00 00 00 00 10 00 00 00 00 00 00  ................
      00B0h: 00 00 10 00 00 00 00 00 00 10 00 00 00 00 00 00  ................
      00C0h: 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00  ................
      00D0h: 00 10 00 00 A0 00 00 00 00 00 00 00 00 00 00 00  .... ...........
      00E0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
      00F0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
      0100h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
      0110h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
      0120h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
      0130h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
      0140h: 00 00 00 00 00 00 00 00                          ........

    Далее следует вставить описатель секции:
    ExpandedWrap disabled
      typedef struct _IMAGE_SECTION_HEADER
      {
           BYTE Name[8];
           DWORD VirtualSize;
           DWORD VirtualAddress;
           DWORD SizeOfRawData;
           DWORD PointerToRawData;
           DWORD PointerToRelocations;
           DWORD PointerToLinenumbers;
           WORD NumberOfRelocations;
           WORD NumberOfLinenumbers;
           DWORD Characteristics;
      } IMAGE_SECTION_HEADER;

    В качестве имени забиваем стандартное '.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 байт нулями. В итоге у нас получается вот такой файл:
    ExpandedWrap disabled
      0000h: 4D 5A 00 00 00 00 00 00 00 00 00 00 00 00 00 00  MZ..............
      0010h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
      0020h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
      0030h: 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00  ............@...
      0040h: 50 45 00 00 64 86 01 00 00 00 00 00 00 00 00 00  PE..d†..........
      0050h: 00 00 00 00 F0 00 22 00 0B 02 00 00 00 10 00 00  ....ð.".........
      0060h: 00 00 00 00 00 00 00 00 AD 10 00 00 00 10 00 00  ........­.......
      0070h: 00 00 40 00 00 00 00 00 00 10 00 00 00 02 00 00  ..@.............
      0080h: 00 00 00 00 00 00 00 00 05 00 02 00 00 00 00 00  ................
      0090h: 00 20 00 00 00 02 00 00 00 00 00 00 02 00 00 0C  . ..............
      00A0h: 00 00 10 00 00 00 00 00 00 10 00 00 00 00 00 00  ................
      00B0h: 00 00 10 00 00 00 00 00 00 10 00 00 00 00 00 00  ................
      00C0h: 00 00 00 00 10 00 00 00 00 00 00 00 00 00 00 00  ................
      00D0h: 00 10 00 00 A0 00 00 00 00 00 00 00 00 00 00 00  .... ...........
      00E0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
      00F0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
      0100h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
      0110h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
      0120h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
      0130h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
      0140h: 00 00 00 00 00 00 00 00 2E 74 65 78 74 00 00 00  .........text...
      0150h: 00 10 00 00 00 10 00 00 00 02 00 00 00 02 00 00  ................
      0160h: 00 00 00 00 00 00 00 00 00 00 00 00 20 00 00 60  ............ ..`
      0170h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
      0180h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
      0190h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
      01A0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
      01B0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
      01C0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
      01D0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
      01E0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
      01F0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
      0200h: 54 10 00 00 00 00 00 00 00 00 00 00 3C 10 00 00  T...........<...
      0210h: 74 10 00 00 64 10 00 00 00 00 00 00 00 00 00 00  t...d...........
      0220h: 49 10 00 00 7C 10 00 00 00 00 00 00 00 00 00 00  I...|...........
      0230h: 00 00 00 00 00 00 00 00 00 00 00 00 6B 65 72 6E  ............kern
      0240h: 65 6C 33 32 2E 64 6C 6C 00 75 73 65 72 33 32 2E  el32.dll.user32.
      0250h: 64 6C 6C 00 84 10 00 00 00 00 00 00 00 00 00 00  dll.„...........
      0260h: 00 00 00 00 92 10 00 00 00 00 00 00 00 00 00 00  ....’...........
      0270h: 00 00 00 00 84 10 00 00 00 00 00 00 92 10 00 00  ....„.......’...
      0280h: 00 00 00 00 00 00 45 78 69 74 50 72 6F 63 65 73  ......ExitProces
      0290h: 73 00 00 00 4D 65 73 73 61 67 65 42 6F 78 41 00  s...MessageBoxA.
      02A0h: 48 65 6C 6C 6F 20 77 6F 72 6C 64 21 00 48 83 EC  Hello world!.Hƒì
      02B0h: 28 49 C7 C1 40 00 00 00 4D 31 C0 48 8D 15 DE FF  (IÇÁ@...M1ÀH
      02C0h: FF FF 48 31 C9 FF 15 B1 FF FF FF 48 31 C9 FF 15  ÿÿH1Éÿ.±ÿÿÿH1Éÿ.
      02D0h: A0 FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00   ÿÿÿ............
      02E0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
      02F0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
      0300h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
      0310h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
      0320h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
      0330h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
      0340h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
      0350h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
      0360h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
      0370h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
      0380h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
      0390h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
      03A0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
      03B0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
      03C0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
      03D0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
      03E0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
      03F0h: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................

    Теперь если попробовать запустить его, то у нас появится сообщение, как мы и ожидали ).
    user posted image
    Также можно поиграться с параметром FileAlignment дабы уменьшить размер файла.
    Надеюсь вам было интересно, спасибо за внимание!
    С уважением,
    The trick.
    Прикреплённый файлПрикреплённый файлHEX_exe_by_The_trick.zip (350 байт, скачиваний: 101)
    Сообщение отредактировано: TheTrik -
      seems exe cannot execute on winxp and win7 x86
        Цитата loquat @
        seems exe cannot execute on winxp and win7 x86

        This is because the executable is 64 bit one.
          TheTrik
          Функции винды использовать некошерно.
          Надо чтоб на голом железе работало.
            В hosted писать в стиле freestanding? Хм... любопытненько. Покажешь какой-нибудь пример?
            Одни с годами умнеют, другие становятся старше.
            1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
            0 пользователей:


            Рейтинг@Mail.ru
            [ Script Execution time: 0,1367 ]   [ 16 queries used ]   [ Generated: 25.08.19, 10:39 GMT ]