Получить адрес адреса импортируемой функции

Тема в разделе "LANGS.C", создана пользователем katrus, 9 апр 2008.

  1. katrus

    katrus New Member

    Публикаций:
    0
    Регистрация:
    7 мар 2007
    Сообщения:
    612
    Забавная вещь - на С не могу получить адрес по которому кранится адрес импортируемой функции, хотя на асме это делается элементарно
    Код (Text):
    1. __asm  lea eax, MessageBoxA
    На С не могу найти ничего похожего. Например
    Код (Text):
    1. void *f = MessageBoxA;
    2. или
    3. void *f = &MessageBoxA;
    помещает в f собственно адрес функции MessageBoxA а не адрес адреса.
     
  2. wsd

    wsd New Member

    Публикаций:
    0
    Регистрация:
    8 авг 2007
    Сообщения:
    2.824
    katrus
    getprocaddress
    Код (Text):
    1. FARPROC GetProcAddress(
    2.   HMODULE hModule,
    3.   LPCSTR lpProcName
    4. );
     
  3. katrus

    katrus New Member

    Публикаций:
    0
    Регистрация:
    7 мар 2007
    Сообщения:
    612
    wsd
    GetProcAddress возвращает адрес самой функции.
    Например:
    Код (Text):
    1. MessageBox(...);
    компилятор транслирует в что то типа:
    Код (Text):
    1. push ...
    2. ...
    3. push ...
    4. call dword ptr [1234h]   ; содержимое адреса 1234h - 5678h
    в результе call программа перейдет к 5678h. А как на с получить адрес адреса, т.е., 1234h ?
     
  4. wsd

    wsd New Member

    Публикаций:
    0
    Регистрация:
    8 авг 2007
    Сообщения:
    2.824
    katrus
    это же IAT
    читай статьи про хуки иата
     
  5. censored

    censored New Member

    Публикаций:
    0
    Регистрация:
    5 июл 2005
    Сообщения:
    1.615
    Адрес:
    деревня "Анонимные Прокси"
    katrus
    Сканировать код функции (с дизассемблером длин) на предмет нахождения инструкции 0xff 0x15?

    hint: bcc генерирует другую инструкцию для вызова API
     
  6. zoool

    zoool New Member

    Публикаций:
    0
    Регистрация:
    1 дек 2007
    Сообщения:
    412
    _asm
    {
    lea eax, dword ptr [MessageBoxA]
    mov [f], eax
    };

    бгг
     
  7. katrus

    katrus New Member

    Публикаций:
    0
    Регистрация:
    7 мар 2007
    Сообщения:
    612
    zoool

    Ну так это ведь в точности то что я написал. Мне интересно можно ли подобную конструкцию написать на чистом С?
     
  8. z0mailbox

    z0mailbox z0

    Публикаций:
    0
    Регистрация:
    3 фев 2005
    Сообщения:
    635
    Адрес:
    Russia СПБ
    katrus
    это на встроенном асме!
    если у тебя файл *.asm - всегда строится промежуточная jmptable
    и вызов выглядит так:
    call GetProcessHeap e8 xx xx xx xx
    ...
    GetProcessHeap:
    jmp dword ptr [_imp_GetProcessHeap] ff 25 xx xx xx xx

    а вот если у тебя файл *.с/cpp - то там так:
    call dword ptr GetProcessHeap ff 15 xx xx xx xx

    по-поводу адреса адреса на си - фактически ты хочешь адрес внутри таблицы импорта
    простого способа думаю нет, первое что приходит в голову - через PE-header - IAT

    -----
    пока вспоминал коды - уже ответили :)

    пойми - пойнтер в таблице импорта - это не элемент языка Си для которого существует понятие "адрес"
    это - детали конкретной реализации
     
  9. zoool

    zoool New Member

    Публикаций:
    0
    Регистрация:
    1 дек 2007
    Сообщения:
    412
    Код (Text):
    1. #include "stdafx.h"
    2. #include <windows.h>
    3.  
    4. #define GetImpFunc(macro_FuncName, macro_DestVar) _asm{lea eax, macro_FuncName} _asm{mov macro_DestVar, eax}
    5.  
    6. int main(int argc, char* argv[])
    7. {
    8. PVOID f;
    9.  
    10.     GetImpFunc(MessageBoxA, f);
    11.     return 0;
    12. }
    вроде так. Не сложно ж ))
     
  10. wsd

    wsd New Member

    Публикаций:
    0
    Регистрация:
    8 авг 2007
    Сообщения:
    2.824
    zoool
    ему чистый си нужен :)
    а ты просто асм в дефайн убрал ;)
     
  11. zoool

    zoool New Member

    Публикаций:
    0
    Регистрация:
    1 дек 2007
    Сообщения:
    412
    дефайн - это уже Си )))
    а в макросах я имею права писать что угодно :Р
     
  12. z0mailbox

    z0mailbox z0

    Публикаций:
    0
    Регистрация:
    3 фев 2005
    Сообщения:
    635
    Адрес:
    Russia СПБ
    zoool

    непереносимый код получается
     
  13. cppasm

    cppasm New Member

    Публикаций:
    0
    Регистрация:
    18 июл 2006
    Сообщения:
    923
    не более непереносимый чем сканировать IAT :)
     
  14. z0mailbox

    z0mailbox z0

    Публикаций:
    0
    Регистрация:
    3 фев 2005
    Сообщения:
    635
    Адрес:
    Russia СПБ
    cppasm
    сканирование и патчинг IAT - 100% сишный код
    для 32 и 64 бит один сорц без единого #ifdef _WIN64
    что же по-твоему тогда переносимый? или так просто сказал?
     
  15. zoool

    zoool New Member

    Публикаций:
    0
    Регистрация:
    1 дек 2007
    Сообщения:
    412
    z0mailbox
    Не ищите проблему там, где ее нет.
     
  16. n0name

    n0name New Member

    Публикаций:
    0
    Регистрация:
    5 июн 2004
    Сообщения:
    4.336
    Адрес:
    Russia
    z0mailbox
    под переносимостью предпологается простота портирования на другие платформы. А не только на x86-64. Может нужно будет на *nix'ах юзать приложение, или вообще на встраиваемых системах.
     
  17. z0mailbox

    z0mailbox z0

    Публикаций:
    0
    Регистрация:
    3 фев 2005
    Сообщения:
    635
    Адрес:
    Russia СПБ
    n0name
    нуну
    сама постановка задачи - "получить адрес импортированой функции ОС-независимым образом"
    мегалол ваще, децкий сад

    в С нет такого понятия - "импортированная функция", это особенности реализации на конкретном виде исполняемых файлов, например PE. Все оси исполняющие PE и имеющие в СДК хедер winnt.h (IMAGE_*) - все эти оси получат переносимый код. Все остальные оси никаким хером не получат ни переносимый ни какой другой код. Вот в досе например ваще не было никаких импортируемых функций и что - С не юзали там чтоли?
     
  18. Sol_Ksacap

    Sol_Ksacap Миша

    Публикаций:
    0
    Регистрация:
    6 мар 2008
    Сообщения:
    623
    Код (Text):
    1. SOL.K>dumpbin /linkermember:1 user32.lib | find "MessageBoxW"
    2.     388D4 _MessageBoxW@16
    3.     388D4 __imp__MessageBoxW@16
    _imp__MessageBoxW, что бы это могло быть?

    Код (Text):
    1. extern "C" void __stdcall _imp__MessageBoxW(int, int, int, int);
    2.  
    3. void main()
    4. {
    5.     volatile PVOID pFunc1 = _imp__MessageBoxW;
    6.     volatile PVOID pFunc2 = &_imp__MessageBoxW; // то же, что и предыдущая строка
    7. }
    Бинго. Получаем адрес элемента IAT, содержащий адрес MessageBoxW. Почти что средствами Си.
    У кого есть возможность - можете потестить на отличных от MS компиляторах. Скорее всего тоже будет работать.
     
  19. Sol_Ksacap

    Sol_Ksacap Миша

    Публикаций:
    0
    Регистрация:
    6 мар 2008
    Сообщения:
    623
    С тех пор как это уже сделано, вот бонус - выкусывает _imp_* из библиотек. Чтобы вручную не определять.

    MakeImps.bat user32.lib > user32_imps.h
    Код (Text):
    1. @rem
    2. @rem MakeImps.bat - thingy to define loads of pointers to IAT
    3. @rem
    4. @rem Usage: MakeImps.bat kernel32.lib > kernel_imps.h
    5. @rem
    6. @rem
    7. @rem To overcome strange behavior of MS C/C++ compiler v15.0 with optimizations enabled,
    8. @rem "__declspec(dllimport)" now prepended before each declaration. This entails linker
    9. @rem warning 4049, which can be disabled by specifying "/ignore:4049" in command line.
    10.  
    11.  
    12. @rem Info:
    13. @rem For extern "C" linkage the following function mangling scheme defined:
    14. @rem ________________________________________________________________________________________________
    15. @rem            original func name      mangled func name   mangled import thunk
    16. @rem ________________________________________________________________________________________________
    17. @rem __cdecl    void    func0()         ->  _func0      ->  __imp__func0
    18. @rem __cdecl    void    func1(int)      ->  _func1      ->  __imp__func1
    19. @rem __stdcall  void    func2()         ->  _func2@0    ->  __imp__func2@0
    20. @rem __stdcall  void    func3(int, int, int)    ->  _func3@12   ->  __imp__func3@12
    21. @rem __fastcall void    func4()         ->  @func4@0    ->  __imp_@func4@0
    22. @rem __fastcall void    func5(int, int)     ->  @func5@8    ->  __imp_@func5@8
    23. @rem ________________________________________________________________________________________________
    24. @rem
    25. @rem (!) Don't be fooled by the "mangled func name" column in the table above - function still
    26. @rem     exported by it's original name (of course, if there's no "real" mangling made by compiler)
    27. @rem
    28. @rem (!) No information for x64 currently
    29.  
    30.  
    31.  
    32. @if "%1" == "" @goto error
    33. @if NOT "%2" == "ExtendedSyntaxEnabled" (@cmd.exe /V:ON /C %0 %1 ExtendedSyntaxEnabled) & (@goto :EOF)
    34.  
    35.  
    36.  
    37. @echo Stage1... >con
    38. @dumpbin.exe /linkermember:2 %1 | find "__imp_" > %tmp%\list.txt
    39. @type %%tmp%%\list.txt | @find "__imp_@" > %tmp%\list_fastcall.txt
    40. @type %%tmp%%\list.txt | @find "__imp__" > %tmp%\list2.txt
    41. @type %%tmp%%\list2.txt | @find /V "@" > %tmp%\list_cdecl.txt
    42. @type %%tmp%%\list2.txt | @find "@" > %tmp%\list_stdcall.txt
    43.  
    44.  
    45.  
    46. @echo Stage2. Wait... >con
    47.  
    48. @echo //
    49. @echo // IAT addresses defines from %1
    50. @echo //
    51. @echo.
    52. @echo.
    53. @echo extern "C"
    54. @echo {
    55.  
    56.  
    57.  
    58. @rem CDECL
    59. @rem
    60. @for %%i in (%tmp%\list_cdecl.txt) do @if %%~zi == 0 @goto CDECL_END
    61. @echo //
    62. @echo // cdecl
    63. @echo //
    64.  
    65. @for /F "tokens=2*" %%i in (%tmp%\list_cdecl.txt) do @set f=%%i & @set f=!f:~1! & @call :put __cdecl !f! 0
    66. :CDECL_END
    67.  
    68.  
    69.  
    70. @rem FASTCALL
    71. @rem
    72. @for %%i in (%tmp%\list_fastcall.txt) do @if %%~zi == 0 @goto FASTCALL_END
    73. @echo.
    74. @echo.
    75. @echo.
    76. @echo //
    77. @echo // fastcall
    78. @echo //
    79.  
    80. @for /F "tokens=3* delims=@ " %%i in (%tmp%\list_fastcall.txt) do @set f=_imp_@%%i & @call :put __fastcall !f! %%j
    81. :FASTCALL_END
    82.  
    83.  
    84.  
    85. @rem STDCALL
    86. @rem
    87. @for %%i in (%tmp%\list_stdcall.txt) do @if %%~zi == 0 @goto STDCALL_END
    88. @echo.
    89. @echo.
    90. @echo.
    91. @echo //
    92. @echo // stdcall
    93. @echo //
    94. @echo.
    95.  
    96. @for /F "tokens=2,3* delims=@ " %%i in (%tmp%\list_stdcall.txt) do @set f=%%i & @set f=!f:~1! & @call :put __stdcall !f! %%j
    97. :STDCALL_END
    98.  
    99.  
    100. @echo.
    101. @echo }
    102. @goto cleanup
    103.  
    104.  
    105.  
    106. :put
    107. @set s=__declspec(dllimport) void %1 %2(
    108. @for /L %%i in (8, 4, %3) do @set s=!s!int,
    109. @if /I %3 GTR 0 @set s=%s%int
    110. @set s=%s%);
    111. @echo %s%
    112. @goto :EOF
    113.  
    114.  
    115. :error
    116. @echo Something wrong
    117. @echo Usage: MakeImps.bat kernel32.lib ^> kernel_imps.h
    118. @goto :EOF
    119.  
    120.  
    121. :cleanup
    122. @del %tmp%\list.txt
    123. @del %tmp%\list2.txt
    124. @del %tmp%\list_cdecl.txt
    125. @del %tmp%\list_fastcall.txt
    126. @del %tmp%\list_stdcall.txt
    127.  
    128.  
    129. @echo Done.>con
    130. @exit
    Edit: обновлён MakeImps.bat
     
  20. Sol_Ksacap

    Sol_Ksacap Миша

    Публикаций:
    0
    Регистрация:
    6 мар 2008
    Сообщения:
    623
    Было обнаружено, что при следующих условиях
    при этих условиях компилятор из MS VS9.0 сходит с ума и генерирует при вызове конкретной импортируемой функции вместо
    Код (Text):
    1. FF15 00304000   call [403000]
    вот это:
    Код (Text):
    1. E8 AC300000 call 403000
    (Здесь 403000 - VA таблицы импорта, в данном случае по этому адресу располагается адрес импортируемой функции).

    Забавно, но способ избавиться от этого без отключения оптимизаций заключается в объявлении указателя на таблицу импорта с модификатором __declspec(dllimport). Например:
    Код (Text):
    1. extern "C" __declspec(dllimport) void __cdecl _imp__DllOneProc();
    После этого, правда, линкер начинает показывать warning 4049 (locally defined symbol imported), который приходится отключать (/ignore:4049).