▄▄ █ ▀▀▀ Virus Magazine █ Box 10, Kiev 148, Ukraine IV 1996 ▀██ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ █ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀ ▀ ▀▀▀▀▐▀▀▀ █▀▀▀▀▀▀▀█ ▐█ █▀▄ █▀▀ ▄▀▀ ▄▀▀ ▄█▄ ▄▀▀ █▀█ ▌ █ ▄▀█ █ ▄▀▀ █▄▄ █ █ █▀█ █ █ █ █ █▀ █▀ █ █ █▀ █ █ █ █ █ █ █ █ █ █ █ █ █ █ █ ▐ ▐ ▐ ▐▄▄ ▐▄▄ ▐ ▐▄▄ ▐▄▀ ▀█ ▀▄█ ▐ ▐▄▄ ▐▄▄▄ █ █ █▄█ █ ▐ ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄ █▄▄▄▄▄▄▄█ (C) Copyright, 1994-96, by STEALTH group WorldWide, unLtd. ============================================================================= ╔═════════════════════════════════════════════════════╗ ║ ОПРЕДЕЛЕНИЕ ТИПА ПРОЦЕССОРА ║ ║ ░░░░░░░░░░░░░░░ by MrStrange ░░░░░░░░░░░░░░░ ║ ╚═════════════════════════════════════════════════════╝ Часто встречаются случаи, когда программе необходимо знать тип процессора, под которым она работает. Процессор 80286 имеет много полезных комманд, которых нет у 8086, они могли бы значительно укоротить ваш вирус. Процессор 386 имеет отладочные регистры, которые также можно использовать for best results. Про отладочные регистры читайте в IV5, файл iv_5.03b. Там же написано, что для того, чтобы распознать процессор 80386 достаточно перехватить прерывание 6 (INVALID OPCODE) и выполнить любую комманду, которой нет у 286 (что-нибудь, использующее 32-битные регистры, например). Если при этом выполнится прерывание INVALID OPCODE, значит процессор ниже 386-го. Однако такой метод не совсем корректен. Дело в том, что прерывание 6 при попытке исполнения незнакомой комманды возникает только в компьютерах с процессорами 286 и выше. Что происходит с 8086 и 80186 я не знаю. Я испытывал использование 6-го прерывания на одной машине XT, там программа просто завершилась на инстукции push 1, 6-е прерывание молчало. Все-таки я хотел бы, чтобы кто-нибудь просветил меня относительно реакции 8086 и 80186 на незнакомую инструкцию. Для того, чтобы определить тип процессора, достаточно знать, что его отличает от предшественников. Чем отличается 186 и любой другой старший процессор от 8086? У всех 80x86 есть инструкция shr XX,cl (XX - любой регистр), которая сдвигает содержимое регистра XX на cl бит вправо (в двоичном представлении, естественно. Например, cl = 5, ax = 37 = 100101b => после shr ax,cl ax = 1). Однако 8086 сдвигает ТОЧНО на cl бит, а 80186 и выше - на cl mod 20h. Например, cl = 21h, ax = 0ffffh = 1111 1111 1111 1111b. Для 8086 после shr ax,cl в ax будет 0, 80186+ сдвинет лишь на 1 бит и AX = 7fffh. Далее, интересна инструкция push sp. 8086 и 80186 сначала модифицируют содержание sp, затем помещают его в стек. Процессоры 80286+ делают все наоборот. Таким образом, в результате выполнения: push sp pop ax на процессорах 8086 и 80186 ax==sp-2, а на 80286+ ax==sp. Теперь уже, если мы точно выяснили, что у нас процессор 286 или выше, можно использовать прерывание 6. Для этого нужно знать инструкции, которые есть у старшего процессора и которых нет у младшего. Для определения "тройки" можно использовать любую комманду, которая оперирует с 32-разрядными регистрами. У "четверки" появилась комманда xadd (== add + xchg), которой нет у "тройки". Про Pentium я знаю лишь то, что ничего не знаю... Хотя известно, что программно невозможно определить наличие у Pentium конвейера. Это я и использую в своей программе для определения Pentium. В результате выполнения последовательности: mov cs:change_me,0 db 0b9h ; 0b9h - код mov cx,const change_me dw 1 на любом процессоре 80x86 в cx будет помещено 1. При выполнении этой же последовательности на Pentium cx == 0. Если кто-нибудь имеет информацию про конвейер Pentium прошу сообщить мне (письма отправлять на адрес клуба, пометить "для MrStrange"). Меня интересует, как отслеживает Pentium такие изменения в памяти. Я думаю, что он действительно следит за этим, так как конвейер физически все-таки на P5 имеется. В приведенной ниже программе имеется функция cpu, которая не требует параметров при вызове и возвращает: ax = 0 для 8086/8088 ax = 1 для 80186 ax = 2 для 80286 eax = ax = 3 для 80386 eax = ax = 4 для i486 eax = ax = 5 для Pentium ════════════════════════════════════════════════════════════════════════════ .model tiny .code org 100h .8086 start: jmp begin cpu proc near push cx dx bx es ds push cs pop ds mov ax,0ffffh mov cl,21h shr ax,cl ; Для 8086 ax == 0, для 80186 и выше - 7fffh xchg ax,cx jcxz this_is_8086 push sp pop ax cmp ax,sp ; для 286 ax == sp, но не для 186 jne this_is_186 ; Проверим на Pentium mov change_me,0 db 0b9h ; 0b9h - код mov cx,непосредственное_значение change_me dw 1 jcxz this_is_pentium ; Если мы все еще тут, то процессор - 286, 386 или 486. ; Установим обработчик 6-го прерывания на себя mov ax,3506h int 21h push es push bx mov ax,2506h mov dx,offset myInt1 int 21h mov ax,2 .386 ; Выполняем инструкцию процессора 386 xor eax,eax ; Можем позволить себе обнулить eax mov ax,3 .486 xadd eax,edx ; Эта инструкция работает только на 486 и выше mov eax,4 ; four eighty six .8086 now_we_know_cpu: pop dx pop ds push ax mov ax,2506h int 21h ; Восстановили старый вектор 6 pop ax jmp exit_cpu this_is_pentium: .386 mov eax,5 .8086 jmp exit_cpu this_is_186: mov ax,1 jmp exit_cpu this_is_8086: xor ax,ax exit_cpu: pop ds es bx dx cx retn cpu endp myInt1 proc pop cx mov cx,offset now_we_know_cpu push cx iret ; Вернулись на метку now_we_know_cpu myInt1 endp ; Демонстрация работы функции cpu. Там дальше everything is ; clear, so I didn't insert any comment. firstMessage db "Detect CPU type, Copyright (c) by MrStrange." db " The show must go on!" db 13,10,10,"You've got ",'$' _8086 db "8086/8088",'$' _186 db "80186",'$' _286 db "80286",'$' _386 db "80386",'$' _486 db "i486",'$' _pent db "Pentium",'$' message dw offset _8086, offset _186, offset _286, offset _386 dw offset _486, offset _pent begin: mov ah,9 mov dx,offset firstMessage int 21h call cpu shl ax,1 xchg ax,si mov dx,message[si] mov ah,9 int 21h int 20h end start ════════════════════════════════════════════════════════════════════════════ Компилировать лучше в 2 прохода (tasm filename /m2). Эта программа не испытывалась на Pentium и 80186. Handle with care. Кстати, если вам известна какая-нибудь комманда процессора Pentium, которой нет у i486, вы самостоятельно можете несколько укоротить функцию cpu, подогнав распознование P5 под общую схему -> шуточку с конвейером убрать, а после строчек: xadd eax,edx mov eax,4 дописать: Any_Unique_P5_command mov eax,5 Последнюю строчку можно заменить на inc ax, если, конечно, Any_Unique_P5_command не изменяет содержимое eax. Естественно, если необходимо получить не конкретный тип процессора, а лишь информацию типа: процессор 80x86 or higher, было бы лишним включать в свою программу всю процедуру cpu (она занимает около 100 байт). Если нужно провести проверку наличия процессора 186 или выше в программу можно вставить следующие строки: mov ax,0ffffh mov cl,21h shr ax,cl or ax,ax jz error_this_is_8086 this_is_80186_or_higher: ; ... Этот код занимает 11 байт Для проверки наличия 80286 вставте в программу: push sp pop ax cmp ax,sp jne error_this_is_80186_or_lower this_is_80286_or_higher: ;... Этот код занимает 6 байт Для проверки на наличие процессора 386 или лучшего можно использовать одну особенность регистра флагов. Как известно, регистр флажков процессоров 8086 и 80186 имеет следующие поля: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 ┌──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┐ │XX│XX│XX│XX│OF│DF│IF│TF│SF│ZF│XX│AF│XX│PF│XX│CF│ └──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┘ Состояния битов 12-15 в неопределены. Однако комманда pushf запоминает в стеке на месте битов 12-15 единицы (т.е. после выполнения: pushf pop ax, старшие четыре бита ax будут единицами, ax == 1111 ???? ???? ????b). В процессоре 80286 и старше формат регистра flags такой: 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 ┌──┬──┬─────┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┐ │00│NT│IO PL│OF│DF│IF│TF│SF│ZF│00│AF│00│PF│01│CF│ └──┴──┴─────┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┘ NT nested task - вложенная задача IO PL input/output privelege level - уровень привилегий в/в Флажки 12-14 не имеют никакого смысла в реальном режиме работы процессора. Процессор 80286 не дает возможности менять их. Они всегда сброшены в 0. В процессоры 80386+ флаги 12-14 установлены в соответствии с теми значениями, которые были туда занесены последними. Состояния этих флажков никак не влияет на работу процессора в R-режиме. Таким образом, для определения процессора 80386+ достаточно вставить в свою программу такие строки: mov ax,1000h push ax popf pushf pop ax and ax,0f000h cmp ax,01000h jne error_this_is_80286_or_lower this_is_80386_or_higher: ;... Этот код занимает 15 байт Для проверки наличия Pentium используем конвейер: mov cs:change_me,0 db 0b9h ; 0b9h - код mov cx,непосредственное_значение change_me dw 1 jcxz this_is_pentium error_this_is_not_pentium: ;.... Этот код занимает 12 байт. Я не знаю, как проверить наличие процессора i486 без использования прерывания 6. Но "четверка" так мало отличается от "тройки", что вряд-ли кому-либо понадобится специально убеждаться в наличии 486+.