Собственно проблема в следующем - имеется название api функции а надо узнать количество её параметров. Вопрос вроде бы простой но на практике никак это реализовать не получается - если искать конец функции( retn n), дизассемблизируя код в библиотеках, то тут основная проблема-дойти до этого retn потому как это тогда придётся выполнять последовательно команды а не просто превращать шестнадцатиричные коды в команды ассемблера. Вот например когда я в delphi набираю какую-нибудь функцию, то мне тут же высвечивается количество параметров и даже их названия - видимо он читает это из какой-то базы данных.
Подобные задачи невозможно решить статически не используя граф. Создаёте базовый граф(Nesting Level = 1) и трассируете его, выполняя поиск инструкции Ret N. Для этого движка http://files.virustech.org/indy/Code/XcptGp/ калбэк будет элементарным, просто юзаете IsRetOpcode() и извлекаете размер.
kaledonia007 Когда вы работаете в среде разработки (delphi в частности) то интерфейсы функций загружаются из специальных файлов (посмотрите в папке delphi\lib\) - не зря же вы пишите что-то типа: uses Windows, Messages, Dialogs, StdCtrls....; После сборки dll в ней в прямом виде нет информации об интерфейсах экспортируемых функций (зависит от конвенций вызова) - здесь надо анализировать код... можно определить кол-во и размер переменных... возьмите IDA - попробуйте...
Код (Text): ; + ; o !GP_PARSE_SEPARATE ; GpTraceCallback: %GET_CURRENT_GRAPH_ENTRY GpTraceCallbackInternal proc uses ebx esi edi GpEntry:PVOID, ArgsCount:PVOID mov esi,GpEntry mov ebx,ArgsCount test dword ptr [esi + EhEntryType],TYPE_MASK ; !HEADER_TYPE_LINE jne Exit cmp dword ptr [ebx],-1 mov edi,BLOCK_HEADER._Size[esi] mov esi,BLOCK_HEADER.Address[esi] jne Exit Ip: invoke QueryPrefixLength, Esi movzx ecx,byte ptr [esi + eax] cmp cl,0C3H ; retn je ip_ret cmp cl,0CBH ; retf je ip_ret cmp cl,0C2H ; retn x je ip_ret_x cmp cl,0CAh ; retf x je ip_ret_x Call VirXasm32 test eax,eax jz Exit add esi,eax sub edi,eax ja Ip Exit: ret ip_ret: xor eax,eax jmp Store ip_ret_x: movzx eax,word ptr [esi + eax + 1] Store: shr eax,2 mov dword ptr [ebx],eax jmp Exit GpTraceCallbackInternal endp Вызываем так: Код (Text): Local ArgsCount:ULONG lea eax,ArgsCount mov ArgsCount,-1 push eax %GET_GRAPH_ENTRY GpTraceCallback push eax push GpBase ; Graph base addr. Call GpTrace Получаем число параметров в ArgsCount.
N может быть разным, нужно еще модификацию esp учитывать + размеры параметров могут быть не только 4 байта
fsd В NT размер параметра не может быть не 4 байта, так как архитектура требует выравнивание стека на 4 байта. Изучайте матчасть, только потом лечите.
Иди ты наверное в гости p.s. Вопрос никак не касался каких то там выравниваний, положить в стек можно и 2 байта
fsd Положить-то можно, но api требует выравнивание на 4, так что если параметр-word он будет выровнен нулями.
Clerk Как всегда в ударе! С учётом того что любой параметр можно представить как DWORD открываются интересные перспективы по универсальным хукам... А топик стартер видно просто спросил как узнать параметры функции по её названию... Вкл. метод дедукции с учётом темы дельфи... Делаем вывод: http://msdn.microsoft.com/ru-ru/default.aspx ему в помощь
если не можешь определить отладчиком, то используй APIMonitor http://www.google.ru/#hl=ru&source=hp&q=api+monitor
Опишу кратко движок, мб кто юзать будет. Архитектура проста и логична. В данном случае базовый граф это список описателей каждой инструкции, причём только её размера, поэтому и базовый. Позволяет оптимально решить многие задачи, например: o Определение принадлежности инструкции графу, в частном случае процедуре. Определять вызывающий калбэк код. o Искать ссылки на инструкции. o Определять начало процедур, их размер и тп. o Разделять процедуры на разных уровнях вложенности. o Отделять процедуры от стороннего кода. o Выполнять всевозможный анализ кода, поиск приватных ссылок, переменных и процедур. Все инструкции разделены на 4 условных типа, это безусловные ветвления(jxx), условные ветвления(jcc, jcx), процедурные ветвления(call) и линейные инструкции, не изменяющие непосредственно Ip(Ip' = Ip + OpSize). Так как граф занимает много памяти, то в целях оптимизации группа из нескольких линейных инструкций описывается одним описателем(в теле линейного блока нет меток, тоесть ветвлений в этот блок не на начало его), это задаётся при создании графа. Каждый описатель это структура содержащая следующую информацию(http://files.virustech.org/indy/Code/XcptGp/Table.inc): o Ссылку на инструкцию. o Размер блока/инструкции. o Ссылку на описатель следующей инструкции. o Ссылку на описатель предыдущей инструкции. o Для ветвлений адрес куда выполняется ветвление. o Ссылку на описатель инструкции, на которую происходит ветвление. o Пользовательские данные и различные флажки. Все описатели в графе связаны между собой ссылками. Тоесть выполнено абстрагирование от кода. Полноценный граф, в отличие от базового содержит более подробную информацию об инструкциях, что реализуется не расширением описателей, а введением ссылок на расширенную информацию, извлекаемую дизассемблером. Это излишне для прикладных задач. На все свободные поля описателей налаживается маска, это сделано в целях оптимизации. Тоесть граф должен быть выравнен в памяти на границу 4'х байт, при этом младшие биты ссылок свободны и заполнены флажками. Младшие два бита описателя определяют его тип. При создании графа его размер не известен. По этой причине буфер в котором создаётся граф должен иметь в конце не доступную или стророжевую страницу(PAGE_NOACCESS/PAGE_GUARD). При обращении к этой странице буфер может быть расширен http://files.virustech.org/indy/Code/XcptGp/, http://files.virustech.org/indy/Code/IDP/Bin/Graph/Dasm/Belong/. Трассировка графа - перечисление описателей графа(http://files.virustech.org/indy/Code/XcptGp/Temp/GrpTrace.asm), причём это не просто перечисление подряд идущих описателей, а логичное перечисление, при котором вначале перечисляются описатели кода до безусловного ветвления, либо окончания линейного блока, после чего начинается трассировка первой ветви, на которую обнаружено условное/процедурное ветвление и тд. Трассировщик помечает перечисленные описатели выполняя инверсию флажка, это ставит запрет на следующие действия: o Рекурсивный вызов трассировщика. o Неожиданное прекращение трассировки, это выход из трассировочного калбэка, либо исключения. Для обхода этого можно выполнить цикл очистки флажка трассировщика в графе, после исполнения трассировки. Такого типа трассировка является медленной. Может использоваться быстрая трассировка, она не логична и это простое перечисление подряд идущих описателей: Код (Text): GpDirectSearchEntryReferenceInternal proc uses ebx GpBase:PVOID, GpLimit:PVOID, GpEntry:PVOID mov ebx,GpBase Check: cmp GpLimit,ebx ja @f xor eax,eax jmp Exit @@: cmp GpEntry,ebx mov eax,dword ptr [ebx + EhEntryType] je Next mov ecx,dword ptr [ebx + EhFlink] and ecx,NOT(TYPE_MASK) cmp GpEntry,ecx je Save and eax,TYPE_MASK jz Next cmp eax,HEADER_TYPE_JXX mov ecx,dword ptr [ebx + EhBranchLink] je IsValid test dword ptr [ebx + EhBranchType],BRANCH_DEFINED_FLAG jz Next IsValid: and ecx,NOT(TYPE_MASK) cmp GpEntry,ecx je Save Next: add ebx,ENTRY_HEADER_SIZE jmp Check Save: mov eax,ebx Exit: ret GpDirectSearchEntryReferenceInternal endp Флажки и структуры определены в хидере.