у меня 2 идеи: 1. не использовать глобальных переменных и повыёживаться с Апишками. Все глобальные переменные запихнуть в структуру, а указатель на неё будет возвращать функция, что-то типа: Код (Text): void* __declspec(naked) get_global_struct_pointer() { __asm { call $+5 pop eax sub eax, ... } } Что касается Апишек - тут можно заставить линкер сгенерировать их вызов в виде Код (Text): ... call some_func ... some_func: db 0bB8, 0, 0, 0 jmp eax помойму, такое возможно. минус - придётся изуродовать сишный код. 2. Релоки. Тут проблема в том, чтобы сгенерировать "чистый" экзешник, с одной секцией - чтобы потом можно было её легко выдрать. Линкер упорно отказывается совмещать .reloc с другими секциями. Можно, конечно, собрать свой линкер, но не очень-то охота.
т.к. это Си, то будет малость сложнее. 1 что надо найти - handle of kernel 1) анализируем seh 2) анализируем адрес возврата из программы (но т.к. это Си, то с этим будут траблы, хотя этот способ проще и работает даже под Windows 7) найдя handle of kernel анализируем PE заголовок kernel32 (ибо handle это и есть указатель на загруженную dll), и ищем 2 API LoadLibraryA и GetProcAddress (ну последнюю можно и не искать, ее аналог придется написать для поиска первой), а дальше все - живи Код (Text): api call (TAPIName)(GetProcAddress(LoadLibrary(getstr(STR_KERNEL32)), getstr(STR_APINAME)))(api params); где getstr - функция возвращающая указатель на нужную строку из динамической памяти
киньте в меня тапком, если эта тема не поднималась на васме (вроде бы 1-2 года назад). п.с.: лучше дельту хранить в ebx, а не eax
Прошу прощения, но поиск апишек меня не интересует. меня интересует именно базонезависимый код. Что касается "дельту хранить в евх" - не совсем понятно как вы заставите делать это компилятор?
DWORD __declspec(naked)get_delta() { __asm { call __1 __1: pop eax sub eax, offset __1 ret } } для дельты, вызываю каждый раз когда надо. переменные храню в функцие забитой нулями. для работы с переменными делаю так: DWORD get_var(DWORD var) { return *(PDWORD)((DWORD)&__variables__ + get_delta() + var); } void set_var(DWORD var, DWORD val) { *(PDWORD)((DWORD)&__variables__ + get_delta() + var) = val; } надеюсь идея ясна.
Сам сейчас занимаюсь написанием базонезависимого кода на C++. Удалось спроектировать прогу так, что глобальные переменные не потребовались (впрочем, как и секция данных - все данные генерируются кодом). Дельта-смещение понадобилось всего в одном месте - для получения стартового адреса процедуры, которая крутиццо в другом потоке. Адреса API функций загружаю в структуру, указатель на которую в дальнейшем передаю куда надо. Сама структура хранится в стеке текущего потока. На асме в проге написано от силы 10 строк, остальное на С++. Код (Text): void __declspec(naked) EntryPoint() { __asm { ... // исполняем свой код call Main ... } } void Main() { // инициализируем таблицу вызовов CALLTABLE CallTable; if (!InitializeCallTable(&CallTable)) // если во время инициализации таблицы вызовов произошла ошибка - вернем управление return; ... // возвращаем управление return; } // структура таблицы вызовов struct CALLTABLE { // загружаются непосредственно кодом проги DWORD (*Kernel32_LoadLibraryA)(PCHAR ModuleName); DWORD (*Kernel32_GetProcAddress)(DWORD ModuleHandle,PCHAR ProcedureName); // загружаются с использованием LoadLibraryA/GetProcAddress DWORD (*Kernel32_CreateThread)(DWORD ThreadAttributes,DWORD StackSize,DWORD StartAddress,PVOID Parameter,DWORD CreationFlags,PDWORD ThreadId); DWORD (*Kernel32_Sleep)(DWORD DelayLength); ... };
Кстати, по поводу ebx - есть такая директива register. Вот что говорит о ней microsoft: The register keyword specifies that the variable is to be stored in a machine register, if possible. The compiler does not accept user requests for register variables; instead, it makes its own register choices when global register-allocation optimization (/Oe option) is on. However, all other semantics associated with the register keyword are honored. так и зачем она нужна, эта директива? просто чтобы код позапутаннее был?
Quark кернигана надо было внимательнее читать Registry нужен для того чтобы компилятор знал что эта переменная будет использоваться очень часто и выделял под неё отдельный регистр.
по привычке офтоплю есть пременная __declspec(thread) struct SavedStackRoot *o = 0; это стек сохраненных вершин маш стеков (и доп инфы). работать с данными по ней приходится полностью на регистрах, тк ни локальные, ни глобальные переменные юзать нельзя. Видимо все должно быть сделано в асм вставке. вопрос такой - как передать в регистр значение "o"? Можно ли решить эту задачу не используя асм (приходится восстанавливать регистры)? простите меня, нуба, за дурацкие вопросы