Я могу программно вывести соглашение о вызовах, используемое C++ dll?

Предположите, что требуется записать программу, которая тестирует функции в C++ dll файл. Необходимо позволить пользователю выбрать dll (мы предполагаем, что говорим о C++ dlls). Он должен смочь получить список всех функций, экспортируемых dll. Затем пользователь должен смочь выбрать имя функции из списка, вручную ввести список аргументов (аргументами являются все основные типы, как интервал, дважды, bool или массивы символов (например, строки c-типа)), и попытайтесь выполнить выбранную функцию с указанными аргументами. Он хотел бы знать, делают ли функциональные выполнения с указанными аргументами, или они заставляют это отказывать (потому что они не соответствуют подписи, например).

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

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

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

Таким образом (наконец:) вот мой вопрос: я могу вывести соглашение о вызовах программно? Зависимость Walker не поможет мне, и я понятия не имею, как вручную считать формат PE.

5
задан agf 29 September 2011 в 14:55
поделиться

5 ответов

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

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

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

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

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

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

3
ответ дан 14 December 2019 в 04:36
поделиться

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

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

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

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

2
ответ дан 14 December 2019 в 04:36
поделиться

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

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

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

0
ответ дан 14 December 2019 в 04:36
поделиться

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

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

3
ответ дан 14 December 2019 в 04:36
поделиться

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

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

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

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

0
ответ дан 14 December 2019 в 04:36
поделиться
Другие вопросы по тегам:

Похожие вопросы: