Титла: Достъп до sys_call_table в 2.6.32 Публикувано от: st0ne в Mar 17, 2010, 02:11 От няколко дни се се опитвам да напиша LKM, с който дапроменя няколко функции от sys_call_table с чисто екпериментална и учебна цел, но нямам особен успех :( Липсата на export на sys_call_table не беше проблем - вземам адреса като използвам техниката с IDT. След като имам адреса понеже тази част от паметта е read-only извиквам set_memory_rw(sys_call_table, 1), но тя ми връща 0 и паметта наистина не е достъпна за писане. Видях, че преди е ставало с change_page_attr(), но тази ф-ция вече е deprecated. Все трябва да има някакъв начин. Нали все пак съм в ring 0 и имам уш пълен достъп до всичко. Ако някой може да ми обясни как точно действа това ограничение за read-only и как да го избегна ще съм му много благодарен. Мисля да пробвам с код написан на assembler да сменя стойностите, но не съм сигурен дали ще се получи.
Титла: Re: Достъп до sys_call_table в 2.6.32 Публикувано от: gat3way в Mar 17, 2010, 10:13 Няма да се получи, set_memory_rw проверява дали адреса не е в rodata секцията. Единият вариант е да видиш как се променят page атрибутите в arch/*/mm/pageattr.c и да се опиташ да си напишеш собствена функция, която заобикаля ограничението, обаче това не е особено лесна задача. Другият вариант е ако наистина ти е за експериментални цели, а не да си пишеш rootkit-ове, просто да си прекомпилираш ядрото. Отваряш arch/*/kernel/entry.S и просто променяш позволенията на страниците, заети от rodata секцията (там трябва да е описано нещо от сорта на .section .rodata,"a" - променяш го на .section .rodata, "aw" и прекомпилираш ядрото).
* се заменя с твоята архитектура (x86, x86_64, etc) Титла: Re: Достъп до sys_call_table в 2.6.32 Публикувано от: st0ne в Mar 17, 2010, 14:51 За експериментални цели ми е и точно за това искам да го направя без да прекомпилирам ядрото. За rootkit бих се насочил към нещо с debug регистрите, понеже доколкото съм чел то е най-трудно за откриване (като изключим концепцията за използване на хардуерна виртуализация, но поне на мен тя ми се вижда доста трудоемко начинание).
Не се бях сетил да проверя как е направено. Мога да се опитам да направя нещо подобно като гледам кода в pageattr.c, но щом казваш че е трудно не знам какъв успех ще имам. Тези дни ще пробвам и ще пиша. А как точно работи тази проверка дали адреса е ro? Ако директно напиша някакъв асемблерски код, който сменя стойността на клетката в паметта как ще ме хване, че пипам по read-only? Извинявам се ако въпросите са малко глупави, но не открих никъде да е описано как стават тези неща. Титла: Re: Достъп до sys_call_table в 2.6.32 Публикувано от: gat3way в Mar 17, 2010, 15:26 Ами ако погледнеш pageattr.c (визирам x86-кия), ще видиш че set_memory_rw() вика change_page_attr_set, която от своя страна вика __change_page_attr(). Някъде в тази функция има следното:
Код
Във въпросната функция static_protections() се прави самата проверка: Код
И дефакто, атрибутите на страницата не се променят щом като се намира във въпросната секция. Титла: Re: Достъп до sys_call_table в 2.6.32 Публикувано от: st0ne в Mar 21, 2010, 15:33 Реших, че може би ще е по-лесно направо с assembler да се обходи таблицата със страниците и да се сменят правата на подходящата страница. Ето един примерен код, който открих:
Код: void *origaddr = (void*) 0; Тук myfunc() сменя правата на подходящата страница и след това може да се редактират стойностите. Кода е подходящ за 32 bit Intel/AMD с по-малко от 4G RAM. Сега съм си свалил manual-а за system development на Intel и ще се опитам да разбера какво точно става в асемблерския код. Не успях да намеря никъде обяснено как се обхожда таблицата със страниците и как се сменят права на страница. Титла: Re: Достъп до sys_call_table в 2.6.32 Публикувано от: gat3way в Mar 21, 2010, 16:37 CR3 регистъра държи адреса към page директорията на процеса. Всеки процес си има отделен набор от page таблици и съответно при context switch, стойността на CR3 регистъра се променя.
Page директорията е нещо като масив от 32-битови стойности, съдържащ адреси на отделни pagetables. Въпросните pagetables са нещо като масив от 32-битови елементи, съдържащ адресите на отделните страници памет + атрибутите им. Дефакто става нещо като йерархична система от няколко нива - първото е page директорията, после page таблицата и накрая въпросната страница. Ама това е за 32-битова система без PAE, с PAE нещата са организирани малко по-различно, както и при 64-битовите системи, има още едно ниво на йерархия и масивите са от 64-битови елементи. Та не ми се рови в асемблерския код, но предполагам вземат стойността на CR3 регистъра, обхождат page директорията и нейните таблици и сет-ват въпросните битове (атрибути) когато открият търсената страница. Определено правят някакви магии с тези побитови маски, обаче нямам идея какви точно, трябва да хвана да прочета разни интелски документации за да схвана за какво иде реч. Титла: Re: Достъп до sys_call_table в 2.6.32 Публикувано от: st0ne в Mar 21, 2010, 17:43 Оказа се, че съвсем ще съм затруднен в моите начинания - процесора ми е с Intel EM64T. Тези процесори само IA-32e paging ли използват? Не съм сигурен понеже kernel release-а ми завършва на i686.PAE, а от документацията на Intel останах с впечатление, че Intel 64 използват само IA-32e paging.
Титла: Re: Достъп до sys_call_table в 2.6.32 Публикувано от: gat3way в Mar 21, 2010, 17:47 втф...това е интелската x86_64 архитектура. Ще ползва такъв paging механизъм, какъвто реши операционната система. Щом като е i686.PAE, нещата изглеждат така:
(http://upload.wikimedia.org/wikipedia/commons/thumb/0/0d/X86_Paging_PAE_4K.svg/621px-X86_Paging_PAE_4K.svg.png) Титла: Re: Достъп до sys_call_table в 2.6.32 Публикувано от: st0ne в Apr 10, 2010, 20:20 Имам известен напредък с PAE paging-а, но от вчера ударих на камък. Това е вариант за 4KB paging. Ето какво съм направил:
Код: __asm__ __volatile__ ( "movl %%cr3, %%eax\n\t" Тук addr е адреса, чиято PTE трябва да се намери. Понеже от PDPTEi се вземат 40 бита (битове 51:12) аз ги съхранявам в две променливи - bits_low и bits_high. Първата съдържа ниските 32 бита, а втората високите 8. До тук изглежда, че всичко e наред. bits_high е нула при мен, но аз имам само 2GB RAM и това ми изглежда нормално. За ниските битове получавам стойност A8C. Тази стойност използвам след това, за да прочета PDE-то на адреса. Код: __asm__ __volatile__ ( "movl %2, %%eax\n\t" bits_low сочи към началото на 4KB структура от 512 64-биови записа. Битове 29:21 от адреса оказват точния PDE запис. Би трябвало в pde_low_bits да имам първите 32 бита от PDE, но стойността е нула. Ако добавя отместване от 0x4, за да взема вторите 32 бита резултата пак е нула. Не виждам грешка нито вгода, нито в логиката. |