Показать сообщение отдельно

  #3  
Старый 07.03.2009, 16:38
0x0c0de
Постоянный
Регистрация: 25.05.2007
Сообщений: 448
Провел на форуме:
4226446

Репутация: 1564
Отправить сообщение для 0x0c0de с помощью ICQ
По умолчанию

В случае, если по прерыванию прошлись по F7 в ольге то в eax положим -4, если все ок, то 4. А значит, в юзермоде эта проверка

Код:
.text:004013A1                 add     eax, 0FFFFFFFCh // + (-4)
.text:004013A4                 jz      short loc_4013AA
.text:004013A6
.text:004013A6 loc_4013A6:                             ; CODE XREF: int_call2+A j
.text:004013A6                 push    0FFFFFFFFh // переполнение стека
.text:004013A8                 jmp     short loc_4013A6
приобрела много больше смысла. 4-4 = 0 и нас не трассирут. -4-4!=0 => нас трассируют. Окей. Двигаемся дальше

Код:
.text:004013E8 loc_4013E8:                             ; CODE XREF: sub_4013AB+24 j
.text:004013E8                 and     eax, 0
.text:004013EB                 mov     ax, fs
.text:004013EE                 mov     [ebp+var_4], eax
.text:004013F1                 call    int_call2
.text:004013F1 sub_4013AB      endp
.text:004013F1
.text:004013F6 ; ---------------------------------------------------------------------------
.text:004013F6                 push    edi
.text:004013F7                 lea     eax, [ebp-10h]
.text:004013FA                 push    eax
.text:004013FB                 push    0Ch
.text:004013FD                 push    offset dword_40CCB4
.text:00401402                 push    4
.text:00401404                 lea     eax, [ebp-4]
.text:00401407                 push    eax
.text:00401408                 push    222004h
.text:0040140D                 push    hDevice
.text:00401413                 call    ds:DeviceIoControl
.text:00401419                 test    eax, eax
.text:0040141B                 jz      loc_4014FE
.text:00401421                 call    int_call2
.text:00401426 ; ---------------------------------------------------------------------------
.text:00401426                 call    int_call2 // проверка на трассировку
.text:0040142B ; ---------------------------------------------------------------------------
.text:0040142B                 push    offset loc_40135D
.text:00401430                 mov     eax, dword_40CCB4
.text:00401435                 push    dword ptr [eax]
.text:00401437                 mov     [eax], esp
.text:00401439                 ud2

Всматриваемся в код внимательно и видим, что в драйвер передается содержание сегментного регистра fs. Окей. Ну тогда снова в драйвер. В процедуру обработки ioctl запросов. На этот раз запрос 222004h. Вычитаем как обычно 222004h. Получаем нулевой кейз. Ай-да его ковырять. Всякие проверки, имеющие отношение только к стабильности я опускаю. Перейдем сразу к делу.

Код:
.text:00011728                 sgdt    fword ptr gdtr__ // опять? )))))))
.text:0001172F                 mov     eax, [esi]
.text:00011731                 lea     edx, [esp+20h+var_8]
.text:00011735                 push    edx
.text:00011736                 push    eax
.text:00011737                 push    offset gdtr__
.text:0001173C                 call    sub_11200
Зайдем в sub_11200. Судя по всему этой процедуре зачем-то нужна gdt.

