Import x64

Тема в разделе "WASM.ARTICLES", создана пользователем Mikl___, 28 июн 2017.

  1. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.709

    Импорт

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

    Секция IAT (Import Address Table ― таблица адресов импорта) состоит из массива 20-байтовых элементов типа IMAGE_IMPORT_DESCRIPTOR. Каждый элемент IMAGE_IMPORT_DESCRIPTOR соответствует одной из DLL, с которой неявно связан данный РЕ-файл. Одной DLL может соответствовать несколько элементов IMAGE_IMPORT_DESCRIPTOR. Так как количество элементов в массиве нигде явно не указано, поэтому последний элемент массива IMAGE_IMPORT_DESCRIPTOR должен имеет поля, содержащие NULL. Для размещения массива IMAGE_IMPORT_DESCRIPTOR, описывающего N библиотек, нужно (N+1)×20 байт памяти.

    За импорт в РЕ-файле отвечают элементы DATA DIRECTORY
    IMAGE_DIRECTORY_ENTRY_IMPORT1Указатель на таблицу импортируемых функций, используемую для связи файла с внешними DLL, и активируемую системным загрузчиком, когда все остальные механизмы импорта недоступны. Используется RVA- и VA-адресация
    IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT11Указатель на таблицу диапазонного импорта, имеющей приоритет над IMAGE_DIRECTORY_ENTRY_IMPORT и обрабатываемой загрузчиком в первую очередь. Используется RVA- и RRAW-адресация
    IMAGE_DIRECTORY_ENTRY_IAT12указатель на IAT. В DATA DIRECTORY указатель на IAT может быть обнулен. Используется RVA- и VA-адресация
    IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT13указатель на таблицу отложенного импорта. Используется RVA/VA-адресация
    RVA (Relative Virtual Address ― относительный виртуальный адрес). Многие поля в РЕ-файлах заполнены RVA. RVA ― это смещение данного элемента по отношению к адресу, с которого начинается отображение РЕ-файла в памяти. Допустим, загрузчик Windows отобразил РЕ-файл в виртуальное адресное пространство, начиная с адреса 400000h (базовый адрес РЕ-файла) и, допустим, некая таблица в отображении РЕ-файла начинается с адреса 401464h (виртуальный адрес таблицы (VA - Virtual Address)), тогда RVA данной таблицы равно 1464h:

    401464h(виртуальный адрес(VA)) - 400000h(базовый адрес) = 1464h(RVA)​
    Чтобы перевести RVA в виртуальный адрес, прибавьте RVA к базовому адресу.
    1. Классический импорт по именам
    2. Классический импорт по ординалам
    3. Отложенный импорт
    4. Импорт с привязкой к DLL (старый стиль)
    5. Импорт с привязкой (новый стиль)

    Классический импорт по именам

    Теория

    Секция импорта содержит названия dll-файлов, имена функции, имена глобальных переменных и имена ресурсов импортируемых из dll-файлов, в виде ASCIIZ-строк.
    Ключевым элементом этой секции является Import Directory Table (массив импорта) представляющий из себя массив 20-ти байтовых элементов Import Directory Entry (входы в таблицу импорта) типа IMAGE_IMPORT_DESCRIPTOR. Самый последний элемент Import Directory Entry заполнен нулями и сигнализирует о конце массива Import Directory Table.
    [​IMG]
    Одному элементу Import Directory Entry соответствует одна DLL. Но одна DLL может соответствовать нескольким элементам Import Directory Entry.
    структура IMAGE_IMPORT_DESCRIPTOR
    Код (ASM):
    1. IMAGE_IMPORT_DESCRIPTOR    STRUCT
    2.     OriginalFirstThunk      DD   ? ;В этом поле содержится смещение (RVA) массива
    3. ;двойных слов. Каждое из этих двойных слов - объединение типа IMAGE_THUNK_DATA.
    4. ;Каждое двойное слово IMAGE_THUNK_DATA соответствует одной функции, импортируемой
    5. ;данным файлом. Массив _IMAGE_THUNK_DATA32 называется Import Lookup Table
    6. ;Каждый элемент Import Lookup Table содержит RVA на структуру _IMAGE_IMPORT_BY_NAME.
    7. ;Этот массив в процессе загрузки программы не изменяется и может совсем не использоваться
    8.     TimeDateStamp           DD   0
    9.     ForwarderChaine         DD   0
    10.     ModName                 DD   ? ;RVA строки символов ASCII, оканчивающейся
    11. ;нулем и содержащей имя импортируемой DLL (например, KERNEL32.DLL или USER32.DLL)
    12.     FirstThunk              DD   ? ;RVA массива _IMAGE_THUNK_DATA32, называемого
    13. ;Import Address Table. До загрузки программы идентичен Import Lookup Table, после
    14. ;загрузки элементы массива содержат проекцию адресов функций
    15. IMAGE_IMPORT_DESCRIPTOR ends
    Import Lookup Table и Import Address Table ― массивы 8-ми байтовых элементов типа IMAGE_THUNK_DATA. Первые 4 байта элемента IMAGE_THUNK_DATA содержат RVA структуры _IMAGE_IMPORT_BY_NAME, вторые 4 байта равны нулю.
    структура IMAGE_IMPORT_BY_NAME
    Код (ASM):
    1. IMAGE_IMPORT_BY_NAME STRUCT
    2. Hint DW   ? ;индекс строки с именем импортируемой функции в DLL
    3. ;если индексируемое имя не совпадает с Name_ - выполняется поиск строки по всей
    4. ;Export Name Pointer Table
    5. Name_        DB ? DUP(?),0;название импортированной функции, ASCIIZ-строка
    6. Pad          DB ($ and 1) DUP(0);длинна строки выравнивается до четной границы
    7. ;еще одним 0
    8. IMAGE_IMPORT_BY_NAME ends
    структура _IMAGE_IMPORT_BY_NAME состоит из 2-байтового числа (Hint), за которым следует имя функции. Так как количество элементов типа IMAGE_THUNK_DATA находящихся в одной DLL нигде явно не указывается, поэтому последний элемент IMAGE_THUNK_DATA является нулевым.

    Import Directory Table, Import Address Table,
    Hint/Name Table, DLL Name Table

    [​IMG]
    Import Table и Orignal First Thunk
    [​IMG]
    Import Table после переписывания
    PE-загрузчиком

    [​IMG]
    Загрузчик заполняет соответствующую таблице функций таблицу адресов после загрузки в адресное пространство исполняемого файла всех необходимых библиотек. Происходит вызов LoadLibrary для каждой требуемой библиотеки, а затем вызов GetProcAddress для каждой импортируемой функции. Самый простой и часто использующийся, но самый медленный способ импортирования функций.

    Практика


    Минимальный компилируемый пример, содержащий суть проблемы состоит только из вызова функции MessageBoxA. Минимизация проблемы позволяет исключить все ТО лишнее, эффект ЧЕГО в противном случае пришлось бы учитывать.
    Код (ASM):
    1. ; GUI #
    2. include win64a.inc
    3. .code
    4. MsgBoxText      db "Win64 Assembly is Great!",0
    5. MsgCaption      db "import by name",0
    6. WinMain proc
    7.     push rbp
    8.     mov edx,offset MsgBoxText
    9.     lea r8,[rdx+sizeof MsgBoxText]
    10.     invoke MessageBox,NULL,,,MB_OK
    11.     pop rbp
    12.     ret
    13. WinMain endp
    14. end
    собирается при помощи следующего bat-файла
    Код (Text):
    1. ::стираем с экрана
    2. cls
    3. ::путь к masm64 на диске
    4. set masm64_path=\masm59\
    5. ::передаем bat-файлу название обрабатываемого asm-файла
    6. set filename=%~n1
    7. ::удаляем ненужные файлы
    8. if exist %filename%.exe del %filename%.exe
    9. if exist %filename%.obj del %filename%.obj
    10. if exist errors.txt del errors.txt
    11. ::компиляция программы
    12. %masm64_path%bin\ml64 /Cp /c /I"%masm64_path%Include" %filename%.asm >> errors.txt
    13. ::если компиляция прошла неудачно, тогда в файле errors.txt содержатся найденные ошибки
    14. ::выход из программы
    15. if errorlevel 1 exit
    16. ::линковка программы
    17. %masm64_path%bin\link /SUBSYSTEM:WINDOWS /LIBPATH:"%masm64_path%Lib" ^
    18. /LARGEADDRESSAWARE:NO /BASE:0x400000 /STUB:%masm64_path%bin\stubby.exe ^
    19. /SECTION:.text,W /ALIGN:16 /entry:WinMain /MERGE:.rdata=.text ^
    20. /fixed  /nocoffgrpinfo %filename%.obj >> errors.txt
    21. ::если линковка прошла неудачно, тогда в файле errors.txt содержатся найденные ошибки
    22. ::выход из программы
    23. if errorlevel 1 exit
    24. ::удаляем программный мусор
    25. del %filename%.obj
    26. del errors.txt
    компилируем, получаем приложение в 624 байта, запускаем
    [​IMG]
    Загружаем получившийся exe-файл в hiew32.exe, F4 (mode), Select modeDecode, F8(Header), F10(dir)
    видим расположение таблиц отвечающих за импорт
    [​IMG]
    Esc, F8, F7(Import)
    видно:
    1. hint импортируемой функции (482),
    2. ее название (MessageBoxA)
    3. имя dll откуда функция была импортирована (user32.dll)
    [​IMG]
    нажали на Enter и перешли к тому месту в программе, где происходит вызов MessageBoxA
    [​IMG]
    F3(Edit)
    [​IMG]
    видно, что для вызова функции MessageBox происходит обращение к ячейке памяти с адресом 1C0h
     

    Вложения:

    • 2_5.gif
      2_5.gif
      Размер файла:
      4,2 КБ
      Просмотров:
      2.633
    • import_table_1_0.gif
      import_table_1_0.gif
      Размер файла:
      7,2 КБ
      Просмотров:
      2.450
    • import_table_2.gif
      import_table_2.gif
      Размер файла:
      2,3 КБ
      Просмотров:
      2.471
    • import_table_3.gif
      import_table_3.gif
      Размер файла:
      1,4 КБ
      Просмотров:
      2.444
    • 05.png
      05.png
      Размер файла:
      18,3 КБ
      Просмотров:
      2.500
    • 06.png
      06.png
      Размер файла:
      50,8 КБ
      Просмотров:
      2.547
    • 07.png
      07.png
      Размер файла:
      27,3 КБ
      Просмотров:
      2.503
    • 08.png
      08.png
      Размер файла:
      32,9 КБ
      Просмотров:
      2.531
    • 09.png
      09.png
      Размер файла:
      28,4 КБ
      Просмотров:
      2.479
    • 10.png
      10.png
      Размер файла:
      22,9 КБ
      Просмотров:
      2.411
    • 11.png
      11.png
      Размер файла:
      33,5 КБ
      Просмотров:
      2.446
    • 12.png
      12.png
      Размер файла:
      30,6 КБ
      Просмотров:
      2.423
    • 13.png
      13.png
      Размер файла:
      55,4 КБ
      Просмотров:
      2.449
    • hoodfig02.gif
      hoodfig02.gif
      Размер файла:
      10,1 КБ
      Просмотров:
      2.493
    • hoodfig03.gif
      hoodfig03.gif
      Размер файла:
      14,2 КБ
      Просмотров:
      2.514
    • 14.png
      14.png
      Размер файла:
      16,6 КБ
      Просмотров:
      2.399
    • 15.png
      15.png
      Размер файла:
      70,3 КБ
      Просмотров:
      2.409
    • 16.png
      16.png
      Размер файла:
      43,3 КБ
      Просмотров:
      2.401
    • 21.png
      21.png
      Размер файла:
      34,1 КБ
      Просмотров:
      2.425
    • 22.png
      22.png
      Размер файла:
      32,4 КБ
      Просмотров:
      2.344
    • 23.png
      23.png
      Размер файла:
      39,2 КБ
      Просмотров:
      2.356
    • 17.png
      17.png
      Размер файла:
      77,9 КБ
      Просмотров:
      2.431
    • 09.png
      09.png
      Размер файла:
      28,4 КБ
      Просмотров:
      2.393
    Последнее редактирование: 21 окт 2019
    Pavia и kero нравится это.
  2. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.709
    01C0:48 02 00 0000 00 00 0000 00 00 0000 00 00 00H☻
    .....
    0210: 38 02 00 0000 00 00 0000 00 00 0056 02 00 008☻ ______ V☻
    0220: C0 01 00 0000 00 00 0000 00 00 0000 00 00 00└☺
    0230: 00 00 00 0000 00 00 0048 02 00 0000 00 00 00______ H☻
    0240: 00 00 00 0000 00 00 00E2 01 4D 6573 73 61 67______ т☺Messag
    0250: 65 42 6F 7841 00 75 7365 72 33 322E 64 6C 6CeBoxA user32.dll
    0260: 00 00 00 0000 00 00 0000 00 00 0000 00 00 00

    Объединяем наши теоретические знания с тем, что нам показывает hiew32
    First Trunck
    01C0:dq 248h ;RVA на имя функции
    01C8:dq 0 ;NULL конец таблицы Import Address Table
    Import Directory Entry 1
    0210:dd 238h ;RVA Ordinal First Trunck = 0238h
    dd 0 ;TimeDateStump = 0
    dd 0 ;ForwarderChain = 0
    dd 256h ;RVA DLL Name = 0256h
    dd 1C0h ;RVA First Trunck = 01C0h
    Import Directory Entry 2
    0224:dd 0,0,0,0,0;все поля NULL
    Ordinal First Trunck
    0238:dq 248h ;RVA на имя функции
    0240:dq 0 ;NULL конец таблицы Import Lookup Table
    0248:db 0E2h,1,"MessageBoxA",0
    Import DLL Name
    0256:db "user32.dll",16 dup(0)

    Мэтт Питрек в "Форматы РЕ и COFF объектных файлов" пишет "Для пользователей Borland есть некоторая дополнительная тонкость в этом описании. В РЕ-файле, созданном TLINK32, отсутствует один из массивов. В таких файлах содержимое поля Characteristics в IMAGE_IMPORT_DESCRIPTOR (то есть ссылка на массив Name/hint) равно нулю (очевидно, загрузчики Win32 не нуждаются в этом массиве). Таким образом, во всех РЕ-файлах вообще обязан быть только массив, на который указывает поле FirstThunk (массив адресов импорта)."
    Попробуем и мы обнулить адрес таблицы Import Lookup Table.0210: 0,0,0,256h,1C0h
    Программа нормально запускается
    Если указатель нулевой ― обнуляем содержимое таблицы Import Lookup Table
    01C0: dq 248h,0
    ...
    0210:dd 0,0,0,256h,1C0h
    0224:dd 0,0,0,0,0
    0238:dq 0,0
    0248:db 0E2,1,"MessageBoxA",0
    0256:db "user32.dll",16 dup(0)

    Программа нормально запускается
    сдвигаем на освободившееся место название функции и DLL и исправляем адреса ссылок на имя функции и имя DLL
    01C0: dq 238h,0
    ...
    0210: dd 0,0,0,246h,1C0h
    0224: dd 0,0,0,0,0
    0238: db 0E2h,1,"MessageBoxA",0
    0246:db "user32.dll",16 dup(0)

    Программа нормально запускается
    TLINK32 фирмы Borland обнуляет значение hint и ничего, файлы работают
    1. обнуляем hint ― программа нормально запускается
    2. удаляем 16 завершающих нулей ― программа нормально запускается
    3. удаляем ".dll" ― программа нормально запускается
    Наша модифицированная программа всё больше становится похожей на танк, которому оторвало башню, но он, несмотря ни на что, движется вперед :)
    00.jpg
    01C0: dq 236h,0
    ...
    0210: dd 0,0,0,244h,1C0h
    0224: dd 0,0,0,0,0
    0238: db "MessageBoxA",0
    0244: db "user32"

    сдвигаем на 2 освободившихся байта названия функции и DLL ― программа нормально запускается
    Везде пишут Самый последний вход в таблицу импорта заполнен нулями и сигнализирует о конце массива. Но действительно ли должны быть заполнены нулями ВСЕ 20 байт? После недолгих экспериментов становится понятно, что нулевыми достаточно оставить только первый и последний 4-х байтовый элемент
    01C0: dq 236h,0
    ...
    0210: dd 0,0,0,244h,1C0h
    0224: dd 0,01234567h,89ABCDEFh,0FEDCBA98h,0
    0238: db "MessageBoxA",0
    0244: db "user32"

    программа нормально запускается. 12 свободных байт соответствуют числу символов в имени функции "MessageBoxA" и терминирующему строку нулю
    01C0:dq 226h, 0
    ...
    0210:dd 0,0,0,238h, 1C0h
    0224:dd 0
    0228:db "MessageBoxA", 0
    0234:dd 0
    0238:db "user32"
    получаем приложение в 574 байта
    обратите внимание таблица Import Address Table заканчивается на 3 нулевых элемента, а Import Directory Entry 1 также начинается на 3 нулевых элемента, нельзя ли их совместить? Правим
    • адрес начала кода Entry point [0B8]=1F8h → 1E8h
    • адрес импорта [120h]=210 → 204h
    • адрес таблицы импорта [178h]=1C0h → 200h
    • сдвигаем код и данные на 16 байт
    • адрес функции call [1C0h] → call [200h]
    • адрес начала строки заголовка mov edx,4001D0h → mov edx,4001C0h
    0200: dd 21Ah,0,0,0
    0210: dd 22Ch,200h,0
    021C: db "MessageBoxA",0
    0228: dd 0
    022C: db "user32"

    получаем приложение в 562 байта

    Классический импорт по ординалам

    Теория

    При программировании в 16-разрядных Windows, каждой импортируемой через DLL функции присваивался номер (ординал). Если программист не указывал для импортируемой функции номер, то этот номер назначал компоновщик. При программировании и в 16-разрядных, и в 32-разрядных Windows, автоматически присваиваемые ординалы могли различаться в разных сборках DLL. В 16-битных Windows импорт по имени не поощрялся (по соображениям производительности), и в результате каждой экспортируемой функции явно присваивался номер, что и было предпочтительным способом связывания функций. В Windows 32-64 именованный импорт является нормой, а явное присваивание номеров функций ушло в прошлое. Так как номера в таблице экспорта не были фиксированы.
     
    Последнее редактирование: 21 окт 2019
    Коцит, Pavia и kero нравится это.
  3. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.709
    Многие библиотеки DLL Windows экспортируют порядковые номера для поддержки устаревшего кода. В 16-разрядном коде Windows часто использовались порядковые номера, так как это позволяло уменьшить размер DLL. Сейчас MicroSoft не рекомендует экспортировать функции по порядковым номерам, если это не требуется для поддержки устаревшего кода. Файл LIB будет содержать сопоставление между порядковым номером, именем и адресом размещения в памяти функции, что позволяет использовать имя функции, как обычно в проектах, использующих DLL.

    Одному элементу таблицы соответствует одна DLL. В первом ее 4-х байтовом элементе указан ординал этой функции, во втором 4-х байтовом элементе будет любое отрицательное число (старший бит равен 1). Список заканчивается 8-ми байтовым нулевым элементом.
    Практика
    ищем ординал, который указан в user32.dll для функции MessageBoxA
    Код (Text):
    1. %masm64_path%\bin\dumpbin.exe /EXPORTS %windir%\system32\user32.dll /OUT:user32.txt
    в файле user32.txt находим строку
    Код (Text):
    1. ordinal hint RVA      name
    2.  ....
    3. 2043  212 000712B8 MessageBoxA
    создаем файл MyFunc.def со следующим содержимым
    Код (Text):
    1. LIBRARY "user32.dll"
    2. EXPORTS
    3. MyMessageBox @2043 NONAME
    1. Выдуманное вами имя функции
    2. @ordinal позволяет указать, что номер, а не имя функции попадет в таблицу экспорта библиотеки DLL.
    3. Дополнительное ключевое слово NONAME позволяет экспортировать только порядковый номер и сократить размер таблицы экспорта в DLL.
    На основе файла MyFunc.def создаем MyFunc.lib при помощи lib.exe
    Код (Text):
    1. %masm64_path%\bin\lib /DEF:MyFunc.def /OUT:MyFunc.lib /MACHINE:X64
    или, если нет файла lib.exe, используем link.exe с ключом -lib
    Код (Text):
    1. %masm64_path%\bin\link -lib /DEF:MyFunc.def /OUT:MyFunc.lib /MACHINE:X64
    создаем файл MyFunc.inc со следующим содержимым
    Код (Text):
    1. extern __imp_MyMessageBox:qword
    2. MyMessageBox TEXTEQU <__imp_MyMessageBox>
    добавляем в asm-файл строки includelib MyFunc.lib и include MyFunc.inc
    Код (ASM):
    1. include win64a.inc
    2. includelib MyFunc.lib
    3. include MyFunc.inc
    4. .code
    5. MsgBoxText      db "Win64 Assembly is Great!",0
    6. MsgCaption      db "import by ordinal",0
    7. WinMain proc
    8.     push rbp
    9.     mov edx,offset MsgBoxText
    10.     lea r8,[rdx+sizeof MsgBoxText]
    11.     invoke MyMessageBox,NULL,,,MB_OK
    12.     pop rbp
    13.     ret
    14. WinMain endp
    15. end
    компилируем, получаем приложение в 592 байта, запускаем hiew32
    F4 (Mode), Select mode Decode, F8 (Header), F7 (Import)
    [​IMG]
    Enter
    [​IMG]
    F3(Edit)
    [​IMG]
    F9(Update), F8(Header), F10(Dir)
    [​IMG]
    004001B0:FB 07 00 0000 00 00 8000 00 00 0000 00 00 00√●____А
    ......
    .00400200:30 02 00 0000 00 00 0000 00 00 00____0☻
    .00400210:40 02 00 00B0 01 00 0000 00 00 0000 00 00 00 @☻
    .00400220:00 00 00 0000 00 00 0000 00 00 0000 00 00 00
    .00400230: FB 07 00 0000 00 00 8000 00 00 0000 00 00 00√●____А
    .00400240: 75 73 65 7233 32 2E 646C 6C 00 0000 00 00 00 user32.dll_____
    First Trunck
    01B0: dd 7FBh,80000000h;ординал функции
    01C8: dd 0,0 ;NULL конец таблицы Import Address Table
    Import Directory Entry 1
    0204: dd 230h ;RVA Ordinal First Trunck = 0230h
    dd 0 ;TimeDateStump = 0
    dd 0 ;ForwarderChain = 0
    dd 240h ;RVA DLL Name = 0240h
    dd 1B0h ;RVA First Trunck = 01B0h
    Import Directory Entry 2
    0224: dd 0,0,0,0,0;все поля NULL
    Ordinal First Trunck
    0230: dd 7FBh,80000000h;ординал функции
    0238: dd 0,0 ;NULL конец таблицы Import Lookup Table
    Import DLL Name
    0240: db "user32.dll",6 dup(0)

    используем одну таблицу вместо двух, удаляем ".dll" и терминирующие нули из названия библиотеки
     
    Последнее редактирование: 21 окт 2019
    kero нравится это.
  4. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.709
    .004001B0: FB 07 00 0000 00 00 8000 00 00 0000 00 00 00√●_____А
    ....
    .00400200:B0 01 00 0000 00 00 0000 00 00 00_____░☺
    .00400210:40 02 00 00B0 01 00 0000 00 00 0075 73 65 72@☻__░☺____user
    .00400220: 33 32 32

    компилируем, получаем приложение в 546 байта, запускаем.
    Отложенный импорт

    Теория

    Исполняемые файлы, которые используют отложенный импорт, неявно ссылаются на DLL, указанную после опции /DELAYLOAD. Основная идея заключается в перенаправлении элементов таблицы импорта на специальный обработчик, динамически загружающий соответствующие DLL по мере необходимости вызова функций из этих DLL. Этот обработчик подставляет адреса этих функций в таблицу импорта.
    Очевидным преимуществом использования отложенного импорта является сокращение времени загрузки и инициализации DLL. Предположим, ваша программа вызывает достаточно редко какие-то функции из какой-то DLL. Если вы используете отложенный импорт для такой DLL ― вы сократите время работы загрузчика. Если функции из такой DLL по каким-то условиям за время работы программы не будут вызываться совсем, то загрузка такой DLL так и не произойдет.
    При использовании отложенного импорта компоновщик фактически генерирует небольшие кодовые заглушки и вставляет их вместе с кодом, генерируемым компилятором.
    Когда вы вызываете функцию, исполняемый файл неявно ссылается на DLL. Создает данные, описывающие имя функции и DLL, а затем делает переход к небольшой заглушке. При первом вызове заглушки он использует данные для вызова LoadLibrary и GetProcAddress. Адрес, возвращаемый GetProcAddress, сохраняется в заглушке, поэтому следующие вызовы идут напрямую к функции минуя заглушку.
    В коде заглушки можно также найти GetLastError, RaiseException, FreeLibrary и LocalAlloc функции.
    При использовании отложенного импорта компоновщик создает псевдо таблицу адресов импорта (IAT) и псевдотаблицу имен импорта (INT) для каждой DLL, которая использует отложенный импорт. Для каждой из библиотек DLL есть одна IAT и INT.
    Каждая запись IAT и INT представляет одну импортированную функцию в этой DLL.
    Структуры данных IAT и INT такиже какие используются при обычном импорте.
    Операционная система не знает о том, что у исполняемого файла есть дополнительные таблицы псевдоимпорта. Выбор хранить таблицы отложенного импорта в том же формате, что и обычный импорт, исключительно удобен для компоновщика и функции __delayLoadHelper.
    Кроме функций LoadLibrary и GetProcAddress, остальная часть кода манипулирует псевдотаблицами IAT и INT. Цель ― оптимизировать последующие вызовы функций. При первом вызове функции, запись в IAT для функции указывает на созданный компоновщиком код. После успешного завершения заглушки запись IAT указывает непосредственно на целевую функцию (Рисунок 1). Другой способ представить это выглядит так ― внутри вашего исполняемого файла загруженная при помощи отложенного импорта DLL имеет псевдотаблицу IAT с записями, в которых записаны адреса функций загруженные в память.
    Использование таблицы адресов псевдоимпорта
    [​IMG]
    Параметр dliNotify является одним из перечислений dliXXX, указанных в DELAYIMP.H. Параметр pdli является указателем на структуру DelayLoadInfo, которая также объявлена в файле DELAYIMP.H. Структура DelayLoadInfo содержит все, что вам нужно знать об этой конкретной функции, включая ее имя и имя DLL из которой она вызывается. Структура DelayLoadInfo строится «на лету» в функции __delayLoadHelper. Когда вы используете отложенный импорт для данной DLL, компоновщик создает два разных типа заглушек:
    • Первым тип это заглушка «per-API». Компоновщик создает по одной такой заглушке для каждой функции, вызываемой из DLL-файла. Компоновщик присваивает имя в форме __imp_load_XXX, где XXX является именем функции. Например, заглушка для вызова MessageBoxA выглядит так:
    Код (ASM):
    1. __imp__load_MessageBoxA:
    2. 400297: mov [rsp+8],rcx
    3. 40029C: mov [rsp+10],rdx
    4. 4002A1: mov [rsp+18],r8
    5. 4002A6: mov [rsp+20],r9
    6. 4002AB: sub rsp,68
    7. 4002AF: movdqa [rsp+20],xmm0
    8. 4002B5: movdqa [rsp+30],xmm1
    9. 4002BB: movdqa [rsp+40],xmm2
    10. 4002C1: movdqa [rsp+50],xmm3
    11. 4002C7: mov rdx,rax; rdx=offset MessageBoxA
    12. ; jmp __tailMerge_USER32; так как у нас только одна функция поэтому jmp отсутствует
    13. __tailMerge_USER32:
    14. 4002CA: lea rcx,[40064C];offset DELAY_IMPORT_DESCRIPTOR_USER32
    15. 4002D1: call __delayLoadHelper ;call 40031C
    16. 4002D6: movdqa xmm0,[rsp+20]
    17. 4002DC: movdqa xmm1,[rsp+30]
    18. 4002E2: movdqa xmm2,[rsp+40]
    19. 4002E8: movdqa xmm3,[rsp+50]
    20. 4002EE: mov rcx,[rsp+70]
    21. 4002F3: mov rdx [rsp+78]
    22. 4002F8: mov r8,[rsp+80]
    23. 400300: mov r9,[rsp+88]
    24. 400308: add rsp,68
    25. 40030A: jmp rax
    Первые восемь команд
    Код (ASM):
    1.        sub rsp,68
    2.        mov [rsp+70],rcx
    3.        mov [rsp+78],rdx
    4.        mov [rsp+80],r8
    5.        mov [rsp+88],r9
    6.        movdqa [rsp+20],xmm0
    7.        movdqa [rsp+30],xmm1
    8.        movdqa [rsp+40],xmm2
    9.        movdqa [rsp+50],xmm3
    сохраняют значения изменяемых в функции регистров rcx, rdx, r8, r9 и xmm0-xmm3 в стеке. Команда mov rdx,rax передает через второй параметр в функцию адрес псевдо-IAT-записи для функции MessageBoxA. Код __delayLoadHelper, исправляет псевдо-IAT-запись перед возвратом. Когда импорт с задержкой вызывается в первый раз, запись псевдо-IAT указывает на эту заглушку для каждой функции. В первый раз управление передается на эту заглушку, а не на реальную функцию MessageBoxA. Последующие вызовы функции MessageBoxA будут передаваться функции MessageBoxA. Первый параметр указывает на второй тип сгенерированного линкером заглушки («per-DLL»). Таким образом, независимо от того, для скольких функций вы создаете отложенный импорт из USER32.DLL, всегда будет только одна заглушка USER32.DLL. Компоновщик называет эти заглушки __tailMerge_XXX, где XXX ― это имя DLL. Например, заглушка для USER32 выглядит так:
    Код (ASM):
    1. __tailMerge_USER32:
    2.        lea rcx,__DELAY_IMPORT_DESCRIPTOR_USER32
    3.        CALL  ___delayLoadHelper
    4.        movdqa xmm0,[rsp+20]
    5.        movdqa xmm1,[rsp+30]
    6.        movdqa xmm2,[rsp+40]
    7.        movdqa xmm3,[rsp+50]
    8.        mov rcx,[rsp+70]
    9.        mov rdx [rsp+78]
    10.        mov r8,[rsp+80]
    11.        mov r9,[rsp+88]
    12.        add rsp,68
    13.        jmp rax
    Первая команда заглушки для каждой DLL помещает адрес структуры данных, которую компоновщик включил в другом месте исполняемого файла. Эта структура имеет тип ImgDelayDescr, определенный в DELAYIMP.H. Структура ImgDelayDescr содержит указатели на имя DLL, указатели на псевдо-IAT и INT библиотеки DLL и другие элементы, необходимые функции __delayLoadHelper. Это структура данных, на которую указывает слот IMAGE_DIRECTORY_ENTRY_DELAY_ IMPORT в DataDirectory исполняемого файла.
    Все значения указателей в ImgDelayDescr являются виртуальными адресами (то есть нормальными линейными адресами, которые могут использоваться в качестве указателей).
    Следующая инструкция заглушки для DLL делает фактический вызов __delayLoadHelper. Функция __delayLoadHelper возвращает адрес функции в регистре RAX. Следующие инструкции восстанавливают содержимое регистров rcx, rdx, r8, r9 и xmm0-xmm3, которые были помещены в стек заглушкой per-API. Последния команда делает косвенный переход на адрес, который находится в регистре RAX (то есть, значение, возвращаемое функцией __delayLoadHelper). Так как __delayLoadHelper исправил псевдо-IAT-запись, заготовка для каждой импортируемой функции выполняется только один раз. Последующие вызовы проходят псевдо-IAT непосредственно к функции. Аналогично, для каждого DLL-заглушки выполняется только один раз для каждой функции, загруженного через отложенный импорт.
    [​IMG]
     
    Pavia, shufps и kero нравится это.
  5. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.709
    структура ImgDelayDescr
    Код (ASM):
    1. ImgDelayDescr struct
    2. grAttrs dd ?;задает тип адресации, применяющийся в служебных
    3. ;структурах отложенного импорта (0 – VA, 1 – RVA)
    4. szName dd ?;содержит RVA/VA-указатель на ASCIIZ-строку с именем загружаемой DLL
    5. phmod dd ?;в это поле загрузчик DelayHelper помещает дескриптор динамически загружаемой DLL.
    6. pIAT dd ?;содержит указатель на таблицу адресов отложенного импорта, организованную точно
    7. ;так же, как и обычная IAT, с той разницей, что все элементы таблицы отложенного импорта ведут к delayloadhelper'у
    8. ;специальному динамическому загрузчику, который вызывает LoadLibrary (если библиотека еще не была загружена),
    9. ;а затем вызывает GetProcAddress и замещает текущий элемент таблицы отложенного импорта эффективным адресом
    10. ;импортируемой функции, поэтому все последующие вызовы данной функции будут осуществляется в обход delayloadhelper'а.
    11. pINT dd ?;содержит RVA-указатель на таблицу имен, во всем повторяющую
    12. ;стандартную таблицу имен
    13. pBoundIAT dd ?;полю хранящее RVA-указатель на таблицу диапазонного импорта. Если таблица диапазонного
    14. ;импорта не пуста и указанная временная метка совпадает с временной меткой соответствующей DLL, системный загрузчик
    15. ;проецирует ее на адресное пространство данного процесса и механизм отложенного импорта дезактивируется.
    16. pUnloadIAT dd ?;При выгрузке DLL из памяти, DLL может восстановить таблицу отложенного импорта
    17. ;в исходное состояние, обратившись к ее оригинальной копии, RVA-указатель на которую хранится в поле pUnloadIAT.
    18. ;Если копии нет, тогда указатель на нее будет обращен в ноль
    19. dwTimeStamp dd ?;0 если нет привязки,
    20.    ;O.W. date/time stamp of DLL bound to Old BIND
    21. ImgDelayDescr ends
    Внутри Delay Load Directory Table есть стандартная таблица импорта, может выполняться привязка, то есть возникать Bound Delay Import Table, есть Unload Delay Import Table и т.п.

    Практика

    Код (ASM):
    1. ; GUI #
    2. include win64a.inc
    3. .code
    4. MsgBoxText      db "Win64 Assembly is Great!",0
    5. MsgCaption      db "delay import",0
    6. WinMain proc
    7.        push rbp
    8.        mov edx,offset MsgBoxText
    9.        lea r8,[rdx+sizeof MsgBoxText]
    10.        invoke MessageBox,NULL,,,MB_OK
    11.        pop rbp
    12.        ret
    13. WinMain endp
    14. end
    собирается при помощи следующего bat-файла
    Код (Text):
    1. cls
    2. set masm64_path=\masm59\
    3. set filename=%~n1
    4. %masm64_path%bin\ml64 /Cp /c /I"%masm64_path%Include" %filename%.asm >> errors.txt
    5. %masm64_path%bin\link /SUBSYSTEM:WINDOWS /LIBPATH:"%masm64_path%Lib" ^
    6. /LARGEADDRESSAWARE:NO /BASE:0x400000 /STUB:%masm64_path%bin\stubby.exe ^
    7. /SECTION:.text,W /ALIGN:16 /entry:WinMain /MERGE:.rdata=.text ^
    8. /fixed /DELAYLOAD:user32.dll %filename%.obj >> errors.txt
    9. if errorlevel 1 exit
    10. del %filename%.obj
    11. del errors.txt
    компилируем, получаем приложение в 1952 байта, запускаем
    [​IMG]
    без ключа /DELAYLOAD:user32.dll было бы приложение в 624 байта, то есть добавилась заглушка в 1952-624=1328 байт.
    Загружаем получившийся exe-файл в hiew32.exe, F4 (mode), Select mode→Decode, F8(Header), F10(dir) видим расположение таблиц отвечающих за импорт
    [​IMG]
    Видно, что используется Import, Exeption, Import Table, Delay Import
    [​IMG]
    к импортируемой функции MessageBoxA из user32.dll добавились функции RaiseExeption, LocalAlloc, LoadLibraryA, GetProcAddress, GetLastError и FreeLibrary из kernel32.dll
    [​IMG]
    F3 (Edit)
    [​IMG]
    видно, что адрес функции «MessageBoxA» находится в ячейке с RVA 0750h
    [​IMG]
    [0750h]=00400316h, по адресу 00400316h в регистр rax передается адрес строки с названием функции «MessageBoxA» и происходит переход на адрес 40029Dh, где произойдет:
    • вызов кода заглушки «per-API»
    • после сохранения содержимого регистров rcx, rdx, r8, r9, xmm0-xmm3
    • передачи в rcx адреса DELAY_IMPORT_DESCRIPTOR_USER32, а в rdx адреса имени «MessageBoxA»
    • вызов функции delayLoadHelper (call 400324h)
    [​IMG]
    Import RVA=678h Size 28h обратите внимание, что здесь только функции из kernel32.dll
    First Trunck
    0210: dq 726h ;RVA "RaiseException"
    0218: dq 718h ;RVA "LocalAlloc"
    0220: dq 708h ;RVA "LoadLibraryA"
    0228: dq 6F6h ;RVA "GetProcAddress"
    0230: dq 6E6h ;RVA "GetLastError"
    0238: dq 6D8h ;RVA "FreeLibrary"
    0240: dq 0 ;NULL конец таблицы Import Address Table
    Import Directory Entry 1
    0678: dd 6A0h ;RVA Ordinal First Trunck = 06A0h
    dd 0 ;TimeDateStump = 0
    dd 0 ;ForwarderChain = 0
    dd 738h ;RVA DLL Name = 0738h
    dd 210h ;RVA First Trunck = 0210h
    Import Directory Entry 2
    0224: dd 0,0,0,0,0;все поля NULL
    Ordinal First Trunck
    06A0: dq 726h ;RVA "RaiseException"
    06A8: dq 718h ;RVA "LocalAlloc"
    06B0: dq 708h ;RVA "LoadLibraryA"
    06B8: dq 6F6h ;RVA "GetProcAddress"
    06C0: dq 6E6h ;RVA "GetLastError"
    06C8: dq 6D8h ;RVA "FreeLibrary"
    06D0: dq 0 ;NULL конец таблицы Import Address Table
    Import DLL Name
    0738: db "kernel32.dll",12 dup(0)

    Exeption RVA=780h RVA=18
    780: dd 29Dh
    784: dd 314h
    788: dd 5E8h
    78C: dd 324h
    790: dd 5E6h
    794: dd 5F0h
    798: dd 0,0

    Delay Import RVA 608h Size 40h
    DELAY_IMPORT_DESCRIPTOR_USER32
    608: dd 1,250h,760h,750h,648h,668h,0,0
    628: dd 0, 0, 0, 0, 0, 0,0,0

    Код (ASM):
    1. ImgDelayDescr struct
    2. grAttrs dd 1;тип адресации=RVA
    3. szName dd 250h;"user32.dll" pointer to dll name
    4. phmod dd 760h; address of module handle
    5. pIAT dd 750h;400316h address of the IAT
    6. pINT dd 648h;658h address of the INT
    7. pBoundIAT dd 668h;0 address of the optional bound IAT
    8. pUnloadIAT dd 0; address of optional copy of original IAT
    9. dwTimeStamp dd 0;0 if not bound, O.W. date/time stamp of DLL bound to Old BIND
    10. ImgDelayDescr ends
     
    Pavia, shufps, kero и ещё 1-му нравится это.
  6. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.709
    Импорт с привязкой к DLL (bound import)
    Биндинг
    Этот механизм заключается в записи в файле на диске по определенным смещениям адресов импортируемых функций, что уменьшает время загрузки файла, если временной штамп идентифицирующий файл и временной штамп загружаемой dll совпадают. При наличии такого импорта, проверка на совпадение временного штампа осуществляется для каждой dll, и в зависимости от ее результатов применяется этот или другой механизм импорта. Запись адресов в файл осуществляется утилитой bind. С этим механизмом связана проблема форвардинга ― передачи экспорта, когда экспортирующая функцию библиотека не содержит самой функции, а отсылает к другой библиотеке, содержащей эту функцию, может быть под другим именем. Это делается для обеспечения совместимости приложений с различными версиями ОC Windows. Существует старый и новый стиль биндинга, отличающиеся тем, как они решают проблему форвардинга. И старый и новый стиль использует ту же директорию, что и стандартный механизм импорта. Но старый хранит в ней и информацию о форвардных функциях, а новый использует для этого директорию импорта с привязкой, адресуемую через элемент IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT таблицы директорий.
    Bound-импорт
    Bound или привязанный импорт используется при новом стиле биндинга, а также и как самостоятельный механизм. Он сходен с предыдущим механизмом, но также позволяет приводить адреса форвардных функций к адресам, расположенных в библиотеках, непосредственно эти функции экспортирующих. При данной схеме работы в поля TimeDateStamp=-1 и ForwardChain=-1 и информация о связывании хранится в ячейке DataDirectory с индексом IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (=11). То есть это своего рода сообщение загрузчику о том, что нужно использовать bound import. Так же для «цепочки bound импорта» фигурируют свои структуры. Алгоритм работы заключается в следующем ― в виртуальную память приложения выгружается необходимая библиотека и все необходимые адреса «биндятся» еще на этапе компиляции. Используется в Windows для стандартных исполняемых файлов (Calculator, Minesweeper, NotePad и так далее), так как Windows меняет стандартные библиотеки достаточно редко. Из недостатков ― при перекомпиляции dll, нужно будет перекомпилировать само приложение, так как адреса функций изменены и по старым адресам ничего уже нет.
    Теория
    Связанный импорт сводится к проецированию необходимых библиотек на адресное пространство процесса, с жесткой прошивкой экспортируемых адресов на стадии компиляции приложения.
    Импорт с привязкой (Bound import) ― это вид импорта, при котором предполагается, что для определенной версии модуля, содержащего импортируемую функцию, адрес функции известен к моменту компиляции. Это относится, главным образом, к системным библиотекам, которые загружаются в память всегда с одного и того же адреса для данной версии DLL. В таблицу импорта файла, импортирующего такую функцию, можно заранее, еще до загрузки модуля, записать предполагаемый адрес функции. Для обеспечения контроля версии модуля, к которому привязан данный, при осуществлении привязки создается дополнительная таблица информации о привязанных модулях, на которую ссылается поле ForwarderChain. В поле TimeDateStamp помещается отметка времени модуля, содержащего функцию (значение поля TimeDateStamp из PE-заголовка этого модуля).
    Существует «новый стиль» привязки ― TimeDateStamp = -1, а таблица информации о привязках доступна через элемент IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT каталога DataDirectory.
    При настройке таблицы импорта файла, импортирующего функции из некоторой DLL с привязкой, загрузчик первым делом сравниваетTimeDateStamp для каждого элемента таблицы импорта с временной отметкой (TimeDateStamp) DLL. Если они равны, то соответствующая этому элементу подтаблица вообще не нуждается в настройке, так как содержит верные адреса. В противном же случае адреса считаются устаревшими, и загрузчик перезаписывает основную подтаблицу (на которую указывает FirstThunk данного элемента), исходя из данных оригинальной подтаблицы (на которую ссылается OriginalFirstThunk).
    Со связанным импортом связана всего одна структура (элемент IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT DATA_DIRECTORYуказывает на массив таких структр, завершающийся нулевым элементом):
    Код (ASM):
    1. IMAGE_BOUND_IMPORT_DESCRIPTOR struct
    2.     TimeDateStamp            dd ?;временную метку DLL для bound импорта,
    3. ;и такой импорт будет осуществлен тогда, когда временные метки структуры и dll
    4. ;совпали, либо когда TimeDateStamp = 0
    5.         OffsetModuleName        dw ?;указатель на имя dll, отсчитываемый
    6. ;от начала массива структур [B]IMAGE_BOUND_IMPORT_DESCRIPTOR[/B]
    7.     NumberOfModuleForwarderRefs dw ?;указывает на количество форвардов,
    8. ;назначение этого поля не ясно (Array of zero or more IMAGE_BOUND_FORWARDER_REF follows
    9. IMAGE_BOUND_IMPORT_DESCRIPTOR ends
    Если временная отметка DLL соответствует временной отметке, прописанной в PE- заголовке, загрузчик проецирует адреса вызываемых функций на адресное пространство DLL.
    Практика
    Код (ASM):
    1. ; GUI #
    2. include win64a.inc
    3. .code
    4. MsgBoxText      db "Win64 Assembly is Great!",0
    5. MsgCaption      db "bind import",0
    6. WinMain proc
    7.     push rbp
    8.     mov edx,offset MsgBoxText
    9.     lea r8,[rdx+sizeof MsgBoxText]
    10.     invoke MessageBox,NULL,,,MB_OK
    11.     pop rbp
    12.     ret
    13. WinMain endp
    14. end
    собирается при помощи следующего bat-файла
    Код (Text):
    1. cls
    2. set masm64_path=\masm59\
    3. set filename=%~n1
    4. %masm64_path%bin\ml64 /Cp /c /I"%masm64_path%Include" %filename%.asm >> errors.txt
    5. %masm64_path%bin\link /SUBSYSTEM:WINDOWS /LIBPATH:"%masm64_path%Lib" ^
    6. /LARGEADDRESSAWARE:NO /BASE:0x400000 /STUB:%masm64_path%bin\stubby.exe ^
    7. /SECTION:.text,W /ALIGN:16 /entry:WinMain /MERGE:.rdata=.text ^
    8. /fixed  %filename%.obj >> errors.txt
    9. if errorlevel 1 exit
    10. %masm64_path%bin\bind -o -u %filename%.exe
    11. del %filename%.obj
    12. del errors.txt
    компилируем, получаем приложение в 624 байта
    напомню строку, которую мы выдернули при помощи утилиты dupmbin из user32.dll
    ordinalhintRVAname
    2043 212 000712B8 MessageBoxA
    78C20000h+712B8h=78C912B8h
    First Trunck
    1C0: dd 78C912B8h,0 ;адрес в памяти по которому расположена функция MessageBoxA
    1C8: dd 0,0 ;NULL конец таблицы Import Address Table
    Import Directory Entry 1
    20C: dd 238h ;RVA Ordinal First Trunck = 0238h
    210: dd 58E501ECh ;TimeDateStump = 5 апреля 2017 22:40:44 1491403244
    214: dd 0FFFFFFFFh ;ForwarderChain = -1
    218: dd 256h ;RVA DLL Name = 0256h
    21C: dd 1C0h ;RVA First Trunck = 01C0h
    Import Directory Entry 2
    220: dd 0,0,0,0,0;все поля NULL
    Ordinal First Trunck
    238: dd 248h,0 ;RVA имя функции
    240: dd 0,0 ;NULL конец таблицы Import Lookup Table
    248: db 0E2h,1,"MessageBoxA",0
    Import DLL Name
    256: db "user32.dll",16 dup(0)
     
    Последнее редактирование: 21 окт 2019
    Pavia, shufps и kero нравится это.
  7. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.709
    Код (Text):
    1. cls
    2. set masm64_path=\masm59\
    3. set filename=%~n1
    4. %masm64_path%bin\ml64 /Cp /c /I"%masm64_path%Include" %filename%.asm >> errors.txt
    5. %masm64_path%bin\link /SUBSYSTEM:WINDOWS /LIBPATH:"%masm64_path%Lib" ^
    6. /LARGEADDRESSAWARE:NO /BASE:0x400000 /STUB:%masm64_path%bin\stubby.exe ^
    7. /SECTION:.text,W /ALIGN:16 /entry:WinMain /MERGE:.rdata=.text ^
    8. /fixed  %filename%.obj >> errors.txt
    9. if errorlevel 1 exit
    10. %masm64_path%bin\bind -u %filename%.exe
    11. del %filename%.obj
    12. del errors.txt
    Код (Text):
    1. usage: BIND [switches] image-names...
    2. [-o] disable new import descriptors
    [​IMG]
    First Trunck
    1C0: dq 78C912B8h ;адрес в памяти по которому расположена функция MessageBoxA
    1C8: dq 0 ;NULL конец таблицы Import Address Table
    Import Directory Entry 1
    20C: dd 238h ;RVA Ordinal First Trunck = 0238h
    210: dd 0FFFFFFFFh ;TimeDateStump = -1
    214: dd 0FFFFFFFFh ;ForwarderChain = -1
    218: dd 256h ;RVA DLL Name = 0256h
    21C: dd 1C0h ;RVA First Trunck = 01C0h
    Import Directory Entry 2
    220: dd 0,0,0,0,0 ;все поля NULL
    Ordinal First Trunck
    238: dq 248h ;RVA имя функции
    240: dq 0 ;NULL конец таблицы Import Lookup Table
    248: db 0E2h,1,"MessageBoxA",0
    Import DLL Name
    256: db "user32.dll",16 dup(0)

    Использованная литература
    1. Мэтт Питрек "Форматы PE и COFF объектных файлов"
    2. Mett Pietrek "Under The Hood" Microsoft system journal 1998 Dec
    3. Volodya, NEOx "Об упаковщиках в последний раз: Часть первая - теоретическая"
    4. Kris Kaspersky "Путь воина – внедрение в pe/coff-файлы"
    5. dx "PE-формат. Часть 3 — Импорт"
     
    Pavia, shufps, kero и ещё 1-му нравится это.