Выгрузить User32.dll через FreeLibrary()

Тема в разделе "WASM.X64", создана пользователем Marylin, 5 фев 2025.

  1. Marylin

    Marylin Active Member

    Публикаций:
    0
    Регистрация:
    17 фев 2023
    Сообщения:
    268
    Всем привет!
    Столкнулся с проблемой, что когда через LoadLibrary() загружаю либу lpk.dll (и не только её), видимо из-за зависимостей она автоматом подгружает и User32.dll. Но по условию User32 должна отсутствовать в памяти процесса, и если я пытаюсь её выгрузить через FreeLibrary(), то система не даёт этого сделать. GetLastError() вообще никак не реагирует, возвращая код далеко предыдущей ошибки. Есть-ли способ в этой ситуации избавиться от User32.dll ?
     
  2. HoShiMin

    HoShiMin Well-Known Member

    Публикаций:
    5
    Регистрация:
    17 дек 2016
    Сообщения:
    1.486
    Адрес:
    Россия, Нижний Новгород
    Как же ты выгрузишь либу, если от неё зависят другие?
    Сделай так, чтобы твоя либа и её зависимости от user32 не зависели - и не будет она грузиться.
     
  3. Marylin

    Marylin Active Member

    Публикаций:
    0
    Регистрация:
    17 фев 2023
    Сообщения:
    268
    HoShiMin, в общем это тесты с LdrRegisterDllNotification() из Ntdll.dll
    Регаю 2 колбека - первый парсит загрузку, а второй выгрузку библиотек.
    В импорте прожки только Ntdll, Kernel32 и Msvcrt.dll, а дальше колбек исправно срабатывает при LoadLibrary().

    В логе ниже я загружаю всего одну системную либу MF.dll, а она тянет за собой ещё 19 штук, среди которых есть и User32. Конкретно из MF.dll ни одна функция не обращается к User32, хотя некоторые форвардятся в Gdi32.dll, функции которой видимо и зависят от User32. Вот я и хочу оборвать как-то эту цепочку, но видимо не получится. Хотя когда выгружаю одну IMM32.dll, она на автомате прихватывает за собой и Msctf.dll:
    Код (Text):
    1. LdrpDllNotificationList ::: Ntdll base: 0x0000000076E80000
    2. ----------------------------------------------------------
    3. 1.  Flink: 0x00000000000F5300 -> Blink: 0x0000000076FB2CD0. Callback: 0x0000000000402000
    4. 2.  Flink: 0x0000000076FB2CD0 -> Blink: 0x00000000000F52B0. Callback: 0x0000000000402070
    5.  
    6. NotificationListHead offset from Ntdll: 0x0000000000132CD0
    7.  
    8. Dll loaded  :  0x000007fee4c50000   4036 kByte  mf.dll
    9. Dll loaded  :  0x000007fefa900000    104 kByte  ATL.DLL
    10. Dll loaded  :  0x0000000076d80000   1004 kByte  USER32.dll
    11. Dll loaded  :  0x000007feff100000    416 kByte  GDI32.dll
    12. Dll loaded  :  0x000007fefd780000     56 kByte  LPK.dll
    13. Dll loaded  :  0x000007fefd4a0000    812 kByte  USP10.dll
    14. Dll loaded  :  0x000007fef9d70000    436 kByte  MFPlat.DLL
    15. Dll loaded  :  0x000007fefd1a0000    904 kByte  ADVAPI32.dll
    16. Dll loaded  :  0x000007fefeb00000    124 kByte  sechost.dll
    17. Dll loaded  :  0x000007fefeb20000   1172 kByte  RPCRT4.dll
    18. Dll loaded  :  0x000007fefd790000    308 kByte  WS2_32.dll
    19. Dll loaded  :  0x000007fefd7e0000     32 kByte  NSI.dll
    20. Dll loaded  :  0x000007fefd890000   2052 kByte  ole32.dll
    21. Dll loaded  :  0x000007fefcee0000    880 kByte  OLEAUT32.dll
    22. Dll loaded  :  0x000007fefd570000    452 kByte  SHLWAPI.dll
    23. Dll loaded  :  0x000007fefb2a0000     36 kByte  AVRT.dll
    24. Dll loaded  :  0x000007fefb940000     48 kByte  VERSION.dll
    25. Dll loaded  :  0x00000000745f0000     24 kByte  ksuser.dll
    26. Dll loaded  :  0x000007fefce10000    184 kByte  IMM32.DLL
    27. Dll loaded  :  0x000007fefd5f0000   1072 kByte  MSCTF.dll
    28. Dll unloaded:  ----> IMM32.DLL
    29. Dll unloaded:  ----> MSCTF.dll
     
  4. MaKsIm

    MaKsIm Active Member

    Публикаций:
    0
    Регистрация:
    11 фев 2008
    Сообщения:
    151
    А если попробовать загрузить эту библиотеку вручную и слинковать все вручную без USER32.DLL. Это конечно, не тривиально, но должно помочь.
     
  5. Ahimov

    Ahimov Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2024
    Сообщения:
    137
    Когда процесс выполняет загрузку user, поток который это делает на стороне ядра прогружает теневую вторую сервисную таблицу. Такой тред уже может вызывать ядерные интерфейсы gui. В процесс отображается ядерная память окон, становятся доступными обратные ядерные вызовы. Это нельзя отменить.
     
    Marylin нравится это.
  6. Marylin

    Marylin Active Member

    Публикаций:
    0
    Регистрация:
    17 фев 2023
    Сообщения:
    268
    MaKsIm, мне нужен LoadLibrary(), чтобы сработал колбек.
    Конечно в папке Win можно найти либу, которая грузится без зависимости от User32.dll,
    но как оказалось таких крайне мало и все они привлекают лишнее внимание.

    Строкой NotificationListHead offset from Ntdll: 0x0000000000132CD0 я получаю смещение списка LIST_ENTRY в секции-данных Ntdll - этот лист перечисляет все колбеки нотификации, и если вклиниться в него в удалённом процессе, то можно будет запустить свой шелл. Поэтому пытаюсь избавиться от всех лишних DLL, т.к. действие будет происходить в чужом консольном процессе без User32.

    Плохо то, что если чз LoadLibrary() попытаться загрузить уже имеющуюся в памяти DLL, то колбек не срабатывает, иначе вообще проблем-бы не было.
     
    Последнее редактирование: 6 фев 2025
  7. Ahimov

    Ahimov Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2024
    Сообщения:
    137
    Если удалить юзер либу из памяти, то вероятно возникнет исключение при попытке обратного вызова гуя. Потому что массив ссылок на процедуры загружен при инит гуя.

    Гуи тоесть тень(shadow) по возможности вынесена в юзер мод. Это сделано для защиты от атак на ядро гуя. Если упадет процесс, не произойдет выполнения кода с ядерными правами.

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

    Что то я не помню про удаленную установку каких то обработчиков. Это невозможно из за разделений адресов(aslr). Что бы внести запись в список необходимо вначале открыть процесс, затем напрямую список изменить. Эти операции открытия-записи делают бессмысленными модификацию каких то списков. Если можно писать в память, можно что угодно изменить.
    --- Сообщение объединено, 6 фев 2025 ---
    > ни одна функция не обращается к User32

    Загрузчик сконвертирует поток в гуи, такой поток отличается от нэйтив. Разумеется будет загружено окружение тени. На сколько помню есть маркер в пе формате.
     
  8. Marylin

    Marylin Active Member

    Публикаций:
    0
    Регистрация:
    17 фев 2023
    Сообщения:
    268
    Так ASLR меняет-же базу только при загрузке системы, и вплоть до последующего ребута она будет стабильной во всех процессах, т.к. сис.либы не загружаются в юм-процессы, а мапятся. Это легко проверить в ProcessHacker/Explorer - у всех процессов Ntdll лежит по одному адресу. Но даже если и менялась-бы база, у меня есть оффсет головы колбек-листа от начала либы. В общем с этим нет проблем.
    ..например дедовским способом стартовать шелл чз CreateRemoteThread()?
    в наше время любой авер с базами 80-х годов прибьёт эту технику ещё на взлёте,
    а потому я и пытаюсь реализовать что-то новое, чз те-же колбеки LDR - описание лежит тут: https://shorsec.io/blog/dll-notification-injection/
     
  9. Ahimov

    Ahimov Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2024
    Сообщения:
    137
    Знаю довольно хорошо про атаки на ядро нт. Вы не верно понимаете защиту, каждый процесс локален, его память и описатели. В целях защиты используется рандом. Два модуля не релоцируемы, так как в них находятся фиксированые адреса процедур, это нэйтив и тень. При попытке повторного отображения загрузчик выдаст окно с ошибкой и прокинет фаулт(исключение). Сурки паблик, посмотрите сами.
    --- Сообщение объединено, 6 фев 2025 ---
    Тут я немного поискал по LdrpXX, тема не новая. Если можно писать в память, то нет никакого смысла лезть в андок приват нэйтив механиизмы.
     
  10. Marylin

    Marylin Active Member

    Публикаций:
    0
    Регистрация:
    17 фев 2023
    Сообщения:
    268
    ну это кому-как.. у каждого свой смысл.
     
  11. R81...

    R81... Active Member

    Публикаций:
    0
    Регистрация:
    1 фев 2020
    Сообщения:
    166
    Не нравится мне (заказчику) этот Сенкевич.
    Ну не нравится не ешь.
    Переименуй все у себя в user33.dll и саму в своей соотв. Dir - у меня работает, без user33.dll соотв. ошибка.
     
  12. Marylin

    Marylin Active Member

    Публикаций:
    0
    Регистрация:
    17 фев 2023
    Сообщения:
    268
    ничего не понял, но обычный ренейм профита не даёт
    вот экзешник для тестов - просит ввести имя либы для загрузки/выгрузки (можно без расширения *.dll).
     

    Вложения:

  13. R81...

    R81... Active Member

    Публикаций:
    0
    Регистрация:
    1 фев 2020
    Сообщения:
    166
    ../LdrDllNotifi.EXE не является приложением Win32.
    Заказчик с подобным формальным требованием
    рискует оказаться - "одушевленным унитазом
    в женском туалете".

    "Выгрузить User32.dll через FreeLibrary()"
    про профит речи в 1-м посте нет.
    - т.е. User33.dll можно и оставить.
    В стартере-загрузчике Mew32.exe
    ссылки на User32.dll еще нужны,
    а в MEWLIB33.dll уже нет.
    как пример:

    P.S. Я не изучал Win - нет
    интереса, он только инструмент.
     

    Вложения:

    • User33.7z
      Размер файла:
      610,9 КБ
      Просмотров:
      69
  14. Marylin

    Marylin Active Member

    Публикаций:
    0
    Регистрация:
    17 фев 2023
    Сообщения:
    268
    Cмена имени либы не даёт ровным счётом ничего, т.к. зависимости прописаны в секциях импорта/экспорта DLL. Может при статическом анализе либа и спрячется (хотя в данном случае user32 в обоих файлах торчит и в IDA), а при загрузке в память сразу-же всплывёт. Это видно в логах отладчика:
    Код (Text):
    1. CommandLine: "F:\User33\MEWLIB32.dll с user_32\Mew32.exe"
    2. 0:000> bp @$exentry
    3. *** WARNING: Unable to verify checksum for image00000000`00400000
    4.  
    5. 0:000> g
    6. ModLoad: 00000000`77530000  00000000`7764f000   WOW64_IMAGE_SECTION
    7. ModLoad: 00000000`74ef0000  00000000`75000000   WOW64_IMAGE_SECTION
    8. ModLoad: 00000000`77530000  00000000`7764f000   NOT_AN_IMAGE
    9. ModLoad: 00000000`77430000  00000000`7752b000   NOT_AN_IMAGE
    10. ModLoad: 00000000`74ef0000  00000000`75000000   C:\Windows\syswow64\kernel32.dll
    11. ModLoad: 00000000`76920000  00000000`76967000   C:\Windows\syswow64\KERNELBASE.dll
    12. ModLoad: 00000000`75520000  00000000`75620000   C:\Windows\syswow64\user32.dll      <--------------//
    13. ModLoad: 00000000`75620000  00000000`756b0000   C:\Windows\syswow64\GDI32.dll
    14. ModLoad: 00000000`769c0000  00000000`769ca000   C:\Windows\syswow64\LPK.dll
    15. ModLoad: 00000000`75200000  00000000`7529d000   C:\Windows\syswow64\USP10.dll
    16. ModLoad: 00000000`756c0000  00000000`7576c000   C:\Windows\syswow64\msvcrt.dll
    17. ModLoad: 00000000`76810000  00000000`768b4000   C:\Windows\syswow64\ADVAPI32.dll
    18. ModLoad: 00000000`769d0000  00000000`769e9000   C:\Windows\SysWOW64\sechost.dll
    19. ModLoad: 00000000`76c40000  00000000`76d30000   C:\Windows\syswow64\RPCRT4.dll
    20. ModLoad: 00000000`74e10000  00000000`74e70000   C:\Windows\syswow64\SspiCli.dll
    21. ModLoad: 00000000`74e00000  00000000`74e0c000   C:\Windows\syswow64\CRYPTBASE.dll
    22. ModLoad: 00000000`77180000  00000000`77212000   C:\Windows\syswow64\oleaut32.dll
    23. ModLoad: 00000000`766b0000  00000000`76810000   C:\Windows\syswow64\ole32.dll
    24. ************************************************************
    25.  
    26. CommandLine: "F:\User33\MEWLIB33.dll с user_33\Mew33.exe"
    27. 0:000> bp @$exentry
    28. *** WARNING: Unable to verify checksum for image00000000`00400000
    29.  
    30. 0:000> g
    31. ModLoad: 00000000`77530000  00000000`7764f000   WOW64_IMAGE_SECTION
    32. ModLoad: 00000000`74ef0000  00000000`75000000   WOW64_IMAGE_SECTION
    33. ModLoad: 00000000`77530000  00000000`7764f000   NOT_AN_IMAGE
    34. ModLoad: 00000000`77430000  00000000`7752b000   NOT_AN_IMAGE
    35. ModLoad: 00000000`74ef0000  00000000`75000000   C:\Windows\syswow64\kernel32.dll
    36. ModLoad: 00000000`76920000  00000000`76967000   C:\Windows\syswow64\KERNELBASE.dll
    37. ModLoad: 00000000`75520000  00000000`75620000   C:\Windows\syswow64\user32.dll     <-----------//
    38. ModLoad: 00000000`75620000  00000000`756b0000   C:\Windows\syswow64\GDI32.dll
    39. ModLoad: 00000000`769c0000  00000000`769ca000   C:\Windows\syswow64\LPK.dll
    40. ModLoad: 00000000`75200000  00000000`7529d000   C:\Windows\syswow64\USP10.dll
    41. ModLoad: 00000000`756c0000  00000000`7576c000   C:\Windows\syswow64\msvcrt.dll
    42. ModLoad: 00000000`76810000  00000000`768b4000   C:\Windows\syswow64\ADVAPI32.dll
    43. ModLoad: 00000000`769d0000  00000000`769e9000   C:\Windows\SysWOW64\sechost.dll
    44. ModLoad: 00000000`76c40000  00000000`76d30000   C:\Windows\syswow64\RPCRT4.dll
    45. ModLoad: 00000000`74e10000  00000000`74e70000   C:\Windows\syswow64\SspiCli.dll
    46. ModLoad: 00000000`74e00000  00000000`74e0c000   C:\Windows\syswow64\CRYPTBASE.dll
    47. ModLoad: 00000000`77180000  00000000`77212000   C:\Windows\syswow64\oleaut32.dll
    48. ModLoad: 00000000`766b0000  00000000`76810000   C:\Windows\syswow64\ole32.dll
     
  15. Ahimov

    Ahimov Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2024
    Сообщения:
    137
    Между прочим, имеется сервис NtAreMappedFilesTheSame, который был еще в wrk, а стало быть и сначала самой нт. Он проверяет два указателя на принадлежность одной файловой проекции. И предназначен для загрузчика, что бы из за имен не прогрузить вновь модуль. В новых версиях ос там огород куда больше.
     
  16. R81...

    R81... Active Member

    Публикаций:
    0
    Регистрация:
    1 фев 2020
    Сообщения:
    166
    Похоже мое не пройдет. Просто
    этот у меня уже был тестовый
    пример - как (ветвь графа)
    проще модифицировать, и т.к.
    там тоже речь шла о user32.dll
    ошибочно притянул сюда.
    Т.Е. "контейнер - докер" для
    user33.dll будет ~с весь Win32.