Студопедия

КАТЕГОРИИ:

АстрономияБиологияГеографияДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРиторикаСоциологияСпортСтроительствоТехнологияФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника


Теоретичні відомості. В нашому випадку прийдеться використовувати захисний режим, в якому розподіляються виконуючі задачі разом з використовуючими даними




В нашому випадку прийдеться використовувати захисний режим, в якому розподіляються виконуючі задачі разом з використовуючими даними. В сегментні регістри замість реальних адрес завантажувати так звані селектори, тобто вказівник на 8-байтовий блок пам’яті, який вміщає всю необхідну інформацію про сегмент. Всі ці блоки зібрані в таблиці глобальних (GDT – Global Descriptor Table) і локальних (Lokal Descriptor Table) дескрипторів. Крім того існує таблиця дескрипторів переривань (IDT - Interrupt Descriptor Table). Селектор складається із номера дескриптора (адреси) в таблиці (біти 3-15), типу таблиці (1- LTD, 0- GDT) (біт 2) і рівня привілей в бітах 0-1 (біти 0-3). Самий високий рівень привілей (00b) дозволяє програмі працювати на рівні ядра. Другий рівень (01b) дає повний доступ до апаратури. Третій рівень (10b) і четвертий (11b) управляють різними прикладними програмами і розширеннями. Для доступу до портів вводу-виводу потрібно виходити на самий високий рівень – нульовий, для чого потрібно отримати методом перебору вільний дескриптор.

Далі розберемо використання найвищого рівня привілей тільки для операційних систем Windows 95/98/ME. Напишемо ще один клас для прямого доступу до портів вводу-виводу. В нижченаведених програмах ІО32_0 представлені відповідні підходи, які дозволять працювати напряму з будь-якими пристроями в операційних системах Windows 95/98/ME.

Покроковий хід роботидля написання програми класу IO32_0 для прямого доступу до портів вводу-виводу:

1. Об’являємо клас IO32_0 для прямого доступу до портів вводу-виводу.

2. Загальнодоступні конструктори і функції - public:

3. Конструктор IO32_0 ().

4. Деструктор ~IO32_0 ().

5. Загальні функції:

6. Прочитати значення із порту функцією inPort типу bool з параметрами: wPort типу WORD, pdwValue типу PDWORD, bSize BYTE, які були розглянуті на попередній практичній роботі у класовій програмі.

7. Записати значення в порт функцією outPort типу bool з параметрами: wPort типу WORD, pdwValue типу PDWORD, bSize BYTE, які були розглянуті на попередній практичній роботі у класовій програмі.

8. Недоступні функції – private тобто закрита частина класу:

9. Реалізація дії pack (1) як константи чи макроса через директиву #pragma.

10. Об’явлення структури для пошуку дескриптора в таблиці:

11. Об’являємо структуру_GDT як складову класу командою typedef.

12. Об’являємо змінну Limit типу WORD для ліміту значення дескриптора.

13. Об’являємо змінну бази Base типу DWORD.

14. Закінчуємо структуру. Зразок структури GDT.

15. Опис дескриптора для сегменту даних:

16. Об’являємо структуру_GDT_HANDLE як складову класу командою typedef.

17. Об’являємо елемент структури L_0_15 типу WORD - біти 0-15 ліміту.

18. Об’являємо елемент структури В_0_15 типу WORD - біти 0-15 бази сегменту.

19. Об’являємо елемент структури В_16_23 типу BYTE - біти 16-23 бази сегменту.

20. Об’являємо елемент структури Access : 4 типу BYTE – для доступу до сегменту.

21. Об’являємо елемент структури Type : 1 типу BYTE - тип сегменту 1- код 0- дані.

22. Об’являємо елемент структури DPL : 2 типу BYTE - рівень привілей для дескриптора сегменту.

23. Об’являємо елемент структури IsRead : 1 типу BYTE - перевірка наявності сегменту.

24. Об’являємо елемент структури L_16_19 типу BYTE - біти 16-19 ліміту.

25. Об’являємо елемент структури OS : 1 типу BYTE - визначається операційною системою.

26. Об’являємо елемент структури RSV_NULL : 1 типу BYTE – резерв.

27. Об’являємо елемент структури B_32is16 : 1 типу BYTE – розрядність (1- 32-розрядний сегмент, 0- 16-розрядний).

