2010-02-17 2 views
5

Представьте, что вы хотите написать программу, которая проверяет функции в dll-файле C++. Вы должны разрешить пользователю выбирать dll (мы предполагаем, что мы говорим о dll C++). Он должен иметь возможность получить список всех функций, экспортируемых DLL. Затем пользователь должен иметь возможность выбрать имя функции из списка, вручную ввести список аргументов (аргументы - это все основные типы, такие как массивы int, double, bool или char (например, строки c-type)) и попытаться для запуска выбранной функции с указанными аргументами. Он хотел бы знать, работает ли функция с указанными аргументами или они приводят к сбою (потому что они не соответствуют подписи, например).Могу ли я программно вывести соглашение о вызове, используемое dll C++?

Основная проблема заключается в том, что C++, будучи строго типизированным языком, требует, чтобы вы знали количество и тип аргументов для вызова функции во время компиляции. И в моем случае я просто не знаю, что эти аргументы пока пользователь не выберет их во время выполнения.

Единственное решение, с которым я столкнулся, состояло в том, чтобы использовать сборку для ручного ввода аргументов в стек вызовов.

Однако я пришел к пониманию, что если я хочу общаться с сборкой, я должен удостовериться, что я знаю, какие соглашения о вызове являются функциями в dll.

Итак (наконец-то :) вот мой вопрос: могу ли я вывести вызывающую конвенцию программно? Dependency Walker не поможет мне, и я не знаю, как вручную читать формат PE.

+0

Почему у вас нет указателя на вызов? По умолчанию stdcall (это то, что есть на DLL, сгенерированном компиляторами microsoft в эти дни), но позволяет пользователю изменять его. – 2010-02-17 03:31:43

+0

Ну, черт. Я просто об этом не думал! Я должен проверить, разрешено ли мне это делать, но если это так, это будет допустимым обходным решением :))) –

ответ

3

Ответ Возможно.

Если имена функций оформлены на C++, вы можете определить количество и типы аргументов из украшений имен, это ваш наилучший сценарий, и, скорее всего, если MSVC использовался для написания кода в первую очередь.

Если экспортированные функции являются стандартными вызовами stdcall (по умолчанию для windows api), вы можете определить количество байтов, которые нужно нажать, но не типы аргументов.

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

http://en.wikipedia.org/wiki/X86_calling_conventions

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

+0

Ну, я в значительной степени воспринимаю это как заданное, что я не могу получить никакой информации о аргументах функции. Я буду просто счастлив найти способ «заставить кормить» au ser определите список аргументов функции и посмотрите, сработает ли она. –

+0

@Emil: Вы должны знать, что существуют различия между соглашениями о вызовах в том, вызывает ли вызывающий или вызываемый аргументы. –

2

Скомпилированный код не просто говорит: «Здесь эта функция является fastcall, а эта, к сожалению, является stdcall».

Даже современные дизассемблеры, подобные IDA, пытаются вывести типы вызовов по умолчанию (там может быть плагин или опция где-то idk).

В принципе, если вы человек, вы cn посмотрите на первые несколько инструкций и скажите 90% времени. Если они являются pop и push, то его stdcall, если его проходящие параметры проходят через регистры (особенно ecx), то его cdecl. Fastcall также использует регистры, но делает что-то особенное .. dunno от верхней части головы. Но вся эта информация бесполезна, потому что ваша программа, очевидно, не будет человеком.

Если вы проводите тестирование, не имеете ли вы, по крайней мере, файлы заголовков? Это очень трудный путь к коже кошки ..

+1

Сравнивая с https://en.wikibooks.org/wiki/X86_Disassembly/Calling_Conventions, ваша эвристика не кажется подать заявление. Оба stdcall и cdecl передают параметры в стеке. – jpa

0

Если вы хотите знать, что соглашение о вызове функции C++ использует, ваша лучшая надежда изучить

  1. заголовок, который декларирует эту функцию, и
  2. Документация для компилятора, который скомпилировал вашу конкретную DLL.

Но все это звучит немного беспорядочно, честно. Почему ваш друг хочет, чтобы это удалось, и почему он не может получить необходимую ему информацию, анализируя заголовок, который объявляет соответствующие функции?

+0

Я знаю, это звучит как нечто большее чем беспорядок :) Я делаю это для компании, в которой я интернирую, и это просто функциональность, которую они должны предоставить. Что вызывает затруднение в том, что я видел программа от одного из наших конкурентов, который делает именно то, что я описал, поэтому я знаю, что это выполнимо. Я не уверен, что мой метод - путь, но у меня нет других идей :( –

+0

I несколько раз читал статью о том, как компания A всегда повышала конкуренцию, потому что они использовали другой язык. Возможно ли, что они что-то делают? Возможно, у них есть скриптовый слой или какая-то другая странность? – Narfanator

+0

Кроме того, если у вас есть образец, пойти на научный метод и попытаться выяснить, как они это делают. – Narfanator

3

Вы не указали, разговариваете ли вы с 32-битным или 64-битным здесь, а трудности, описанные вами и другими плакатами, в основном относятся к 32-битовому коду. В 64-битной Windows существует, по существу, только одно соглашение о вызове (оно также находится в статье Википедии, связанной с Джоном Кноллером), а это значит, что вы знаете, что вы вызываете конвенцию (конечно, за исключением кого-то, кто готовит свои собственные) ,

Кроме того, в соответствии с соглашением о назначении Microsoft x64, не зная количества параметров вызываемой функции, вы не можете позвонить вам, указав столько параметров, сколько пожелаете/пожелаете. Это потому, что вы, как вызывающий, отложили пространство стека и очистили его потом. - Конечно, не предоставление правильных [число] параметров может по-прежнему иметь вызываемую функцию, делая глупые вещи, потому что вы предоставляете недопустимый ввод, но это уже другая история.

+0

Да, извините, я имел в виду 32 бит. –

0

Эта страница описывает путь VC++ 6 кодирует параметр и призывающую информацию конвенционного в имени символа: http://www.bottledlight.com/docs/mangle.html

я подозреваю, что более поздние версии VC++ будут совместимы, но я не подтвердили это.

Есть также некоторые инструменты, которые автоматизируют этот, которые сопровождают компилятор: http://msdn.microsoft.com/en-us/library/5x49w699.aspx

Название коверкая применяется только для функций C++; если функция «extern» C "', то это не сработает.