Код:
.text:00011200 GetFsBase       proc near               ; CODE XREF: DeviceControlRoutine+18C p
.text:00011200
.text:00011200 arg_0           = dword ptr  4
.text:00011200 selector        = dword ptr  8
.text:00011200 arg_8           = dword ptr  0Ch
.text:00011200
.text:00011200                 mov     ecx, [esp+arg_0]
.text:00011204                 mov     eax, [esp+selector]
.text:00011208                 mov     edx, [ecx+2]
.text:0001120B                 push    esi
.text:0001120C                 shr     eax, 3
.text:0001120F                 lea     esi, [edx+eax*8]
.text:00011212                 push    esi             ; VirtualAddress
.text:00011213                 call    ds:MmIsAddressValid
.text:00011219                 test    al, al
.text:0001121B                 jnz     short valid
.text:0001121D                 xor     eax, eax
.text:0001121F                 pop     esi
.text:00011220                 retn    0Ch
.text:00011223 ; ---------------------------------------------------------------------------
.text:00011223
.text:00011223 valid:                                  ; CODE XREF: GetFsBase+1B j
.text:00011223                 mov     eax, [esp+4+arg_8]
.text:00011227                 mov     ecx, [esi]
.text:00011229                 mov     [eax], ecx
.text:0001122B                 mov     edx, [esi+4]
.text:0001122E                 xor     ecx, ecx
.text:00011230                 mov     [eax+4], edx
.text:00011233                 mov     ch, [eax+7]
.text:00011236                 pop     esi
.text:00011237                 mov     cl, dl
.text:00011239                 movzx   edx, word ptr [eax+2]
.text:0001123D                 shl     ecx, 10h
.text:00011240                 or      ecx, edx
.text:00011242                 mov     eax, ecx
.text:00011244                 retn    0Ch
.text:00011244 GetFsBase       endp

Объясняю суть того, что здесь происходит. Как мы помним, передан был селектор на дескриптор. Я уже написала как по селектору высчитать индекс в дескрипторной таблице.
Ну так вот. Сначала получаем указатель на сам дескриптор, а потом копируем его содержимое.

Код:
.text:0001173C                 call    GetFsBase
.text:00011741                 add     [esp+20h+var_6], 0F000h
.text:00011748                 add     [esp+20h+var_8], 3E8h
.text:0001174F                 lea     ecx, [esp+20h+var_8]
.text:00011753                 push    ecx
.text:00011754                 mov     edi, eax
.text:00011756                 call    AddDescriptorIntoGdt
.text:0001175B                 cmp     eax, ebx
.text:0001175D                 jnz     short all_good_
.text:0001175F                 mov     ebp, [esp+20h+var_10]
.text:00011763                 mov     ebx, STATUS_UNSUCCESSFUL
.text:00011768                 jmp     short loc_11791
.text:0001176A ; ---------------------------------------------------------------------------
.text:0001176A
.text:0001176A all_good_:                              ; CODE XREF: DeviceControlRoutine+1AD j
.text:0001176A                 mov     uFsDescr, eax
.text:0001176F                 mov     [esi+4], eax
.text:00011772                 mov     [esi], edi
.text:00011774                 mov     ebp, 8
.text:00011779                 call    CheckIdtHook // снова проверка на хуки в итд, это все будет иметь смысл при генерации ключа
.text:0001177E                 neg     eax
.text:00011780                 sbb     eax, eax
.text:00011782                 and     eax, DBG_TERMINATE_THREAD
.text:00011787                 mov     [esi+8], eax
.text:0001178A                 jmp     short loc_11791
.text:0001178C ; --------------------------------------------------
Значит скопировали дескриптор, на который указывает селектор в fs. Потом мы его редактируем, а именно новая база нового сегмента будет на 0x1000 меньше. Окей, потом пересчитываем лимит (причем я пересчитываю его не точно, но реально это не имеет значения, так как нужный диапазон это с лихвой покрывает). Скажу тут сразу, что селектор на новый дескриптор будет использован мной для установки seh обработчиков через gs. Так же как и база старого fs. Так что подробно уже на этом не останавливаюсь. Покажу как это в юзермоде

Код:
0040142B   68 5D134000      PUSH reversem.0040135D
00401430   A1 B4CC4000      MOV EAX,DWORD PTR DS:[40CCB4]
00401435   FF30             PUSH DWORD PTR DS:[EAX]
00401437   8920             MOV DWORD PTR DS:[EAX],ESP
00401439   0F0B             UD2
0040143B   66:8EE8          MOV GS,AX                                ; Modification of segment register
0040143E   59               POP ECX
0040143F   59               POP ECX
00401440   68 DD124000      PUSH reversem.004012DD
00401445   65:FF35 00100000 PUSH DWORD PTR GS:[1000] 
0040144C   65:8925 00100000 MOV DWORD PTR GS:[1000],ESP
00401453   0F0B             UD2
Видите? Сначала устанавливается обработчик по имеющейся базе. Вот его код