28. Об’являємо елемент структури L_Granul : 1 типу BYTE: 1- 4Кб 0 - в байтах.

29. Об’являємо елемент структури B_24_31 типу BYTE - біти 24-31 бази сегменту.

30. Закінченняструктури. Структура зразка GDT_HANDLE.

31. Опис дескриптора шлюзу:

32. Об’являємо структуру_Sluice_Handle як складову класу командою typedef.

33. Об’являємо елемент структури Task_Offset_0_15 типу WORD - молодше слово зміщення для шлюзу задачі.

34. Об’являємо елемент структури Segment_S типу WORD - селектор сегменту.

35. Об’являємо елемент структури DWORD_Count : 5 типу WORD - число подвійних слів для роботи стеку.

36. Об’являємо елемент структури NULL_5_7 : 3 типу WORD рівне 0.

37. Об’являємо елемент структури Access : 4 типу WORD - доступ до сегменту.

38. Об’являємо елемент структури Type : 1 типу WORD - тип шлюзу.

39. Об’являємо елемент структури DPL : 2 типу WORD - рівень привілей для дескриптора шлюзу.

40. Об’являємо елемент структури IsRead : 1 типу WORD - перевірка наявності сегменту.

41. Об’являємо елемент структури Task_Offse_16_31 типу WORD - старше слово зміщення для шлюзу зада.

42. Закінченняструктури. Структура зразка Sluice_HANDLE.

43. Реалізація дії pack () як константи чи макроса через директиву #pragma.

44. Функція доступу до портів:

45. Об’являємо функцію ClassAccess в класі типу bool з параметрами: FunctionAddress типу PVOID, wPort типу WORD, pdwValue типу PDWORD, bSize типу BYTE.

46. Закінчення класу.

 

Покроковий хід роботидля написання програми файлу IO32_0.cpp:

1. Включаємо бібліотечний файл "stdafx.h".

2. Включаємо клас "IO32_0.h".

3. Реалізація класу:

4. Підключаємо функцію коду класу IO32_0 :: IO32_0 () до його реалізації.

5. Об’являємо пустий конструктор.

6. Потрібні дві функції для обробки портів вводу-виводу:

7. Функція як елемент класу __declspec з параметром naked і функція для запису в порт _outPortValue () типу повернення void.

8. Підключаємо асемблер командою _asm.

9. Порівнюємо (cmp), якщо розмір даних cl рівний 1 байту.

10. Записуємо байт _Byte.

11. Порівнюємо, якщо розмір даних cl рівний слову – 2 байти.

12. Записуємо слово _Word.

13. Порівнюємо, якщо розмір даних cl рівний подвійному слову – 4 байти.

14. Записуємо подвійне слово _Dword.

15. Обробляємо тип _Byte:

16. Заносимо в регістр al значення [ebx].

17. Записуємо байт al в порт dx.

18. Виходим командою retf.

19. Обробляємо тип _Word:

20. Заносимо в регістр aх значення [ebx].

21. Записуємо байт aх в порт dx.

22. Виходим командою retf.

23. Обробляємо тип _Dword:

24. Заносимо в регістр еaх значення [ebx].

25. Записуємо байт еaх в порт dx.

26. Виходим командою retf.

27. Кінець функції:

28. Функція для читання з порту як елемент класу __declspec з параметром naked і функція _inPortValue () типу повернення void.

29. Підключаємо асемблер командою _asm.

30. Порівнюємо (cmp), якщо розмір даних cl рівний 1 байту

31. Записуємо байт _Byte.

32. Порівнюємо, якщо розмір даних cl рівний слову – 2 байти.

33. Записуємо слово _Word.

34. Порівнюємо, якщо розмір даних cl рівний подвійному слову – 4 байти.

35. Записуємо подвійне слово _Dword.

36. Обробляємо тип _Byte:

37. Читаємо в регістр al байт із порту dx.

38. Записуємо байт al в порт [ebx].

39. Виходим командою retf.

40. Обробляємо тип _Word:

41. Читаємо в регістр aх слово із порту dx.

42. Записуємо слово [ebx] в порт al.

43. Виходим командою retf.

44. Обробляємо тип _Dword:

45. Читаємо подвійне слово dx із порту eax.

46. Записуємо слово [ebx] в порт еaх.

47. Виходим командою retf.

