Внедрение DLL драйвером ядра. Работа на протяжении жизни процесса.

Тема в разделе "WASM.NT.KERNEL", создана пользователем iSecure, 2 дек 2011.

  1. iSecure

    iSecure New Member

    Публикаций:
    0
    Регистрация:
    17 сен 2011
    Сообщения:
    9
    Добрый день.

    Есть драйвер, делающий внедрение DLL в user-mode процесс с помощью APC.
    Постановка APC в очередь происходит для первичного потока целевого процесса во время загрузки образа ntdll.dll в адресное пространство процесса.
    Рабочий вариант DLL выполняет некоторую работу во время входа в DllMain единожды.
    Затем драйвер выгружает DLL из адресного пространства процесса. Пока все отлично.

    Встала задача выполнять некоторую работу не единожды, а на протяжении жизни процесса.
    Добавил в DllMain создание нового потока, в котором в цикле будет выполняться необходимое действие с некоторым интервалом.
    Убрал из драйвера код, отвечающий за выгрузку DLL после отработки DllMain (я так понимаю, если выгрузить DLL, создавшую поток, ничего хорошего не будет).
    В результате проведенных манипуляций стал падать целевой процесс.

    Вопрос: в чем может быть проблема? Есть подозрение, что это связано с созданием потока в DllMain. Однако вариант библиотеки с созданием нового потока, в котором вызывается скажем MessageBox без цикла, рабочий. Также вариант библиотеки с созданием нового потока и выполнением в цикле, но загруженная не драйвером, а простым приложением через LoadLibrary, также является рабочим.

    Надеюсь на помощь гуру форума. Заранее спасибо!
     
  2. shchetinin

    shchetinin Member

    Публикаций:
    0
    Регистрация:
    27 май 2011
    Сообщения:
    715
    iSecure
    На какой Reason происходит создания потока ?
    Вообщем DllMain в студию!
     
  3. iSecure

    iSecure New Member

    Публикаций:
    0
    Регистрация:
    17 сен 2011
    Сообщения:
    9
    Код (Text):
    1. BOOL APIENTRY DllMain( HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved )
    2. {
    3.     HANDLE      hThread;
    4.     DWORD       dwThreadId;
    5.  
    6.     switch (ul_reason_for_call)
    7.     {
    8.         case DLL_PROCESS_ATTACH:
    9.             hThread = CreateThread( NULL, 0, Working, NULL, 0, &dwThreadId );
    10.  
    11.             if ( hThread == NULL )
    12.                 MessageBoxA( 0, "[-] CreateThread failed.", NULL, 0 );
    13.             break;
    14.         case DLL_THREAD_ATTACH:
    15.         case DLL_THREAD_DETACH:
    16.         case DLL_PROCESS_DETACH:
    17.             break;
    18.     }
    19.     return TRUE;
    20. }
     
  4. shchetinin

    shchetinin Member

    Публикаций:
    0
    Регистрация:
    27 май 2011
    Сообщения:
    715
    iSecure
    Очевидно ведь! или нет?



    You should never perform the following tasks from within DllMain:
    • Call LoadLibrary or LoadLibraryEx (either directly or indirectly). This can cause a deadlock or a crash.
    • Synchronize with other threads. This can cause a deadlock.
    • Acquire a synchronization object that is owned by code that is waiting to acquire the loader lock. This can cause a deadlock.
    • Initialize COM threads by using CoInitializeEx. Under certain conditions, this function can call LoadLibraryEx.
    • Call the registry functions. These functions are implemented in Advapi32.dll. If Advapi32.dll is not initialized before your DLL, the DLL can access uninitialized memory and cause the process to crash.
    • Call CreateProces. Creating a process can load another DLL.
    • Call ExitThread. Exiting a thread during DLL detach can cause the loader lock to be acquired again, causing a deadlock or a crash.
    Call CreateThread. Creating a thread can work if you do not synchronize with other threads, but it is risky.
    • Create a named pipe or other named object (Windows 2000 only). In Windows 2000, named objects are provided by the Terminal Services DLL. If this DLL is not initialized, calls to the DLL can cause the process to crash.
    • Use the memory management function from the dynamic C Run-Time (CRT). If the CRT DLL is not initialized, calls to these functions can cause the process to crash.
    • Call functions in User32.dll or Gdi32.dll. Some functions load another DLL, which may not be initialized.
    • Use managed code.

    The following tasks are safe to perform within DllMain:
    • Initialize static data structures and members at compile time.
    • Create and initialize synchronization objects.
    • Allocate memory and initialize dynamic data structures (avoiding the functions listed above.)
    • Set up thread local storage (TLS).
    • Open, read from, and write to files.
    • Call functions in Kernel32.dll (except the functions that are listed above).
    • Set global pointers to NULL, putting off the initialization of dynamic members. In Microsoft Windows Vista™, you can use the one-time initialization functions to ensure that a block of code is executed only once in a multithreaded environment.

    http://msdn.microsoft.com/en-us/windows/hardware/gg487379.aspx
    Вообщем создовать тред в дллмайн это плохо:)
     
  5. iSecure

    iSecure New Member

    Публикаций:
    0
    Регистрация:
    17 сен 2011
    Сообщения:
    9
    да, я это читал, и много где пишут, что нельзя.
    только это не аргумент, если это невозможно в силу архитектурных особенностей, хотелось бы о них поподробнее.

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

    не исключаю, что может быть мой подход к решению задачи в корне не правильный. Задача максимум: выполнение произвольного кода на протяжении жизненного цикла целевого процесса, код внедрен должен быть из ядра. Нужно для дипломной работы.
     
  6. shchetinin

    shchetinin Member

    Публикаций:
    0
    Регистрация:
    27 май 2011
    Сообщения:
    715
    iSecure
    Вы не внимательно читали. В том то и бролема что это архитекрутная особеность. DllMain сериализуемая(Loader locker ) Это синхронизируется в ntdll.dll
    Так что Поток вам придется создовать отделно из ядра. Загрузили либу, а потом создали поток.
     
  7. shchetinin

    shchetinin Member

    Публикаций:
    0
    Регистрация:
    27 май 2011
    Сообщения:
    715
    А ну да , в CSRSS прорегались?
     
  8. XshStasX

    XshStasX New Member

    Публикаций:
    0
    Регистрация:
    9 авг 2008
    Сообщения:
    991
    iSecure
    Сделай два APC один для загрузки длл, а второй(после отработки первого) для ее инициализации.
     
  9. XshStasX

    XshStasX New Member

    Публикаций:
    0
    Регистрация:
    9 авг 2008
    Сообщения:
    991
    shchetinin
    Знаю что не стоит создавать поток в DllMain но когда то по началу создавал, и это все проходило.
    Можешь привести пример когда будет креш или деадлок ?
     
  10. iSecure

    iSecure New Member

    Публикаций:
    0
    Регистрация:
    17 сен 2011
    Сообщения:
    9
    Нет, не знал что нужно, да и не знаю как, мат часть страдает, че уж тут говорить =)

    в качестве APC процедуры делать не LoadLibrary, а CreateThread? получается мне в коде драйвера нужно будет реализовать user-mode логику функции Working? Тогда и DLL вроде уже не зачем, или я не правильно вас понял?
     
  11. iSecure

    iSecure New Member

    Публикаций:
    0
    Регистрация:
    17 сен 2011
    Сообщения:
    9
    можно поподробнее, что в данном случае будет являться "инициализацией"? вызов экспортируемой функции вместо DllMain?
     
  12. XshStasX

    XshStasX New Member

    Публикаций:
    0
    Регистрация:
    9 авг 2008
    Сообщения:
    991
    Я так понимаю ты делаешь внедрение на основе этой статьи : http://www.rsdn.ru/article/baseserv/InjectDll.xml
    Код (Text):
    1. KeInitializeApc(
    2.     startApc,
    3.     KeGetCurrentThread(),
    4.     OriginalApcEnvironment,
    5.     SpecialApcRoutine,     // будет вызвана после того как твоя АПС отработает
    6.     RundownApcRoutine,
    7.     loadDllThunkRoutine,
    8.     UserMode,
    9.     ldrContext);
    В SpecialApcRoutine можно создать еще одну АРС которая вызовет экспортируемую функцию из твоей длл вот тогда и создавай потоки, только думаю не стоить делать вторую АРС форсированной.

    Еще можно в DllMain перехватить EntryPoint основного модуля, тогда все будет инициализировано .
     
  13. iSecure

    iSecure New Member

    Публикаций:
    0
    Регистрация:
    17 сен 2011
    Сообщения:
    9
    Да, на основе этой статьи.

    Многое становится понятным уже, спасибо. Но вопросы еще остаются =)

    То есть выходит схема такая:
    1 APC - loadlibrary на мою DLL, у которой DllMain пустая.
    2 APC - createthread на адрес экспортируемой функции (например working из кода выше)

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

    у меня и первая APC не форсированная, убрал за ненадобностью эту часть из драйвера.

    поток этот будет висеть пока не завершится целевой процесс? ОС сама все подчистит или нужно предусмотреть в коде драйвера корректную выгрузку при получении уведомления о завершении процесса?
     
  14. XshStasX

    XshStasX New Member

    Публикаций:
    0
    Регистрация:
    9 авг 2008
    Сообщения:
    991
    Весь UserMode ОС подчистит , а вот например когда выделяешь память под АРС надо вручную возвращать память обратно (ExFreePool) :)
     
  15. iSecure

    iSecure New Member

    Публикаций:
    0
    Регистрация:
    17 сен 2011
    Сообщения:
    9
    ну это понятно, вроде как дров из статьи это учел, даже если и нет, это грозит только memory-leak, на результат поставленной задачи в принципе не влияет, ведь так? в дипломе не стоит задачи написания production/bug-free кода =)

    Будем пробовать. Думается мне, вылезет еще что-нибудь =)
     
  16. 100gold

    100gold New Member

    Публикаций:
    0
    Регистрация:
    26 фев 2010
    Сообщения:
    165
    Здесь говорится не о том, что нельзя вообще создавать поток из dllMain, а о том, что очень опасно в этом случае делать синхронизацию между потоками внутри DllMain.

    Может быть проблема в регистрации в CSRSS, но реальное выполнение APC должно происходить после NtResumeThread, который в CreateProcess выполняется после регистрации - т.е. в тот момент когда выполняется APC поток уже зарегистрирован.
     
  17. shchetinin

    shchetinin Member

    Публикаций:
    0
    Регистрация:
    27 май 2011
    Сообщения:
    715
    100gold
    Как же будет тогда доставлена нотофикация DLL_THREAD_ATTACH (Из нового потока)?
     
  18. iSecure

    iSecure New Member

    Публикаций:
    0
    Регистрация:
    17 сен 2011
    Сообщения:
    9
    Задача решена по схеме 2-этапного APC: 1) загрузка длл; 2) вызов экспорта длл, в котором создается поток.
     
  19. Person

    Person Hugh Person

    Публикаций:
    0
    Регистрация:
    29 июн 2011
    Сообщения:
    23
    Вы сошли с ума, просто создайте поток в ЕП дллки и все будет работать, ошибка в другом.
     
  20. steelfactor

    steelfactor New Member

    Публикаций:
    0
    Регистрация:
    26 апр 2007
    Сообщения:
    501
    Person
    В чем же? Поподробнее, если можно