Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Wykorzystanie sterownika Capcom w bezpieczny sposób
#1
Widziałem tak wielu ludzi używających sterownika Capcom w niebezpieczny sposób, że chciałem zrobić ten post, po prostu wyjaśniając, dlaczego niektóre praktyki są niesamowicie niebezpieczne i jak możemy to naprawić. Kiedy te problemy są wskazane, odpowiedzią najczęściej jest "praca na mojej maszynie / wzruszanie ramionami", ale kiedy nie jesteś jedynym użytkownikiem, ustawiasz się na porażkę (mówiąc z własnego doświadczenia). To prawda, że sterownik Capcom jest z natury niebezpieczny, jednak przy pewnych zmianach możemy uczynić go znacznie bardziej niezawodnym.   Istnieją dwa sposoby wykorzystania drivera Capcom: 1) Pozostań _disable () 'd i módl się NT procedurami z wymaganiami IRQL jakoś działa. 2) Call _enable () i módlcie się, że nie nastąpi przełączenie kontekstu / patchguard nie denerwuje się.   Problem z włączaniem przerwań polega na tym, że podczas wykonywania może nastąpić zmiana kontekstu, resetowanie wartości CR4, ponowne włączenie SMEP. Oznacza to, że gdy wrócimy do naszego kodu w trybie użytkownika, sprawdzimy błąd. Ale wciąż potrzebujemy przerwań, aby móc wywoływać określone funkcje w jądrze, więc nie mamy wyboru ... czy my?   Tak, możemy, możemy polegać na małej sztuczce, właściwości ExAllocatePoolWithTag, aby była konkretna.   Kiedy dokonamy małej alokacji (mniejszej niż 0xFE0 bajtów) w specjalnej puli, ExAllocatePoolWithTag faktycznie przydzieli nowe strony dla naszej puli, jeśli nie znajdzie bloku dla naszego rozmiaru i nie może podzielić dużych bloków, aby ukończyć nasz przydział - - co nigdy się nie dzieje - i na szczęście dla nas proces ten nie wymaga włączania przerwań.     Kod:   PVOID __stdcall ExAllocatePoolWithTag (POOL_TYPE PoolType, SIZE_T NumberOfBytes, ULONG Tag) {... if (! MmSpecialPoolTag ||! ExpUseSpecialPool (NumberOfBytes_, (unsigned int) v10)) {LABEL_10: if (NumberOfBytes_> 0xFE0) {result = (PVOID) ExpAllocateBigPool (0i64, v5, NumberOfBytes_, v10, 0); if (result) return result; goto LABEL_260; } ... // Wpływa na przydzielenie małej puli ... ...   Zamierzamy przydzielić stub w pamięci jądra, który wykonuje dla nas te wywołania.     Kod:   0x0F, 0x20, 0xE0, // mov rax, cr4; - 0x48, 0x0F, 0xBA, 0xE8, 0x14, // bts rax, 0x14; | będzie nop'd, jeśli nie ma obsługi SMEP 0x0F, 0x22, 0xE0, // mov cr4, rax; - 0xFB, // sti 0x48, 0x8D, 0x05, 0x07, 0x00, 0x00, 0x00, // lea rax, [rip + 0x7]; kontynuuj 0x8F, 0x40, 0x12, // pop QWORD PTR [rax + 0x12]; ret_store 0x50, // push rax 0xFF, 0x60, 0x1A, // jmp QWORD PTR [rax + 0x1a]; call_store 0xFA, // cli 0x0F, 0x20, 0xE1, // mov rcx, cr4 0x48, 0x0F, 0xBA, 0xF1, 0x14, // btr rcx, 0x14 0x0F, 0x22, 0xE1, // mov cr4, rcx 0xFF, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp QWORD PTR [rip + 0x0]; ret_store 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // ret_store: dq 0 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // call_store: dq 0   Ten mały kod pośredniczący włącza SMEP i przerwań, zapisuje wskaźnik powrotu do przydzielonego miejsca, zamienia go na nasz epilog (który wyłącza przerwania i SMEP, i wraca do zapisanego wskaźnika) i przeskakuje do procedury.   Zamierzamy zainicjować i nazwać to jak poniżej:     Kod:   NON_PAGED_CODE static void Khk_AllocatePassiveStub () {PVOID Out = (PVOID) Khk_ExAllocatePool (0ull, sizeof (Kh_PassiveCallStubData)); Np_memcpy (Out, Kh_PassiveCallStubData, sizeof (Kh_PassiveCallStubData)); Khk_PassiveCallStub = (fnPassiveCall) Out; } Template <typename ... Params> NON_PAGED_CODE static uint64_t Khk_CallPassive (PVOID Ptr, Params && ... params) {* (PVOID *) (((PUCHAR) Khk_PassiveCallStub) + Kh_PassiveCallStubCallStoreOffset) = Ptr; return Khk_PassiveCallStub (std :: forward <Params> (params) ...); } Static void Khu_Init (CapcomContext * CpCtx, KernelContext * KrCtx) {int CpuInfo [4]; __cpuid (CpuInfo, 0x7); if (! (CpuInfo [1] & (1 << 7))) // EBX: 1 << 7 = SMEP {printf ("[+] Brak obsługi SMEP! \ n"); memset (Kh_PassiveCallStubData, 0x90, Kh_PassiveCallStubSmepEnabledOffset); } Khk_ExAllocatePool = KrCtx -> GetProcAddress <fnFreeCall> ("ExAllocateP
Reply
#2
Dużo bardziej gejzer, ale wciąż działająca i bezpieczna metoda polega na prostym remapowaniu i przenoszeniu całego pliku binarnego na tryb jądra. Byłem winien tego raz.
Reply
#3
Wspaniale jest zobaczyć solidne informacje na temat sterownika capcom. To z pewnością pomoże ludziom!
Reply
#4
Zacytować: Napisał namazso Dużo bardziej gejzer, ale wciąż działająca i bezpieczna metoda polega na prostym remapowaniu i przenoszeniu całego pliku binarnego na tryb jądra. Byłem winien tego raz. Będziesz musiał przydzielić pamięć dla twojego pliku binarnego, który nie jest bezpieczny albo używam głównie Capcom do mapowania mojego sterownika.
Reply
#5
Zacytować: Wysłane przez can1357 pierwotnie Będziesz musiał przydzielić pamięć dla twojego pliku binarnego, który nie jest bezpieczny albo używam głównie Capcom do mapowania mojego sterownika. Możesz zastosować technikę opisaną tutaj, aby przydzielić i zapamiętywać początkową kopię km. Jest to podobne do mapowania sterownika, z wyjątkiem tego, że pojedynczy plik wykonywalny jest zarówno sterownikiem, jak i programem um
Reply
#6
Zacytować: Napisał namazso Możesz zastosować technikę opisaną tutaj, aby przydzielić i zapamiętywać początkową kopię km. Jest to podobne do mapowania sterownika, z wyjątkiem tego, że pojedynczy plik wykonywalny jest zarówno sterownikiem, jak i programem um Jeśli przydzielisz więcej niż 4 kb, może być wymagane włączenie przerwań (lub masz na myśli, że zrobiłeś coś podobnego do mnie?)
Reply
#7
Zacytować: Wysłane przez can1357 pierwotnie Jeśli przydzielisz więcej niż 4 kb, może być wymagane włączenie przerwań (lub masz na myśli, że zrobiłeś coś podobnego do mnie?) Tak, przydziel małą pamięć dla abonenta wywołującego, takiego jak Ty, a następnie przydzielij dużą pulę za pomocą tego i zmień tam cały swój obraz. Zasadniczo jest to alternatywa dla tego, co robisz, umieszczając wszystko w sekcji niestandardowej i VirtualLocking, i wywołując wszystko za pomocą kodu pośredniczącego. Nie zrobiłem tego, po prostu skopiowałem całość do niestronicowanej pamięci jądra
Reply
#8
Zacytować: Napisał namazso Tak, przydziel małą pamięć dla abonenta wywołującego, takiego jak Ty, a następnie przydzielij dużą pulę za pomocą tego i zmień tam cały swój obraz. Zasadniczo jest to alternatywa dla tego, co robisz, umieszczając wszystko w sekcji niestandardowej i VirtualLocking, i wywołując wszystko za pomocą kodu pośredniczącego. Nie zrobiłem tego, po prostu skopiowałem całość do niestronicowanej pamięci jądra Nie ryzykujesz, że oryginalny obraz jest stronicowany, chyba że wirtualnie zablokujesz funkcję, w której przydzielasz kod pośredniczący (lub cały obraz, jeśli skopiujesz go za pomocą memcpy UM zamiast przerwań włączonych + nt memcpy)?
Reply
#9
Zacytować: Wysłane przez can1357 pierwotnie Nie ryzykujesz, że oryginalny obraz jest stronicowany, chyba że wirtualnie zablokujesz funkcję, w której przydzielasz kod pośredniczący (lub cały obraz, jeśli skopiujesz go za pomocą memcpy UM zamiast przerwań włączonych + nt memcpy)? Shellcode na stosie i nt memcpy. Stos afaik nigdy nie zostanie wywołany, gdy wątek jest uruchomiony
Reply
#10
Zacytować: Napisał namazso Shellcode na stosie i nt memcpy. Stos afaik nigdy nie zostanie wywołany, gdy wątek jest uruchomiony No dobrze, to brzmi dobrze (y)
Reply




Users browsing this thread: 1 Guest(s)