48. Кінець функції:

49. Функція пошуку вільного дескриптора в системі:

50. Функція CallAccess класу IO32_0 типу bool з параметром FunctionAddress типу PVOID, wPort типу WORD, pdwValue типу PDWORD і bSize типу BYTE.

51. Об’являємо лічильник циклів wNum = 1 типу WORD.

52. Об’являємо масив Addr [3] - адреса для нашої задачі типу WORD.

53. Об’являємо змінну регістру gdt типу GDT.

54. Створюємо посилання *pHANDLE на тип GDT_HANDLE.

55. Отримуємо регістр GDTR, починаючи з 286 процесора _asm sgdt [gdt]:

56. Переходимо до другого дескриптора сегменту даних:

57. Через посилання GDT_HANDLE*на адресу початку структури gdt і з’єднання з елементом Base через операцію «.», добавляємо 8 і присвоюємо значення змінній pHANDLE.

58. Виконуємо пошук вільного дескриптора в таблиці GDT:

59. Організовуємо цикл «для» по змінній wNum = 1 до < (gdt.Limit / 8 з наростанням wNum++.

60. Якщо вказані поля структури рівні 0, вільний дескриптор знайдений:

61. Якщо pHANDLE->IsRead=0 і pHANDLE->DPL=0 і pHANDLE->Type=0 і pHANDLE->Access=0, де операція «->» - означає з’єднання з елементом підструктури із його значенням.

62. Визначаємо параметри Sluice_Handle для дескриптора шлюзу через посилання на *pSluice (взяття початкової адреси).

63. Параметру pSluice присвоюємо pHANDLE через посилання на тип (Sluice_Handle*).

64. Молодше слово адреси нашої функції:

65. Елемент Task_Offset_0_15 структури pSluice, який з’єднується для присвоєння йому значення операцією «.», отримує значення LOWORD (FunctionAddress).

66. Селектор сегменту з найвищим рівнем привілей:

67. Елемент Segment_S структури pSluice, з’єднаний для присвоєння йому адреси 0x28.

68. Елемент DWORD_Count структури pSluice, з’єднаний для присвоєння йому значення 0.

69. Елемент NULL_5_7 структури pSluice, з’єднаний для присвоєння йому значення 0.

70. Елемент Access структури pSluice, з’єднаний для присвоєння йому значення 0x0C.

71. Елемент Type структури pSluice, з’єднаний для присвоєння йому значення 0.

72. Елемент DPL структури pSluice, з’єднаний для присвоєння йому значення 3.

73. Елемент IsRead структури pSluice, з’єднаний для присвоєння йому значення 1.

74. Старше слово адреси нашої функції:

75. Елемент Task_Offset_16_31 структури pSluice, який з’єднується для присвоєння йому значення операцією «->», отримує значення HIWORD (FunctionAddress).

76. Заповнюємо адресу для подальшого виклику:

77. 0-й елемент масиву Addr отримує адресу 0x00.

78. 1-й елемент масиву Addr отримує адресу 0x00.

79. 2-й елемент масиву Addr отримує адресу (wNum<<3) | 3 через побітове додавання «|» і операцію зсуву << вліво.

80. Передаємо наші параметри:

81. Підключаємо асемблер командою _asm.

82. Переміщаємо в регістр ebx значення передавання [pdvValue].

83. Переміщаємо в регістр cl значення передавання [bSize] - розмір значення передавання.

84. Переміщаємо в регістр dx номер порту вводу-виводу [wPort].

85. Виконуємо подальший виклик call fword зформованих параметрів в масиві ptr [Addr].

86. Обнулюємо дескриптор.

87. Здійснюємо призначення пам’яті командою memset з параметрами pHANDLE, 0, 8.

88. Виходим із функції з поверненням значення true.

89. Перевіряємо наступний дескриптор:

90. Збільшуємо значення дескриптора pHANDLE на 1.

91. Не знайдено ні одного вільного дескриптора, повертаємо значення false.

92. Кінець функції.

93. Загальнодоступні функції вводу-виводу:

94. Функція запису в порт outPort класу IO32_0 типу повернення bool з параметрами: wPort типу WORD, dwValue типу DWORD, bSize BYTE.

95. Виклик функції CallAccess з параметрами: _outPortValue класової структури типу (PVOID), wPort, взяттям адреси на dwValue і bSize) здійснює повернення значення функції.

