Получение адреса процедуры класса DLL в Delphi

У меня есть файл DLL, из которого мне нужен адрес памяти процедуры класса. Я получаю дескриптор DLL-файла, но при использовании GetProcAddress не могу получить адрес процедуры. Я пробовал следующие строки для параметра имени процесса:

"ProcName"
"ProcClass.ProcName"
"ProcClass::ProcName"
"ProcInterface::ProcName"
"ProcInterface.ProcName"

Ни в одном из случаев я не получил адрес памяти процедуры. Я почти уверен, что процедура публичная.

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

procedure ProcName(); stdcall; far; external 'Example.DLL';

ProcPointer := @ProcName;

person mnuzzo    schedule 18.03.2011    source источник
comment
Кстати, в последнее время вы задали довольно много вопросов на эту тему, и это хорошо. Однако вы не приняли многие ответы. Я думаю, вы могли бы принять некоторые ответы, которые являются хорошим способом выразить свою признательность!   -  person David Heffernan    schedule 18.03.2011
comment
Вы написали эту DLL? Откуда вы знаете, что в нем есть процедура класса, а не обычная процедура?   -  person Warren P    schedule 19.03.2011


Ответы (3)


GetProcAddress дает вам только адрес для экспортируемых функций. Ваша DLL точно не экспортирует методы класса!

Используйте проводник PE для поиска экспортированных имен. Например, используйте проводник PE, доступный в GExperts. У меня есть пункт меню «Информация о PE» в меню GExperts.

person Cosmin Prund    schedule 18.03.2011
comment
Обходчик зависимостей — еще один очевидный инструмент для экспорта, но этот метод вряд ли будет экспортирован, как вы говорите. - person David Heffernan; 18.03.2011
comment
PE Explorer с heaventools.com — еще один инструмент для просмотра экспортированных имен. Он покажет вам прототипы функций в синтаксисе Delphi! - person Wylder; 19.03.2011

Вы находитесь на территории реверс-инжиниринга.

Я думаю, что если бы я был на вашем месте, я бы просто прошел через представление ЦП отладчика, после вызова интересующего метода, и нашел бы адрес точки входа. Я бы вычел его из базового адреса DLL, и это было бы смещением. Затем, чтобы вычислить адрес во время выполнения, вы просто добавляете смещение к базовому адресу DLL в памяти в то время. Узнать базовый адрес можно вызовами LoadLibrary или GetModuleHandle.

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

Наконец, когда вы реализуете метод замены, вам нужно будет заменить его глобальной функцией/процедурой с дополнительным параметром, первым параметром, который заменяет Self.

