Есть написанная мной простая dll. На момент написания все в ней работало корректно. В общем, написал ее, выложил для пользователей, жалоб не было, и я забыл про нее. Понадобилось мне немного модифицировать dll под новые запросы пользователей. И тут вскрылось нечто загадочное. Оказалось, что в Windows 10 со всеми обновлениями dll загружается через раз. Точнее, корректно загружается она очень редко, а нормальной ситуацией является либо ERROR_DLL_INIT_FAILED, либо какой AV где то внутри системы. Это происходит только в Windows 10. В dllmain ничего криминального не делается.
Я стал сокращать функциональность, что бы поймать момент, в который dll будет грузиться нормально. В какой то момент это случилось. Я сравнил импорт новой dll и старой — разница в импорте одной функции InternetCrackUrlW. Я включил весь свой исходный код, отключенный в эксперименте, поставил заглушку на InternetCrackUrlW (что бы она не появлялась в импорте) — и, о чудо, dll стала грузиться нормально. Но где логика?
Я где читал, что в Creators Update был оптимизирован механизм загрузки dll. Может ли моя ситуация быть следствием этого? Также заметил что Delphi, на которой я пишу, иногда в импорт помещает одну и туже функцию несколько раз. Это вообще законно?
A>Я стал сокращать функциональность, что бы поймать момент, в который dll будет грузиться нормально. В какой то момент это случилось. Я сравнил импорт новой dll и старой — разница в импорте одной функции InternetCrackUrlW. Я включил весь свой исходный код, отключенный в эксперименте, поставил заглушку на InternetCrackUrlW (что бы она не появлялась в импорте) — и, о чудо, dll стала грузиться нормально. Но где логика?
Очень похоже на срабатывание эвристических правил детекта антивируса: размер, строки и набор импортов, например.
A>Как искать решение такой проблемы?
Если сторонних антивирусных решений нет, то для подтверждения false positiv'а нужно смотреть логи Windows Defender. У него должен быть свой журнал, плюс стоит посмотреть в системный EventLog.
Что бы Windows Defender/SmartScreen совсем не ругался можно купить и подписать EV-цифровой подписью (SmartScreen и сертификат CodeSign EV, например, обсуждалось). Или экспериментировать (подбирать безопасные импорты и т.п.).
A>Есть написанная мной простая dll. На момент написания все в ней работало корректно. В общем, написал ее, выложил для пользователей, жалоб не было, и я забыл про нее. Понадобилось мне немного модифицировать dll под новые запросы пользователей. И тут вскрылось нечто загадочное. Оказалось, что в Windows 10 со всеми обновлениями dll загружается через раз. Точнее, корректно загружается она очень редко, а нормальной ситуацией является либо ERROR_DLL_INIT_FAILED, либо какой AV где то внутри системы. Это происходит только в Windows 10. В dllmain ничего криминального не делается.
Хочу заметить что AV внутри DllMain будет словлено SEH фильром загрузчика и наверх вылезет тот же самый ERROR_DLL_INIT_FAILED
Так что полагаю стоит подебажить этот AV, когда он виден
Как много веселых ребят, и все делают велосипед...
Здравствуйте, EreTIk, Вы писали:
ETI>Очень похоже на срабатывание эвристических правил детекта антивируса: размер, строки и набор импортов, например.
Ок, пусть это будет родной виндовый антивирус. Но почему возникают AV? И после это процесс не закрывается (его не возможно удалить, и не возможно удалить dll), но исчезает из диспетчера задач.
A>>Как искать решение такой проблемы?
ETI>Если сторонних антивирусных решений нет, то для подтверждения false positiv'а нужно смотреть логи Windows Defender. У него должен быть свой журнал, плюс стоит посмотреть в системный EventLog.
В системном логе есть записи, которые относятся к моей проблеме, они имею вид:
A>Ок, пусть это будет родной виндовый антивирус. Но почему возникают AV? И после это процесс не закрывается (его не возможно удалить, и не возможно удалить dll), но исчезает из диспетчера задач.
AV в оригинальном сообщении это был ACCESS_VIOLATION. Сорри, я не верно понял суть проблемы
A>В системном логе есть записи, которые относятся к моей проблеме, они имею вид: A>Faulting application name: Client.exe, version: 1.0.0.0, time stamp: 0x5a2532f2 A>Faulting module name: unknown, version: 0.0.0.0, time stamp: 0x00000000 A>Exception code: 0xc0000005 A>Fault offset: 0x36b436af A>Faulting process id: 0x1cb0 A>Faulting application start time: 0x01d36cfb217b489b A>Faulting application path: D:\Delphi\Projects\Test\Client.exe A>Faulting module path: unknown A>Report Id: ad90fc20-d29b-4052-af87-1a75389ca473 A>Faulting package full name: A>Faulting package-relative application ID: A>Но мне это ничего не дает.
Так надо запустить под отладчиком (WinDbg, например) и посмотреть на точку возникновения исключения: что за код, кем вызван и т.п.
Здравствуйте, Aniskin, Вы писали:
A>Как искать решение такой проблемы?
Проблему решил, но тем не менее ее причины мне до сих пор не ясны.
Delphi при создании таблицы импорта для одной и той же dll может создавать несколько IMAGE_IMPORT_DESCRIPTOR, и в каждой будет свой (может быть даже пересекающийся) набор импортируемых функций. В моем случае для wininet.dll создавались две записи IMAGE_IMPORT_DESCRIPTOR, в первой была функция InternetCrackUrlW, во второй InternetTimeFromSystemTimeW. Некоторыми манипуляциями с кодом я добился создания одной записи с двумя функциями. После этого проблема исчезла.
Нашел статью, она немного описывает изменения в методике загрузки dll в Windows 10. Правда, в статье описываются проблемы при нескольких записях в таблице экспорта, а не импорта, но возможно, у этих проблем общее начало.
Здравствуйте, EreTIk, Вы писали:
ETI>Так надо запустить под отладчиком (WinDbg, например) и посмотреть на точку возникновения исключения: что за код, кем вызван и т.п.
Пишу на Delphi, соответственно использую отладчик Delphi. Вижу следующее. После того, как произошел вызов LoadLibrary, но до вызова dllmain происходит AV. Где конкретно — данных в отладчике нет.
Здравствуйте, Aniskin, Вы писали:
A>Здравствуйте, Aniskin, Вы писали:
A>>Как искать решение такой проблемы?
A>Проблему решил, но тем не менее ее причины мне до сих пор не ясны.
A>Delphi при создании таблицы импорта для одной и той же dll может создавать несколько IMAGE_IMPORT_DESCRIPTOR, и в каждой будет свой (может быть даже пересекающийся) набор импортируемых функций. В моем случае для wininet.dll создавались две записи IMAGE_IMPORT_DESCRIPTOR, в первой была функция InternetCrackUrlW, во второй InternetTimeFromSystemTimeW. Некоторыми манипуляциями с кодом я добился создания одной записи с двумя функциями. После этого проблема исчезла.
Ничего криминального, в нескольких записей для одной и той же библиотеки в импорте, нет. Посмотрите на таблицу импорта любого delphi файла с gui, там наверняка несколько записей для kernel32.dll и user32.dll. В общем, ситуация штатная.
Скорее всего проблема в чем то другом, просто решилась попутно.
ETI>>Так надо запустить под отладчиком (WinDbg, например) и посмотреть на точку возникновения исключения: что за код, кем вызван и т.п.
A>Пишу на Delphi, соответственно использую отладчик Delphi. Вижу следующее. После того, как произошел вызов LoadLibrary, но до вызова dllmain происходит AV. Где конкретно — данных в отладчике нет.
Много лет уже не видел среду Delphi, как там выглядит отладка и не помню уже. Нужно взять любой отладчик, который сможет отображать системные символы (внутри ntdll.dll, kernelbase.dll и т.п.) и отладочную информацию Delphi. Возможно поддержка Delphi и не понадобиться, если падение происходит в системном коде.
Если выбор падет на WinDbg, то в строке ввода команд (в момент отлова целевого ACCESS_VIOLATION) нужно ввести что-то такое:
Здравствуйте, enigmas, Вы писали:
E>Скорее всего проблема в чем то другом, просто решилась попутно.
Я не утверждаю, что проблема в загрузчике Windows. Но ситуация такова, что dll, которая корректно загружалась до Creators Update перестала загружаться с Creators Update, в котором были изменения в механизме загрузки dll. Повторюсь, в dllmain нет ничего, кроме инициализации глобальных структур. Могу выложить эту dll. Если кому либо интересно, то можете посмотреть, что происходит при загрузке. У меня на это знаний не хватает.
A>Я не утверждаю, что проблема в загрузчике Windows. Но ситуация такова, что dll, которая корректно загружалась до Creators Update перестала загружаться с Creators Update, в котором были изменения в механизме загрузки dll. Повторюсь, в dllmain нет ничего, кроме инициализации глобальных структур. Могу выложить эту dll. Если кому либо интересно, то можете посмотреть, что происходит при загрузке. У меня на это знаний не хватает.
А какие нибудь глобальные объекты с конструкторами есть, которые конструируются _до_ dllmain (а по сути — внутри него)? Я с делфями давно дел не имел, не помню как у него с этим.
Как много веселых ребят, и все делают велосипед...
Здравствуйте, Aniskin, Вы писали:
A>Я не утверждаю, что проблема в загрузчике Windows. Но ситуация такова, что dll, которая корректно загружалась до Creators Update перестала загружаться с Creators Update, в котором были изменения в механизме загрузки dll. Повторюсь, в dllmain нет ничего, кроме инициализации глобальных структур. Могу выложить эту dll. Если кому либо интересно, то можете посмотреть, что происходит при загрузке. У меня на это знаний не хватает.
выложите, желательно так, чтобы ее можно было запустить без танцев.
Каждый, просыпаясь утром, должен задавать себе вопрос — что он может сегодня сделать, чтобы россиянства
Здравствуйте, mjau, Вы писали:
A>>Могу выложить эту dll. Если кому либо интересно, то можете посмотреть, что происходит при загрузке. У меня на это знаний не хватает.
M>выложите, желательно так, чтобы ее можно было запустить без танцев.
Ссылка. В архиве две dll: good.eDecoder.32.dll — в этой dll обе функции из wininet.dll находятся в одной IMAGE_IMPORT_DESCRIPTOR, и bad.eDecoder.32.dll, в которой функции из wininet.dll находятся в разных IMAGE_IMPORT_DESCRIPTOR. Это единственное отличие в библиотеках. Проверка очень простая — вызвать LoadLibrary для каждой библиотеки. У меня good.* грузится корректно, bad.* — ERROR_DLL_INIT_FAILED, иногда ловится исключение. Ну а сама dll — это просто плагин для 7Zip.
Здравствуйте, ononim, Вы писали:
O>А какие нибудь глобальные объекты с конструкторами есть, которые конструируются _до_ dllmain (а по сути — внутри него)? Я с делфями давно дел не имел, не помню как у него с этим.
Не понятно, что подразумевается под термином "до dllmain". Как мой код может получить управление до вызова dllmain? В любом случае в dllmain происходит только выделение небольшого количества памяти под список и его заполнение.
M>>выложите, желательно так, чтобы ее можно было запустить без танцев.
A>Ссылка. В архиве две dll: good.eDecoder.32.dll — в этой dll обе функции из wininet.dll находятся в одной IMAGE_IMPORT_DESCRIPTOR, и bad.eDecoder.32.dll, в которой функции из wininet.dll находятся в разных IMAGE_IMPORT_DESCRIPTOR. Это единственное отличие в библиотеках. Проверка очень простая — вызвать LoadLibrary для каждой библиотеки. У меня good.* грузится корректно, bad.* — ERROR_DLL_INIT_FAILED, иногда ловится исключение. Ну а сама dll — это просто плагин для 7Zip.
Windows 10.0.15063 — не проявляется
Windows 10.0.16299 — не проявляется
Возможно, для воспроизведения нужен еще и специфический exe-файл, вызывающий LoadLibrary?
ETI> Windows 10.0.15063 — не проявляется ETI> Windows 10.0.16299 — не проявляется ETI>
Спасибо за информацию. А битность систем какая? У меня x64.
ETI>Возможно, для воспроизведения нужен еще и специфический exe-файл, вызывающий LoadLibrary?
У меня любое приложение, что сам 7zip, что простая программа выполняющая единственный LoadLibrary воспроизводят проблему.
Здравствуйте, Aniskin, Вы писали:
A>>>Могу выложить эту dll. Если кому либо интересно, то можете посмотреть, что происходит при загрузке. У меня на это знаний не хватает. M>>выложите, желательно так, чтобы ее можно было запустить без танцев.
A>Ссылка. В архиве две dll: good.eDecoder.32.dll — в этой dll обе функции из wininet.dll находятся в одной IMAGE_IMPORT_DESCRIPTOR, и bad.eDecoder.32.dll, в которой функции из wininet.dll находятся в разных IMAGE_IMPORT_DESCRIPTOR. Это единственное отличие в библиотеках. Проверка очень простая — вызвать LoadLibrary для каждой библиотеки. У меня good.* грузится корректно, bad.* — ERROR_DLL_INIT_FAILED, иногда ловится исключение. Ну а сама dll — это просто плагин для 7Zip.
у меня bad грузится нормально, видимо у вас чисто местные или трудновоспроизводимые грабли.
Каждый, просыпаясь утром, должен задавать себе вопрос — что он может сегодня сделать, чтобы россиянства
Здравствуйте, mjau, Вы писали:
M>у вас чисто местные или трудновоспроизводимые грабли.
Видимо вы правы. Специально поставил на виртуалку чистую десятку — не воспроизводится. Буду надеяться, что я единственный такой неудачник с такой комбинацией железа и ПО.