Код:
.text:0040135D loc_40135D:                             ; DATA XREF: .text:0040142B o
.text:0040135D                 mov     ecx, [esp+0Ch]
.text:00401361                 lea     eax, [ecx+0B8h]
.text:00401367                 add     dword ptr [eax], 2 // модификация адреса возврата из seh
.text:0040136A                 mov     edx, [eax]
.text:0040136C                 push    esi
.text:0040136D                 mov     esi, dwCount // а вот тут мы при возврате из seh добавляем еще наш счетчик между int 2a в начале 
.text:00401373                 add     edx, esi
.text:00401375                 mov     [eax], edx
.text:00401377                 mov     eax, dword_40CCB8
.text:0040137C                 mov     [ecx+0B0h], eax
.text:00401382                 xor     eax, eax
.text:00401384                 pop     esi
.text:00401385                 retn    10h
Этот обработчик не делает ничего интересного, кроме как неявно проверяет счетчки между вызовами KiGetTickCount и кладет в ax селектор на новый созданный дескриптор. Окей! Разобрались. Двигаемся дальше. Второй обработчик

Код:
.text:004012DD ; int __cdecl SEH2Handler(DWORD NumberOfBytesWritten, int, int)
.text:004012DD SEH2Handler     proc near
.text:004012DD
.text:004012DD NumberOfBytesWritten= dword ptr  8
.text:004012DD arg_8           = dword ptr  10h
.text:004012DD
.text:004012DD                 push    ebp
.text:004012DE                 mov     ebp, esp
.text:004012E0                 mov     eax, [ebp+NumberOfBytesWritten]
.text:004012E3                 mov     eax, [eax]
.text:004012E5                 cmp     eax, EXCEPTION_BREAKPOINT
.text:004012EA                 jz      short loc_401329
.text:004012EC                 cmp     eax, EXCEPTION_ILLEGAL_INSTRUCTION
.text:004012F1                 jnz     short loc_401342
.text:004012F3                 push    0               ; lpOverlapped
.text:004012F5                 lea     eax, [ebp+NumberOfBytesWritten]
.text:004012F8                 push    eax             ; lpNumberOfBytesWritten
.text:004012F9                 push    nNumberOfBytesToWrite ; nNumberOfBytesToWrite
.text:004012FF                 push    offset byte_40CC70 ; lpBuffer
.text:00401304                 push    hDevice         ; hFile
.text:0040130A                 call    ds:WriteFile
.text:00401310                 push    0               ; lpOverlapped
.text:00401312                 push    offset NumberOfBytesRead ; lpNumberOfBytesRead
.text:00401317                 push    0               ; nNumberOfBytesToRead
.text:00401319                 push    0               ; lpBuffer
.text:0040131B                 push    hDevice         ; hFile
.text:00401321                 call    ds:ReadFile
.text:00401327                 jmp     short loc_401342
.text:00401329 ; ---------------------------------------------------------------------------
…
…
…

.text:0040135C SEH2Handler     endp
Итак, инструкция ud2 спровоцирует EXCEPTION_ILLEGAL_INSTRUCTION => Начинается процесс обращения к драйверу через ReadFile/WriteFile. Скажу сразу, что тут только калькуляция серийного номера. WriteFile считает серийник, ReadFile заканчивает калькуляцию вот так

Код:
.text:000117E0 ReadHandler:                            ; DATA XREF: DllEntryPoint+6A o
.text:000117E0                 mov     eax, [esp+8]
.text:000117E4                 xor     serialnumb, 33223322h
.text:000117EE                 push    0
.text:000117F0                 push    0
.text:000117F2                 push    eax
.text:000117F3                 call    CompleteIrp
.text:000117F8                 retn    8
Переменная serialnumb сохранена в драйвере и будет использоваться при заключительной проверке. WriteHandler я оставляю интересующимся.

Отлично, мы отработали в seh – хендлере. Теперь

