Запрет изменения базы kernel32

Тема в разделе "WASM.WIN32", создана пользователем float, 12 май 2011.

  1. float

    float New Member

    Публикаций:
    0
    Регистрация:
    7 янв 2010
    Сообщения:
    113
    В общем по умолчанию так делать конечно нельзя. Но я слышал, что эту проверку можно как-то обойти. Какие есть варианты?

    цель - усложнить процесс снятия хуков в kernel32 И ntdll. Потому что любой процесс может переписать мой kernel32 скопировав свой. Почему не драйвер - потому что на х64 куча проблем с патчгвардом и подписью драйверов.
     
  2. gaeprust

    gaeprust New Member

    Публикаций:
    0
    Регистрация:
    2 май 2011
    Сообщения:
    188
    float
    Это делается элементарно - создаётся секция(Odj), проецируется, в неё копируется по секциям все секции данных модуля, затем области кода восстанавливаются с диска, и поверх этого восстанавливаются секции данных из сохранённых в секции(Obj).

    Был один семпл(x86) для обнаружения модификаций кода посредством сравнения кода, описанного графом. Это старый семпл, уже давно на кряклатиносе и клабе был выложен(на клабе в силу низкого порога вхождения у "кодеров" началось негодование :)). Суть вот в чём. Копия образа загружается средствами загрузчика - LdrLoadDll(). Так как нужно образ релоцировать(ибо модуль уже загружен), то необходимо загрузчик изменить. Разумеется не в памяти изменить. Он трассируется и выполняются необходимые манипуляции. Можно конечно вручную, но это очень, очень не тру, именно изза совместимости и множества нюансов. К чему такая релокация приводит - релоцируется код, при этом ссылки на секции данных не изменны. Этот принцип используется в межмодульном переключении тредов(описывать не буду, но если кратко то это своего рода патч, но без изменения оригинальной проекции ;)).

    http://rghost.ru/6076641
     
  3. float

    float New Member

    Публикаций:
    0
    Регистрация:
    7 янв 2010
    Сообщения:
    113
    не очень понял. т.е. смысл в том чтобы PE заголовок остался на месте а изменились только местоположения секций?
     
  4. gaeprust

    gaeprust New Member

    Публикаций:
    0
    Регистрация:
    2 май 2011
    Сообщения:
    188
    float
    Нет. На месте остались переменные, тоесть секции данных(там на скрине это видно). Это даёт возможность сделать непосредственно джамп в восстановленную вторую проекцию. А её можно безопасно изменить. Например имеется последовательность вложенных процедур A-B-C-D. Какимто образом мы получаем управление в процедуре B. Нужно изменить процедуру D(тоесть внести в неё какието поправки). Она изменяется в копии проекции, а из полученного управления в процедуре B выполняется поправка: Ip = Ip + Delta, где Ip это Eip, Delta - дельта адресов двух проекций. После этого выполняется код второй проекции, переменные используются из первой проекции, детектор обнаруживает оригинальную проекцию не изменной. Если нужно получить управление при понижении NL(тоесть изменить нужно B, а управление получаем в D), то выполняется поправка всей SFC(или только определённого фрейма), тогда возврат будет выполнятся во вторую проекцию. Это аналогично переключению потока на отморфленный код, только без морфинга(это когда процедуры A целиком(также и B etc.) морфится - она пересобирается в буфере с необходимыми изменениями и поток переключается на этот код).
     
  5. float

    float New Member

    Публикаций:
    0
    Регистрация:
    7 янв 2010
    Сообщения:
    113
    если я правильно понял, по настоящим адресам вместо функций будут джампы на новые адреса? если так то это по идее не спасет от полного восстановления кода из внешнего процесса. Если конкретнее - вот такой код, выполненный из внешнего процесса, разхучит мою LdrLoadDll

    DWORD l1 = (DWORD)GetProcAddress(kDLL, "LdrLoadDll");
    VirtualProtectEx(hProcessToAttach,(LPVOID)l1,64,PAGE_EXECUTE_READWRITE,&op);
    WriteProcessMemory(hProcessToAttach,(LPVOID)l1,(LPCVOID)l1,64,&w); (скорее всего эта функция в защищаемом процессе будет на том же адресе, поэтому я и хочу как-то полностью сменить базу ntdll и kernel32)
    VirtualProtectEx(hProcessToAttach,(LPVOID)l1,64,op,&op);
     
  6. gaeprust

    gaeprust New Member

    Публикаций:
    0
    Регистрация:
    2 май 2011
    Сообщения:
    188
    float
    Заменить файловую проекцию на не файловую с атрибутом RE. Секции данных в проекции RW. Открыть доступ на запись в проекцию в таком случае не получится, а значит и код нельзя будет изменять. Ну из юзермода разумеется и без перемапа проекции.
     
  7. float

    float New Member

    Публикаций:
    0
    Регистрация:
    7 янв 2010
    Сообщения:
    113
    Заменить Imag на Map? Я полагаю это делается так - копирую все что у нас в ntdll куда-нибудь в сторону, далее ZwUnmapViewOfSection на ntdll, далее ZwCreateSection с нужными правами, и ZwMapViewOfSection туда же, и восстанавливаем оригинальные байты?
     
  8. gaeprust

    gaeprust New Member

    Публикаций:
    0
    Регистрация:
    2 май 2011
    Сообщения:
    188
    float
    Переменные должны остаться неизменными. Восстанавливаются только кодесекции. "куда-нибудь" это в секцию(Obj). После этого она мапится по размеру файловых секций и с опред. атрибутами. Этот код давно написан, поиск по форуму.
     
  9. float

    float New Member

    Публикаций:
    0
    Регистрация:
    7 янв 2010
    Сообщения:
    113
    я нашел кусок кода из утерянного ProtectImage от Клерка. В общем я как-то так и предполагал. С кернелом 32 это все ясно, а вот самая беда с ntdll. даже если загрузить второй ntdll в память, там при вызове функций будет проблема с этим кодом:

    00D9D0B3 BA 0003FE7F MOV EDX,7FFE0300
    00D9D0B8 FF12 CALL DWORD PTR DS:[EDX]

    7FFE0300 - там должен быть записан адрес KiFastSystemCall
    но он размаплен. а записать адрес нового не выходит.

    и да, не очень понимаю как читается "это в секцию(Obj)."
     
  10. gaeprust

    gaeprust New Member

    Публикаций:
    0
    Регистрация:
    2 май 2011
    Сообщения:
    188
    float
    0x7FFE0300 - данная переменная находится в USD, тоесть глобальна и туда загружается ссылка при инициализации ядра. Со стабами вообще не может быть проблем, так как их код базонезависимый.

    Чтобы не путать термины я указал в скобках что секция обьект(Section Object), а не файловая секция в модуле. Так как оба термина одинаковы, это вызывает путаницу, для этого введена поправка.
     
  11. float

    float New Member

    Публикаций:
    0
    Регистрация:
    7 янв 2010
    Сообщения:
    113
    базонезависимый - так то оно так, но KiFastsystemCall затирается при анмапе старой секции кода.
     
  12. gaeprust

    gaeprust New Member

    Публикаций:
    0
    Регистрация:
    2 май 2011
    Сообщения:
    188
    Аа ясно, я сразу не подумал. Вы наверно пытаетесь дёрнуть сервис из анмапленной проекции. Нужно шлюз у себя в коде разместить и через сискол или Int 0x2e дёргать.
     
  13. deLight

    deLight New Member

    Публикаций:
    0
    Регистрация:
    26 май 2008
    Сообщения:
    879
    gaeprust
    Так идея с контролем кода загрузчика это оказалось с латиноса.
    Что же вы так, без копирайтов то...

    Кодес с модулями без фиксапов дружит, кстати?
     
  14. float

    float New Member

    Публикаций:
    0
    Регистрация:
    7 янв 2010
    Сообщения:
    113
    блин что-то не могу понять
    когда я создаю проекцию памяти на чтение и исполнение, как мне свой код то туда записать?

    Код (Text):
    1. HANDLE sec = 0;
    2. DWORD addr = 0;
    3. LARGE_INTEGER secoffset = {0};
    4. SIZE_T viewsize = {0};
    5. secoffset.LowPart = 0x1000;
    6. NtCreateSection(&sec,SECTION_MAP_EXECUTE|SECTION_MAP_READ,NULL, &secoffset,PAGE_EXECUTE_READ,SEC_COMMIT,NULL);
    7. NtMapViewOfSection(sec,NtCurrentProcess(),(PVOID *)&addr,NULL,NULL,NULL, &viewsize,ViewUnmap,NULL,PAGE_EXECUTE_READ);
    вот так он нормально мапит, но эти нули уже ничем не переписать получается
     
  15. gaeprust

    gaeprust New Member

    Публикаций:
    0
    Регистрация:
    2 май 2011
    Сообщения:
    188
    deLight
    О чём вы говорите ?
    По пунктам плз.

    float
    Есть такой обьект секция. Она мапится, на RW, туда данные записываются в проекцию, потом она анмапится, но данные хранятся в секции. Если её снова замапить, то данные отобразятся в память. Если её несколько раз замапить, то создаются общие PTE, тоесть в одной проекции данные меняются, они в другой также меняются, физическая страница то одна.
     
  16. float

    float New Member

    Публикаций:
    0
    Регистрация:
    7 янв 2010
    Сообщения:
    113
    т.е. объект секции привязан к определенной физической странице? а можно ли как-то скопировать хендл секции в другой процесс и замапить там чтобы был такой же прикол с изменением данных?
     
  17. gaeprust

    gaeprust New Member

    Публикаций:
    0
    Регистрация:
    2 май 2011
    Сообщения:
    188
    Данные хранятся в секции. Блок данных из неё(тоесть по определённому смещению в секции) может быть отображён на произвольный адрес. Секция это обьект и обладает всеми свойствами, присущими обьектам, например может иметь описатель(хэндл).
    Можно скопировать описатель - NtDuplicateObject. Проецировать можно в чужой процесс, сервис получает в аргументах описатель процесса.
     
  18. float

    float New Member

    Публикаций:
    0
    Регистрация:
    7 янв 2010
    Сообщения:
    113
    а как быть с гранулярностью? если я допустим создам секцию для пе хедера по адресу 7c800000 то на 7c801000 мне уже не даст замапить секцию. а у pe хедера должны быть права RW а за ним идет text у которого RE так что в 1 секции их не разместить.

    а wow64 и вообще когда я ему сказал замапить 1000 он замапил С0000 байт.
     
  19. gaeprust

    gaeprust New Member

    Публикаций:
    0
    Регистрация:
    2 май 2011
    Сообщения:
    188
    Страничная гранулярность.
     
  20. float

    float New Member

    Публикаций:
    0
    Регистрация:
    7 янв 2010
    Сообщения:
    113
    в смысле? по идее гранулярность у меня = 0х1000 байт. Секцию размером 0х1000 создать получается. А допустим после этой секции через VirtualAlloc можно будет выделить память? даже если можно, как быть с wow64?

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