96. Функція читання з порта inPort класу IO32_0 типу повернення bool з параметрами: wPort типу WORD, dwValue типу DWORD, bSize BYTE.

97. Виклик функції CallAccess з параметрами: _inPortValue класової структури типу (PVOID), wPort, взяттям адреси на pdwValue і bSize) здійснює повернення значення функції.

98. Кінець загальнодоступних функцій:

 

Принцип роботи класу ІО32_0 побудований за наступним алгоритмом: спочатку виконуємо пошук вільного дескриптора в таблиці GDT. Для отримання початкового вказівника на таблицю застосовуємо команду sgdt, шукаючи вільного дескриптора. Якщо дескриптор знайдений, присвоюємо йому вказівник на заповнений дескриптор шлюзу (SluiceHandle). Через структуру шлюзу визначаємо адресу функції, на яку буде передано управління шляхом дальнього виклику, а також загальні параметри доступу і рівень привілей. Далі записуємо аргументи для функції і безпосередньо виконуємо дальній виклик, який буде оброблений процесором з максимальним пріоритетом. Таким чином отримуємо доступ до апаратних портів, і операційна система не буде мішати цьому.

Варіанти практичних завдань. Написати фрагменти програм і функцій на мові С++.

 

Варіант Завдання
Варіант 1 Написати програми класу IO32_0 для прямого доступу до портів вводу-виводу.
Варіант 2 Написати програму функції запису в порт _outPortValue ().
Варіант 3 Написати програму функції читання з порту _inPortValue ().
Варіант 4 Написати програму функції пошуку вільного дескриптора CallAccess класу IO32_0.
Варіант 5 Сформулювати загальнодоступні функції вводу-виводу та структуризувати файл IO32_0.cpp.

 


 

Додаток А. Програмні коди функцій користувача, які можуть використовуватися при читанні і записі інформації на зовнішніх пристроях.

/*Програмний код функції для читання інформації з пристрою з використанням бібліотечних системних функцій читання.*/

// підключаємо необхідний файл ресурсів з бібліотеки.

#include <conio.h>

// прочитаємо значення базової пам’яті в кілобайтах.

іnt GetBaseMemory ()

{

//об’являємо змінні для отримання старшого і молодшого байтів.

BYTE lowBase = 0, highBase = 0;

//читаємо інформацію з CMOS-пам’яті

_outp (0x70, 0x15); //записуємо номер першого регістру

lowBase = _inp (0x71); //читаємо молодший біт

_outp (0x70, 0x16); // записуємо номер другого регістру

highBase = _inp (0x71); //читаємо старший байт

// повертаємо розмір базової пам’яті в кілобайтах

return ((highBase << 8) | lowBase);

}

 

// функція користувача для управління клавіатурою.

void KeyBoardOnOff (bool bOff)

{

BYTE state; //текучий стан

if (bOff) // виключити клавіатуру

{

//отримуємо текучий стан

state = _inp (0x61);

//встановлюємо біт 7 в 1

state |=0x80;

// записуємо обновлене значення в порт

_outp (0x61, state);

}

}

/* Функція користувача дляскидання даних пристрою АТА/АТАРІ з використанням бібліотечних функцій запису.*/

bool ResetDrive ()

{

// перший пристрій на другому каналі (як правило CD-ROM)

_outp (0x177, 0x08); // пишемо команду скидання 08h

//перевіряємо результат виконання

for (int i=0; i<5000, i++)

{

//перевіряємо біт 7 BUSY

if (( _inp (0x177) & 0x80) == 0x00)

return true; //команда успішно завершена

}

return false; //

}

/*Функція користувача для управління лоткомCD-ROM і використанням бібліотечних функцій запису.*/

void Eject ( bool bOpen )

