Не могу оставить этот вопрос без ответа вот так. Поскольку, хотя замечание Младена в значительной степени подходит для этого конкретного нативного API, вся тема заслуживает подробного обсуждения.
Предварительное предупреждение
Вначале я должен отметить, что во многих случаях не желательно и не необходимо использовать одну из встроенных функций API в Windows . Однако есть несколько случаев, когда Win32 API не предоставляет средства для запроса информации или даже манипулирования данными и так далее. Одним из таких случаев будет несколько информационных классов, доступных для NtQueryInformationFile
/ ZwQueryInformationFile
.
Один хороший пример - перечисление альтернативных потоков данных в файлах и каталогах, что можно сделать с помощью Win32 API, в частности, с помощью API резервного копирования, но в этом случае потребуются специальные привилегии. Не так, если вы прибегаете к нативному API. То же самое было справедливо для жестких ссылок до Windows 2000, которая ввела CreateHardLink
в Win32 API. Хотя в данном конкретном случае, если бы вы знали свой путь, вы могли бы использовать MoveFileEx
с MOVEFILE_CREATE_HARDLINK
с момента его появления (хотя Microsoft до сих пор на момент написания этой статьи помечает его как Зарезервировано для использования в будущем ... meh).
Канонические книги о нативном API - это две:
... есть и другие, в том числе те, в которых обсуждается NT 4 и предшествующая книга Неббетта. Но книга Неббетта использовала шумиху вокруг родного API, так же, как книга Хоглунда начала шумиху вокруг руткитов Windows. Не справочник по теме Native API, но все же хорошо:
- Windows Internals, Марк Руссинович и др. и др.
Посетите этот веб-сайт для огромного количества «задокументированных» функций API:
Итак, помните: при использовании этих функций риск заключается в том, что они исчезнут в будущей версии Windows или их семантика изменится без предварительного уведомления. Так что будьте осторожны , когда вы используете их, , если вы используете их.
На славу ...
Как вызывать собственные функции API
На самом деле есть два способа вызвать эти функции. Несколько лет назад Microsoft была вынуждена раскрыть некоторые функции нативного API в одном из антимонопольных исков. Они были добавлены в winternl.h
SDK. Microsoft выражает это так:
Документация NtOpenFile
предоставляется для полного API
охват. NtOpenFile
эквивалентно функции ZwOpenFile
задокументировано в ДДК. Для получения дополнительной информации о ZwOpenFile
и
связанные функции, перейдите к http://msdn.microsoft.com/library. В
в левой панели выберите «Разработка Windows», затем нажмите «Драйвер»
Комплект разработчика.
Однако в SDK нет сопровождающего файла ntdll.lib
. Microsoft предлагает вам динамически связывать эти функции (второй вариант ниже).
У вас есть несколько вариантов:
- Самое распространенное - это делать как ты. Но библиотека импорта
ntdll.lib
является лишь частью WDK, а не DDK.
- Используйте
GetProcAddress
, чтобы найти указатель на функцию и вызвать его. GetModuleHandle
достаточно для подсистемы Win32, поскольку каждая программа Win32 гарантированно загрузила ntdll.dll
.
Метод 1: ntdll.lib
Если у вас есть DDK / WDK - для комплекта разработки драйверов и комплект драйверов для Windows соответственно - вы уже получите полный набор ntdll.lib
файлов. В моей системе (Windows 7 WDK 7600.16385.1):
C:\WINDDK\7600.16385.1\lib\win7\amd64\ntdll.lib
C:\WINDDK\7600.16385.1\lib\win7\i386\ntdll.lib
C:\WINDDK\7600.16385.1\lib\win7\ia64\ntdll.lib
C:\WINDDK\7600.16385.1\lib\wlh\amd64\ntdll.lib
C:\WINDDK\7600.16385.1\lib\wlh\i386\ntdll.lib
C:\WINDDK\7600.16385.1\lib\wlh\ia64\ntdll.lib
C:\WINDDK\7600.16385.1\lib\wnet\amd64\ntdll.lib
C:\WINDDK\7600.16385.1\lib\wnet\i386\ntdll.lib
C:\WINDDK\7600.16385.1\lib\wnet\ia64\ntdll.lib
C:\WINDDK\7600.16385.1\lib\wxp\i386\ntdll.lib
Создайте свой собственный импровизированный ntdll.lib
В противном случае вы должны сгенерировать ntdll.lib
самостоятельно из вывода dumpbin
(или с помощью других средств, которые позволяют анализировать экспорт DLL), которые затем можно вывести в файл определения модуля, из которого можно построитьэкспорт .lib
.Звучит запутанно?Не так уж много, давайте посмотрим;)
Используя модуль Ero Carrera pefile
Python , мы можем сделать это:
import os, re, sys
from os.path import basename, dirname, join, realpath
try:
import pefile
except ImportError:
try:
sys.path.append(join(realpath(dirname(__file__)), "pefile"))
import pefile
except:
raise
def main(pename):
from pefile import PE
print "Parsing %s" % pename
pe = PE(pename)
if not getattr(pe, "DIRECTORY_ENTRY_EXPORT", None):
return "ERROR: given file has no exports."
modname = basename(pename)
libname = re.sub(r"(?i)^.*?([^\\/]+)\.(?:dll|exe|sys|ocx)$", r"\1.lib", modname)
defname = libname.replace(".lib", ".def")
print "Writing module definition file %s for %s" % (defname, modname)
with open(defname, "w") as f: # want it to throw, no sophisticated error handling here
print >>f, "LIBRARY %s\n" % (modname)
print >>f, "EXPORTS"
numexp = 0
for exp in [x for x in pe.DIRECTORY_ENTRY_EXPORT.symbols if x.name]:
numexp += 1
print >>f, "\t%s" % (exp.name)
print "Wrote %s with %d exports" % (defname, numexp)
print "\n\nUse this to create the export lib:\n\tlib /def:%s /out:%s" % (defname, libname)
if __name__ == '__main__':
if len(sys.argv) != 2:
sys.exit("ERROR:\n\tSyntax: fakelib <dllfile>\n")
sys.exit(main(sys.argv[1]))
Пример выходных данных запуска этого скрипта(когда названо fakelib.py
) будет:
> fakelib.py ntdll.dll
Parsing ntdll.dll
Writing module definition file ntdll.def for ntdll.dll
Wrote ntdll.def with 1984 exports
Use this to create the export lib:
lib /def:ntdll.def /out:ntdll.lib
Затем мы запускаем команду, как указано в последней строке.Конечно, лучше указать параметр /machine:
.Это оставлено читателю как «упражнение» (* кашель * * кашель *).Выход с VS 2012 будет:
> lib /def:ntdll.def /out:ntdll.lib
Microsoft (R) Library Manager Version 11.00.51106.1
Copyright (C) Microsoft Corporation. All rights reserved.
LINK : warning LNK4068: /MACHINE not specified; defaulting to X86
Creating library ntdll.lib and object ntdll.exp
Поздравляем.Теперь вы можете использовать ntdll.lib
, созданный Microsoft lib.exe
, для статического импорта из ntdll.dll
, даже не имея «реального» (оригинального) .lib
в вашей системе.
Настройте путь иимена файлов в соответствии с вашими потребностями и вкусами.
При использовании MinGW
Damon указал в комментарии, что набор инструментов, включенный в MinGW, содержит инструмент gendef
, который может выполнятьзадание вышеприведенного скрипта Python и что выходные данные могут быть переданы в dlltool
.
Проблемы
Приведенный выше метод отлично работает при нацеливании на x64 (64-битный), но для x86 (32)-bit) Я иногда сталкивался с ошибками компоновщика.
Проблема в том, что оформление имени для __stdcall
отличается между x64 и x86.Первый действительно не использует тот же __stdcall
, что и x86, и поэтому просто добавляет подчеркивание.Тем не менее, последний также добавляет число аргументов умножить на sizeof(void*)
(то есть 4).Поэтому для одного аргумента оформленное имя функции для int __stdcall foo(int);
становится _foo@4
.
В этой статье базы знаний Майкрософт описан способ обойти эту проблему.
Метод 2: динамически импортируется с использованием GetProcAddress
Документация в состояниях MSDN (для NtOpenFile
):
Обратите внимание, что заголовочный файл DDK Ntdef.h
необходим для многихопределения констант, а также макрос InitializeObjectAttributes
.Связанная библиотека импорта, Ntdll.lib
, также доступна в DDK.Вы также можете использовать функции LoadLibrary
и GetProcAddress
для динамической ссылки на Ntdll.dll
.
Объявить тип функции, например, здесь мы объявляем тип TFNNtOpenFile
, подходящий для вашего случая:
typedef NTSTATUS (NTAPI *TFNNtOpenFile)(
OUT PHANDLE FileHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
OUT PIO_STATUS_BLOCK IoStatusBlock,
IN ULONG ShareAccess,
IN ULONG OpenOptions
);
... и затем получить указатель функции и вызвать его:
TFNNtOpenFile pfnNtOpenFile = (TFNNtOpenFile)GetProcAddress(GetModuleHandle("ntdll.dll"), "NtOpenFile");
status = pfnNtOpenFile(...); // can't be bothered to type out all parameters ;)
альтернативный способ получения указателя функции может быть таким:
static NTSTATUS (NTAPI *NtOpenFile)(
OUT PHANDLE,
IN ACCESS_MASK,
IN POBJECT_ATTRIBUTES,
OUT PIO_STATUS_BLOCK,
IN ULONG,
IN ULONG
);
(FARPROC)&NtOpenFile = GetProcAddress(GetModuleHandle("ntdll.dll"), "NtOpenFile");
, который можно сжать еще больше, используя оператор строкового преобразования препроцессора (#
).Выбор за вами.