Импорт класса

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

  1. GoldFinch

    GoldFinch New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2008
    Сообщения:
    1.775
    Есть готовая длл (engine.dll), она экспортирует методы классов. Пишу следующий код:
    Код (Text):
    1. #pragma comment(lib,"engine.lib")
    2. //...
    3. class UNetworkHandler
    4. {
    5. public:
    6.     UNetworkHandler(class UNetworkHandler const &);
    7.     virtual User* GetUser(int a1);
    8.     virtual User* GetNextCreature(float a1,int a2);
    9. };
    10. //...
    11. UNetworkHandler *g_NetworkHandler;
    12. //...
    13. User *U = g_NetworkHandler->GetUser(g_UserID);
    14. //...
    Компилю, и вижу, что код пытается вызвать GetUser через таблицу методов, а методы класса не импортируются. При этом прога вылетает ошибкой, т.к. в описании класса не все методы и не в том порядке, соответственно смещение в таблице методов получается неправильным.
    Заменяю "User *U = g_NetworkHandler->GetUser(g_UserID);" на
    UNetworkHandler NH(*g_NetworkHandler);
    User *U =NH.GetUser(g_UserID);
    - методы UNetworkHandler импортируются, вызов GetUser производится через таблицу импорта.

    Как сделать так, чтобы в 1м коде методы импортировались и вызов производился через таблицу импорта?

    ЗЫ: компилятор msvc2008
     
  2. GoldFinch

    GoldFinch New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2008
    Сообщения:
    1.775
    Такс... задача несколько изменилась. Статический импорт уже не катит, т.к. я хочу скрыть символьные имена используемых импортов. Кроме того, код пишется под длл конкретной версии, поэтому rva экспортов можно напрямую забить в код. GetProcAddress(hEngine,0x80000000+ord_xxx) вариант, но получать через API заранее известные rva неинтересно.
    Итак, я могу написать скрипт, который извлечет из длл rva и имена, "отдеманглит" их, и сформирует необходимый исходный код для импорта.
    Выглядеть это должно будет примерно так:
    Код (Text):
    1. /* engine.cpp */
    2. class __single_inheritance UNetworkHandler;
    3. __declspec(naked) User* UNetworkHandler::GetUser(int a1) {__asm jmp 0x777};
    4. __declspec(naked) User* UNetworkHandler::GetNextCreature(float a1,int a2) {__asm jmp 0x888};
    5. ...
    6.  
    7. /* init.cpp */
    8. ...
    9. g_hEngine = GetModuleHandle("engine.dll"); //или LoadLibrary()
    10. ...
    11. *(int*)((char*)&UNetworkHandler::GetUser+1)+=(int)g_hEngine;
    12. *(int*)((char*)&UNetworkHandler::GetNextCreature+1)+=(int)g_hEngine;
    или так:
    Код (Text):
    1. /* engine.cpp */
    2. #define RVA(rva) { \
    3.     __asm  start: jmp patch \
    4.     __asm  patch: mov eax,[g_hEngine] \
    5.     __asm  add eax, rva \
    6.     __asm  push eax \
    7.     __asm  sub eax, patch \
    8.     __asm  mov [start+1],eax \
    9.     __asm  ret };
    10.  
    11. class __single_inheritance UNetworkHandler;
    12. __declspec(naked) User* UNetworkHandler::GetUser(int a1) RVA(0x777)
    13. __declspec(naked) User* UNetworkHandler::GetNextCreature(float a1,int a2) RVA(0x888)
    14. ...
    15.  
    16. /* init.cpp */
    17. ...
    18. g_hEngine = GetModuleHandle("engine.dll"); //или LoadLibrary()
    Конечно нормальной защитой от реверсирования это не назовешь, но с 1го взгляда отпугнуть может. Конечно более предпочтителен варинат 2, хоть и больше кода, но он перспективнее, особенно если сделать код базонезависимым, чтобы не палились xref'ы на g_hEngine. Опять же во втором варианте линкер сам удалит неиспользуемые импорты. Однако как нетрудно заметить, этот метод требует записи в секцию кода, а давать ей разрешение на запись, плохо, т.к. начнут орать всякие авиры. Лучше во время исполнения заюзать VirtualProtect, но нужна гарантия что все импорты попадут в одну 0x1000-байтную страницу памяти.

    А вопрос собственно такой - реально ли такое провернуть на С++ ?
     
  3. GoldFinch

    GoldFinch New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2008
    Сообщения:
    1.775
    Как выяснилось, реально)
    Код (Text):
    1. /*init.cpp*/
    2. g_hEngine=(char*)GetModuleHandleA("engine.dll");
    3. ...
    4. DWORD OldProt;
    5. int FirstSectionSize =*(int*)((char*)hModule+*(int*)((char*)hModule+0x3C)+0x18+0xE0+0x10);
    6. VirtualProtect((char*)hModule+0x1000,FirstSectionSize,PAGE_EXECUTE_READWRITE,&OldProt);
    7.  
    8. /*imports.cpp*/
    9. #define RVA(rva) { \
    10.     __asm  start: _emit 0xE9 __asm _emit 0 __asm _emit 0 __asm _emit 0 __asm _emit 0 \
    11.     __asm  patch: \
    12.     __asm  mov eax,[g_hEngine] \
    13.     __asm  add eax, rva \
    14.     __asm  push eax \
    15.     __asm  sub eax, patch \
    16.     __asm  mov [start+1],eax \
    17.     __asm  ret };
    18.  
    19. __declspec(naked) User* UNetworkHandler::GetUser(int a1) RVA(0x003E1554-0x3D0000)
    20. __declspec(naked) User* UNetworkHandler::GetNextCreature(float a1,int a2) RVA(0x003E0BE5-0x3D0000)
    21. ...