{

int iTimeWait = 50000;

//формат пакетної команди для відкриття лотка

WORD Eject [6] = { 0x1B, 0, 2, 0, 0, 0 };

// формат пакетної команди для закриття лотка

WORD Close [6] = { 0x1B, 0, 3, 0, 0, 0 };

//перевіряємо готовність пристрою

while ( -- iTimeWait > 0)

{

//читаємо стан порту

if ((_inp (0x177) & 0x80 == 0x00) && (_inp (0x177) & 0x08 == 0x00)) break;

//закінчився час очікування

if (iTimeWait < 1) return;

}

//вибираємо перший пристрій на другому каналі

_outp ( 0x176, 0xA0);

//перед посилкою пакетної команди потрібно перевірити стан

iTimeWait = 50000;

//очікуємо готовність пристрою

while ( -- iTimeWait > 0)

{

//читаємо стан порту

if ((_inp (0x177) & 0x80 == 0x00) && (_inp (0x177) & 0x08 == 0x00)) break;

//закінчився час затримки

if (iTimeWait < 1) return;

}

// пишемо в порт команду пакетної передачі A0h

_outp ( 0x177, 0xA0);

//очікуємо готовність пристрою

while ( -- iTimeWait > 0)

{

//читаємо стан порту

if ((_inp (0x177) & 0x80 == 0x00) && (_inp (0x177) & 0x08 == 0x01)) break;

// закінчився час затримки

if (iTimeWait < 1) return;

}

//пишемо в порт пакетну команду

if (bOpen) //відкрити лоток

{

for (int i=0; i>6; i++)

{

_outpw (0x170, Eject[i]); //12-байтова команда

}

}

else //закрити лоток

{

for (int j=0; j>6; j++)

{

_outpw (0x170, Close[j]); //12-байтова команда

}

}

//перевіряємо результат виконання команди, якщо потрібно

iTimeWait = 50000;

//очікуємо готовність пристрою

while ( -- iTimeWait > 0)

{

//читаємо стан порту

if ((_inp (0x177) & 0x80 == 0x00) && (_inp (0x177) & 0x01 == 0x00)) &&

(_inp (0x177) & 0x40 == 0x01)) break;

// закінчився час затримки

if (iTimeWait < 1) return;

}

}


 

Додаток Б.Функції користувача для читання сектора з диску і запису на диск з використанням функції DeviceIoControl.

//Функція користувача для читання сектора з диску.

#include "stdafx.h"

#define VWIN32_DIOC_DOS_DRIVEINFO 6 // код функції драйвера

#define CF_FLAG 1 //прапор переносу

//додаткові структури

typedef struct _DIOC_REGISTERS

{

DWORD reg_EBX;

DWORD reg_EDX;

DWORD reg_ECX;

DWORD reg_EAX;

DWORD reg_EDI;

DWORD reg_ESI;

DWORD reg_Flags;

} DIOC_REGISTERS;

#pragma pack (1)

typedef struct _DATABLOCK

{

DWORD dwStartSector; //номер початкового сектору

WORD wNumSectors; //кількість секторів

DWORD pBuffer; //вказівник на буфер даних

} DATABLOCK;

#pragma pack ()

//Функція для читання секторів з диска:

bool ReadSector (unsigned int uDrive, DWORD dwStartSector, WORD wNumSectors, LPBYTE lpBuffer)

{

HANDLE hDriver;

DIOC_REGISTERS reg={0};

DATABLOCK data = {0};

bool bResult;

DWORD dwResult = 0;

//ініціалізуємо драйвер

hDriver = CreateFile (\\\\.\\vwin32, 0, 0, NULL, 0, FILE_FLAG_DELETE_ON_CLOSE, 0);

//якщо драйвер недоступний – виходимо з функції

if (hDriver == INVALID_HANDLE_VALUE) return falce;

//заповнюємо структуру даних DATABLOCK

data.dwStartSector = dwStartSector;

data.wNumtSector = wNumSector;

data.pBuffer = (DWORD) lpBuffer;

//заповнюємо структуру управління

reg.reg_EAX = 0x7305 // функція 7305h переривання 21h

reg.reg_EBX = (DWORD) &data;

reg.reg_ECX = -1;

reg.reg_EDX = uDrive; //номер логічного диску

//викликаємо функцію DeviceIoControl

bResult =DeviceIoControl (hDriver, VWIN32_DIOC_DOS_DRIVEINFO, &reg, sizeof (reg), &reg, sizeof (reg), &dwResult, 0);

//якщо виникла помилка – виходимо із функції

if (!bResult || (reg.reg_Flags &CF_FLAG))

{

CloseHandle (hDriver);

return false;

}

return true;

}

//Приклад функціїReadSector для читання двох секторів диска:

//номер секторів може бути: 0- по замовчуванню, 1- А, 2- В, 3- С, 4-D, 4-E, і //т.д.

