Парсинг ApiSet на Win10 и Win7-8.1

Тема в разделе "WASM.BEGINNERS", создана пользователем HoShiMin, 28 ноя 2017.

  1. HoShiMin

    HoShiMin Well-Known Member

    Публикаций:
    5
    Регистрация:
    17 дек 2016
    Сообщения:
    1.427
    Адрес:
    Россия, Нижний Новгород
    Добрый день форумчанам. Для сбора информации об импортах нужно получить имена всех реальных библиотек из виртуальных (api-ms-win***).
    Парсер писал по этой статье: https://blog.quarkslab.com/runtime-dll-name-resolution-apisetschema-part-ii.html
    Однако возникла проблема со структурами.
    В Win7 (как в статье) есть структура REDIRECTOR, в которой лежит количество редиректов, и на которую ссылается DLLHOSTDESCRIPTOR->OffsetDllRedirector.

    В комментах есть определения структур для Win10. В этих структурах отсутствует REDIRECTOR, а количество редиректов лежит в DLLHOSTDESCRIPTOR'e последним полем, и в ValueOffset лежит ссылка на сам массив редиректов без промежуточной структуры REDIRECTOR'a.

    В связи с этим вопрос, действительно ли в Win10 поменялся сам формат хранения редиректов (что исключило промежуточный REDIRECTOR), или приведённые в комментах структуры неверны? Есть ли какой-то более универсальный и надёжный способ спарсить редиректы?

    При парсинге на Win7 с редиректами всё правильно. На Win10 же встречаются виртуальные библотеки (например, "api-ms-win-coremessaging-host-l1-1-0.dll"), у которых количество редиректов не равно 0, но в структуре редиректа оба оффсета нулевые. Нормальная ли это ситуация?

    И дополнительный вопрос: на Win7 у имён виртуальных библиотек нет префиксов "api-" и "ext-", на Win10 - есть. Как узнать, какие префиксы у конкретной библиотеки на Win7?
     
  2. HoShiMin

    HoShiMin Well-Known Member

    Публикаций:
    5
    Регистрация:
    17 дек 2016
    Сообщения:
    1.427
    Адрес:
    Россия, Нижний Новгород
  3. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    Регистрация:
    29 апр 2011
    Сообщения:
    4.775
    HoShiMin,

    А зачем вам это ?

    Это не какой то фундаментальный механизм ос, при следующем апдейте ваш метод может отвалиться. Не вижу смысла трогать импорт.
     
  4. HoShiMin

    HoShiMin Well-Known Member

    Публикаций:
    5
    Регистрация:
    17 дек 2016
    Сообщения:
    1.427
    Адрес:
    Россия, Нижний Новгород
    Всё затем же - следить за состоянием процесса и смотреть, кто кого откуда и как импортирует (антиинжектов для). В дополнение к фильтрам потоков и сканеру памяти.
    Знаю уже Вашу реакцию. Но для антиинжектов в моём случае подойдёт только эвристика (и в будущем ещё драйвер с каллбэками). И кое-где вмп.
     
  5. HoShiMin

    HoShiMin Well-Known Member

    Публикаций:
    5
    Регистрация:
    17 дек 2016
    Сообщения:
    1.427
    Адрес:
    Россия, Нижний Новгород
    Indy_
    И ещё... Не подскажете, как VS определяет, пользовательская ли библиотека?
    upload_2017-11-29_3-20-44.png
     
  6. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    Регистрация:
    29 апр 2011
    Сообщения:
    4.775
    HoShiMin,

    > Всё затем же - следить за состоянием процесса и смотреть, кто кого откуда и как импортирует (антиинжектов для).

    Я же вам дал годный метод, зачем вы изобретаете нерабочий велосипед". Реализуйте простой визор; за то время, которое вы потратили на поиск решения по инжектам(причём не нашли его), придумывая всякие костыли", вы могли проработать те идеи и механизмы что разработаны и реализовать их. Всё что вы выдумываете не рабочее и никакая не защита.
    Для начала поймите что инжект бывает двух видов - прямой, например смена контекста и косвенный, это OP-атака. Управление может быть передано внесением данных в работу кода, который не корректно написан. Если первое можно тупыми методами заблокировать, как например это делают простые проактивные защиты, то со вторым сложно, первые методы тут вообще не пригодны.

    > Не подскажете, как VS определяет, пользовательская ли библиотека?

    В хидере модуля тип подсистемы https://msdn.microsoft.com/en-us/library/fcc1zstk.aspx

    А на скрине - не корректное определение. Судя по всему критерий связан не с модулем, а с его расположением.
     
    Последнее редактирование: 29 ноя 2017
  7. HoShiMin

    HoShiMin Well-Known Member

    Публикаций:
    5
    Регистрация:
    17 дек 2016
    Сообщения:
    1.427
    Адрес:
    Россия, Нижний Новгород
    Защищать приходится софт без исходников: джава, к ней в импорты цепляется дллка сразу после kernel32, ставит фильтры на потоки, каллбэки на загрузку модулей, на выделение памяти, собирает цепочки импортов. Я не могу делать никаких предположений о том, какое состояние процесса было до подгрузки библиотеки. Задача - не дать заинжектиться и вызвать определённые функции из JNI (предотвратить подгрузку классов со стороны), а также не дать перехватить определённые функции из OpenGL и WinAPI. Причём, нужно учитывать, что не должно быть оверхеда на скорость (защищаемый процесс - игра, которая сама по себе не отличается хорошей оптимизацией).
     
  8. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    Регистрация:
    29 апр 2011
    Сообщения:
    4.775
    HoShiMin,

    Если фильтр грузится после загрузки апп, то можно из юм заблокировать дальнейшую загрузку и аллокацию X-памяти. Но это получается частное решение. Если же фильтр грузится на стартап этапе апп, то тут варинтов нет вообще, так как способ загрузки может быть любым. Вам придётся в общем случае реализовать свою проактивную защиту, мониторя все сервисы. Но и даже в этом случае такая защита получится локальной. Через десять минут анализа найдётся уязвимость, это неизбежно. Такую защиту можно строить для конкретного софта, зная как он инжектится.

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

    На счёт профайла - это наиболее важно, вопрос в том, какой нужен тайминг, вполне вероятно что апп просто не может быть запущено под визором.

    При использовании стандартных средств(дизасм етц) падение профайла десятикратное. Если сравнить с супервизорами, типо вари - профайл не просаживается, так как это не полноценный визор, там пакетная обработка, не пригодная для реализации защиты. Иначе придётся юзать IVT.
     
  9. HoShiMin

    HoShiMin Well-Known Member

    Публикаций:
    5
    Регистрация:
    17 дек 2016
    Сообщения:
    1.427
    Адрес:
    Россия, Нижний Новгород
    Частично согласен. Делаю действительно что-то вроде проактивки, цепляю фильтры на модули, потоки (дабы отсечь CreateRemoteThread), хук на LoadAppInitDLLs, затем составляю карту памяти, чтобы точно знать, где у меня валидная исполняемая память (+ учитываем JIT), фильтры на все аллокации, маппинги и освобождения. Проверяю хэши всех исполняемых секций всех модулей.

    Инжектят паблик-инжекторами, работающими через CreateRemoteThread(LoadLibrary) и через ручной маппинг и CreateRemoteThread. Инжект через SetThreadContext пока в паблике не видел. А от подгрузки библиотеки через модификацию импортов у любой системной либы вариантов защиты не вижу совсем. Но если защита сработает хотя бы на 90% паблик-обходов, это будет очень здорово.

    Насчёт протекта юм-модулей. Смотрел в сторону ремаппинга, но у системных библиотек секции не выровнены по 64 килобайта, а ремаппить свои модули смысла мало - в них никто ничто не хукает.
    Если же речь о SetProcessMitigationPolicy, нужен драйвер, чтобы взвести флажок, отключающий самомодификацию (и неизвестно, как это будет работать с JIT'ом), ведь поддерживается он, насколько знаю, лишь для DRM. И только начиная с Win8.1.

    А насчёт профайла... Если накрыть джаву вмпротектом, всё становится очень грустно. И всё равно не помогает, т.к. просто хукают OpenGL и отключают Z-буфер (простейший Wall Hack)
     
  10. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    Регистрация:
    29 апр 2011
    Сообщения:
    4.775
    HoShiMin,

    Нужны реальные тесты по профайлу. Если апп сможет работать с десятикратной просадкой профайла, то задача решается совершенно чётко. Если же нет, то тогда нормального решения нет. Если пилится чит к примеру, то поставится дров, из которого что угодно можно сделать и никого не волнует эта вся защита такая. Более того можно брать части апп под визор для повышения профайла, в том числе и защитный код.

    У меня понятие по данной теме следующее. Нет общей задачи и цели. Ключевые моменты не изучены(тот же профайл). Методы залива не известны. Короче это защита от рандома построенная на рандоме :)
    Так как общее решение не используется, то возникает просто громадное число костылей, все их проработать не представляется возможным. Имхо не корректный подход к задаче. Более того, чем ниже уровень реализации и больше костылей использовано, то это шикарная площадка для оп атак. Но опять же это зависит от исходной задачи - расплывчато: они это не смогут сделать етц. Слишком всё расплывчато, врядле что то годное при таком раскладе получится.
     
  11. f1redArk

    f1redArk Member

    Публикаций:
    0
    Регистрация:
    10 июл 2008
    Сообщения:
    34
    А какой годный метод?
     
  12. f1redArk

    f1redArk Member

    Публикаций:
    0
    Регистрация:
    10 июл 2008
    Сообщения:
    34
    Как можно заблокировать загрузку и аллокацию?
     
  13. HoShiMin

    HoShiMin Well-Known Member

    Публикаций:
    5
    Регистрация:
    17 дек 2016
    Сообщения:
    1.427
    Адрес:
    Россия, Нижний Новгород
  14. f1redArk

    f1redArk Member

    Публикаций:
    0
    Регистрация:
    10 июл 2008
    Сообщения:
    34
  15. HoShiMin

    HoShiMin Well-Known Member

    Публикаций:
    5
    Регистрация:
    17 дек 2016
    Сообщения:
    1.427
    Адрес:
    Россия, Нижний Новгород
    Единственная найденная структура для ApiSet v4 для Win8.1 по ссылке выше и неполная, и неправильная.
    Нигде в интернете её не нашёл, даже в Dependency Walker'e отмечена как ToDo.
    Если кому-то понадобится, восстановил её из здравого смысла:
    Код (C):
    1.  
    2. typedef struct _API_SET_NAMESPACE4 {
    3.     ULONG Version;
    4.     ULONG Size;
    5.     ULONG Flags;
    6.     ULONG Count;
    7.     // API_SET_NAMESPACE_ENTRY4 Array[0];
    8. } API_SET_NAMESPACE4, *PAPI_SET_NAMESPACE4;
    9.  
    10. typedef struct _API_SET_NAMESPACE_ENTRY4 {
    11.     ULONG Flags;
    12.     ULONG NameOffset;
    13.     ULONG NameLength;
    14.     ULONG AliasOffset;
    15.     ULONG AliasLength;
    16.     ULONG DataOffset; // Offset to API_SET_VALUE_ENTRY4
    17. } API_SET_NAMESPACE_ENTRY4, *PAPI_SET_NAMESPACE_ENTRY4;
    18.  
    19. typedef struct _API_SET_VALUE_ENTRY4 {
    20.     ULONG Flags;
    21.     ULONG NumberOfRedirections;
    22.     // API_SET_VALUE_ENTRY4 Array[0];
    23. } API_SET_VALUE_ENTRY4, *PAPI_SET_VALUE_ENTRY4;
    24.  
    25. typedef struct _API_SET_VALUE_INFO4 {
    26.     ULONG Flags;
    27.     ULONG NameOffset;
    28.     ULONG NameLength;
    29.     ULONG ValueOffset;
    30.     ULONG ValueLength;
    31. } API_SET_VALUE_INFO4, *PAPI_SET_VALUE_INFO4;
    32.  
     
  16. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    Регистрация:
    29 апр 2011
    Сообщения:
    4.775
    HoShiMin,

    Спрошу у вас тогда. Вы понимаете как работает CFG MS ?

    Это битовая карта, в которой помечены возможные для вызова адреса. Если управление передаётся не на эти адреса, тогда сработает софтверная ловушка. Но при этом она софтверная и срабатывает через софтверный механизм передачи(индирект ветвление).

    Если пойти дальше - мы можем создать глобальный анклав в адресном пространстве. Оно всё не исполняемо. Тогда каким образом вы выполните произвольный код - в таком случае передача управления возможна лишь через спец шлюзы, которые впрыскиваемый код не знает. И тогда всякая попытка исполнения обречена на ловушку.
     
  17. HoShiMin

    HoShiMin Well-Known Member

    Публикаций:
    5
    Регистрация:
    17 дек 2016
    Сообщения:
    1.427
    Адрес:
    Россия, Нижний Новгород
    Но CFG предназначен для непрямых вызовов и требует явного встраивания проверок на этапе компиляции. Если я из стороннего процесса отображаю библиотеку, а затем создаю поток на DllMain, то никто не сможет это предотвратить. Какими бы ни были проверки на валидность в моём собственном коде, я никак не смогу отследить стороннюю память и сторонние потоки.
     
    RET нравится это.
  18. RET

    RET Well-Known Member

    Публикаций:
    17
    Регистрация:
    5 янв 2008
    Сообщения:
    789
    Адрес:
    Jabber: darksys@sj.ms
    Можете в DllMain как раз отследить паразитные потоки, я гдето тут выкладывал кодес для этого. На руткитсах точно выкладывал, вот не помню только, по моему руткитсы закрылся форум. NtCreateThread перехватываем у себя в case DLL_PROCESS_ATTACH, а в DLL_THREAD_ATTACH смотрим наш поток или сторонний, если не наш - NtTerminateThread
     
    Последнее редактирование: 5 дек 2017
  19. HoShiMin

    HoShiMin Well-Known Member

    Публикаций:
    5
    Регистрация:
    17 дек 2016
    Сообщения:
    1.427
    Адрес:
    Россия, Нижний Новгород
    На самом деле, про потоки я немного слукавил: хук на NtCreateThread и хук на LdrInitializeThunk решат проблему паразитных потоков (в простейшем случае, конечно, ведь нужно учитывать потоки таймеров и тредпула).
    Но как быть с аллокацией со стороны и сменой контекста - пока неясно. Будь процесс хоть трижды под визором, никто не запретит рабочему потоку выполнить сторонний шелл и беспрепятственно вернуться обратно, пока процесс заморожен и ничего не может проверить.
     
  20. unc1e

    unc1e Active Member

    Публикаций:
    2
    Регистрация:
    28 июл 2017
    Сообщения:
    287
    лучше NtContinue мб