Забавная вещь - на С не могу получить адрес по которому кранится адрес импортируемой функции, хотя на асме это делается элементарно Код (Text): __asm lea eax, MessageBoxA На С не могу найти ничего похожего. Например Код (Text): void *f = MessageBoxA; или void *f = &MessageBoxA; помещает в f собственно адрес функции MessageBoxA а не адрес адреса.
wsd GetProcAddress возвращает адрес самой функции. Например: Код (Text): MessageBox(...); компилятор транслирует в что то типа: Код (Text): push ... ... push ... call dword ptr [1234h] ; содержимое адреса 1234h - 5678h в результе call программа перейдет к 5678h. А как на с получить адрес адреса, т.е., 1234h ?
katrus Сканировать код функции (с дизассемблером длин) на предмет нахождения инструкции 0xff 0x15? hint: bcc генерирует другую инструкцию для вызова API
zoool Ну так это ведь в точности то что я написал. Мне интересно можно ли подобную конструкцию написать на чистом С?
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 ----- пока вспоминал коды - уже ответили пойми - пойнтер в таблице импорта - это не элемент языка Си для которого существует понятие "адрес" это - детали конкретной реализации
Код (Text): #include "stdafx.h" #include <windows.h> #define GetImpFunc(macro_FuncName, macro_DestVar) _asm{lea eax, macro_FuncName} _asm{mov macro_DestVar, eax} int main(int argc, char* argv[]) { PVOID f; GetImpFunc(MessageBoxA, f); return 0; } вроде так. Не сложно ж ))
cppasm сканирование и патчинг IAT - 100% сишный код для 32 и 64 бит один сорц без единого #ifdef _WIN64 что же по-твоему тогда переносимый? или так просто сказал?
z0mailbox под переносимостью предпологается простота портирования на другие платформы. А не только на x86-64. Может нужно будет на *nix'ах юзать приложение, или вообще на встраиваемых системах.
n0name нуну сама постановка задачи - "получить адрес импортированой функции ОС-независимым образом" мегалол ваще, децкий сад в С нет такого понятия - "импортированная функция", это особенности реализации на конкретном виде исполняемых файлов, например PE. Все оси исполняющие PE и имеющие в СДК хедер winnt.h (IMAGE_*) - все эти оси получат переносимый код. Все остальные оси никаким хером не получат ни переносимый ни какой другой код. Вот в досе например ваще не было никаких импортируемых функций и что - С не юзали там чтоли?
Код (Text): SOL.K>dumpbin /linkermember:1 user32.lib | find "MessageBoxW" 388D4 _MessageBoxW@16 388D4 __imp__MessageBoxW@16 _imp__MessageBoxW, что бы это могло быть? Код (Text): extern "C" void __stdcall _imp__MessageBoxW(int, int, int, int); void main() { volatile PVOID pFunc1 = _imp__MessageBoxW; volatile PVOID pFunc2 = &_imp__MessageBoxW; // то же, что и предыдущая строка } Бинго. Получаем адрес элемента IAT, содержащий адрес MessageBoxW. Почти что средствами Си. У кого есть возможность - можете потестить на отличных от MS компиляторах. Скорее всего тоже будет работать.
С тех пор как это уже сделано, вот бонус - выкусывает _imp_* из библиотек. Чтобы вручную не определять. MakeImps.bat user32.lib > user32_imps.h Код (Text): @rem @rem MakeImps.bat - thingy to define loads of pointers to IAT @rem @rem Usage: MakeImps.bat kernel32.lib > kernel_imps.h @rem @rem @rem To overcome strange behavior of MS C/C++ compiler v15.0 with optimizations enabled, @rem "__declspec(dllimport)" now prepended before each declaration. This entails linker @rem warning 4049, which can be disabled by specifying "/ignore:4049" in command line. @rem Info: @rem For extern "C" linkage the following function mangling scheme defined: @rem ________________________________________________________________________________________________ @rem original func name mangled func name mangled import thunk @rem ________________________________________________________________________________________________ @rem __cdecl void func0() -> _func0 -> __imp__func0 @rem __cdecl void func1(int) -> _func1 -> __imp__func1 @rem __stdcall void func2() -> _func2@0 -> __imp__func2@0 @rem __stdcall void func3(int, int, int) -> _func3@12 -> __imp__func3@12 @rem __fastcall void func4() -> @func4@0 -> __imp_@func4@0 @rem __fastcall void func5(int, int) -> @func5@8 -> __imp_@func5@8 @rem ________________________________________________________________________________________________ @rem @rem (!) Don't be fooled by the "mangled func name" column in the table above - function still @rem exported by it's original name (of course, if there's no "real" mangling made by compiler) @rem @rem (!) No information for x64 currently @if "%1" == "" @goto error @if NOT "%2" == "ExtendedSyntaxEnabled" (@cmd.exe /V:ON /C %0 %1 ExtendedSyntaxEnabled) & (@goto :EOF) @echo Stage1... >con @dumpbin.exe /linkermember:2 %1 | find "__imp_" > %tmp%\list.txt @type %%tmp%%\list.txt | @find "__imp_@" > %tmp%\list_fastcall.txt @type %%tmp%%\list.txt | @find "__imp__" > %tmp%\list2.txt @type %%tmp%%\list2.txt | @find /V "@" > %tmp%\list_cdecl.txt @type %%tmp%%\list2.txt | @find "@" > %tmp%\list_stdcall.txt @echo Stage2. Wait... >con @echo // @echo // IAT addresses defines from %1 @echo // @echo. @echo. @echo extern "C" @echo { @rem CDECL @rem @for %%i in (%tmp%\list_cdecl.txt) do @if %%~zi == 0 @goto CDECL_END @echo // @echo // cdecl @echo // @for /F "tokens=2*" %%i in (%tmp%\list_cdecl.txt) do @set f=%%i & @set f=!f:~1! & @call :put __cdecl !f! 0 :CDECL_END @rem FASTCALL @rem @for %%i in (%tmp%\list_fastcall.txt) do @if %%~zi == 0 @goto FASTCALL_END @echo. @echo. @echo. @echo // @echo // fastcall @echo // @for /F "tokens=3* delims=@ " %%i in (%tmp%\list_fastcall.txt) do @set f=_imp_@%%i & @call :put __fastcall !f! %%j :FASTCALL_END @rem STDCALL @rem @for %%i in (%tmp%\list_stdcall.txt) do @if %%~zi == 0 @goto STDCALL_END @echo. @echo. @echo. @echo // @echo // stdcall @echo // @echo. @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 :STDCALL_END @echo. @echo } @goto cleanup :put @set s=__declspec(dllimport) void %1 %2( @for /L %%i in (8, 4, %3) do @set s=!s!int, @if /I %3 GTR 0 @set s=%s%int @set s=%s%); @echo %s% @goto :EOF :error @echo Something wrong @echo Usage: MakeImps.bat kernel32.lib ^> kernel_imps.h @goto :EOF :cleanup @del %tmp%\list.txt @del %tmp%\list2.txt @del %tmp%\list_cdecl.txt @del %tmp%\list_fastcall.txt @del %tmp%\list_stdcall.txt @echo Done.>con @exit Edit: обновлён MakeImps.bat
Было обнаружено, что при следующих условиях при этих условиях компилятор из MS VS9.0 сходит с ума и генерирует при вызове конкретной импортируемой функции вместо Код (Text): FF15 00304000 call [403000] вот это: Код (Text): E8 AC300000 call 403000 (Здесь 403000 - VA таблицы импорта, в данном случае по этому адресу располагается адрес импортируемой функции). Забавно, но способ избавиться от этого без отключения оптимизаций заключается в объявлении указателя на таблицу импорта с модификатором __declspec(dllimport). Например: Код (Text): extern "C" __declspec(dllimport) void __cdecl _imp__DllOneProc(); После этого, правда, линкер начинает показывать warning 4049 (locally defined symbol imported), который приходится отключать (/ignore:4049).