//виділяємо пам’ять для двох секторів жорсткого диску

char *buffer = NULL;

buffer =new char [512*2];

//викликаємо функцію читання секторів

ReadSector (3, 0, 2, (LPBYTE) buffer);

//звільняємо пам’ять

delete [] buffer;

 

//Функція користувача для запису сектора на диск.

//функція для запису сектора диску:

bool WriteSector (unsigned int uDrive, DWORD dwStartSector, WORD wNumSectors, LPBYTE lpBuffer)

{

HANDLE hDriver;

DIOC_REGISTERS reg = {0}; // структура управління

DATABLOCK data = {0}; // структура даних

bool bResult;

DWORD dwResult = 0;

//ініціалізуємо драйвер

hDriver=CreateFile (\\\\.\\vwin32, 0,0, NULL, 0, FILE_FLAG_DELETE_ON_CLOSE, 0);

//якщо драйвер недоступний, виходимо з функції

if (hDriver==INVALID_HANDLE_VALUE) return falce;

//заповнюємо структуру даних DATABLOCK

data.dwStartSector = dwStartSector;

data.wNumtSector = wNumSector;

data.pBuffer = (DWORD) lpBuffer;

//заповнюємо структуру управління

reg.reg_EAX = 0x7305 //функція 7305h переривання 21h

reg.reg_EBX = (DWORD) &data;

reg.reg_ECX = -1;

reg.reg_EDX = uDrive; //номер логічного диску

reg.reg_ESI =0x6001;

//викликаємо функцію DeviceIoControl

bResult =DeviceIoControl (hDriver, VWIN32_DIOC_DOS_DRIVEINFO, &reg, sizeof (reg), &reg, sizeof (reg), &dwResult, 0);

//якщо виникла помилка – виходимо із функції

if (!bResult || (reg.reg_Flags &CF_FLAG))

{

CloseHandle (hDriver);

return false;

}

return true;

}


 

Додаток В.Класи для читання і запису інформації з використанням драйвера для роботи в Windows 98/ME з портами.

// Клас IO32.h: interface для класу CIO32.

#include <winioctl.h>

// визначаємо коди функцій для читання і запису

#define IO32_WRITEPORT CTL_CODE (FILE_DEVICE_UNKNOWN, 1, \METHOD_NEITHER,

FILE_ANY_ACCESS)

#define IO32_READPORT CTL_CODE (FILE_DEVICE_UNKNOWN, 2, \METHOD_NEITHER,

FILE_ANY_ACCESS)

// об’являємо клас

class CIO32

{

public:

CIO32 ();

~CIO32 ();

//загальні функції

bool InitPort (); //ініціалізація драйвера

//функція для зчитування значення із порту

bool inPort (WORD wPort, PDWORD pdwValue, BYTE bSize);

//функція для запису значення в порт

bool outPort (WORD wPort, PDWORD pdwValue, BYTE bSize);

private:

//закрита частина класу

HANDLE hVxD; //дескриптор драйвера

//структура управління

#pragma pack (1)

strukt tagPort32

{

USHORT wPort;

ULONG dwValue;

UCHAR bSize;

};

#pragma pack ()

}; //закінчення класу

 

//Приведемо файл ІО32.срр

 

#include "stdafx.h"

#include "IO32.h"

//реалізація класу CIO32

//конструктор

CIO32 :: CIO32 ()

{

hVxD = NULL;

}

//деструктор

CIO32 :: ~CIO32 ()

{

if (hVxD) CloseHandle (hVxD);

hVxD = NULL;

}

//Функції:

bool CIO32 :: InitPort () //Функція ініціалізації порта

{

//завантажуємо драйвер

hVxD = CreateFile (\\\\.\\io32port.vxd, 0, 0, NULL, 0, FILE_FLAG_DELETE_ON_CLOSE, NULL);

//якщо драйвер не доступний, виходим
if (hVxD == INVALID_HANDLE_VALUE) return falce;

return true;

}

//функція читання з порту.

bool CIO32 :: inPort (WORD wPort, PDWORD pdwValue, BYTE bSize)

{

// якщо драйвер не доступний, виходим
if (hVxD == NULL) return falce;

DWORD dwReturn;

tagPort32 port;

port.bSize = bSize;

port.wPort = wPort;

//читаємо значення з указаного порту

return DeviceIOControl (hVxD, IO32_READPORT, &port, sizeof (tagPort32), pdwValue, sizeof (DWORD), &dwReturn, NULL) ;

}

