IceFire Грита способ предполагает палевную и ничем не более простую работу с прерываниями, зачем в таком случае это делать, если можно просто сплайснуть KiSystemServiceRepeat(), либо сразу kssdoit.
Great Подскажи, пожалуйста, что ты имел ввиду вот здесь: Код (Text): ULONG TempVector = HalGetInterruptVector (Internal, 0, 0, 0, &Irql, &Affinity); Почему 3 и 4 параметры - нули? В MSDN прочитал Просто я поиграл с этими параметрами и поставил их равными 7. После чего HalGetInterruptVector вернул: TempVector=0x37, Irql = 0x14, Affinity = 1 и IoConnectInterrupt вернул STATUS_SUCCESS.
Да, еще хотел спросить. Если поле DispatchCode объекта KINTERRUPT недокументировано, как обратиться к нему? на Код (Text): DbIntObj->DispatchCode компилер ругается C2037.
Последний вопрос отпал, структуру KINTERRUPT вытащил из исходников ReactOS. Все-таки, почему в HalGetInterruptVector стоят нули?
Great Попробовал заменить адрес обработчика Sysenter. Вот код: Код (Text): #include <ntddk.h> #define DEBUG #ifdef DEBUG #define DPRINT DbgPrint #else #define DPRINT #endif #define KINTERRUPT_DISPATCH_CODES 106 typedef struct _KINTERRUPT { CSHORT Type; CSHORT Size; LIST_ENTRY InterruptListEntry; PKSERVICE_ROUTINE ServiceRoutine; PVOID ServiceContext; KSPIN_LOCK SpinLock; ULONG TickCount; PKSPIN_LOCK ActualLock; PKINTERRUPT_ROUTINE DispatchAddress; ULONG Vector; KIRQL Irql; KIRQL SynchronizeIrql; BOOLEAN FloatingSave; BOOLEAN Connected; CCHAR Number; BOOLEAN ShareVector; KINTERRUPT_MODE Mode; ULONG ServiceCount; ULONG DispatchCount; ULONG DispatchCode[KINTERRUPT_DISPATCH_CODES]; } KINTERRUPT, *PKINTERRUPT; PKINTERRUPT DbIntObj; ULONG CR0Reg; ULONG OldSyscall; ULONG NewSyscall; //-------------------------------------------------------- void SetXpSyscallHook() { __asm { pushad mov ecx, 0x176 rdmsr mov OldSyscall, eax mov eax, NewSyscall //!!! xor edx, edx wrmsr popad } } void DeleteXpSyscallHook() { __asm { pushad mov ecx, 0x176 mov eax, OldSyscall xor edx, edx wrmsr xor eax, eax mov OldSyscall, eax popad } } //-------------------------------------------------------- void ClearInt() { __asm { cli mov eax, cr0 mov CR0Reg,eax and eax,0xFFFEFFFF mov cr0, eax } } void SetInt() { __asm { mov eax, CR0Reg mov cr0, eax sti } } //-------------------------------------------------------- VOID DriverUnload(IN PDRIVER_OBJECT DriverObject) { if (DbIntObj) { ClearInt(); DeleteXpSyscallHook(); IoDisconnectInterrupt (DbIntObj); SetInt(); } DPRINT("Driver unloaded \n"); return; } //---------------------------------------------------------- BOOLEAN DbgIntBreak( PKINTERRUPT InterruptObject, PVOID Context ) { DbgPrint("Here"); // __asm jmp OldSyscall; return FALSE; } //---------------------------------------------------------- NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) { //---------------------------------------------------------- NTSTATUS Status; KIRQL Irql; KAFFINITY Affinity; ULONG Irq = 7; ULONG TempVector = HalGetInterruptVector(Internal, 0, Irq, Irq, &Irql, &Affinity); DbgPrint("TempVector = %x, Irql = %x, Affinity = %x\n", TempVector, Irql, Affinity); Status = IoConnectInterrupt ( &DbIntObj, DbgIntBreak, NULL, NULL, TempVector, Irql, Irql, Latched, TRUE, Affinity, FALSE ); DbgPrint("IoConnectInterrupt %x\n", Status); if (NT_SUCCESS(Status)) { DbgPrint("ADDRESS KINTERRUPT::DispatchCode: %x\n", DbIntObj->DispatchCode); DbgPrint("Start hooking..."); ClearInt(); NewSyscall=(ULONG)(DbIntObj->DispatchCode); SetXpSyscallHook(); SetInt(); DbgPrint("OldSyscall: %x\n", OldSyscall); DbgPrint("Hooking complete..."); } //---------------------------------------------------------------- DriverObject->DriverUnload = DriverUnload; return STATUS_SUCCESS; } В итоге ничего не получилось, ребут. Я думаю, это произошло из-за того, что не вызван оригинальный обработчик Sysenter из MSR. А как его правильно вызвать? И когда следует понизить IRQL?
Они обозначают тип шины Internal, шину 0 и bus interupt level 0. У меня работало. Какая ОС? Хотя на самом деле значения этих параметров не важны. Их можно даже перебирать в цикле ;DD пока не вернется валидный вектор. Ха! Значит,сисентер подменять обработчик можно, а прерывания уже палевно... Дожили. Может ему это для легального совершенно логгера сисколов. Можно попробовать после этого кода проставить Irql = 0; перед вызовом IoConnectInterrupt. А можно DbgIntBreak начать с KfLowerIrql(PASSIVE_LEVEL) и закончить соответствующим Raise на старый уровень. (больше никогда так не делайте! ) Вообще, надо посмотреть код DispatchCode, я уже не помню, что там Но вообще, само собой, вызывать оригинальный обработчик нужно. Но для этого придется попотеть - он будет создавать KTRAP_FRAME, а он у нас уже создан в DispatchCode. Простой джамп не пойдет! ПС. А DbgPrint'енное сообщение-то выводится? И вообще что за ребут. Должно зависать. Хм. Потрейси в вмваре+виндбг
Great WXP SP2 2600 on MS Virtual PC 2007 Валидный вектор нашел. Да! Я не малвару пишу, я говорил уже об этом. ...и как? =) Нет. Ребут мгновенно.
Короче, я сегодня очень добрый. Я написал за тебя весь код) Драйвер хукает сисентер моим способом и пишет в лог \SystemRoot\syscalls.log все системные вызовы. Надолго не запускай - лог очень быстро растет. Буквально за полминуты вырос на 9 мегабайт. Исходник в аттаче. Если ест вопросы по коду - спрашивай.
Диспатч код напрямую юзать нельзя, как оказалось (я забыл). Обработка сисентер и прерываний отличается. При входе в прерывания процессор сохраняет на стеке eflags,cs,eip и, если произошла смена привилегий, тогда еще и ss,esp. При входе в сисентер такого нет. Поэтому обработчик сисентер ставится на свой стаб, который загружает esp = KTSS.Esp0 и пушает на стек все эти дела. Потом вызывает DispatchCode. DispatchCode тоже напрямую юзать не стоит, поскольку он 1) вызывает KiInterruptDispatch, которая повышает IRQL,а это нам не нужно 2) не сохраняет значение EAX при вызове сисентер, которое потребуется нам как номер сискола. Поэтому JMP KiInterruptDispatch инструкция в DispatchCode заменяется на JMP new_KiInterruptDispatch, а своя new_KiInterruptDispatch делает STI, пушает eax и вызывает SysenterServiceRoutine. После возврата она чекает al (возвращаемое значение из SysenterServiceRoutine) и трактуется: если FALSE - тогда подменяется KTRAP_FRAME::Eip на адрес KiFastCallEntry и KTRAP_FRAME::Cs на 8 и потом вызывается Kei386EoiHelper. Управление передается на системный обработчик (косвенно) если TRUE - тогда просто вызывается Kei386EoiHelper. управление уйдет в юзермод на KiFastSystemCallRet. Вроде расписал подробно..
Great А кто в мср обработчик подменяет, это только автору этого топика нужно. Вы не ответили на вопрос в #42, если легально то зачем эти манипуляции с прерываниями и всю остальную нестабильную в большинстве случаев лабуду нагромождать, тупо записать джамп на обработчик делов то. Снимется также как и замена адреса в IA32_SYSENTER_EIP, про шлюзы аналогично.
Great Кстати я подумал, если считаешь что формирование регистровых фреймов сложной задачей(всегото несколько смещений и адресов дизасмом найти), то можно в принципе сделать так. - Выделяем пул для обработчика. - Трассируем полностью KiFastCallEntry, либо KiSystemService, не раскрывая процедуры. Либо что сложнее использовать хороший дизассемблер. - Копируем инструкции в выделенный пул, с учётом поправки смещений. - Трассируем все ветвления, задача не настолько сложная. В конце получим копию обработчика в нашем пуле. Это в общих чертах, нужно есчо продумать механизм.
Great Вот интересно, если ее сплайсить, треп-фрейм уже будет создан на момент ее вызова? В новом обработчике можно сразу делать полезную работу, или что-то еще нужно?
Great Сделал сплайс: Код (Text): #include <ntddk.h> #include "OpCodeSize.h" #define DEBUG #ifdef DEBUG #define DPRINT DbgPrint #else #define DPRINT #endif #pragma pack(push,2) typedef struct _Idt { USHORT Size; ULONG Base; } TIdt; typedef struct _IDT_DESCRIPTOR { USHORT LowPartOffset; USHORT Selector; USHORT Flags; USHORT HighPartOffset; } IDT_DESCRIPTOR, *PIDT_DESCRIPTOR; typedef UCHAR (BYTE); typedef BYTE* PBYTE; typedef USHORT (WORD); typedef WORD* PWORD; typedef ULONG (DWORD); typedef DWORD* PDWORD; ULONG CR0Reg; ULONG Trap2eOffset=0, Old2eOffset=0, KiSSRAddr=0; PBYTE Trap2ePointer, KiSSRPointer, pMovedKSSRCode; WORD Trap2eSelector; DWORD SegDescBase; BYTE uOrigKSSRHead[8]; //-------------------------------------------------------- void ClearInt() { __asm { cli // запрещаем прерывания mov eax, cr0 mov CR0Reg,eax and eax,0xFFFEFFFF // сбросить WP bit mov cr0, eax } } void SetInt() { __asm { mov eax, CR0Reg mov cr0, eax // востановить содержимое CR0 sti // разрешаем прерывания } } //-------------------------------------------------------- //======================================================== VOID DriverUnload(IN PDRIVER_OBJECT DriverObject) { __asm{ cli mov eax,cr0 and eax,not 10000h mov cr0,eax } memcpy((PVOID)KiSSRAddr,uOrigKSSRHead,8); __asm{ mov eax,cr0 or eax,10000h mov cr0,eax sti } ExFreePool(pMovedKSSRCode); DPRINT("--------------------Driver unloaded--------------------"); return; } __declspec(naked) void MyKSSRFunction(void) { __asm { pop edi pushad } __asm { popad jmp pMovedKSSRCode } } VOID SetHook() { //This function hooks KiSystemServiceRepeat UCHAR cHookCode[8] = { 0x57, //push edi 0xBF,0,0,0,0, //mov edi,0000 0xFF,0xE7}; //jmp edi UCHAR JmpCode[]={0xE9,0,0,0,0}; //jmp near, relative int nCopyLen = 0; int nPos = 0; int i=0; PBYTE pMyKSSRFunction; nPos = KiSSRAddr; while(nCopyLen<8) { nCopyLen += GetOpCodeSize((PVOID)nPos); DPRINT("GetOpCodeSize said: %#0x", GetOpCodeSize((PVOID)nPos)); nPos = KiSSRAddr + nCopyLen; } DPRINT("Bytes to copy: %#0x", nCopyLen); if ((nCopyLen<20) & (nCopyLen>0)) { pMovedKSSRCode = ExAllocatePool(NonPagedPool,nCopyLen+10); memcpy(uOrigKSSRHead,(PVOID)KiSSRAddr,8); for (i=0;i<8;i++) DPRINT("Saved bytes: %#0x", uOrigKSSRHead[i]); *((ULONG*)(JmpCode+1)) = (KiSSRAddr + nCopyLen) - ((ULONG)pMovedKSSRCode + nCopyLen)- 5; DPRINT("KiSSRAddr + nCopyLen addr: %#0x", (DWORD)(KiSSRAddr + nCopyLen)); DPRINT("pMovedKSSRCode + nCopyLen addr: %#0x", (DWORD)(pMovedKSSRCode + nCopyLen)); DPRINT("Jmp offset: %#0x", (DWORD)(JmpCode+1)); memcpy(pMovedKSSRCode,(PVOID)KiSSRAddr,nCopyLen); memcpy((PVOID)(pMovedKSSRCode + nCopyLen),JmpCode,5); //Copy jmp instruction *((ULONG*)(cHookCode+2)) = (ULONG)MyKSSRFunction; DPRINT("Saved KSSR code:0x%08X",pMovedKSSRCode); DPRINT("MyKSSRFunction :0x%08X",MyKSSRFunction); DPRINT("======"); for (i=0;i<8;i++) DPRINT("cHookCode: %#0x", cHookCode[i]); DPRINT("======"); pMyKSSRFunction=(PBYTE)MyKSSRFunction; for (i=0;i<6;i++) DPRINT("MyKSSRCode: %#0x", *(pMyKSSRFunction+i)); DPRINT("======"); for (i=0;i<(nCopyLen+5);i++) DPRINT("MovedKSSRCode: %#0x", *(pMovedKSSRCode+i)); DPRINT("======"); __asm{ cli mov eax,cr0 and eax,not 10000h mov cr0,eax } memcpy((PVOID)KiSSRAddr,cHookCode,8); __asm{ mov eax,cr0 or eax,10000h mov cr0,eax sti } } else { DPRINT("Couldn't splice KiSystemServiceRepeat. Sorry :("); return; } } VOID GetKSSRAddress() { TIdt Idt; TGDT GDT; PTGDTEntry SegDesc; PIDT_DESCRIPTOR Desc2e; int i=0, j=0; ClearInt(); __asm { sidt [Idt] } SetInt(); DPRINT("Idt.Base: %#0x",Idt.Base); DPRINT("Idt.Limit: %#0x",Idt.Size); Desc2e=(PIDT_DESCRIPTOR)(Idt.Base+0x2e*8); DPRINT("Desc2e: %#0x", Desc2e); Trap2eOffset=Desc2e->HighPartOffset; Trap2eOffset=Trap2eOffset<<16; Trap2eOffset+=Desc2e->LowPartOffset; DPRINT("2E Int routine offset: %#0x", Trap2eOffset); //------- Trap2ePointer=(PVOID)Trap2eOffset; for (i=0;i<=0x200;i++) { if (*((PWORD)(Trap2ePointer+i))==0xE9FB) { DPRINT("---------BELOW HERE---------"); KiSSRAddr=*(PDWORD)(Trap2ePointer+i+2); DPRINT("KiSystemServiceRepeat offset: %#0x", KiSSRAddr); KiSSRAddr+=(DWORD)(Trap2ePointer+i+6); // 1 byte for sti, 1 byte for jmp (E9) and 4 bytes for rel32 address DPRINT("KiSystemServiceRepeat addr: %#0x", KiSSRAddr); KiSSRPointer=(PVOID)KiSSRAddr; for (j=0;j<=0x10;j++) DPRINT("%#0x", *((PBYTE)KiSSRPointer+j)); DPRINT("----------------------------"); break; } DPRINT("%#0x", *((PBYTE)Trap2ePointer+i)); } //------- } NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath) { DPRINT("--------------------Driver loaded--------------------"); DriverObject->DriverUnload = DriverUnload; DPRINT("Start Detecting..."); GetKSSRAddress(); if (KiSSRAddr) SetHook(); else { DPRINT("Unable to obtain KiSystemServiceRepeat address. Sorry :("); return STATUS_SUCCESS; } DPRINT("Detecting complete..."); return STATUS_SUCCESS; } Проблема в следующем: вот так - все работает, но стоит вставить DbgPrint в MyKSSRFunction - система зависает. Посмотри, пожалуйста, может подскажешь. OpCodeSize.h был уже в этой ветке выше. Потресить под VM не могу - во-первых, под VM неправильно определяется адрес KiSystemService (не понял пока почему), во-вторых, этот сигнатурный поиск под ядро на VM не прокатывает.
Не понятно причём тут IDT. Вобще это на асме пишут, а нотификация дебуггера - в ядра это верный способ словить бсод, достаточно Int3, дабы всплыл отладчик при исполнениии кода. Под варей корректный адрес обработчика в мср, все остальные проблемы связаны с незнанием среды, на которой код создаётся. А ядро на варе идентично реальному, да обработка исключений не корректна, виртуальная машина обрабатывает некоторые прежде. Вобще в ядре код должен быть соответствующий, это не юзермод гдже можно извращаться как угодно, темболее на столь низком уровне.