на стадии компиляции есть возможность проверить ошибки в студии, доходим до линковки получаем ошибку,запускаем вышеописанный скрипт все компилиться без проблем, вот такая двух-тактная система получилась.
а в свойства проекта залезть религия не позволяет чтоле? написал же куда. раз компилируется build'ом как плоский Си, то и в студии скомпилируется.
Естественно опробованы все вышеуказанные советы, результат тот же. Студия отказывается линковать. Могу дать проект, можете попробовать, если есть желание. И еще, сборка экзешника двухтактный процесс, сначала компиляция затем линковка. Студия компили проект без проблем т.е. создает .obj файл. Проблема возникает при линковке .obj файла с файлом ndis.lib. Линковка с hal.lib Тоже происходит без проблем.
Не забываем, что студия использует свой cl.exe и Link.exe, а утилита бильд свою версию cl.exe и link.exe. link.exe билдера отличается от линкера студии. Замена линкера студии на линкер билдера ни к чему хорошему не привела, говорит ошибка в линковщике, дальше я не разбирался.
Так именно и говорит, что ошибка в линковщике? Ну если студия 2008, то не удивлюсь. link.exe может конечо и разный, но я ещё пока разницы в поведении не замечал. Вот только дрова студией не пытался собирать. Хз, может чисто с ними какие новые затупы. А если ошибка та, которая была в первом посте - то тут link.exe ни при чём. Это просто несоответствие имён.
ок. Делаем очень просто, смотрим какое имя сформировала студия в .obj файле и сравниваем есть ли такое в ndis.lib. Я одного только не пойму, если линковщику нужно всего лишь прописать имя импортируемой функции в таблице импорта, то на кой ей ляд нужен ndis.lib? Если бы код импортируемой функции встраивался в мой экзешник, тогда другое дело.
упс, вот он и косяк нашелся. Вот что у меня получилось, в .obj файле видим символ, который мой компилятор из студии сформировал NdisInitializeEvent@@YGXPAU_NDIS_EVENT@@@Z, в то время как импортируемый символ в этом же .obj файле функции RtlInitUnicodeString такой: _imp_RtlInitUnicodeString@8, теперь смотрим, что в ndis.lib такого символа NdisInitializeEvent@@YGXPAU_NDIS_EVENT@@@Z не наблюдается. Зато есть такой: _imp_NdisInitializeEvent@4!!! Следует вопрос, почему компилятор студии формирует символ функции RtlInitUnicodeString правильный, а символ функции NdisInitializeEvent неправльный? В то время как билдовский компилятор формирует правильный символ в .obj файле: _imp_NdisInitializeEvent@4 Спасибо krabs натолкнул на идею, сравнить импортируемые функции. Вывод, как говорил Гете дьявол в деталях. Зря я на линкер грешил, виноват компилятор.
Да всё дело опять в разнице между C и C++. _imp_NdisInitializeEvent@4 - это обычный сишный stdcall. такие функции и составляют всё API в винде. а вот это: NdisInitializeEvent@@YGXPAU_NDIS_EVENT@@@Z - это та же функция, но в формате C++, где вся инфа о параметрах включается в декорированное имя, за счёт чего линкер видит различия между функциями с одинаковыми именами но разными параметрами. естественно такой функции в .lib нет. поэтому, очевидно Вы всё же не настроили студию на компиляцию плоского Си. попробуйте задать это для каждого файла отдельно чтоле - щелчком правой кнопкой по файлу в дереве проекта. ну или переименуйте файлы в *.c на худой конец. а .lib - это по сути контейнер для множества .obj и линкер хавает одновременно Ваши .obj и внешние .lib и собирает из них исполняемый модуль. и уже из этих входных файлов он смотрит надо ли искать код в этих файлах, либо выводить его на динамический импорт.
Переведено все файлы в .с и настройки сделаны как Compile as C Code (/TC) для всех файлов. Я вижу единственный способ разобраться: 1) Определяем в коде компилятора место, где разветвляется генерация символов. 2) Сравнить почему генерация для _imp_RtlInitUnicodeString@8 идет по одному пути, а генерация для NdisInitializeEvent@@YGXPAU_NDIS_EVENT@@@Z идет по другому пути. Это все равно, что взломать серийник, только проще, потому что никто специально не прячет этот алгоритм. Ладно будет время попробую это сделать, потом напишу. Может даже на статью в wasm потянет. Для опытного кракера - это пол-часа работы.
Итак, смотрим в wdm.h: Код (Text): NTSYSAPI VOID NTAPI RtlInitUnicodeString( __out PUNICODE_STRING DestinationString, __in_z_opt __drv_aliasesMem PCWSTR SourceString ); смотрим в ndis.h Код (Text): EXPORT VOID NdisInitializeEvent( __out PNDIS_EVENT Event ); NTSYSAPI == DECLSPEC_IMPORT EXPORT == DECLSPEC_IMPORT видим разницу в отсутствии NTAPI. NTAPI == __stdcall build по дефолту использует __stdcall. студия по дефолту использует __cdecl. это тоже настраивается в свойствах проекта. однако указанное Вами выше имя не относится и к __cdecl по идее. там должно просто одно "_" добавляться спереди. оно указывает на С++. а посмотрите на DriverEntry в .obj файле - как оно выглядит? если не _DriverEntry@8, то Вас обманули и продолжают компилировать как С++. я не думаю что имеет смысл реверсить студию. Вы потом её и патчить будете чтобы работала? ведь пишут же на ней дрова все кому не лень. значит она работает, просто надо понять что происходит.
Вот так выглядит: DriverEntr@@YGJPAU_DRIVER_OBJECT_@@PAU_UNICODE_STRING@@@Z Попробовал поставить перед DriverEntry _stdcall результат тот же. Создал другую функцию Код (Text): #include "StdAfx.h" PDRIVER_OBJECT g_DriverObject; //object which was top before we connected to it PDEVICE_OBJECT g_topDeviceObj; int _stdcall MyTest(); NTSTATUS _stdcall DriverEntry( IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING RegistryPath ) { MyTest(); return STATUS_SUCCESS; } // end DriverEntry() int _stdcall MyTest() { return 1; } У MyTest такие символы ?MyTest@@YGHXZ Поменял объявление на такое int _cdecl MyTest() та же строка ?MyTest@@YGHXZ - компилятору по-моему пофиг на объявления _cdecl и _stdcall, Можешь скомпилить вышеуказанный пример и сообщить свои результаты?
а вот билдеровский создает правильную строку _DriverEntry@8 Возможно где-то глобальные настройки студии мешают жить, в общем без реверса делать нечего, это единственный способ вывести студию на чистую воду. Возможно патч нужно поставить на студию, у меня ни одного еще не стоит. Сохранить старую студию поставить патч, сравнить папки. Я уже убедился на высоком абстрактном уровне программирования, можно шельмовать сколько угодно, но истина всегда заключена в машинном коде (или в нашем случае мнемонических командах ассеблера) Ассеблер ниже всех поэтому он силнее всех( парафраз китайской пословицы: Почему Океан силнее всех? Потому что он ниже всех. Конфуций по-моему). Или почему уборщица самый опасный человек в организации? Уборщиком пойти что-ли? (Убирать людей из которых дермо лезет(тех, кто такие компиляторы делает) ))))
между прочим вот выдержка из IDA pro Код (Text): text:00000008 ?DriverEntry@@YGJPAU_DRIVER_OBJECT@@PAU_UNICODE_STRING@@@Z proc near .text:00000008 push ebp .text:00000009 mov ebp, esp .text:0000000B call ?MyTest@@YAHXZ ; MyTest(void) .text:00000010 xor eax, eax .text:00000012 pop ebp .text:00000013 retn 8 .text:00000013 ?DriverEntry@@YGJPAU_DRIVER_OBJECT@@PAU_UNICODE_STRING@@@Z endp Как видим несмотря на краказяблики, имеем _stdcall функцию, никак не _cdecl Как я и говорил, Ассемблер - руль!
DriverEntr@@YGJPAU_DRIVER_OBJECT_@@PAU_UNICODE_STRING@@@Z - это С++!!! хоть Вы меня за яйца повесьте. вот как только начнёт оно компилироваться как плоский си, то сразу всё и соберётся как надо. возможно Вам реверсинг подскажет как этого добиться...
В общем почитал о манглинг в интере krabs прав, происходит замангаление функций в стандарте С++. Поэтому сделал следующее Код (Text): export "C" { EXPORT VOID NdisInitializeEvent( IN PNDIS_EVENT Event ); } до этого было так Код (Text): EXPORT VOID NdisInitializeEvent( IN PNDIS_EVENT Event ); Проект успешно начал собираться и линкер увидел функцию NdisInitializeEvent поскольк та стала собираться в обжект файле в нужном формате, однако таким образом уродовать ndis.h думаю плохая затея. Вот такие бывают чудеса.
Вот так теперь получается собирать проект, вот блин, век живи век учись. Спасибо. Тему можно закрывать. Хотя... вопрос то остался почему косячит студия... Правда я сделал так: Код (Text): extern "C" { #include "ndis.h" } Потому как только с этой библиотекой проблемы.
Ну в принципе-то решение вполне годное найдено, многие так делают и пишут свой код на C++. Но если хотите разобраться, присылайте проект целиком ну или файл проекта хотя бы - я поковыряюсь в нём.