person David Heffernan    schedule 18.03.2011
comment
@ Дэвид, можешь опубликовать код для этого из простой функции класса в DLL? Поскольку вы не можете экспортировать членов класса из Delphi (во всяком случае, AFAIK), я не уверен, как вы получите адрес функции класса. Это первый из ваших ответов, за который я почувствовал желание проголосовать против, поэтому я заинтересован в том, чтобы быть здесь неправым. :) - person Ken White; 18.03.2011
comment
@ Кен Нет кода. Вы просто проходите через отладчик и смотрите, куда он вас приведет, читая разборку. Цель состоит в том, чтобы найти точку входа функции, которую вы хотите заменить. Это, вероятно, довольно сложно с IDispatch или чем-то еще, и, вероятно, будет несколько уровней косвенности для навигации. - person David Heffernan; 18.03.2011
comment
@Ken Я бы, вероятно, сгенерировал свой собственный простой IDispatch (если это действительно то, о чем мы говорим), а затем посмотрел, как вызов метода для одного из них реализован на ассемблере. Затем я бы сопоставил это с реальной DLL и определил точку входа. Как только я получу адрес точки входа, я буду использовать свой код из предыдущего вопроса, чтобы перезаписать этот код с помощью JMP на новый код. - person David Heffernan; 18.03.2011
comment
@Ken Я попытался немного уточнить ответ. Я не объяснил это хорошо. В моей голове всё ясно, но тебе это не поможет. Я прямо заявил, что говорю о пошаговом представлении процессора в отладчике. - person David Heffernan; 18.03.2011
comment
@ Дэвид, так лучше. Я не чувствую, что должен минусовать. Не думаю, что я должен голосовать, потому что я не уверен, что что-либо из этого подходит для доступа к функции класса. (Функция класса будет включать в себя поиск класса, а затем поиск в структуре памяти класса, что будет зависеть от реализации, а также будет включать жесткое кодирование смещения, которое может измениться по любому количеству причин.) - person Ken White; 18.03.2011
comment
@Ken Тебе нужно прочитать все предыдущие вопросы. Это в DLL, которую OP не может изменить. Таким образом, ОП может предположить, что он не может измениться. По крайней мере, это мое прочтение предыдущих вопросов. Хотя мне это кажется глупым заданием, это точно. - person David Heffernan; 18.03.2011
comment
@Ken Природа этой проблемы заключается в том, что она зависит от реализации и нарушает все передовые методы, предполагает знание особенностей компилятора, частных деталей макета класса и т. Д. Это взлом обратного проектирования. Это, по крайней мере, мое понимание того, чего хочет ОП. - person David Heffernan; 18.03.2011
comment
@ Дэвид, понял. Я подумал, что это какой-то хак, или вы можете либо собрать его как пакет, либо написать функцию-оболочку, которая вызывает функцию класса, а затем экспортировать эту оболочку. Спасибо за разъяснения. Я думаю, что в этом случае стоит +1. :) Готово. - person Ken White; 18.03.2011
comment
@ Кен Дэвид прав, я не могу это изменить, и, насколько мне известно, мы не будем получать никаких обновлений, поэтому определенное смещение от начала DLL будет работать. Я просто попытался сделать что-то менее хакерское и обнаружил, что функция сложнее, чем я сначала думал, и мне, возможно, придется вставить прыжок где-то посередине :/ - person mnuzzo; 18.03.2011
comment
Когда @mnuzzo поставили задачу взломать какую-то сломанную DLL извне, это звучит для меня как глупое задание. Гораздо веселее работать над чем-то, что вы можете ясно видеть. - person David Heffernan; 18.03.2011
comment
@mnuzzo, у вас есть какой-либо исходный код DLL? Вы хотя бы знаете, на каком языке его построили? Если вы чувствуете необходимость добавить прыжок где-то посередине, боюсь, вам предстоит трудная дорожка, потому что вам нужно будет не только выскочить из процедуры, но и вернуться обратно. , не испортив стек! Если вам нужно это сделать, если вы не мечтаете об ассемблере, вы должны подумать дважды, а может быть, и три раза, стоит ли эта DLL того. - person Cosmin Prund; 18.03.2011
comment
@Cosmin D6, по-видимому, то же самое, что и хост-приложение. - person David Heffernan; 18.03.2011
comment
@mnuzzo Ты понимаешь все, что может пойти не так? Если ваш хук пытается выделить память, которую, как ожидается, освободит исходная DLL, у вас, например, проблемы. Есть сотни ловушек. Вы могли бы помочь нам, точно сообщив, для чего предназначена эта функция. - person David Heffernan; 18.03.2011
comment
@mnuzzo, DLL D6 использует sharemem? Процедура, которую вы хотите зацепить, длинная? Самый простой способ исправить DLL — заменить всю процедуру ВСЮ, а не только неисправные части. Вы можете сделать это с помощью одной введенной инструкции JMP и с помощью остроумной подпрограммы на стороне exe, написанной на Delphi (без ассемблера). Это тривиально, если у вас есть исходный файл для этого класса, даже если у вас нет исходных файлов для остальной части DLL. Честно говоря, если вам нужно вырваться из середины рутины, вы окажетесь на территории «Если вам нужно спросить, вы не можете этого сделать». - person Cosmin Prund; 18.03.2011
comment
У меня нет источника для файла DLL. Я нахожусь на совершенно незнакомой для себя территории. Я, вероятно, воспользуюсь информацией, полученной при обнаружении функции, чтобы воссоздать то, что она делает, поскольку даже прикосновение к чему-либо на таком низком уровне пугает меня. Либо так, либо я закончу тем, что взламываю DLL в самом файле. - person mnuzzo; 18.03.2011
comment
@David Дэвид, я просил определение назначения тупицы. - person mnuzzo; 18.03.2011
comment
@ Дэвид, +1, это хороший ответ. В последнее время много анонимных отрицательных голосов на хорошие вопросы. - person Cosmin Prund; 18.03.2011
comment
@Cosmin Я получил три 2 отрицательных голоса за минуту ранее сегодня, один на этот вопрос. Я не думаю, что это хороший ответ, но вопрос на самом деле не очень четкий. - person David Heffernan; 18.03.2011
comment
@ Дэвид, это случилось со мной некоторое время назад, когда я проголосовал против очень плохого ответа от кого-то и оставил комментарий. Я подозреваю, что этот пользователь недавно просматривал мой профиль и псевдослучайно выбрал 4 или 5 вопросов, чтобы проголосовать против. Сначала я разозлился и действительно хотел отплатить тем же, хотя я этого не сделал, затем научился анонимно голосовать против плохих ответов или вопросов от неизвестных пользователей, чтобы избежать такого рода репрессалий обиженных пользователей, но по-прежнему использую свою силу, чтобы помочь StackOverflow оценить качество контента. Конечно, я не ваш противник, ваши ответы всегда между хорошим и отличным. - person jachguate; 19.03.2011

Я могу читать это неправильно. Но мне кажется, что вы написали DLL.

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

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

Если бы кто-то написал dll на C++ и экспортировал ее методы, вам пришлось бы исследовать правила искажения имен C++.

person Warren P    schedule 19.03.2011
comment
Насколько я могу судить, OP не писал DLL - person David Heffernan; 20.03.2011