Как CallBack func?

Тема в разделе "WASM.BEGINNERS", создана пользователем P_F, 17 июн 2006.

Статус темы:
Закрыта.
  1. P_F

    P_F New Member

    Публикаций:
    0
    Регистрация:
    27 мар 2006
    Сообщения:
    116
    Адрес:
    Russia
    Есть структурка:


    Код (Text):
    1. struct  ExFunc
    2.   PCount dd ?   ;кол-во параметров.
    3.   pPars  dd ?   ;массив параметров.
    4.   FAddr  dd ?   ;адрес функ-и.
    5. ends




    И код её оживляющий (кривой, но главное смысл...):


    Код (Text):
    1. ebx == pointer to ExFunc
    2.  
    3.         mov     edx , [ebx].PCount 
    4.         mov     eax , [ebx].pPars      
    5.         CmpCount:                      
    6.             cmp     edx , 0        
    7.             je      CallTheFunc        
    8.             push        [eax]          
    9.             add     eax , 4            
    10.             dec     edx            
    11.             jmp     CmpCount           
    12.         CallTheFunc:           
    13.         call    [ebx].FAddr
    14.  


    Далее, некая часть памяти с n количеством таких структур назовём мем.скрипт.

    Ессно, немного дописав код, получим функу могущую екзекутить етот мем.скрипт..



    У кого-нить есть идея как, если мы имеем n мем.скрипт'ов

    и 1-у универсальную функу их екзекутирующую, сделать вызов

    функи из произвольной DLL требующей одним из параметров CallBackProc (для простоты (void)), чтоб выполнился ессно

    заданный мем.скрипт.?

    Т.е. какой адрес передать в функу в качестве CBProc?



    И функа с входным параметром калбэком НЕ имеет ещё одного типа (lpVoid *) параметра, сообщаемого автоматически в CallBackProc вот такой вот маленький нюанс.
     
  2. P_F

    P_F New Member

    Публикаций:
    0
    Регистрация:
    27 мар 2006
    Сообщения:
    116
    Адрес:
    Russia
    НАРОД !!! Ну хоть какую мыслю подкинте, а то уже с месяц долбаюсь с этим делом и всё на одном месте...
     
  3. asd

    asd New Member

    Публикаций:
    0
    Регистрация:
    12 мар 2005
    Сообщения:
    952
    Адрес:
    Russia
    Я что-то тебя плохо понял, что ты вообще хочешь. Такое ощущение, что ты делаешь какой-то универсальный перехватчик любых экспортируемых функций???



    Если я правильно понял, тебе нужно: при вызове твоей функции тебе нужно найти структуру ExFunc соответствующую функции из которой тебя вызвали, но ты не можешь передать указатель на неё???



    Если так, то можно сделать следующее: введи в ExFunc параметр return, который будет устанавливаться при перехвате. Затем при получении управления ищешь среди своих структур ту, в которой return=[esp] (если передаёшь управление с помощью call).



    Если я совсем не про то, то поясни задачу.
     
  4. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine


    Где ты её нашёл? Можно сделать указатель на массив структур ExFunc глобальным.
     
  5. P_F

    P_F New Member

    Публикаций:
    0
    Регистрация:
    27 мар 2006
    Сообщения:
    116
    Адрес:
    Russia
    2asd:

    Нет не перехватчик, но универсальный. Ядро итерпретатора под win32, но языково независимое...

    "Если я правильно понял, тебе нужно: при вызове твоей функции тебе нужно найти структуру ExFunc соответствующую функции из которой тебя вызвали, но ты не можешь передать указатель на неё???"

    Да именно так, но не перехватчик :dntknw:, и у меня массивы ExFunc структур...



    Cмысл в том что я передаю адрес своей функи(*) в некую Enum|Event|... функу(**), и при вызове * из внутренностей **, нужно сопоставить что вызывать...



    2IceStudent:

    "массив структур ExFunc" их много, и как раз какой запускать то, и надо понять...





    Глобальный указатель идея на которой я застопорился, всё дело вот в чём :

    1:

    треад1 делает:

    Код (Text):
    1.      m2m GlobalMemFunc, memFunc1
    2.       invoke DemoFunc,MyEnumFunc        ;некая функция энумерации
    3.  


    а в это время треад2 деляет:

    Код (Text):
    1.   m2m GlobalMemFunc, memFunc2
    2.       invoke DemoFunc,MyEnumFunc        ;некая функция энумерации
    3.  


    2:

    мы делаем

    Код (Text):
    1.      m2m GlobalMemFunc, memFunc1
    2.       invoke DemoFunc,MyEnumFunc,EVENT1        ;некая событийная функция
    3.       m2m GlobalMemFunc, memFunc2
    4.       invoke DemoFunc,MyEnumFunc,EVENT2        ;некая событийная функция


    При наступлении события EVENT1 выполнится memFunc2



    как это решить непредставляю...
     
  6. Smile

    Smile New Member

    Публикаций:
    0
    Регистрация:
    28 июл 2004
    Сообщения:
    129
    Cмысл в том что я передаю адрес своей функи(*) в некую Enum|Event|... функу(**), и при вызове * из внутренностей **, нужно сопоставить что вызывать...

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



    [​IMG] 1603539908__cppint1.txt
     
  7. P_F

    P_F New Member

    Публикаций:
    0
    Регистрация:
    27 мар 2006
    Сообщения:
    116
    Адрес:
    Russia
    Smile

    Спасибо, пригодилось, но не для этой задачи :dntknw:
     
  8. P_F

    P_F New Member

    Публикаций:
    0
    Регистрация:
    27 мар 2006
    Сообщения:
    116
    Адрес:
    Russia
    asd

    Если я совсем не про то, то поясни задачу.



    Попробую сформулировать найболее точно (как могу, толи я неселён с востановке, толи задача такакя :)):



    1.Существует несколько массивов структур вида:


    Код (Text):
    1. srtuct ...
    2.     FAddr   dd  ?     ;Адрес некой функции из системной или собственной DLL'ки.
    3.     PCount  dd  ?     ;Количество входных параметров функции.
    4.     Pars    dd  ?     ;Адрес массива параметров
    5. ends




    2.Есть кусок кода который реализует исполнение такого массива (пробегает по массиву и исполняет каждую структуру).



    3.Есть какая то DLL в которой есть функция:
    Код (Text):
    1. typedef void (*Demo_Call_Back_Func_Type)(void);
    2. void Demo_Func(Demo_Call_Back_Func_Type Func);




    Проблема в том что бы написать функцию , типа Demo_Call_Back_Func_Type,

    такую, что б её аддр. можно было передать в Demo_Func. И соответственно когда производился вызов это функции, она переходила к исполнению кода 2. для заданного массива.При этом должно быть возможно "параллельное" выполнение нескольких (как минимум двух) кусков кода

    2. для разных массивов структур 1.
     
  9. Smile

    Smile New Member

    Публикаций:
    0
    Регистрация:
    28 июл 2004
    Сообщения:
    129
    Код (Text):
    1. Проблема в том что бы написать функцию , типа Demo_Call_Back_Func_Type,
    2. такую, что б её аддр. можно было передать в Demo_Func. И соответственно когда производился вызов это функции, она переходила к исполнению кода 2. для заданного массива




    Товаришь, я вас никак не могу понять :). Если нужно привязать определенный массив к функции, почему не зделать так



    typedef void (*Demo_Call_Back_Func_Type)(void);

    void Demo_Func(Demo_Call_Back_Func_Type Func);

    Demo_Func(make_my_callback(&my_struct))



    Сгенерировать функцию которая будет знать свой массив.

    Информацию о входных параметрах, тоже несложно добавить.
     
  10. P_F

    P_F New Member

    Публикаций:
    0
    Регистрация:
    27 мар 2006
    Сообщения:
    116
    Адрес:
    Russia
    2 Smile :

    Я вас то же...

    А можно по подробней проDemo_Func(make_my_callback(&my_struct)), и что вообще имелось ввиду или под этим понималось...
     
  11. asd

    asd New Member

    Публикаций:
    0
    Регистрация:
    12 мар 2005
    Сообщения:
    952
    Адрес:
    Russia
    Смотри: допустим твою Demo_Call_Back_Func_Type вызывают из ф-ии а с помощью call. При передаче управления на Demo_Call_Back_Func_Type в стеке лежит адрес возврата куда-то в ф-ию а, а при вызове из ф-ии б- адрес возврата в б. Так же у тебя есть структуры для а и для б. К примеру создай 2 таблички:

    1. список адресов возврата - все возможные адреса, откуда может быть вызвана Demo_Call_Back_Func_Type

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



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



    Можешь ли ты создать такие таблички?



    Теперь про параллельность исполнения - все переменныё в стек, и проблем быть не должно.



    p.s. это только у меня строки далеко за правую границу заезжают? Причём только в некоторых топиках.
     
  12. P_F

    P_F New Member

    Публикаций:
    0
    Регистрация:
    27 мар 2006
    Сообщения:
    116
    Адрес:
    Russia
    asd

    Можешь ли ты создать такие таблички?

    В том всё и дело что нет...



    Смысл такой:

    Структуру ExFunc исполнить можно, НО если имеем вот так:

    Код (Text):
    1. PCount dd
    1 кол-во параметров равно 1

    Код (Text):
    1. FAddr  dd
    == адрес какой-нибудь функи типа Demo_Func

    Код (Text):
    1. pPars  dd
    ??? а вот сюда надо чё-то засунуть...

    Вопрос в том Что, если знаем какой массив должен быть

    исполнен при переходе на Этот адрес из недр DLL?



    { кстати в FAddr не обязательно функа из win32 API это

    может быть любая написаная юзером-программером }




    p.s. А в опере с выравниванием по ширине не заезжают :),

    вот без :dntknw:

    p.s.s я стараюсь следить...
     
  13. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    P_F

    Похоже, ты упорно пытаешься вытащить себя за волосы :))

    Простой вариант: добавить к массиву ExFunc исполняемый заголовок,

    который будет пушить адрес массива и передавать управление на функцию MyEnumFunc,

    а в Demo_Func нужно передавать адрес самого массива (заголовка)

    Пример заголовка массива (8 байт):

    Код:
    Код (Text):
    1.   nop
    2.   mov eax,MyEnumFunc
    3.   call eax
    Эквивалентная структура заголовка:
    Код (Text):
    1. struct ExFuncHeader
    2.   op1        dw ? ;0B890h = nop + mov eax,imm32
    3.   lpEnumFunc dd ? ;offset MyEnumFunc
    4.   op2        dw ? ;0D0FFh = call eax
    5. ends
    6. proc MyEnumFunc
    7.   ;option prologue : none ;!!! без пролога\эпилога
    8.   ;option epilogue : none
    9.   pop eax ;указатель на первый элемент массива ExFunc
    10.   ......
    11. endp
    PS: Чтобы не нарваться на хардварный DEP в WinXP нужно чтобы страница памяти, в которой хранятся массивы,

    имела атрибут executable

    PPS: в качестве варианта можно еще на основе SEH все это дело замутить, но получится сложнее и медленнее



    asd

    > "строки далеко за правую границу заезжают?"

    Скажи "спасибо" Smile ;) Такая фигня возникает, когда тегом code оформляют длинные строки,

    не умещающиеся на экране. Если уважаемый Smile удосужится исправить свою последнюю цитату,

    то все станет нормально
     
  14. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    P_F

    Если число параллельно запускаемых нумераторов ограничено, то можно и глобальный закольцованный массивчик использовать. К примеру так:
    Код (Text):
    1. MaxExFuncCount = 4    ;макс.число нумераторов, для простоты = 2,4,8
    2. ExFuncArray dd MaxFuncCount+1 dup 0  ;счетчик + кольцевой массив указателей lpExFunc
    3.  
    4. ;функция регистрации ExFunc
    5. RegisterExFunc proc lpExFunc:dword
    6.   mov eax,ExFuncArray            ;счетчик
    7.   inc eax
    8.   and eax,MaxExFuncCount-1       ;кольцо
    9.   mov edx,lpExFunc
    10.   mov [eax*4+ExFuncArray+4],edx  ;пишем ссылку на ExFunc в массив ExFuncArray
    11.   lea eax,[eax*8+MyEnumFunc]     ;выдаем указатель на EnumFunc со смещением в зависимости от счетчика
    12.   ret
    13. RegisterExFunc endp
    14.  
    15. MyEnumFunc proc
    16.   option prologue : none  ;!!! должно быть без пролога
    17.   option epilogue : none
    18.   cnt=0
    19.   repeat MaxExFuncCount   ;блоки по 8 байт
    20.     mov eax,cnt           ;5 байт
    21.     jmp @F                ;2 байта при MaxExFuncCount < 16
    22.     nop                   ;1 байт
    23.     cnt = cnt+1
    24.   endm
    25. @@:
    26.   mov eax,[eax*4+ExFuncArray+4] ;получаем указатель на ExFunc
    27.   ...
    28. MyEnumFunc endp
    29.  
    30. Вызов:
    31.   invoke RegisterExFunc,lpExFunc1
    32.   invoke Demo_Func,eax
     
  15. P_F

    P_F New Member

    Публикаций:
    0
    Регистрация:
    27 мар 2006
    Сообщения:
    116
    Адрес:
    Russia
    leo

    Да имеено так "вытащить себя за волосы" :) ...

    Идея класс!

    Но:

    А если кол-во массивов не ограничено(не считая ресурсных ограничений)?

    И возможно ли задать "атрибут executable" для куска

    памяти выделеного динамически(например вызовом GlobalAlloc)?



    p.s. про SEH'и тоже думал но это изврат, но главное: время критично.
     
  16. P_F

    P_F New Member

    Публикаций:
    0
    Регистрация:
    27 мар 2006
    Сообщения:
    116
    Адрес:
    Russia
    leo

    Чё то я туплю: VirtualAlloc + PAGE_EXECUTE_READWRITE сори...

    А как или куда вернуться из MyEnumFunc?
     
  17. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    P_F

    > "VirtualAlloc + PAGE_EXECUTE_READWRITE"

    Еще есть VirtualQuery для контроля и VirtualProtect для изменения защиты страниц



    > "как или куда вернуться из MyEnumFunc?"

    По обычному ret вернется туда, откуда был вызов заголовка ExFuncHeader.

    Т.к. функции ExFuncHeader и MyEnumFunc формально не имеют параметров, то их вызов по call просто пушит в стек адрес, следующий за call, т.е. вызов заголовка пушит адрес возврата, а вызов MyEnumFunc из заголовка пушит адрес начала массива. Затем MyEnumFunc делает pop адреса массива и в стеке остается адрес возврата, на который и происходит переход по ret. Разумеется MyEnumFunc должна быть 1) без всяких авто-прологов\эпилогов и 2) ее нельзя вызывать иначе как через ExFuncHeader. В принципе конечно можно ее сделать обычной с параметром lpExFunc, но это потребует увеличения кода в заголовке массива
     
  18. P_F

    P_F New Member

    Публикаций:
    0
    Регистрация:
    27 мар 2006
    Сообщения:
    116
    Адрес:
    Russia
    leo



    Немного не понял нюанс:

    Затем MyEnumFunc делает pop адреса массива


    Код (Text):
    1. struct ExFuncHeader
    2.   op1        dw ? ;0B890h = nop + mov eax,imm32
    3.   lpEnumFunc dd ? ;offset MyEnumFunc
    4.   op2        dw ? ;0D0FFh = call eax
    5. [u]ArrayAddr[/u]:
    6. ends
    7.  
    8. proc MyEnumFunc
    9.   ;option prologue none ...
    10.   [u]pop eax[/u] ;указатель на первый элемент массива ExFunc
    11.   ......
    12. endp




    После pop eax в eax будет ArrayAddr?

    И ещё (вопрос, если мона) а этот код будет выполняться на любом Intel'е?
     
  19. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    P_F

    > "После pop eax в eax будет ArrayAddr?"

    Да. Имеется ввиду, что сразу за заголовком идет массив структур ExFunc



    > "этот код будет выполняться на любом Intel'е?"

    Конечно, а чего тут особенного - обычные mov, call и pop.

    Более того, установка атрибута executable требуется только в 64-битных AMD и Intel под XP SP2 (ну или чего там еще MS придумает в будущем :)



    Уточнение насчет второго варианта с кольцевым буфером

    > "А если кол-во массивов не ограничено?"

    Речь идет не о количестве массивов вообще, а о количестве одновременно запущенных Demo_Func, для которых должна быть валидная ссылка на свой массив в этом буфере. Не очень представляю, зачем может понадобиться запускать параллельно скажем более 8-ми нумераторов ? А последовательно, хоть тысячу запускай
     
  20. P_F

    P_F New Member

    Публикаций:
    0
    Регистрация:
    27 мар 2006
    Сообщения:
    116
    Адрес:
    Russia
    leo

    Речь идет не о количестве массивов вообще, а о количестве одновременно запущенных Demo_Func, для которых должна быть валидная ссылка на свой массив в этом буфере.
    Код (Text):
    1. struct ExFuncHeader
    2.   op1        dw ? ;0B890h = nop + mov eax,imm32
    3.   lpEnumFunc dd ? ;offset MyEnumFunc
    4.   op2        dw ? ;0D0FFh = call eax
    5.   lpList     dd ? ; указатель на структуру список
    6. ends


    Я приписал пока Header ко всем, так можно сколько угодно.

    Хотя это не оптимально но пока пойдёт, потом прикручу список и тоже можно будет...



    Не очень представляю, зачем может понадобиться запускать параллельно скажем более 8-ми нумераторов ?

    Повторюсь это интерпретатор, и по возможности пытаюсь предусмотреть все нюансы... К примеру:


    Код (Text):
    1. MyFunc{}
    2. ....
    3. ho = C_Obj();                 //создаёт объект
    4. SetEventAction(ho,OE_*,MyFunc);  //сопостовляет Функу событию ObjectEvent_*




    зтот код на C аналог внутренней структуры проги:

    MyFunc -- массив (список) ExFunc + ExFuncHeader для простоты адрес ExFuncHeader == efhAddr

    И есть другой массив, один из елементов которого ExFunc с полями:
    Код (Text):
    1.  FAddr  =  SetEventAction
    2.  pPars  =  {ho , OE_* , efhAddr}
    3.  pCount =  3


    Смысл: хрен его знает, сколько юэер сделает этих MyFunc'ов,

    сколько зарегит эвентов и когда они будут вызываться, природа обьекта ho не определена...



    P.S. Leo Большое спасибо за идею!

    P.S.S. интересно, а на *nix эту схему возможно перенести или она не канает, адрес возврата тоже в стеке ...
     
Статус темы:
Закрыта.