//функція запису в порт.

bool CIO32 :: outPort (WORD wPort, DWORD dwValue, BYTE bSize)

{

// якщо драйвер не доступний, виходим

if (hVxD == NULL) return falce;

DWORD dwReturn;

tagPort32 port;

port.bSize = bSize;

port.dwValue = dwValue;

port.wPort = wPort;

//записуємо значення в указаний порт

return DeviceIOControl (hVxD, IO32_WRITEPORT, &port, sizeof (tagPort32), NULL, 0, &dwReturn, NULL) ;

}

 

//Приклад роботи з класом CIO32:

//об’являємо клас

CIO32 io;

//ініціалізуємо драйвер

io.initPort ();

//тепер можна працювати з портом

//для прикладу включимо системний динамік і після 4 секунд виключимо

DWORD dwResult = 0;

//читаємо стан порту

io.inPort (0x61, &dwResult, 1);

dwResult |= 0x03; //включаємо

//записуємо значення в порт

io.outPort (0x61, dwResult, 1);

//пауза 4 секунди

Sleep (4000);

//читаємо стан порту

io.inPort (0x61, dwResult, 1);

dwResult &= 0xFC; //виключаємо

//записуємо значення в порт

io.outPort (0x61, dwResult, 1);

 


 

Додаток Г. Приклади програм класів недокументованого доступу до портів в операційних системах Windows 95/98/ME.

//Об’являємо клас IO32_0.

class IO32_0

{

public:

IO32_0 () //конструктор

~IO32_0 () //деструктор

//загальні функції

//прочитати значення із порту

bool inPort (WORD wPort, PDWORD pdwValue, BYTE bSize);

//записати значення в порт

bool outPort (WORD wPort, DWORD dwValue, BYTE bSize);

private:

#pragma pack (1)

//об’являємо структури

//структура для пошуку дескриптора в таблиці

typedef struct _GDT

{

WORD Limit; //ліміт

DWORD Base; //база

} GDT;

//опис дескриптора для сегменту даних

typedef struct _GDT_HANDLE

{

WORD L_0_15; //біти 0-15 ліміту

WORD B_0_15; //біти 0-15 бази сегменту

BYTE B_16_23; //біти 16-23 бази сегменту

BYTE Access : 4; //доступ до сегменту

BYTE Type : 1; //тип сегменту 1- код 0- дані

BYTE DPL : 2; //рівень привілей для дескриптора сегменту

BYTE IsRead : 1; //перевірка наявності сегменту

BYTE L_16_19; //біти 16-19 ліміту

BYTE OS : 1; //визначається операційною системою

BYTE RSV_NULL : 1; //резерв

BYTE B_32is16 : 1; //розрядність (1- 32-розрядний сегмент, 0- 16-розрядн.

BYTE L_Granul : 1; //1- 4Кбб 0- в байтах

BYTE B_24_31; //біти 24-31 бази сегменту

} GDT_HANDLE;

//опис дескриптора шлюзу

typedef struct _Sluice_Handle;

{

WORD Task_Offset_0_15; //молодше слово зміщення для шлюзу задачі

WORD Segment_S; //селектор сегменту

WORD DWORD_Count : 5; //число подвійних слів для роботи //стеку

WORD NULL_5_7 : 3; //рівне 0

WORD Access : 4; //доступ до сегменту

WORD Type : 1; //тип шлюзу

WORD DPL : 2; //рівень привілей для дескриптора шлюзу

WORD IsRead : 1; //перевірка наявності сегменту

WORD Task_Offse_16_31; //старше слово зміщення для //шлюзу задачі

} Sluice_Handle;

#pragma pack ()

//функція доступу до портів

bool ClassAccess (PVOID FunctionAddress, WORD wPort, PDWORD pdwValue, BYTE bSize);

}; //кінець класу

 

 

// Файл IO32_0.cpp

#include "stdafx.h"

#include "IO32_0.h"

//реалізація класу

IO32_0 :: IO32_0 ()

{

//пустий конструктор

}

//дві функції для обробки портів вводу-виводу:

//функція запису в порт.

__declspec (naked) void _outPortValue ()

