патчинг kernel32.dll для внедрения своей DLL

Тема в разделе "WASM.RESEARCH", создана пользователем rendo, 28 авг 2005.

  1. rendo

    rendo New Member

    Публикаций:
    0
    Регистрация:
    28 авг 2005
    Сообщения:
    7
    Пытаюсь реализовать перехват функций Native API в usermode. Существующие методы не нравятся тем, что для внедрения своей DLL в чужой процесс надо этот самый процесс открывать и писать в него, что ловится уже многими антивирусами и файрволлами. Решил попробовать пропатчить KERNEL32.DLL на диске, чтобы он грузил еще и мою DLL в память процесса. Известно, что KERNEL32 грузится в память любого процесса, так что при таком подходе можно реализовать перехват нужных функций во всех без исключения процессах, включая системные.



    Патчил в KERNEL32 функцию DLLMain, в самом ее конце, где происходит возврат из процедуры:



    pop esi

    pop ebx <-- cюда запихал call на свой код в конце секции text. размер text cоответственно увеличил.

    leave

    ret 000C



    cтало:



    pop esi

    call mycode





    моя процедура имеет следующий вид:
    Код (Text):
    1.  
    2. mycode:
    3. pushad                    ;;;сохраняем регистры
    4. push 000000"l"           ;;;суем в стек имя моей DLL
    5. push "dl.x"              ;;;xxxxx.dll
    6. push "xxxx"
    7. push esp                  ;;;указатель на имя
    8. call LoadLibraryA         ;;;грузим DLL
    9. add  esp, 0000000C        ;;;восстанавливаем стек
    10. mov  ebx,[esp+20]         ;;;берем из стека адрес инструкции после моего внедренного call
    11. sub  ebx, 00000005        ;;;ebx указывает на мой внедренный call
    12. push 00000000             ;;;cуем в стек 0
    13. push esp                  ;;;указатель на этот 0 (по нему функция VirtualProtect запишет старый режим доступа)
    14. push 00000040             ;;;режим доступа (40 - читать писать исполнять)
    15. push 00000005             ;;;длина - 5 байт (длина внедренной инструкции call mycode)
    16. push ebx                  ;;;адрес call mycode
    17. call VirtualProtect       ;;;изменяем режим доступа
    18. pop  eax                  ;;;вытаскиваем из стека лишнее значение
    19. mov  dword ptr [ebx],XXXX ;;;восстанавливаем старые инструкции на месте моего call mycode
    20. mov  byte ptr [ebx+4], xx ;;;---//--
    21. popad                     ;;;восстанавливаем регистры
    22. sub  dword ptr [esp], 00000005 ;;;вычитаем из адреса возврата 5, чтобы переход произошел на только что восстановленные инструкции
    23. ret                       ;;;возвращаемся
    24.  




    данная схема вроде бы работала без глюков пока тестил в XP. как только попробовал в 2К, некоторые приложения стали валиться при старте. думал может дело в моей кривой DLL, которая там что-то нарушает (писана на Delphi). убрал из вышеприведенного кода ее загрузку, оставив только восстановление оригинальных инструкций по адресу call mycode. не помогло, так и валится.

    не понимаю, в чем может быть дело. прочитал у микрософтов, что в DLLMain нельзя ставить вызовы LoadLibrary, попробовал патчить не DLLMain, а CreateFileW. так же в конец функции ставил call mycode и потом восстанавливал оригинальные инструкции и на них возвращался. DLL даже не грузил. вообще все заглючило при таком подходе, начал падать проводник, перестали запускаться некоторые приложения и тд.

    не пойму одного - где накосячил? видимо что-то я упускаю в такой схеме, но что никак не могу понять :dntknw:

    подскажите :)
     
  2. Asterix

    Asterix New Member

    Публикаций:
    0
    Регистрация:
    25 фев 2003
    Сообщения:
    3.576




    А что с точки зрения антивирусов это уже противозаконно?







    А в DllMain кажется LoadLibrary нельзя вызывать, если я не путаю.
     
  3. rendo

    rendo New Member

    Публикаций:
    0
    Регистрация:
    28 авг 2005
    Сообщения:
    7




    мне не хочется лишний раз пугать пользователя тем, что всякие левые антивирусы будут выкидывать свои окошки с предпуреждениями о том, что мой процесс произвел запись в чужой и теперь этому процессу отрублен сетевой доступ и тд и тп.. и бороться с этим мерзким софтом тоже не хочется ибо программа вполне обычная, не вирусная и не троянская
     
  4. rendo

    rendo New Member

    Публикаций:
    0
    Регистрация:
    28 авг 2005
    Сообщения:
    7




    читай внимательнее :)

    там у меня написано, что LoadLibrary убирал и пробовал вообще другую функцию патчить, результат тот же...
     
  5. Ms Rem

    Ms Rem New Member

    Публикаций:
    0
    Регистрация:
    17 апр 2005
    Сообщения:
    1.057
    Адрес:
    С планеты "Земля"
    Метод хренов тем, что при установке апдейтов/сервиспаков придет капут такому перехвату.

    И чем тебе HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_DLLs не нравиться?

    Прописал туда свою длл и она подгрузиться к всем процессам использующим user32
     
  6. rendo

    rendo New Member

    Публикаций:
    0
    Регистрация:
    28 авг 2005
    Сообщения:
    7


    ничто не мешает следить из основной программы за кернелом и если его обновили, патчить по новой ;) я даже автоматический патчер любой версии kernel32.dll написал на основе дизассемблера длин от z0mbie. wfp тоже побеждена, так что метод вполне неплох, как мне представляется.





    это слишком на виду + процессы не использующие user32 в пролете...
     
  7. Ms Rem

    Ms Rem New Member

    Публикаций:
    0
    Регистрация:
    17 апр 2005
    Сообщения:
    1.057
    Адрес:
    С планеты "Земля"


    Насколько я понял, ты пишкшь трояна. Тогда зачем тебе нужна основная программа? Не проще ли все сделать в длл?







    Каким образом? Простым ее отключением, или реализован обход проверки одного конкретного файла?



    И вообще, если патчить, так лучше уж ntdll.dll, он точно есть во всех процессах. Правда писать тогда придется только на Native API.



    И вообще, трояна рекомендую реализовывать полностью в драйвере, без использования юзермодной части. Такие вещи как перехват апи и обход фаерволлов там гораздо проще делаются. Да и метод патча kernel32 будет палиться всеми антивирусами, что не есть хорошо.
     
  8. rendo

    rendo New Member

    Публикаций:
    0
    Регистрация:
    28 авг 2005
    Сообщения:
    7


    нет, это не троян а некий системный софт.





    отключением wfp для любого конкретного файла на лету без ребута. юзаются недокументированные функции sfc api.





    вот этого как раз и не хочется мне.





    и этого тоже не очень хочется :dntknw:

    вариант с драйвером тоже прорабатывается, за основу взял и несколько изменил твой пример драйвера из твоей статьи о перехвате, вроде работает пока... но на C я хреновый писатель + разбираться с kernel mode поначалу несколько тяжко... :dntknw:



    но что-то мне подсказывает, что наверное все-таки придется писать драйвер..
     
  9. Ms Rem

    Ms Rem New Member

    Публикаций:
    0
    Регистрация:
    17 апр 2005
    Сообщения:
    1.057
    Адрес:
    С планеты "Земля"




    В легальном софте (тем более коммерческом) такие приемы как патч системных файлов на диске вообще недопустимы.

    Если ты пишешь коммерческую программу (защиту или что-нибудь подобное), то делай драйвер, так как иначе все хуки можно будет легко обойти. К тому-же в драйвере все реализовать куда проще, чем в юзермоде.

    К тому-же для легального софта скрытность совсем не нужна, так что можно использовать AppInit_DLLs.



    Если ты пишешь вирусы-трояны, то для этого хуки в юзермоде иногда могут оказаться куда полезнее и незаметнее драйверов.
     
  10. rendo

    rendo New Member

    Публикаций:
    0
    Регистрация:
    28 авг 2005
    Сообщения:
    7


    в конечном итоге наверное я так бы и пришел к драйверу, но только вот хочется дело с юзермодой до конца довести. зря что ли патчер кернела писал? :) к тому же в исследованиях о перехвате апи метод патчинга системных библиотек на диске упомянут, но практических реализаций я вроде еще пока не видел. вот хотелось сделать proof of concept некий.



    и вопрос к тебе: перехват в кернел моде как лучше и безгеморройнее делать? для коммерческого софта. скрытность перехвата никакая не нужна. писать в KeServiceDescriptorTable или патчить в памяти начало нужной функции? или может еще как?
     
  11. Ms Rem

    Ms Rem New Member

    Публикаций:
    0
    Регистрация:
    17 апр 2005
    Сообщения:
    1.057
    Адрес:
    С планеты "Земля"




    Значит ждем статью посвященную этой теме.







    Если нк нужна скрытность, и необходима стабильная работа, то лучше KeServiceDescriptorTable ничего не придумать.

    Сплайсинг применять стоит только для перехвата неэкспортируемых функций ядра, а для экспортируемых - правка таблицы экспорта ядра (на ранних стадиях загрузки) либо правка таблиц импорта загруженных модулей.



    P.S. Номера функций в SDT лучше не забивать констнтами, а извлекать из начала Zw функций в ntdll.
     
  12. rendo

    rendo New Member

    Публикаций:
    0
    Регистрация:
    28 авг 2005
    Сообщения:
    7


    для этого надо вышеупомянутый код до ума довести :) а то оно работать-то работает, но как-то нестабильно, зависит еще от версии виндов (2к и хр), глючит по страшному (не запускаются некоторые программы, у проводника в хр в произвольные моменты времени слетают темы и тд и тп). даже если из кода убрать LoadLibrary. по идее же тогда функция-пустышка получается, вызвалась, восстановила сплайсенные инструкции и на них вернулась.. но глючит. такое ощущения что просто забываю что-то сохранять...





    на ранних стадиях - это для того, чтобы перехватить нужную функцию по возможности первым, я правильно понимаю? а насчет правки таблиц импорта загруженных модулей - ты о каких модулях? юзермодных ехешниках и дллях?





    а где они там лежат? :) не то ли, что там в eax грузится?
     
  13. Ms Rem

    Ms Rem New Member

    Публикаций:
    0
    Регистрация:
    17 апр 2005
    Сообщения:
    1.057
    Адрес:
    С планеты "Земля"


    Так как перехват идет в ядре, то о модулях ядра.





    Как раз то.



    Вот пример кода получамющего эти номера:


    Код (Text):
    1. PVOID GetInfoTable(ULONG ATableType)
    2. {
    3.     ULONG mSize = 0x4000;
    4.     PVOID mPtr = NULL;
    5.     NTSTATUS St;
    6.     do
    7.     {
    8.         mPtr = ExAllocatePool(PagedPool, mSize);
    9.         memset(mPtr, 0, mSize);
    10.         if (mPtr)
    11.         {
    12.             St = ZwQuerySystemInformation(ATableType, mPtr, mSize, NULL);
    13.         } else return NULL;
    14.         if (St == STATUS_INFO_LENGTH_MISMATCH)
    15.         {
    16.             ExFreePool(mPtr);
    17.             mSize = mSize * 2;
    18.         }
    19.     } while (St == STATUS_INFO_LENGTH_MISMATCH);
    20.     if (St == STATUS_SUCCESS) return mPtr;
    21.     ExFreePool(mPtr);
    22.     return NULL;
    23. }
    24.  
    25. /*
    26.    Получение указателя на IMAGE_NT_HEADERS PE файла.
    27.    Возвращает NULL если PE файл невалиден.
    28. */
    29. PVOID GetNtHeaders(PVOID hModule)
    30. {
    31.     PIMAGE_DOS_HEADER  dHdr = hModule;
    32.     PIMAGE_NT_HEADERS  nHeader;
    33.  
    34.     if (MmIsAddressValid(dHdr) && (dHdr->e_magic == IMAGE_DOS_SIGNATURE))
    35.     {
    36.         nHeader = (PIMAGE_NT_HEADERS)((ULONG)dHdr + dHdr->e_lfanew);
    37.  
    38.         if (MmIsAddressValid(nHeader) &&
    39.             (nHeader->Signature == IMAGE_NT_SIGNATURE)) return nHeader;
    40.  
    41.     }
    42.     return NULL;
    43. }
    44.  
    45. /*
    46.    Получение адреса системного модуля.
    47. */
    48. PVOID GetModuleHandle(PCSTR ModuleName)
    49. {
    50.     ULONG r, s;
    51.     PVOID Result = NULL;
    52.     PSYSTEM_MODULE_INFORMATION_EX Info = GetInfoTable(SystemModuleInformation);
    53.     PCHAR ShortName;
    54.    
    55.     if (!Info) return NULL;
    56.  
    57.     for (r = 0; r < Info->ModulesCount; r++)
    58.     {
    59.         for (s = 255; (Info->Modules[r].ImageName[s] != '\\') && s; s--);
    60.  
    61.         if (!strcmp((PCHAR)&Info->Modules[r].ImageName[s + 1], ModuleName))
    62.         {
    63.             Result = Info->Modules[r].Base;
    64.             break; 
    65.         }
    66.     }
    67.     ExFreePool(Info);
    68.     return Result;
    69. }
    70.  
    71. /*
    72.    Получение адреса экспортируемой функции.
    73. */
    74. PVOID GetProcAddress(PVOID hModule, PCSTR lpProcName)
    75. {
    76.     PIMAGE_NT_HEADERS        nHeader = GetNtHeaders(hModule);
    77.     PIMAGE_EXPORT_DIRECTORY  pExport;
    78.     ULONG                    r;
    79.     PCSTR                    FnName;
    80.     PVOID                    Addres;
    81.  
    82.     if (nHeader)
    83.     {
    84.         pExport = (PIMAGE_EXPORT_DIRECTORY)((ULONG)hModule + nHeader->OptionalHeader.
    85.                    DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress);
    86.         if (MmIsAddressValid(pExport))
    87.         {
    88.             for (r = 0; r < pExport->NumberOfNames; r++)
    89.             {
    90.                 FnName = (PCSTR)(*(PULONG)(pExport->AddressOfNames
    91.     + (ULONG)hModule + r * 4) + (ULONG)hModule);
    92.                 Addres = (PVOID)(*(PULONG)(pExport->AddressOfFunctions
    93.     + (ULONG)hModule + r * 4) + (ULONG)hModule);
    94.                 if (!strcmp(lpProcName, FnName)) return Addres;
    95.             }
    96.         }
    97.     }
    98.     return NULL;
    99. }
    100.  
    101. ULONG GetSdtEntryNumber(PCSTR lpProcName)
    102. {
    103.     return *(PULONG)((ULONG)GetProcAddress(GetModuleHandle("ntdll.dll"), lpProcName) + 1);
    104. }
    105.  
     
  14. CARDINAL

    CARDINAL Member

    Публикаций:
    0
    Регистрация:
    23 янв 2004
    Сообщения:
    551
    Адрес:
    Moscow
    rendo

    да друг, что то у тебя всё сложно как то. Метод твой негоден, потому как винда может матюгнуться на целостность кода библиотек и еще много всякой хрени, такая фишка в 9х бы на ура проконала, а тут нет
     
  15. psu

    psu New Member

    Публикаций:
    0
    Регистрация:
    12 июл 2006
    Сообщения:
    198
    rendo
    А можно поподробнее?...
     
  16. SiruS

    SiruS Алекс

    Публикаций:
    0
    Регистрация:
    19 фев 2005
    Сообщения:
    145
    Адрес:
    Львов
    psu

    Тебе чего, делать совсем нечего, только старые темы поднимать? Если уж так надо, то для этого существует личка.