Здравствуйте! Вообщем задача следующая - востановить таблицу sstd после хуков неизвестным приложением. Покопался - нашел прилично исходников, в освновном половину делают в юзер моде, потом callgate в ринг0 и уже анхучят. Проблема в том, что мне необходимо реализовать драйвером. Есть конечно реализация драйвера by Cr4sh, но я нашел другой код made in China кстате(By XiCao) Вообщем главное отличие в том, что у Cr4sh делается так: ZwOpenFile -> ZwReadFile -> (ProcessImports && ProcessRelocs) у китайцев же как мне кажется попроще(тобишь они указывают откуда читать, а не рыщут по всей памяти) В другом коде ZwOpenFile -> ZwSetInformationFile -> ZwReadFile. Вопрос в том, что лучше использовать? Больше негде не встречал ZwSetInformationFile, да и с его использованием пока косяки. Чтобы не быть голословным приведу код (определения структур и прочую мишуру я уберу) И с вашего разрешения задам пару вопросов в самом коде. Код (Text): #define DEVICE L"\\Device\\ssdt" #define DOSDEVICE L"\\DosDevices\\ssdt" /// GLOBALS __declspec(dllimport) PSERVICE_DESCRIPTOR_ENTRY KeServiceDescriptorTable; PDEVICE_OBJECT DriverDeviceObject = NULL; //ф-ция реализации которых не важны. NTSTATUS STDCALL msgManager(PDEVICE_OBJECT DeviceObject, PIRP Irp); VOID STDCALL DriverUnload(IN PDRIVER_OBJECT DriverObject); NTSTATUS STDCALL DriverDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp); ULONG GetKernelBaseAddress(char* lpszModule) { NTSTATUS nResult; ULONG ulNeededSize, uKernelAddr; PSYSTEM_MODULE_INFORMATION pModuleList; uKernelAddr = 0; ZwQuerySystemInformation(11, &ulNeededSize, 0, &ulNeededSize); pModuleList = ExAllocatePool(NonPagedPool, ulNeededSize); nResult = ZwQuerySystemInformation(11, pModuleList, ulNeededSize, NULL); if (NT_SUCCESS(nResult)) { //ntoskrnl is always first there uKernelAddr =(ULONG) pModuleList->Module[0].Base; strcpy(lpszModule,"\\SystemRoot\\System32\\"); strcat(lpszModule,pModuleList->Module[0].PathLength+pModuleList->Module[0].ImageName); } ExFreePool(pModuleList); return uKernelAddr; } /* * Эта ф-ция почему-то всегда возвращает 0, на этом и завершается работа драйвера, * Правда ошибок в самой ф-ции я не вижу - значит неправильные входные параметры?! */ ULONG RVAToRaw(PVOID lpBase,ULONG VirtualAddress) { IMAGE_DOS_HEADER *pDosHeader; IMAGE_NT_HEADERS *pNtHeader; IMAGE_SECTION_HEADER *pSectionHeader; ULONG NumOfSections,uLoop; pDosHeader=(IMAGE_DOS_HEADER*)lpBase; if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) return 0; pNtHeader=(IMAGE_NT_HEADERS*)((unsigned char*)lpBase+pDosHeader->e_lfanew); NumOfSections=pNtHeader->FileHeader.NumberOfSections; pSectionHeader = (IMAGE_SECTION_HEADER*)((ULONG)pNtHeader + sizeof(ULONG) + sizeof(IMAGE_FILE_HEADER) + pNtHeader->FileHeader.SizeOfOptionalHeader); VirtualAddress -= (ULONG)lpBase; for (uLoop=0; uLoop<NumOfSections; uLoop++) { pSectionHeader = (IMAGE_SECTION_HEADER*)((ULONG)pSectionHeader + sizeof(IMAGE_SECTION_HEADER) * uLoop); if(VirtualAddress>pSectionHeader->VirtualAddress&&VirtualAddress<pSectionHeader->VirtualAddress+pSectionHeader->SizeOfRawData) { ULONG Offset = VirtualAddress-pSectionHeader->VirtualAddress + pSectionHeader->PointerToRawData; return Offset; } } return 0; } //StartService NTSTATUS STDCALL DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) { DbgPrint("DriverEntry() !\n"); UNICODE_STRING DeviceName; UNICODE_STRING DosDeviceName; NTSTATUS status; RtlInitUnicodeString(&DeviceName, DEVICE); RtlInitUnicodeString(&DosDeviceName, DOSDEVICE); status = IoCreateDevice( DriverObject, 0, &DeviceName, FILE_DEVICE_UNKNOWN, 0, FALSE, &DriverDeviceObject); if ( !NT_SUCCESS(status) ) return STATUS_NO_SUCH_DEVICE; status = IoCreateSymbolicLink(&DosDeviceName,&DeviceName); if( !NT_SUCCESS(status) ) { IoDeleteDevice( DriverDeviceObject ); DbgPrint("Failed to create symbolic link\n"); return STATUS_NO_SUCH_DEVICE; } DriverObject->MajorFunction[IRP_MJ_CREATE] = DriverDispatch; DriverObject->MajorFunction[IRP_MJ_CLOSE] = DriverDispatch; DriverObject->MajorFunction[IRP_MJ_READ] = DriverDispatch; DriverObject->MajorFunction[IRP_MJ_WRITE] = DriverDispatch; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = msgManager; DriverObject->DriverUnload = DriverUnload; ULONG uKernelMoule,uImageBase,uSSDTCount,uSSDTBase,uSSDTRaw,uLoop,uOldAddress,uNewAddress; PULONG lpArraySSDT; char szKernelPath[256]; ANSI_STRING aFileName; UNICODE_STRING uFileName; OBJECT_ATTRIBUTES ObjAttr; IO_STATUS_BLOCK ioStatus; FILE_POSITION_INFORMATION FilePos; HANDLE hFile; // get system modules memset(szKernelPath,0,256); uKernelMoule = GetKernelBaseAddress(szKernelPath); uImageBase = ((IMAGE_NT_HEADERS*)(uKernelMoule + ((IMAGE_DOS_HEADER*)uKernelMoule)->e_lfanew))->OptionalHeader.ImageBase; DbgPrint("Kernel ImageBase: 0x%.8X", uImageBase); DbgPrint("Kernel Base: 0x%.8X", uKernelMoule); DbgPrint("Kernel Module Path: %s", szKernelPath); // uSSDTCount = KeServiceDescriptorTable->NumberOfServices; uSSDTBase = (ULONG)KeServiceDescriptorTable->ServiceTableBase; DbgPrint("SSDT BaseAddress: 0x%8X, SSDT Count: 0x%X", uSSDTBase, uSSDTCount); lpArraySSDT = ExAllocatePool(PagedPool, uSSDTCount * sizeof(ULONG)); if (lpArraySSDT == NULL) return status; //SSDT uSSDTRaw = RVAToRaw(&uKernelMoule, uSSDTBase); DbgPrint("SSDT RAW: 0x%.8X", uSSDTRaw); if (uSSDTRaw == 0) { // ВОТ СЮДА попадаем всегда =( DbgPrint("SSDT RAW Error"); ExFreePool(lpArraySSDT); return status; } RtlInitAnsiString(&aFileName,szKernelPath); status = RtlAnsiStringToUnicodeString(&uFileName, &aFileName, TRUE); if(!NT_SUCCESS(status)) { DbgPrint("RtlAnsiStringToUnicodeString Error"); ExFreePool(lpArraySSDT); return status; } InitializeObjectAttributes(&ObjAttr, &uFileName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL); status = ZwOpenFile(&hFile, FILE_READ_DATA, &ObjAttr, &ioStatus, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_SYNCHRONOUS_IO_NONALERT); if (NT_SUCCESS(status) && hFile) { FilePos.CurrentByteOffset.LowPart = uSSDTRaw;//1000;//uSSDTRaw; FilePos.CurrentByteOffset.HighPart = 0; // Тут устанавливаем откуда будем читать status = ZwSetInformationFile(hFile, &ioStatus, &FilePos, sizeof(FILE_POSITION_INFORMATION), FilePositionInformation); if (NT_SUCCESS(status)) { status = ZwReadFile(hFile, NULL, NULL, NULL, &ioStatus, lpArraySSDT, uSSDTCount * sizeof(ULONG), NULL, NULL); if (NT_SUCCESS(status)) { for (uLoop=0; uLoop<uSSDTCount; uLoop++) { uOldAddress = *(lpArraySSDT + uLoop) - uImageBase + uKernelMoule; uNewAddress = *((PULONG)uSSDTBase + uLoop); if (uOldAddress != uNewAddress) { DbgPrint("SSDT No.%X, Old: 0x%.8X, New: 0x%.8X", uLoop, uOldAddress, uNewAddress); /// запрещаем прерывания KeRaiseIrql() аналог __asm cli KIRQL OldIrql; KeRaiseIrql(HIGH_LEVEL, &OldIrql); /* * Данный асм код надо бы перевести в синтаксис AT&T, * Вот заодно сразу и спрошу, возможно ли сбросить wp-bit * на си\си++, если да, то как? */ // asm volatile( // "cli" // "mov eax,cr0" // "and eax,~0x10000" // сбросить WP bit // "mov cr0,eax" // ); // анхучим... *((PULONG)uSSDTBase + uLoop) = uOldAddress; //fast_InterlockedExchange(*(uSSDTBase + uLoop), uOldAddress); // ^^ эта надпись автора кода, я так понял относится к строчке выше? тогда разве не так: // InterlockedExchange(&uNewAddress, uOldAddress); // // asm volatile( // "mov eax,cr0" // "or eax,0x10000" // "mov cr0,eax" // "sti" // ); /// Возвращаем все как было.(разрешаем прерывания) аналог __asm sti KeLowerIrql(OldIrql); } } DbgPrint("SSDT TheEnd..."); } else DbgPrint("Read File Error!"); } // else // DbgPrint("Set File Pos Error!"); if(hFile) ZwClose(hFile); } else DbgPrint("Open File Error!"); RtlFreeUnicodeString(&uFileName); ExFreePool(lpArraySSDT); return STATUS_SUCCESS; } Буду благодарен за Вашу помощь.
Пробовал - не помогло... Китайцы в обсуждении даже переопределили(вроде как) ULONG RVAToRaw(DWORD lpBase,ULONG VirtualAddress)
Извиняюсь, ввел в заблуждение в оригинале используется так "RVAToRaw(uKernelMoule, uSSDTBase)" Вот что выдает DbgPring: OS: NT 5.1 (2600) (winxp sp3 вообщем)
pSectionHeader = (IMAGE_SECTION_HEADER*)((ULONG)pNtHeader + sizeof(ULONG) + sizeof(IMAGE_FILE_HEADER) + pNtHeader->FileHeader.SizeOfOptionalHeader); лучше заменить на pSectionHeader = IMAGE_FIRST_SECTION(pNtHeader) а то как-то подозрительно выглядит
Просто результат тот же, как и вывод дебага. Код (Text): typedef struct _IMAGE_SECTION_HEADER { BYTE Name[IMAGE_SIZEOF_SHORT_NAME]; union { DWORD PhysicalAddress; DWORD VirtualSize; } Misc; DWORD VirtualAddress; DWORD SizeOfRawData; DWORD PointerToRawData; DWORD PointerToRelocations; DWORD PointerToLinenumbers; WORD NumberOfRelocations; WORD NumberOfLinenumbers; DWORD Characteristics; } IMAGE_SECTION_HEADER,*PIMAGE_SECTION_HEADER; Код (Text): typedef struct _IMAGE_NT_HEADERS { DWORD Signature; IMAGE_FILE_HEADER FileHeader; IMAGE_OPTIONAL_HEADER OptionalHeader; } IMAGE_NT_HEADERS32,*PIMAGE_NT_HEADERS32; Что то я смысла в "pSectionHeader = IMAGE_FIRST_SECTION(pNtHeader)" не вижу. Но попробовал - тот же результат. Ф-ция возвращает 0;
wrk. Код (Text): // IMAGE_FIRST_SECTION doesn't need 32/64 versions since the file header is the same either way. #define IMAGE_FIRST_SECTION( ntheader ) ((PIMAGE_SECTION_HEADER) \ ((ULONG_PTR)ntheader + \ FIELD_OFFSET( IMAGE_NT_HEADERS, OptionalHeader ) + \ ((PIMAGE_NT_HEADERS)(ntheader))->FileHeader.SizeOfOptionalHeader \ )) PIMAGE_SECTION_HEADER RtlSectionTableFromVirtualAddress ( IN PIMAGE_NT_HEADERS NtHeaders, IN PVOID Base, IN ULONG Address ) /*++ Routine Description: This function locates a VirtualAddress within the image header of a file that is mapped as a file and returns a pointer to the section table entry for that virtual address Arguments: NtHeaders - Supplies the pointer to the image or data file. Base - Supplies the base of the image or data file. Address - Supplies the virtual address to locate. Return Value: NULL - The file does not contain data for the specified directory entry. NON-NULL - Returns the pointer of the section entry containing the data. --*/ { ULONG i; PIMAGE_SECTION_HEADER NtSection; NtSection = IMAGE_FIRST_SECTION( NtHeaders ); for (i=0; i<NtHeaders->FileHeader.NumberOfSections; i++) { if ((ULONG)Address >= NtSection->VirtualAddress && (ULONG)Address < NtSection->VirtualAddress + NtSection->SizeOfRawData ) { return NtSection; } ++NtSection; } return NULL; } PVOID RtlAddressInSectionTable ( IN PIMAGE_NT_HEADERS NtHeaders, IN PVOID Base, IN ULONG Address ) /*++ Routine Description: This function locates a VirtualAddress within the image header of a file that is mapped as a file and returns the seek address of the data the Directory describes. Arguments: NtHeaders - Supplies the pointer to the image or data file. Base - Supplies the base of the image or data file. Address - Supplies the virtual address to locate. Return Value: NULL - The file does not contain data for the specified directory entry. NON-NULL - Returns the address of the raw data the directory describes. --*/ { PIMAGE_SECTION_HEADER NtSection; NtSection = RtlSectionTableFromVirtualAddress( NtHeaders, Base, Address ); if (NtSection != NULL) { return( ((PCHAR)Base + ((ULONG_PTR)Address - NtSection->VirtualAddress) + NtSection->PointerToRawData) ); } else { return( NULL ); } }
008888 Да, показалось. Гадать можно долго, потрассировать быстрее. Может там количество секций в памяти тоже пропатчено...
Код (Text): pSectionHeader = (IMAGE_SECTION_HEADER*)((ULONG)pSectionHeader + sizeof(IMAGE_SECTION_HEADER) * uLoop); за такое банить надо %) Правильный вариант сам прищумаешь?
2 n0name -угу, протупил, дефайна не заметил... 2 Clerk Код (Text): IMAGE_DOS_HEADER *pDosHeader; IMAGE_NT_HEADERS *pNtHeader; ULONG NumOfSections,uLoop; pDosHeader=(IMAGE_DOS_HEADER*)lpBase; if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) return 0; pNtHeader=(IMAGE_NT_HEADERS*)((unsigned char*)lpBase+pDosHeader->e_lfanew); if(!pNtHeader) DbgPrint("Smth WRONG!\n"); pointer = RtlAddressInSectionTable(pNtHeader,lpBase,VirtualAddress); if(pointer == NULL) { DbgPrint("pointer = null\n"); return status; } RtlAddressInSectionTable возвращает NULL...
Нда... наверное нужен подфорум с названием "я ничо не понял, помогите скомпилить чтоб заработало"... 008888 Посмотри здесь. Неплохое начало по твоей теме. http://www.wasm.ru/forum/viewtopic.php?id=19538&p=1
Ого,быстро тут сообщения трут некоторые. Ну да ладно, вообщем вроде бы разобрался,один вопрос остался, почему в KeServiceDescriptorTable->TableSize такое огромное число?
008888 Оскорбления и флейм стираются нещадно и незаметно для пользователей. А вот и не правда, у вас какое?