Перехват неиспользуемого прерывания

Тема в разделе "WASM.WIN32", создана пользователем drmist, 31 июл 2006.

  1. drmist

    drmist New Member

    Публикаций:
    0
    Регистрация:
    31 май 2005
    Сообщения:
    112
    После прочетния статьи Ms-Rem'а "Обнаружение скрытых процессов" мне рпишла в голову идея попробывать перехватить какое-нибудь неиспользуемое прерывание. Было бы удобно обращаться к драйверу не через Write File, а через ассемблерную инструкцию int. Для перехвата int 2Eh автор использовал код:
    pushad
    cli
    sidt [Idt]
    mov esi, NewSyscall
    mov ebx, Idt.Base
    xchg [ebx + 0x170], si
    rol esi, 0x10
    xchg [ebx + 0x176], si
    ror esi, 0x10
    mov OldSyscall, esi
    sti
    popad
    Я так понял, что Idt.Base указывает на массив структур размером по 8 байт (0x170/0x2E) типа
    WORD малдший адрес callback
    DWORD незнаю что
    WORD старший адрес callback
    Затем я предположил, что прерывание int 55h не используется системой и накатал следующее:
    void Int55Hook()
    {
    IDT_STRUCT IDT;
    _asm
    {
    pushad
    cli
    sidt [IDT]
    mov esi, NewInt55Proc
    mov ebx, IDT.Base
    xchg [ebx + 8*55h], si
    rol esi, 16
    xchg [ebx + 8*55h+6], si
    rol esi, 16
    mov OldInt55Proc, esi
    sti
    popad
    }

    DPRINT("Int55HookDriver: int 55h is hooked");
    }
    ......
    После того, как я получил bsod стал вопрос:
    Правильно ли я понял формат и размер структуры на массив которых указывает IDT.Base? Является ли прерывание int 55h неиспользуемым? Какие вобще прерывания я могу использывать в своих целях?
    Буду благодарен за ответы.
     
  2. drmist

    drmist New Member

    Публикаций:
    0
    Регистрация:
    31 май 2005
    Сообщения:
    112
    Да и еще, что означает __declspec(naked)?
    чем объявленная таким образом функция отличается от stdcall?
     
  3. Ms Rem

    Ms Rem New Member

    Публикаций:
    0
    Регистрация:
    17 апр 2005
    Сообщения:
    1.057
    Адрес:
    С планеты "Земля"
    Для начала смотрим с помощью IdtDump, юзается ли прерывание - это раз. Затем, не забываем переключать регистр fs на ядро, и загрузать все сегментные регистры (если они модифицированы юзермодным кодом). После чего - не забываем корректно ставить PreviousMode в структуре потока. Как это делаеться - смотри в сорцах винды функцию KiSestemService. И всеравно, при вызовах некоторых апей может произойти падение (причем не сразу, а только иногда). Причину этого я не нашел, видно просто забыл учесть какую-либо особенность.

    Учим матчасть по компилятору. Это означает, что функция не будет иметь пролога и эпилога, и компилиться так как есть.


    З.Ы. и еще советую не забывать про обработку прерываний на многопроцессорных системах. Пример я гдето тут выкладывал.
     
  4. drmist

    drmist New Member

    Публикаций:
    0
    Регистрация:
    31 май 2005
    Сообщения:
    112
    Я так понимаю, все это относиться уже к функции-обработчику прерывания?
    Если да, то во-первых вот она:
    void NewRealInt55Proc(ULONG reg_eax)
    {
    DPRINT("Int55HookDriver: int 55h is called, eax == %x08.", reg_eax);
    }

    void _declspec(naked) NewInt55Proc()
    {
    _asm
    {
    pushad
    pushfd
    push fs
    mov di, 0x30
    mov fs, di

    push eax
    call NewRealInt55Proc

    pop fs
    popfd
    popad
    }
    }

    а во-вторых система падает во время установки обработчика, то есть до NewInt55Proc() дело не доходит.
    ItdDump говорит, что прерывание свободно
    0055 0008:804DE6D2 0 P 32 bits Interrupt Gate User Defined (Non-reserved) Interrupts

    --добавлено--
    да, кстати что-то мне подсказывает, что в конце NewInt55Proc() должен стоять iret....
     
  5. drmist

    drmist New Member

    Публикаций:
    0
    Регистрация:
    31 май 2005
    Сообщения:
    112
    вписал int 3 в обработчик DriverObject->MajorFunction[IRP_MJ_WRITE] в той части, где приходит irp пакет от юзера с указанием на то, что нужно поставить хук.
    из SoftIce я смог выжать только то, что bsod наступает сразу после выполнения инструкции xchg [ebx + 8*55h], si. надпись на синем экране разобрать не успеваю - она держиться меньше cекунды. зато если не ставить бряк на функцию IRP_MJ_WRITE, SoftIce показывает что где-то внутри ядра происходит ошибка IRQL_NOT_LESS_OR_EQUAL, не имею понятия, чей IRQL не подходит. Как будто кто-то пытается вызвать функцию прерывания, пока я еще не установил вторую часть адреса.
    Выкладываю сурсы на всеобщее обозрение, авось кто поможет :dntknw:.
     
  6. electron

    electron New Member

    Публикаций:
    0
    Регистрация:
    26 май 2005
    Сообщения:
    32
    Попробуй такой код:
    Код (Text):
    1. IDT_STRUCT* pIdtStr;
    2. IDT_STRUCT* p55IdtStr;
    3. __asm
    4. {
    5.              sidt pIdStr;  
    6. }
    7. p55IdtStr=&(pIdtStr[0x55]);
    8. __asm
    9. {
    10.     cli;
    11.     lea eax,NewInt55Proc;
    12.     mov ebx,p55IdtStr;
    13.     mov [ebx],ax;
    14.     shr eax,16;
    15.     mov [ebx+6],ax;
    16.     sti;
    17. }
     
  7. drmist

    drmist New Member

    Публикаций:
    0
    Регистрация:
    31 май 2005
    Сообщения:
    112
    electron
    эффект тот же.
    где в твоем коде, например, обращение к записи Base?
     
  8. electron

    electron New Member

    Публикаций:
    0
    Регистрация:
    26 май 2005
    Сообщения:
    32
    Напутал, вроде сейчас поправил:
    Код (Text):
    1. typedef struct _IDT
    2. {
    3.    USHORT IDTLimit;
    4.    USHORT LowIDTbase;
    5.    USHORT HiIDTbase;
    6. }IDT,*PIDT;
    7.  
    8. #pragma pack(1)
    9. typedef struct _IDTSTRUCT
    10. {
    11.      USHORT LowOffset;
    12.      USHORT selector;
    13.      UCHAR unused_lo;
    14.      unsigned char unused_hi:5;
    15.      unsigned char DPL:2;
    16.      unsigned char P:1;        
    17.      USHORT HiOffset;
    18. } IDTSTRUCT,*PIDTSTRUCT;
    19. #pragma pack()
    20.  
    21. IDT idt;
    22. PIDTSTRUCT* pIdtStr;
    23. PIDTSTRUCT* p55IdtStr;
    24. __asm
    25. {
    26.              sidt idt;  
    27. }
    28. pIdtStr=(PIDTSTRUCT)MAKELONG(idt.LowIDTbase,idt.HiIDTbase);
    29. p55IdtStr=&(pIdtStr[0x55]);
    30. __asm
    31. {
    32.     cli;
    33.     lea eax,NewInt55Proc;
    34.     mov ebx,p55IdtStr;
    35.     mov [ebx],ax;
    36.     shr eax,16;
    37.     mov [ebx+6],ax;
    38.     sti;
    39. }
     
  9. ProgramMan

    ProgramMan New Member

    Публикаций:
    0
    Регистрация:
    13 янв 2004
    Сообщения:
    263
    Смотри код.(FASM)
     
  10. clone

    clone New Member

    Публикаций:
    0
    Регистрация:
    4 июл 2006
    Сообщения:
    84
    drmist
    В ключе HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\CrashControl установи значение AutoReboot в ноль.
     
  11. drmist

    drmist New Member

    Публикаций:
    0
    Регистрация:
    31 май 2005
    Сообщения:
    112
    В общем я присмотрелся к драйверу в IDA и сразу стало понятно, почему он не пашет (вобще дурак я - через soft ice мог бы углядеть).
    Там получается код типа
    Код (Text):
    1. Int55Hook:
    2.   sidt [ebp+x]
    3.   ; ...
    то есть мы пытаемся работать с локальной переменной, память под которую почему-то не выделена. При этом функция была объявлена, как в первом поcте.
    Вот что у меня получилось:
    Код (Text):
    1. #define HOOKED 0x55
    2. ULONG OldInt55Proc;
    3. ULONG IDT_Base;
    4.  
    5. void _declspec(naked) Int55Hook()
    6. {
    7.   _asm
    8.   {
    9.     pushad
    10.     mov ebp, esp
    11.     sub esp, 6
    12.     mov edi, esp
    13.     sidt [edi]
    14.     inc edi
    15.     inc edi
    16.     mov edi, [edi]
    17.     mov IDT_Base, edi
    18.     mov esi, NewInt55Proc
    19.     cli
    20.     xchg si, [edi + 8*HOOKED]
    21.     rol esi, 16
    22.     xchg si, [edi + 8*HOOKED+6]
    23.     sti
    24.     rol esi, 16
    25.     mov OldInt55Proc, esi
    26.     mov esp, ebp
    27.     popad
    28.     ret
    29.   }
    30. }
    31.  
    32. void _declspec(naked) Int55Unhook()
    33. {
    34.   _asm
    35.   {
    36.     pushad
    37.     mov edi, IDT_Base
    38.     mov esi, OldInt55Proc
    39.     cli
    40.     mov [edi + 8*HOOKED], si
    41.     shr esi, 16
    42.     mov [edi + 8*HOOKED+6], si
    43.     sti
    44.     popad
    45.     ret
    46.   }
    47. }
    Правда я расчитывал, что смогу в ring3 делать int 55h и переходить к обработчику в драйвере, а вместо этого получаю STATUS_ACCES_VIOLATION. Так и запланированно или я может не туда адрес обработчика вписал?
     
  12. Ms Rem

    Ms Rem New Member

    Публикаций:
    0
    Регистрация:
    17 апр 2005
    Сообщения:
    1.057
    Адрес:
    С планеты "Земля"
    Товарищи, о чем спорите? Я же обьяснил, что выкладывал на форуме модуль, позволяющий работать с прерываниями (в том числе и добавлять новые). Привожу ключевые фрагменты кода:

    Код (Text):
    1. typedef struct _DPC_PARAMS
    2. {
    3.     KDPC           Dpc;
    4.     PCALLBACK_PROC Proc;
    5.     PVOID          Param;
    6.     PKEVENT        SyncEvent;
    7.     BOOLEAN        Syncronous;
    8. } DPC_PARAMS, *PDPC_PARAMS;
    9.  
    10. void DpcRoutine(
    11.     IN PKDPC Dpc,
    12.     IN PVOID DeferredContext,
    13.     IN PVOID SystemArgument1,
    14.     IN PVOID SystemArgument2
    15.     )
    16. {
    17.     PDPC_PARAMS Params = DeferredContext;
    18.  
    19.     Params->Proc(Params->Param);
    20.  
    21.     if (Params->Syncronous) KeSetEvent(Params->SyncEvent, IO_NO_INCREMENT, FALSE);
    22.  
    23.     ExFreePool(Params);
    24. }
    25.  
    26. void CallToProcessor(
    27.                   IN CCHAR          Cpu,
    28.                   IN PCALLBACK_PROC Proc,
    29.                   IN PVOID          Param,
    30.                   IN BOOLEAN        Syncronous
    31.                   )
    32. {
    33.     KEVENT       SyncEvent;
    34.     PDPC_PARAMS  DpcParams;
    35.  
    36.     DpcParams = ExAllocatePool(NonPagedPool, sizeof(DPC_PARAMS));
    37.  
    38.     if (DpcParams)
    39.     {
    40.         KeInitializeEvent(&SyncEvent, NotificationEvent, FALSE);
    41.  
    42.         DpcParams->Syncronous = Syncronous;
    43.         DpcParams->Param      = Param;
    44.         DpcParams->Proc       = Proc;
    45.         DpcParams->SyncEvent  = &SyncEvent;
    46.  
    47.         KeInitializeDpc(&DpcParams->Dpc, DpcRoutine, DpcParams);
    48.  
    49.         KeSetTargetProcessorDpc(&DpcParams->Dpc, Cpu);
    50.  
    51.         KeInsertQueueDpc(&DpcParams->Dpc, NULL, NULL);
    52.  
    53.         if (Syncronous) KeWaitForSingleObject(&SyncEvent, Executive, KernelMode, FALSE, NULL);
    54.     }  
    55. }
    56.  
    57.  
    58. void CallToAllProcessors(
    59.                   IN PCALLBACK_PROC Proc,
    60.                   IN PVOID          Param,
    61.                   IN BOOLEAN        NoSelfCall,
    62.                   IN BOOLEAN        Syncronous
    63.                   )
    64. {
    65.     KIRQL        OldIrql;
    66.     CCHAR        Num;
    67.     ULONG        MyProc;
    68.     PDPC_PARAMS  DpcParams;
    69.  
    70.     if (KeNumberProcessors == 1)
    71.     {
    72.         if (!NoSelfCall)
    73.         {
    74.             OldIrql = KeRaiseIrqlToDpcLevel();
    75.            
    76.             Proc(Param);
    77.  
    78.             KeLowerIrql(OldIrql);
    79.         }
    80.     } else
    81.     {
    82.         MyProc = KeGetCurrentProcessorNumber();
    83.  
    84.         for (Num = 0; Num < KeNumberProcessors; Num++)
    85.         {
    86.             if (!NoSelfCall || Num != MyProc) CallToProcessor(Num, Proc, Param, Syncronous);
    87.         }
    88.     }      
    89. }
    90.  
    91. void GetInt(
    92.         IN OUT INTERRUPT *Interrupt
    93.         )
    94. {
    95.     IDTR      Idt;
    96.     PINTDESC  IntGate;
    97.  
    98.     __asm sidt[Idt];
    99.  
    100.     IntGate = &((PINTDESC)Idt.Base)[Interrupt->IntNum];
    101.    
    102.     Interrupt->Handler  = (PVOID)((IntGate->OffsetHi << 16) | IntGate->OffsetLo);
    103.     Interrupt->Selector = IntGate->Selector;
    104.     Interrupt->Access   = IntGate->Access;
    105. }
    106.  
    107. void SetInt(
    108.         IN INTERRUPT *Interrupt
    109.         )
    110. {
    111.     IDTR      Idt;
    112.     PINTDESC  IntGate;
    113.  
    114.     __asm cli;
    115.     __asm sidt[Idt];
    116.  
    117.     IntGate = &((PINTDESC)Idt.Base)[Interrupt->IntNum];
    118.  
    119.     IntGate->OffsetHi = (USHORT)((ULONG)Interrupt->Handler >> 16);
    120.     IntGate->OffsetLo = (USHORT)Interrupt->Handler;
    121.     IntGate->Selector = Interrupt->Selector;
    122.     IntGate->Access   = Interrupt->Access;
    123.  
    124.     __asm sti;
    125. }
    126.  
    127. void GetInterrupt(
    128.           IN  UCHAR      IntNum,
    129.           OUT INTERRUPT *Interrupt
    130.           )
    131. {
    132.     KIRQL OldIrql = KeRaiseIrqlToDpcLevel();
    133.  
    134.     Interrupt->IntNum = IntNum;
    135.  
    136.     GetInt(Interrupt);
    137.  
    138.     KeLowerIrql(OldIrql);  
    139. }
    140.  
    141.  
    142. void GetInterruptEx(
    143.           IN  CCHAR      Cpu,
    144.           IN  UCHAR      IntNum,
    145.           OUT INTERRUPT *Interrupt
    146.           )
    147. {
    148.     Interrupt->IntNum = IntNum;
    149.    
    150.     CallToProcessor(Cpu, GetInt, Interrupt, TRUE);
    151. }
    152.  
    153.  
    154. void SetInterruptEx(
    155.           IN  CCHAR      Cpu,
    156.           IN  PINTERRUPT Interrupt
    157.           )
    158. {  
    159.     CallToProcessor(Cpu, SetInt, Interrupt, TRUE);
    160. }
    161.  
    162.  
    163. void SetInterrupt(
    164.           IN  PINTERRUPT Interrupt
    165.           )
    166. {  
    167.     CallToAllProcessors(SetInt, Interrupt, FALSE, TRUE);
    168. }
    169.  
    170. UCHAR GetFreeInterrupt()
    171. {
    172.     KIRQL     OldIrql = KeRaiseIrqlToDpcLevel();
    173.     IDTR      Idt;
    174.     PINTDESC  IntGate;
    175.     USHORT    IntNum;
    176.     UCHAR     Result = 0;
    177.  
    178.     __asm sidt[Idt];
    179.  
    180.     for (IntNum = 0; IntNum <= Idt.Limit / sizeof(INTDESC); IntNum++)
    181.     {
    182.         IntGate = &((PINTDESC)Idt.Base)[IntNum];
    183.  
    184.         if (!(IntGate->Access & ACC_PRESENT))
    185.         {
    186.             Result = (UCHAR)IntNum;
    187.             break;
    188.         }          
    189.     }  
    190.  
    191.     KeLowerIrql(OldIrql);      
    192.    
    193.     return Result;
    194. }
    195.  
    196. BOOLEAN AddInterrupt(
    197.              IN OUT INTERRUPT *Interrupt
    198.              )
    199. {
    200.     Interrupt->IntNum = GetFreeInterrupt();
    201.  
    202.     if (Interrupt->IntNum) SetInterrupt(Interrupt);
    203.  
    204.     return Interrupt->IntNum;
    205. }
    Код (Text):
    1. #define ACC_PRESENT    0x80 // ñåãìåíò åñòü â ïàìÿòè
    2. #define ACC_CSEG       0x18 // ñåãìåíò êîäà
    3. #define ACC_DSEG       0x10 // ñåãìåíò äàííûõ
    4. #define ACC_EXPDOWN    0x04 // ñåãìåíò ðàñøèðÿåòñÿ âíèç
    5. #define ACC_CONFORM    0x04 // ñîãëàñîâàííûé ñåãìåíò
    6. #define ACC_DATAWR     0x02 // ðàçðåøåíà çàïèñü
    7. #define ACC_INT_GATE   0x06 // âåíòèëü ïðåðûâàíèÿ
    8. #define ACC_TRAP_GATE  0x07 // âåíòèëü èñêëþ÷åíèÿ
    9. #define ACC_CALL_GATE  0x0C // øëþç âûçîâà
    10. #define ACC_32BIT      0x08 // 32 áèòíûé äåñêðèïòîð  
    11.  
    12. #define DPL_0 0x00
    13. #define DPL_1 0x20
    14. #define DPL_2 0x40
    15. #define DPL_3 0x60
    16.  
    17. #define DATA_ACC  ACC_PRESENT | ACC_DSEG | ACC_DATAWR               // ñåãìåíò äàííûõ
    18. #define CODE_ACC  ACC_PRESENT | ACC_CSEG | ACC_CONFORM              // ñåãìåíò êîäà
    19. #define STACK_ACC ACC_PRESENT | ACC_DSEG | ACC_DATAWR | ACC_EXPDOWN // ñåãìåíò ñòåêà
    20.  
    21. #define IDT_ACC   DATA_ACC                    // áàéò äîñòóïà ñåãìåíòà òàáëèöû IDT
    22. #define INT_ACC   ACC_PRESENT | ACC_INT_GATE  | ACC_32BIT // áàéò äîñòóïà âåíòèëÿ ïðåðûâàíèÿ
    23. #define GATE_ACC  ACC_PRESENT | ACC_CALL_GATE | ACC_32BIT // áàéò äîñòóïà øëþçà âûçîâà
    24. #define TRAP_ACC  ACC_PRESENT | ACC_TRAP_GATE | ACC_32BIT // áàéò äîñòóïà âåíòèëÿ èñêëþ÷åíèÿ
    25.  
    26. #pragma pack(push, 1)
    27.  
    28. typedef struct _INTDESC
    29. {
    30.     USHORT OffsetLo;
    31.     USHORT Selector;
    32.     UCHAR  Unused;
    33.     UCHAR  Access;
    34.     USHORT OffsetHi;
    35. } INTDESC, *PINTDESC;
    36.  
    37. typedef struct _GATEDESC
    38. {
    39.     USHORT OffsetLo;
    40.     USHORT Selector;
    41.     UCHAR  Unused;
    42.     UCHAR  Access;
    43.     USHORT OffsetHi;
    44. } GATEDESC, *PGATEDESC;
    45.  
    46. typedef struct _GDTR
    47. {
    48.     USHORT Limit;
    49.     ULONG  Base;
    50. } GDTR, *PGDTR;
    51.  
    52.  
    53. typedef struct _INTERRUPT
    54. {
    55.     UCHAR  IntNum;
    56.     PVOID  Handler;
    57.     USHORT Selector;
    58.     UCHAR  Access;
    59. } INTERRUPT, *PINTERRUPT;
    С его помощью добавление прерывания - тривиальное дело, и выгляди так:
    Код (Text):
    1.     IntGate.Access   = INT_ACC | DPL_3;
    2.     IntGate.Handler  = SystemService;
    3.     IntGate.Selector = 0x08;
    4.  
    5.     Result = AddInterrupt(&IntGate);
    Вот мой вариант обработчика системных вызовов (найди три ошибки)
    Код (Text):
    1. _declspec(naked) SystemService()
    2. {
    3.     __asm
    4.     {
    5.         push fs
    6.         push 0x30
    7.         pop  fs
    8.         sti
    9.         cmp  eax, MAX_SYSCALL
    10.         jnb  __exit
    11.         cmp  edx, MmUserProbeAddress
    12.         jnb  __exit  
    13.         push __handler
    14.         push dword ptr fs:[0]
    15.         mov  dword ptr fs:[0], esp
    16.         movzx  ecx, ArgumentTable[eax]
    17.         lea  edx, [edx + ecx * 4 - 4]
    18.     __next:
    19.         jecxz __call
    20.         push [edx]
    21.         sub  edx, 0x04
    22.         dec  ecx
    23.         jmp  __next
    24.     __call:
    25.         call ServiceTable[eax * 4]
    26.         jmp  __unseh
    27.     __handler:
    28.         mov  eax, [esp + 0x0C]
    29.         mov  ecx, [esp + 0x08]
    30.         mov  ebx, __unseh
    31.         mov  [eax + 0xB8], ebx
    32.         mov  ebx, 0xC0000005
    33.         mov  [eax + 0xB0], ebx
    34.         mov  [eax + 0xC4], ecx
    35.         xor  eax, eax
    36.         ret
    37.     __unseh:
    38.         pop  dword ptr fs:[0]
    39.         add  esp, 4
    40.     __exit:
    41.         pop  fs
    42.         iretd
    43.     }
    44. }
    Надеюсь что этот код поможет, но сомневаюсь (сильно долго вы мучаетесь с примитивных мобавлением прерывания, без учета SMP и прочих гадостей).
     
  13. drmist

    drmist New Member

    Публикаций:
    0
    Регистрация:
    31 май 2005
    Сообщения:
    112
    Большое спасибо.
    Значицо я не указал Selector и Access.

    --добавлено--
    В аттаче утилита-пример, которая делает то, что мне хотелось (сурсы+бинарник).
    Работает при условии, что в машине один процессор и int 55h никем не занят.
    Использование:
    load
    hook
    int55
    unhook
    unload
    exit

    Предварительно не зыбываем включить DbgView.