{

_asm

{

cmp cl, 1 //якщо розмір даних рівний байту

je _Byte //записуємо байт

cmp cl, 2 //якщо розмір даних рівний слову

je _Word //записуємо слово

cmp cl, 4 //якщо розмір даних рівний подвійному слову

je _Dword //записуємо подвійне слово

_Byte:

mov al, [ebx]

out dx, al //записуємо байт в порт

retf //виходим

_Word:

mov ax, [ebx]

out dx, ax //записуємо слово в порт

retf //виходим

_Dword:

mov eax, [ebx]

out dx, eax //записуємо подвійне слово в порт

retf //виходим

}

}

//функція читання з порта.

__declspec (naked) void _inPortValue ()

{

_asm

cmp cl, 1 //якщо розмір даних рівний байту

je _Byte //читаєм байт

cmp cl, 2 // якщо розмір даних рівний слову

je _Word //читаємо слово

cmp cl, 4 // якщо розмір даних рівний подвійному слову

je _Dword //читаєм подвійне слово

_Byte:

in al, dx //читаємо байт із порту

mov [ebx], al

retf

_Word:

In ax, dx //читаємо слово із порту

mov [ebx], ax

retf

_Dword:

In eax, dx //читаємо подвійне слово із порту

mov [ebx], eax

retf

}

}

//Функція пошуку вільного дескриптора в системі.

bool IO32_0 :: CallAccess (PVOID FunctionAddress, WORD wPort, PDWORD pdwValue, BYTE bSize)

{

WORD wNum = 1; //лічильник циклів

WORD Addr [3]; //адреса для нашої задачі

GDT gdt;

GDT_HANDLE *pHANDLE;

// отримуємо регістр GDTR, починаючи c 286 процесора

_asm sgdt [gdt]

// переходимо до другого дескриптора сегменту даних

pHANDLE = (GDT_HANDLE*) (gdt.Base +8);

// виконуємо пошук вільного дескриптора в таблиці GDT

for (wNum = 1; wNum < (gdt.Limit / 8); wNum++)

{

//якщо вказані поля структури рівні 0б

//вільний дескриптор знайдений

if (pHANDLE->IsRead==0 && pHANDLE->DPL==0 && pHANDLE->Type==0 && pHANDLE->Access==0)

{

//визначаємо параметри для дескриптора шлюзу

Sluice_Handle *pSluice;

pSluice = (Sluice_Handle*) pHANDLE;

//молодше слово адреси нашої функції

pSluice->Task_Offset_0_15=LOWORD (FunctionAddress);

//селектор сегменту з найвищим рівнем привілей

pSluice->Segment_S=0x28;

pSluice->DWORD_Count=0;

pSluice->NULL_5_7=0;

pSluice->Access=0x0C;

pSluice->Type=0;

pSluice->DPL=3;

pSluice->IsRead=1;

//старше слово адреси нашої функції

pSluice->Task_Offse_16_31=HIWORD (FunctionAddress);

//заповнюємо адресу для подальшого виклику

Addr[0]=0x00;

Addr[1]=0x00;

Addr[2]=(wNum<<3) | 3;

//передаємо наші параметри

_asm

{

mov ebx, [pdvValue] //значення передавання

mov cl, [bSize] //розмір значення передавання

mov dx, [wPort] //номер порту вводу-виводу

//виконуємо подальший виклик

call fword ptr [Addr]

}

//обнулюємо дескриптор

memset (pHANDLE, 0, 8);

return true; // виходим із функції

}

// перевіряємо наступний дескриптор

pHANDLE++;

}

//не знайдено ні одного вільного дескриптора

return false;

}

//Загальнодоступні функції вводу-виводу.

bool IO32_0 :: outPort (WORD wPort, DWORD dwValue, BYTE bSize)

{

return CallAccess ((PVOID) _outPortValue, wPort, &dwValue, bSize);

}

bool IO32_0 :: inPort (WORD wPort, PDWORD pdwValue, BYTE bSize)

{

return CallAccess ((PVOID) _inPortValue, wPort, pdwValue, bSize);

}

 



Поделиться:

Дата добавления: 2015-08-05; просмотров: 65; Мы поможем в написании вашей работы!; Нарушение авторских прав





lektsii.com - Лекции.Ком - 2014-2024 год. (0.007 сек.) Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав
Главная страница Случайная страница Контакты