Код:
.text:00401342 return:                                 ; CODE XREF: SEH2Handler+14 j
.text:00401342                                         ; SEH2Handler+4A j
.text:00401342                 mov     eax, [ebp+arg_8]
.text:00401345                 add     eax, 0B8h
.text:0040134A                 add     dword ptr [eax], 2 // eip+2
.text:0040134D                 mov     ecx, [eax]
.text:0040134F                 mov     edx, dwCount // снова учет времени между int 0x2a
.text:00401355                 add     ecx, edx
.text:00401357                 mov     [eax], ecx
.text:00401359                 xor     eax, eax
.text:0040135B                 pop     ebp
.text:0040135C                 retn
.text:0040135C SEH2Handler     endp
Возврат из хендлера.

Код:
.text:0040145A                 push    edi
.text:0040145B                 lea     eax, [ebp-0Ch]
.text:0040145E                 push    eax
.text:0040145F                 push    3EAh
.text:00401464                 push    dword_40CCCC
.text:0040146A                 call    ds:GetDlgItemInt // серийник- число онли!
.text:00401470                 cmp     [ebp-0Ch], edi
.text:00401473                 mov     [ebp-14h], eax
.text:00401476                 jz      short loc_4014B1
.text:00401478                 mov     eax, NtstatusSave // а вот и наш NtStatus, о котором я говорила в самом начале
.text:0040147D                 mov     ecx, dword_40CCBC
.text:00401483                 add     ecx, eax
.text:00401485                 add     [ebp-14h], ecx
.text:00401488                 pusha
.text:00401489                 mov     eax, [ebp-14h] // eax - серийник
.text:0040148C                 mov     edi, 'last' // окей, снова в прерывание
.text:00401491                 call    int_call2
.text:00401496 ; ---------------------------------------------------------------------------
.text:00401496                 sub     esi, 0 // серийник верный, в esi адрес перехода?
.text:00401499                 jz      short loc_4014A5
.text:0040149B                 push    esi
.text:0040149C                 pop     edi
.text:0040149D                 add     edi, dword_40CCEC
.text:004014A3                 call    edi 
.text:004014A5
.text:004014A5 loc_4014A5:                             ; CODE XREF: .text:00401499 j
Обратите внимание, что серийник, введенный юзером, считается с учетом наличия отладчика. И если вы решили пойти по пути отладки и были невнимательны, даже в случае нахождения верного ключа - аплодесментов не получите ). Ага, снова отправляемся в наше прерывание и смотрим что будет, если edi == ‘last’.

