Жажда скорости Крис Касперски Хакер, номер #095, стр. 095-130-5 MOV CR4, EAX … Следующий код обеспечивает взаимодействие драйвера с прикладной программой через API-функцию DeviceIOControl, передающую в IOCTL-коде номер события, за которым необходимо вести мониторинг. По соображениям наглядности здесь используется всего лишь один счетчик производительности, управляемый MSR-регистром PerfEvtSel0. IRP_MJ_DEVICE_CONTROL: ; // процедура обработки IOCTL-запросов ; // настраиваем регистр perfevtsel0 для мониторинга нужных событий XOR EDX, EDX MOV EAX, pisl->Parameters.DeviceIoControl.IoControlCode ; //номер события TEST EAX, EAX ; // если код события равен нулю JZ wrt ; // то вырубаем счетчик OR EAX, 10000h ; // делаем счетчик доступным ; // с прикладного уровня OR EAX, 400000h ; // пускаем счетчик wrt: MOV ECX,0x186 ; // выбираем MSR-регистр PERFEVTSEL0 WRMSR При деинициализации драйвера крайне желательно запретить доступ к команде RDPMC с прикладного уровня и остановить все ранее запущенные счетчики производительности, сбросив флажок Enable Counter в MSR-регистрах PerfEvtSel0/PerfEvtSel1 (код, приведенный ниже, останавливает только PerfEvtSel0): DriverUnload: ; // процедура деинициализации драйвера … ; // сбрасываем бит PCE регистра CR4 для запрета чтения ; // счетчика производительности с пользовательского уровня MOV EAX, CR4 MOV ECX, 100h NOT ECX ; // запрещаем доступ к RDPMC с прикладного уровня AND EAX, ECX MOV CR4, EAX ; // останавливаем счетчик производительности XOR EDX, EDX XOR EAX, EAX MOV ECX, 186h WRMSR … Прикладная программа первым делом должна загрузить драйвер (пусть для определенности он будет называться 996.SYS), открыв его с помощью функции CreateFile. При этом управление получит процедура инициализации, открывающая доступ к машинной команде RDPMC. Но сами счетчики производительности еще не заданы, так что читать, собственно говоря, нечего и незачем. Нет никакой необходимости писать загрузку драйвера на ассемблере, лучше всего воспользоваться для этой цели языком Си: // определения необходимых констант #define PrefCtrl0 0x0000 #define DCU_MISS_OUTSTANDING 0x0048 // дескриптор драйвера 996 static HANDLE _996_handle = INVALID_HANDLE_VALUE; int _996_init() { if (_996_handle == INVALID_HANDLE_VALUE) { _996_handle = CreateFile("\\\\.\\996",GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (_996_handle == INVALID_HANDLE_VALUE) return 0; } return 1; } То же самое относится и к функции, вызывающей DeviceIoControl и передающей ей код интересующего нас события. На языке Си она выглядит гораздо нагляднее: int _996_select(int xCode, int REG) { DWORD x; if (REG != PrefCtrl0) return 0; // если программист забыл загрузить драйвер, // данная функция делает это самостоятельно if (_996_handle == INVALID_HANDLE_VALUE) _996_init(); // если загрузка драйвера провалилась, сваливаем отсюда if (_996_handle == INVALID_HANDLE_VALUE) return 0; return DeviceIoControl(_996_handle, xCode, &x,0, &x, 0, &x, 0); } |