BYTE LayoutInfo[0xFFFF];
// Для WinNT получаем информацию о расположении лог. дисков на утройстве hDisk.
// То что hDisk — лог. диск не имеет значения, функция выполнится для физ. диска,
// на котором находится hDisk. Если у нас Win9x, то DeviceIoControl вернет FALSE
if(!DeviceIoControl(hDisk, IOCTL_DISK_GET_DRIVE_LAYOUT, NULL, 0,
LayoutInfo, 0xFFFF, &junk, NULL))
{
CloseHandle(hDisk);
continue;
}
// Сохраняем сигнатуру физического диска для данного лог. диска
list[*counter].sign = ((DRIVE_LAYOUT_INFORMATION*)LayoutInfo)->Signature;
CloseHandle(hDisk);
}
counter++;
}
}
Для NT:
Далее вызываем QueryDosDevice: QueryDosDevice("PhysicalDriveN", Buff, 1024) для каждого диска. Если она вернула TRUE, то диск имеется
и можно получить его сигнатуру, описанным выше способом:
// Получаем номер физичексого диска (от нуля)
int PhDiskNo = 0x80 — map.dmiInt13Unit;
}
CloseHandle(hVxD);
Вот и все.
Re[4]: Сколько HDD в системе?
От:
Аноним
Дата:
09.12.03 12:22
Оценка:
Здравствуйте, Lipatov, Вы писали:
L>Здравствуйте, Dexter, Вы писали:
D>>А надо и под NT и под 9х... L>Задачу решается по разному для NT и Win9x.
L>Сначала получаем список всех логических дисков, определяем их тип и сохраняем полученную информацию
L>res = GetLogicalDrives(); L>if(!res) return 0;
L>int i = 0; L>sprintf(drv,"a:\\"); L>for (i=1;i<32;i++) L>{ L> int j=0; L> int pw = 1; L> for (;j<(i-1);j++) pw = pw*2;
L> if((res & pw) != 0) L> { L> char dl; L> dl = 'A' + i — 1; L> drv[0] = dl; L> DWORD dt = GetDriveType(drv); L> list[counter].DriveLetter = dl; L> list[counter].sign = 0; L> if(dt == DRIVE_FIXED) L> { L> nHDD++; L> strcpy(list[*counter].type, "HDD"); L> char name[] = "\\\\.\\A:"; L> name[4] = list[counter].DriveLetter; L> HANDLE hDisk = CreateFile(name, GENERIC_READ|GENERIC_WRITE, L> FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); L> DWORD junk;
L> BYTE LayoutInfo[0xFFFF]; L> // Для WinNT получаем информацию о расположении лог. дисков на утройстве hDisk. L> // То что hDisk — лог. диск не имеет значения, функция выполнится для физ. диска, L> // на котором находится hDisk. Если у нас Win9x, то DeviceIoControl вернет FALSE L> if(!DeviceIoControl(hDisk, IOCTL_DISK_GET_DRIVE_LAYOUT, NULL, 0, L> LayoutInfo, 0xFFFF, &junk, NULL)) L> { L> CloseHandle(hDisk); L> continue; L> }
L> // Сохраняем сигнатуру физического диска для данного лог. диска L> list[*counter].sign = ((DRIVE_LAYOUT_INFORMATION*)LayoutInfo)->Signature; L> CloseHandle(hDisk); L> }
L> counter++; L> } L>}
L>Для NT: L>Далее вызываем QueryDosDevice: QueryDosDevice("PhysicalDriveN", Buff, 1024) для каждого диска. Если она вернула TRUE, то диск имеется L>и можно получить его сигнатуру, описанным выше способом:
L>HANDLE hDevice = CreateFile(DriveName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); L>if(hDevice == INVALID_HANDLE_VALUE) continue;
L>DWORD junk;
L> if(DeviceIoControl(hDevice, IOCTL_DISK_GET_DRIVE_LAYOUT, NULL, L> 0, LayoutInfo, 0xFFFF, &junk, NULL)) L>{ L> // Получаем сигнатуру и сравниваем с уже полученными L>}
L>Для Win9x:
L>#define VWIN32_DIOC_DOS_IOCTL 1
L>HANDLE hVxD = CreateFile("\\\\.\\vwin32", 0, 0, NULL, 0, FILE_FLAG_DELETE_ON_CLOSE, NULL);
L>if(hVxD == INVALID_HANDLE_VALUE) return -2;
L>DRIVE_MAP_INFO map; L>DIOC_REGISTERS reg; L>DWORD junk;
L>// для всех fixed дисков L>for(j = 0; j < counter; j++) L>{ L> if(strcmp(list[j].type, "HDD")) continue; L> SetLastError(0);
L> reg.reg_EAX = 0x440D; // IOCTL for block devices L> reg.reg_EBX = list[j].DriveLetter + 1 — 'A';// zero-based drive identifier L> reg.reg_ECX = 0x86F; // Get Media ID command L> reg.reg_EDX = (DWORD) ↦ // receives media identifier information L> reg.reg_Flags = 0x0001; // assume error (carry flag is set)
L> map.dmiAllocationLength = sizeof(map);
L> if(!DeviceIoControl(hVxD, VWIN32_DIOC_DOS_IOCTL, L> ®, sizeof(reg), L> ®, sizeof(reg), L> &junk, NULL)) continue;
L> // Получаем номер физичексого диска (от нуля) L> int PhDiskNo = 0x80 — map.dmiInt13Unit; L>}
L>CloseHandle(hVxD);
L>Вот и все.
Подход неправильный, поскольку если на диске нет томов(разделов) с буквами, то по твоей логике этого диска не увидишь.
Под NT очень просто:
CreateFileW( L"\\PHYSICALDRIVE%d", ... ),
где вместо %d надо подставлять 0,1,2,...
Если получил handle, то можешь затем вызвать DeviceIoControl( IOCTL_DISK_GET_DRIVE_GEOMETRY, .... )
А>Подход неправильный, поскольку если на диске нет томов(разделов) с буквами, то по твоей логике этого диска не увидишь. А>Под NT очень просто: А>CreateFileW( L"\\PHYSICALDRIVE%d", ... ), А>где вместо %d надо подставлять 0,1,2,... А>Если получил handle, то можешь затем вызвать DeviceIoControl( IOCTL_DISK_GET_DRIVE_GEOMETRY, .... )
соглашусь с этим, только напомню что права нужны для этого соответствующие (я про CreateFileW( L"\\PHYSICALDRIVE%d", ... ),
... << RSDN@Home 1.1.2 beta 2 >>
Valery A. Boronin, RSDN Team, linkedin.com\in\boronin
R&D Mgmt & Security. AppSec & SDL. Data Protection and Systems Programming. FDE, DLP, Incident Management. Windows Filesystems and Drivers.
Здравствуйте, Аноним, Вы писали:
А>Подход неправильный, поскольку если на диске нет томов(разделов) с буквами, то по твоей логике этого диска не увидишь. А>Под NT очень просто: А>CreateFileW( L"\\PHYSICALDRIVE%d", ... ), А>где вместо %d надо подставлять 0,1,2,...
QueryDosSevice делает тоже самое
А>Если получил handle, то можешь затем вызвать DeviceIoControl( IOCTL_DISK_GET_DRIVE_GEOMETRY, .... )
А>Под 9x чуть сложнее, но долго писать.
Так это тоже сделано
Резюме:
Во-первых, здесь определяется не только сколько дисков в системе, но и какие на них
имеются тома.
Во-вторых, насчет того что дисков можно не увидеть, то это тоже не правда, т.к. приведен
реально работающий пример из реально работающей тулзы. (единтственное, я немного урезал
его, т.к. там делалось еще кое что, может хватил лишку)
L>QueryDosSevice делает тоже самое
QueryDosDevice возвращает символические линки, но ни как ни физические устройства.
L>Во-вторых, насчет того что дисков можно не увидеть, то это тоже не правда, т.к. приведен L>реально работающий пример из реально работающей тулзы. (единтственное, я немного урезал L>его, т.к. там делалось еще кое что, может хватил лишку)
Ты хочешь сказать, что если у тебя есть диск, на котором нет ни одного тома, или у этих томов нет буквы, то твой код увидит этот диск?
Здравствуйте, MShura, Вы писали:
MS>QueryDosDevice возвращает символические линки, но ни как ни физические устройства.
В моем коде QueryDosDevice используется это рудимент, т.к. по началу я хотел использовать ее в Win9x для определения кол-ва физ. дисков, но во-первых, как оказалось, в Win9x нет устройств типа PhysicalDriveX, а во-вторых, если бы и были, то я бы все равно не определил какие на диске тома (это было основная задача).
Конечно лучше использовать CreateFile("\\\\.\\PhysicalDriveX",...), но мой вариант тоже работает. Насчет символических линков, то, насколько я понимаю, если диск есть, то и линк на него есть, а я опреджеляю лишь сам факт наличия диска (по крайней мере, за 2 года использования к этому нареканий не было).
MS>Ты хочешь сказать, что если у тебя есть диск, на котором нет ни одного тома, или у этих томов нет буквы, то твой код увидит этот диск?
А черт, извиняюсь! В Win9x на самом деле диски без томов не найдутся. Для определения числа дисков я использовал вызовы своей библиотеки, а скопировать это забыл. Для чтения дисков под Win9x пришлось писать 16-битную DLL, которая вызывалась из 32-битной DLL, которая подгружалась к программе (может и переборно хитро, но других способов чтения с физических дисков под Win9x (кроме VxD) я не знаю. Если есть — подскажите пожалуйста). Как писать такую библиотеку есть в базе знаний MSDN.
Здравствуйте, Lipatov, Вы писали:
L>Здравствуйте, MShura, Вы писали:
MS>>QueryDosDevice возвращает символические линки, но ни как ни физические устройства. L>В моем коде QueryDosDevice используется это рудимент, т.к. по началу я хотел использовать ее в Win9x для определения кол-ва физ. дисков, но во-первых, как оказалось, в Win9x нет устройств типа PhysicalDriveX, а во-вторых, если бы и были, то я бы все равно не определил какие на диске тома (это было основная задача). L>Конечно лучше использовать CreateFile("\\\\.\\PhysicalDriveX",...), но мой вариант тоже работает. Насчет символических линков, то, насколько я понимаю, если диск есть, то и линк на него есть, а я опреджеляю лишь сам факт наличия диска (по крайней мере, за 2 года использования к этому нареканий не было).
В общем так должно быть, поскольку CreateFile("\\\\.\\PhysicalDriveX",...) как раз сначало читает то, что возвращает QueryDosDevice. Надо только не забывать спрашивать про параметры диска, иначе могут перечислятся также разные устройства типа UFB Flash, эмуляторы и т.д.
MS>>Ты хочешь сказать, что если у тебя есть диск, на котором нет ни одного тома, или у этих томов нет буквы, то твой код увидит этот диск? L>А черт, извиняюсь! В Win9x на самом деле диски без томов не найдутся. Для определения числа дисков я использовал вызовы своей библиотеки, а скопировать это забыл. Для чтения дисков под Win9x пришлось писать 16-битную DLL, которая вызывалась из 32-битной DLL, которая подгружалась к программе (может и переборно хитро, но других способов чтения с физических дисков под Win9x (кроме VxD) я не знаю. Если есть — подскажите пожалуйста). Как писать такую библиотеку есть в базе знаний MSDN.
Мы к сожалению также пользуемся такими подходами (16-бит и/или VXD ). И итоге обычно в комплект наших программ для Win9x входит 32-бит DLL + 16-бит DLL + VXD.
>>Для определения числа дисков я использовал вызовы своей библиотеки, а скопировать это забыл. Для чтения дисков под Win9x пришлось писать >>16-битную DLL, которая вызывалась из 32-битной DLL, которая подгружалась к программе (может и переборно хитро, но других способов чтения с >>физических дисков под Win9x (кроме VxD) я не знаю. Если есть — подскажите пожалуйста). Как писать такую библиотеку есть в базе знаний MSDN.
Здравствуйте, rastoman, Вы писали:
R>А чем Ring-0 не устраивает в Win98 ?
Так для перехода в ring-0 и надо писать VxD, или какою нибудь хитрую штуку с перехватом прерывания, как это делают вирусы.
>>>Для определения числа дисков я использовал вызовы своей библиотеки, а скопировать это забыл. Для чтения дисков под Win9x пришлось писать >>16-битную DLL, которая вызывалась из 32-битной DLL, которая подгружалась к программе (может и переборно хитро, но других способов чтения с >>физических дисков под Win9x (кроме VxD) я не знаю. Если есть — подскажите пожалуйста). Как писать такую библиотеку есть в базе знаний MSDN.
Здравствуйте, MShura, Вы писали:
MS>Здравствуйте, Lipatov, Вы писали:
L>>Здравствуйте, MShura, Вы писали:
MS>>>Ты хочешь сказать, что если у тебя есть диск, на котором нет ни одного тома, или у этих томов нет буквы, то твой код увидит этот диск? L>>А черт, извиняюсь! В Win9x на самом деле диски без томов не найдутся. Для определения числа дисков я использовал вызовы своей библиотеки, а скопировать это забыл. Для чтения дисков под Win9x пришлось писать 16-битную DLL, которая вызывалась из 32-битной DLL, которая подгружалась к программе (может и переборно хитро, но других способов чтения с физических дисков под Win9x (кроме VxD) я не знаю. Если есть — подскажите пожалуйста). Как писать такую библиотеку есть в базе знаний MSDN.
MS>Мы к сожалению также пользуемся такими подходами (16-бит и/или VXD ). И итоге обычно в комплект наших программ для Win9x входит 32-бит DLL + 16-бит DLL + VXD.
Вообще-то, что другой способ есть. Для примера Acronis Disk Editor пользуется только одной DLL, в которой определены все функи для работы с диском. Никаких VxD не используется и работает очень быстро. Как они это делают я не знаю.
L>Так для перехода в ring-0 и надо писать VxD, или какою нибудь хитрую штуку с перехватом прерывания, как это делают вирусы.
Есть очень хороший пример доступа к винту через порты без всяких там VXD — diskid32. В Win9x всё через ring0.
Приведу отрывок из кода для перехода в нулевое кольцо и его использования:
// These are our ring 0 functions responsible for tinkering with the hardware ports.
// They have a similar privilege to a Windows VxD and are therefore free to access
// protected system resources (such as the page tables) and even place calls to
// exported VxD services.__declspec(naked) void Ring0GetPortVal()
{
_asm
{
Cmp CL, 1
Je ByteVal
Cmp CL, 2
Je WordVal
Cmp CL, 4
Je DWordVal
ByteVal:
In AL, DX
Mov [EBX], AL
Retf
WordVal:
In AX, DX
Mov [EBX], AX
Retf
DWordVal:
In EAX, DX
Mov [EBX], EAX
Retf
}
}
__declspec(naked) void Ring0SetPortVal()
{
_asm
{
Cmp CL, 1
Je ByteVal
Cmp CL, 2
Je WordVal
Cmp CL, 4
Je DWordVal
ByteVal:
Mov AL, [EBX]
Out DX, AL
Retf
WordVal:
Mov AX, [EBX]
Out DX, AX
Retf
DWordVal:
Mov EAX, [EBX]
Out DX, EAX
Retf
}
}
// This function makes it possible to call ring 0 code from a ring 3
// application.bool CallRing0(PVOID pvRing0FuncAddr, WORD wPortAddr, PDWORD pdwPortVal, BYTE bSize)
{
struct GDT_DESCRIPTOR *pGDTDescriptor;
struct GDTR gdtr;
WORD CallgateAddr[3];
WORD wGDTIndex = 1;
_asm Sgdt [gdtr]
// Skip the null descriptor
pGDTDescriptor = (struct GDT_DESCRIPTOR *)(gdtr.dwGDTBase + 8);
// Search for a free GDT descriptorfor (wGDTIndex = 1; wGDTIndex < (gdtr.wGDTLimit / 8); wGDTIndex++)
{
if (pGDTDescriptor->Type == 0 &&
pGDTDescriptor->System == 0 &&
pGDTDescriptor->DPL == 0 &&
pGDTDescriptor->Present == 0)
{
// Found one !
// Now we need to transform this descriptor into a callgate.
// Note that we're using selector 0x28 since it corresponds
// to a ring 0 segment which spans the entire linear address
// space of the processor (0-4GB).struct CALLGATE_DESCRIPTOR *pCallgate;
pCallgate = (struct CALLGATE_DESCRIPTOR *) pGDTDescriptor;
pCallgate->Offset_0_15 = LOWORD(pvRing0FuncAddr);
pCallgate->Selector = 0x28;
pCallgate->ParamCount = 0;
pCallgate->Unused = 0;
pCallgate->Type = 0xc;
pCallgate->System = 0;
pCallgate->DPL = 3;
pCallgate->Present = 1;
pCallgate->Offset_16_31 = HIWORD(pvRing0FuncAddr);
// Prepare the far call parameters
CallgateAddr[0] = 0x0;
CallgateAddr[1] = 0x0;
CallgateAddr[2] = (wGDTIndex << 3) | 3;
// Please fasten your seat belts!
// We're about to make a hyperspace jump into RING 0.
_asm Mov DX, [wPortAddr]
_asm Mov EBX, [pdwPortVal]
_asm Mov CL, [bSize]
_asm Call FWORD PTR [CallgateAddr]
// We have made it !
// Now free the GDT descriptor
memset(pGDTDescriptor, 0, 8);
// Our journey was successful. Seeya.return true;
}
// Advance to the next GDT descriptor
pGDTDescriptor++;
}
// Whoops, the GDT is fullreturn false;
}
bool GetPortVal(WORD wPortAddr, PDWORD pdwPortVal, BYTE bSize)
{
bool Result;
DWORD dwBytesReturned;
struct tagPort32Struct Port32Struct;
if (IsNT)
{
if (!IsWinIoInitialized)
return false;
Port32Struct.wPortAddr = wPortAddr;
Port32Struct.bSize = bSize;
if (!DeviceIoControl(hDriver, IOCTL_WINIO_READPORT, &Port32Struct,
sizeof(struct tagPort32Struct), &Port32Struct,
sizeof(struct tagPort32Struct),
&dwBytesReturned, NULL))
return false;
else
*pdwPortVal = Port32Struct.dwPortVal;
}
else
{
Result = CallRing0((PVOID)Ring0GetPortVal, wPortAddr, pdwPortVal, bSize);
if (Result == false)
return false;
}
return true;
}
bool SetPortVal(WORD wPortAddr, DWORD dwPortVal, BYTE bSize)
{
DWORD dwBytesReturned;
struct tagPort32Struct Port32Struct;
if (IsNT)
{
if (!IsWinIoInitialized)
return false;
Port32Struct.wPortAddr = wPortAddr;
Port32Struct.dwPortVal = dwPortVal;
Port32Struct.bSize = bSize;
if (!DeviceIoControl(hDriver, IOCTL_WINIO_WRITEPORT, &Port32Struct,
sizeof(struct tagPort32Struct), NULL, 0, &dwBytesReturned, NULL))
return false;
}
else
return CallRing0((PVOID)Ring0SetPortVal, wPortAddr, &dwPortVal, bSize);
return true;
}
Здравствуйте, rastoman, Вы писали:
L>>Так для перехода в ring-0 и надо писать VxD, или какою нибудь хитрую штуку с перехватом прерывания, как это делают вирусы.
R>Есть очень хороший пример доступа к винту через порты без всяких там VXD — diskid32. В Win9x всё через ring0. R>Приведу отрывок из кода для перехода в нулевое кольцо и его использования:
Я видел этот пример, но, если я не ошибаюсь, он работает долько для IDE дисков.
L>Я видел этот пример, но, если я не ошибаюсь, он работает долько для IDE дисков.
На SCSI винтах потестить не вышло. Я работаю только с ATA-интерфейсами для IDE-винтов.
Если кто поможет какой-нить докой по SCSI винтам, буду премного благодарен
MS>>Мы к сожалению также пользуемся такими подходами (16-бит и/или VXD ). И итоге обычно в комплект наших программ для Win9x входит 32-бит DLL + 16-бит DLL + VXD. L>Вообще-то, что другой способ есть. Для примера Acronis Disk Editor пользуется только одной DLL, в которой определены все функи для работы с диском. Никаких VxD не используется и работает очень быстро. Как они это делают я не знаю.
Я не видел их DE, но думаю, что очень просто.
То что у нас в 32-бит DLL у них наверное подлинковывается в виде статической либы.
Наша прога также умеет работать без VXD, правда будут какие-то ограничения. Какие точно сказать не могу потому, как не я писал этот код, я его только поддерживаю...
Но наверняка часть функций из VXD можно перетащить в 16-бит DLL.
Если дизассемблировать их код. то думаю, можно понять. Только мне это например не нужно.
L>>Вообще-то, что другой способ есть. Для примера Acronis Disk Editor пользуется только одной DLL, в которой определены все функи для работы с диском. Никаких VxD не используется и работает очень быстро. Как они это делают я не знаю.
MS>Я не видел их DE, но думаю, что очень просто. MS>То что у нас в 32-бит DLL у них наверное подлинковывается в виде статической либы.
Нет. Как раз DLL и них 32 разрядная.
Мы предполагаем, что у них VxD засунут в ресурсы и они его при каждом запуске достают и загружают.
Это легко проверить, но ка-то руки не доходят