Код:
.text:000113E0 InterruptHandler proc near              ; DATA XREF: DeviceControlRoutine+CD o
.text:000113E0                                         ; DeviceControlRoutine+D6 o
.text:000113E0
.text:000113E0 arg_4           = dword ptr  8
.text:000113E0
.text:000113E0                 cmp     edi, 'bran'
.text:000113E6                 jz      short msrset
.text:000113E8                 cmp     edi, 'sele'
.text:000113EE                 jz      short secondcheck
.text:000113F0                 cmp     edi, 'last'
.text:000113F6                 jnz     short check_tf
.text:000113F8                 mov     edi, serialnumb // вот серийник, сохраненный в дрове
.text:000113FE                 xor     eax, edi // ксорим что в eax [значение введенное юзером в поле серийника + учет отладки] 
.text:00011400                 mov     ebx, eax
.text:00011402                 mov     edi, 'sele' // прерывание готовится вернутся снова на нструкцию int xx и вызвать прерывание снова
.text:00011407                 mov     eax, [esp+0]
.text:0001140A                 sub     eax, 2 // eip_ret - 2
.text:0001140D                 mov     [esp+0], eax
.text:00011410                 jmp     short intreturn
.text:00011412 ; ---------------------------------------------------------------------------
.text:00011412
.text:00011412 check_tf:                               ; CODE XREF: InterruptHandler+16 j
.text:00011412                 mov     eax, [esp+arg_4]
.text:00011416                 bt      eax, 8
.text:0001141A                 jnb     short not_tf
.text:0001141C                 mov     eax, 0FFFFFFFCh
.text:00011421                 jmp     short intreturn
.text:00011423 ; ---------------------------------------------------------------------------
.text:00011423
.text:00011423 secondcheck:                            ; CODE XREF: InterruptHandler+E j
.text:00011423                 cmp     ebx, 0 // результат ксора
.text:00011426                 jnz     short not_valid_serial
.text:00011428                 mov     esi, 4010F1h // если валид сериал.
.text:0001142D                 mov     eax, [esp+0]
.text:00011430                 sub     eax, 2
.text:00011433                 mov     [esp+0], eax
.text:00011436                 sub     edi, edi
.text:00011438                 jmp     short intreturn
.text:0001143A ; ---------------------------------------------------------------------------
.text:0001143A
.text:0001143A not_valid_serial:                       ; CODE XREF: InterruptHandler+46 j
.text:0001143A                 mov     esi, 0
.text:0001143F                 mov     eax, [esp+0]
.text:00011442                 sub     eax, 2
.text:00011445                 mov     [esp+0], eax
.text:00011448                 sub     edi, edi
.text:0001144A                 jmp     short intreturn
.text:0001144C ; ---------------------------------------------------------------------------
.text:0001144C
.text:0001144C not_tf:                                 ; CODE XREF: InterruptHandler+3A j
.text:0001144C                 mov     eax, 4
.text:00011451                 jmp     short intreturn
.text:00011453 ; ---------------------------------------------------------------------------
.text:00011453
.text:00011453 msrset:                                 ; CODE XREF: InterruptHandler+6 j
.text:00011453                 mov     ecx, 1D9h
.text:00011458                 rdmsr
.text:0001145A                 or      eax, 3
.text:0001145D                 wrmsr
.text:0001145F
.text:0001145F intreturn:                              ; CODE XREF: InterruptHandler+30 j
.text:0001145F                                         ; InterruptHandler+41 j ...
.text:0001145F                 iret
.text:0001145F InterruptHandler endp
А вот тут уже надо быть еще внимательней. Хендлер прерывания, получая 'last' в edi, ксорит серийник из юзермода с вычисленным значением в дрове, затем изменяет eip (то место, куда по идее надо бы вернуться после iret) и кладет в edi 'sele' . И возврат снова на инструкцию прерывания. Но в edi будет уже 'sele' и если разница между верным серийником и тем, что введено пользователем 0, то в esi кладется адрес 4010F1h.

Usermode part

Код:
.text:00401496                 sub     esi, 0
.text:00401499                 jz      short loc_4014A5
.text:0040149B                 push    esi
.text:0040149C                 pop     edi
.text:0040149D                 add     edi, dword_40CCEC
.text:004014A3                 call    edi
Если серийник верный, то мы перейдем по адресу 4010F1h. Что там?

Код:
.text:004010F1 loc_4010F1:                             ; DATA XREF: sub_401630+8 o
.text:004010F1                 int     3               ; Trap to Debugger
.text:004010F2                 nop
.text:004010F3                 retn
И все =) Однако, вспомним, что у нас до сих пор установлен обработчик исключений SEH2Handler. И там была проверка на эксепшн EXCEPTION_BREAKPOINT.

Код:
]
text:004012E5                 cmp     eax, EXCEPTION_BREAKPOINT
.text:004012EA                 jz      short loc_401329
…
…
…

.text:00401329 loc_401329:                             ; CODE XREF: SEH2Handler+D j
.text:00401329                 push    40004h          ; fdwSound
.text:0040132E                 push    0               ; lpModuleName
.text:00401330                 call    ds:GetModuleHandleW
.text:00401336                 push    eax             ; hmod
.text:00401337                 push    83h             ; pszSound
.text:0040133C                 call    ds:PlaySoundW
.text:00401342
.text:00401342 return:                                 ; CODE XREF: SEH2Handler+14 j
И))))) Если серийник верный, хендлер прерывания возвращает в esi адрес перехода, мы переходим по нему в юзермоде, по этому адресу int 3 == EXCEPTION_BREAKPOINT и мы слышим аплодисменты. Вот таки дела.

Я не объяснила ВСЕ. Но тем, кто пробовал, пускай даже не отписался, этого будет достаточно, чтобы понять что к чему. Надеюсь, эта моя работа будет для кого-то познавательной. Тогда я не зря потратила время.



На этом пока прощаюсь, удачи!

Последний раз редактировалось 0x0c0de; 07.03.2009 в 22:59..
 
Ответить с цитированием