• XSS.stack #1 – первый литературный журнал от юзеров форума

Бесплатно напишу/исправлю софт на Rust

reqwest

(L3) cache
Пользователь
Регистрация
05.05.2022
Сообщения
231
Реакции
137
Гарант сделки
2
Депозит
0.00
Всем привет! Выпало чуток свободного времени, бесплатно напишу софт по вашему ТЗ/помогу скомпилить/исправить существующий софт. Все исходники будут выкладываться в теме.
 
Функция по получению списка физических дисков (PhysicalDrive) Windows.
Структура диска должна содержать тип диска и его разделы (LogicalDrive).

Знаю, что раздел и LogicalDrive не одно и тоже, но в данном контексте можно пренебречь этой неточностью.

Код:
enum DriveType {
    SSD,
    HDD,
}
struct PhysicalDrive {
    partitions: Vec<LogicalDrive>,
    _type: DriveType,
}
struct LogicalDrive {
    mount: PathBuf
}
fn physical_drives() -> Vec<PhysicalDrive> {
    todo!()
}

Не надеюсь, что ты будешь этим заниматься, если честно)
 
Функция по получению списка физических дисков (PhysicalDrive) Windows.
Структура диска должна содержать тип диска и его разделы (LogicalDrive).

Знаю, что раздел и LogicalDrive не одно и тоже, но в данном контексте можно пренебречь этой неточностью.

Код:
enum DriveType {
    SSD,
    HDD,
}
struct PhysicalDrive {
    partitions: Vec<LogicalDrive>,
    _type: DriveType,
}
struct LogicalDrive {
    mount: PathBuf
}
fn physical_drives() -> Vec<PhysicalDrive> {
    todo!()
}

Не надеюсь, что ты будешь этим заниматься, если честно)
Возьмусь, скинь пример результата.
 
Что-то такого плана:

Код:
[
    PhysicalDrive {
        partitions: [
            LogicalDrive {
                mount: "C:/",
            },
            LogicalDrive {
                mount: "D:/",
            },
        ],
        _type: SSD,
    },
    PhysicalDrive {
        partitions: [
            LogicalDrive {
                mount: "E:/",
            },
        ],
        _type: HDD,
    },
]

То есть нужно понять какие в системе есть физические диски и какие разделы к ним привязанны.
 
Что-то такого плана:

Код:
[
    PhysicalDrive {
        partitions: [
            LogicalDrive {
                mount: "C:/",
            },
            LogicalDrive {
                mount: "D:/",
            },
        ],
        _type: SSD,
    },
    PhysicalDrive {
        partitions: [
            LogicalDrive {
                mount: "E:/",
            },
        ],
        _type: HDD,
    },
]

То есть нужно понять какие в системе есть физические диски и какие разделы к ним привязанны.
Вроде как нужно получить все логические диски (GetLogicalDrives()/GetLogicalDrivesStringsW(...)), получить хэндл \\.\{disk_letter}: (с правами админа) и далее DeviceIoControl(...) - но не пойму какие control codes нужны для получения инфы о разделах?
 
Вроде как нужно получить все логические диски (GetLogicalDrives()/GetLogicalDrivesStringsW(...)), получить хэндл \\.\{disk_letter}: (с правами админа) и далее DeviceIoControl(...) - но не пойму какие control codes нужны для получения инфы о разделах?

Да, нужны права для получения дескриптора диска. Вчера писидел немного. Решил получить для начала физические диски. Это сделать удалось. Теперь нужно через DeviceIoControl получить партишены как-то.

Вот контрольные коды, которые могут понадобиться:

Если доделаю, дополню код. Или может у тебя получится.

Текущий набросок:

Код:
use windows_sys::Win32::Devices::DeviceAndDriverInstallation::{
    DIGCF_DEVICEINTERFACE, DIGCF_PRESENT, SP_DEVICE_INTERFACE_DATA,
    SP_DEVICE_INTERFACE_DETAIL_DATA_W, SetupDiGetClassDevsW,
    SetupDiEnumDeviceInterfaces, SetupDiGetDeviceInterfaceDetailW
};
use windows_sys::Win32::Foundation::{
    FALSE, INVALID_HANDLE_VALUE, ERROR_INSUFFICIENT_BUFFER,
    GENERIC_READ, BOOL, HANDLE, CloseHandle
};
use windows_sys::Win32::System::Ioctl::{
    GUID_DEVINTERFACE_DISK, IOCTL_STORAGE_GET_DEVICE_NUMBER,
    STORAGE_DEVICE_NUMBER, IOCTL_DISK_GET_DRIVE_LAYOUT_EX
};
use windows_sys::Win32::System::IO::DeviceIoControl;
use windows_sys::Win32::Storage::FileSystem::{
    FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_SHARE_WRITE,
    OPEN_EXISTING, CreateFileW
};
use std::path::PathBuf;
use std::ptr;
use std::mem;
use std::io;

pub struct PhysicalDrive {
    partitions: Vec<LogicalDrive>
}

pub struct LogicalDrive {
    mount: Option<PathBuf>
}

pub fn local() -> io::Result<Vec<PhysicalDrive>> {
    let disk_class_devices = unsafe {
        SetupDiGetClassDevsW(
            &GUID_DEVINTERFACE_DISK,
            ptr::null(),
            0,
            DIGCF_PRESENT | DIGCF_DEVICEINTERFACE
        )
    };
    
    if disk_class_devices == INVALID_HANDLE_VALUE {
        return Err(io::Error::last_os_error())
    }

    let mut device_iface_data = SP_DEVICE_INTERFACE_DATA {
        cbSize: mem::size_of::<SP_DEVICE_INTERFACE_DATA>() as u32,
        ..unsafe { mem::zeroed() }
    };

    for device_index in 0.. {
        if cvt(unsafe {
            SetupDiEnumDeviceInterfaces(
                disk_class_devices,
                ptr::null(),
                &GUID_DEVINTERFACE_DISK,
                device_index,
                &mut device_iface_data
            )
        }).is_err() {
            break
        }

        let mut required_size = 0;

        if let Err(e) = cvt(unsafe {
            SetupDiGetDeviceInterfaceDetailW(
                disk_class_devices,
                &device_iface_data,
                ptr::null_mut(),
                0,
                &mut required_size,
                ptr::null_mut(),
            )
        }) {
            let err = e.raw_os_error()
                .map(|raw| raw as u32 != ERROR_INSUFFICIENT_BUFFER)
                .unwrap_or(false);
            if err {
                return Err(e);
            }
        }

        let align = mem::align_of::<SP_DEVICE_INTERFACE_DETAIL_DATA_W>();
        let buf_size = required_size as usize + align - 1;
        let mut buf = Vec::<u8>::with_capacity(buf_size);
        let offset = buf.as_mut_ptr().align_offset(align);

        let device_iface_detail = unsafe {
            &mut *(buf.as_mut_ptr().offset(offset as isize)
                as *mut mem::MaybeUninit<SP_DEVICE_INTERFACE_DETAIL_DATA_W>)
        };

        device_iface_detail.write(
            SP_DEVICE_INTERFACE_DETAIL_DATA_W {
                cbSize: mem::size_of::<SP_DEVICE_INTERFACE_DETAIL_DATA_W>() as u32,
                DevicePath: [0],
            }
        );

        cvt(unsafe {
            SetupDiGetDeviceInterfaceDetailW(
                disk_class_devices,
                &device_iface_data,
                device_iface_detail.as_mut_ptr(),
                required_size,
                ptr::null_mut(),
                ptr::null_mut()
            )   
        })?;

        let path = ptr::addr_of! (
            unsafe { device_iface_detail.assume_init_ref() }.DevicePath[0]
        );

        let storage = Handle::new(unsafe {
            CreateFileW(
                path,
                GENERIC_READ,
                FILE_SHARE_READ | FILE_SHARE_WRITE,
                ptr::null(),
                OPEN_EXISTING,
                FILE_ATTRIBUTE_NORMAL,
                0
            )
        })?;

        let mut number = unsafe {
            mem::zeroed::<STORAGE_DEVICE_NUMBER>()
        };

        let mut bytes_returned = 0;

        cvt(unsafe {
            DeviceIoControl(
                storage.raw(),
                IOCTL_STORAGE_GET_DEVICE_NUMBER,
                ptr::null(),
                0,
                &mut number as *const _ as _,
                mem::size_of::<STORAGE_DEVICE_NUMBER>() as u32,
                &mut bytes_returned,
                ptr::null_mut()
            )
        })?;

        dbg!(number.DeviceNumber);
    }
    todo!()
}

struct Handle(HANDLE);
impl Handle {
    fn new(handle: HANDLE) -> io::Result<Self> {
        if handle == INVALID_HANDLE_VALUE {
            Err(io::Error::last_os_error())
        } else {
            Ok(Handle(handle))
        }
    }
    fn raw(&self) -> HANDLE {
        self.0
    }
}
impl Drop for Handle {
    fn drop(&mut self) {
        unsafe { CloseHandle(self.0) };
    }
}

fn cvt(status: BOOL) -> io::Result<BOOL> {
    if status == FALSE {
        Err(io::Error::last_os_error())
    } else {
        Ok(status)
    }
}
 
Тип диска HDD/SSD безошибочно (и с малой кровью) можно получить несколькоми способами:

1. Послать диску ATA-команду "IDENTIFY_DEVICE = ECh" и в возвращённой структуре "IDENTIFY_DEVICE_DATA" (см.хидер ATA.h) проверить слово(217) под названием "NomimalMediaRotationRate" (скорость вращения носителя). У дисков SSD нет блинов, поэтому скорость будет =1. Любые другие значения указывают на HDD.

2. Послать драйверу запрос "IOCTL_STORAGE_QUERY_PROPERTY" с флагом PropertyId =14h (StorageDeviceProtocolSpecificProperty). Другой вариант PropertyId =7 (StorageDeviceSeekPenaltyProperty), который возвращает наличие задержки перед поиском файлов на носителе. Логическая единица, и для SSD должно быть False=0 (нет задержки, в виде времени на перемещение головок HDD).

3. Через "IOCTL_SMART_RCV_DRIVE_DATA" запросить у диска SMART, где среди прочего будет информация и об SSD, например атрибут(64h) "Erase/Program Cycles" (счётчик стирания/программирования за всё время работы SSD). В случае HDD здесь будет лежать нуль. Прочие атрибуты см.здесь.

Есть и другие варианты чекнуть на HDD/SSD, но они работают только на Win8/10/11. А перечисленные выше способы универсальны по убывающей, вплоть до Win-XP.
 
Тип диска HDD/SSD безошибочно (и с малой кровью) можно получить несколькоми способами
Это полезно, спасибо. Вы случайно не знаете, как можно определить программный/аппаратный рейд?
 
как можно определить программный/аппаратный рейд?
"IOCTL_STORAGE_QUERY_PROPERTY" с флагом PropertyId =0 (StorageDeviceProperty).
Функция DeviceIoControl() вернёт данные в структуру "STORAGE_DEVICE_DESCRIPTOR", в которой нужно проверить поле "BusType". Возможные значения в нём перечислены ниже, так-что можно чекать диски не только на RAID=8, но возможно и на SSD (NVM=17, Non Voltage Memory), хотя я не проверял:

C-подобный:
;// http://msdn.microsoft.com/en-us/library/aa363465(VS.85).aspx
;// Константы "STORAGE_BUS_TYPE" ===============================
;//=============================================================
   BusTypeUnknown      = 0
   BusTypeScsi         = 1
   BusTypeAtapi        = 2
   BusTypeAta          = 3
   BusType1394         = 4
   BusTypeSsa          = 5
   BusTypeFibre        = 6
   BusTypeUsb          = 7
   BusTypeRAID         = 8
   BusTypeiSCSI        = 9
   BusTypeSas          = 10
   BusTypeSata         = 11
   BusTypeSd           = 12
   BusTypeMmc          = 13
   BusTypeVirtual      = 14
   BusTypeSpaces       = 16
   BusTypeNvme         = 17
   BusTypeSCM          = 18
   BusTypeUfs          = 19
   BusTypeMaxReserved  = 127

Так можно вычислить аппаратный RAID, но если нужно программный (RAID=0,1,5), то как вариант, через FindFirstVolume/FindNextVolume() перебирать все разделы, и если встретим две (и более) одинаковые буква типа C:\ , то делаем вывод, что это массив RAID. Возможно есть и другие способы - не знаю..
 
Последнее редактирование:
Это полезно, спасибо.
У меня нет дисков SSD, а потому проверить варианты не могу.
Если у вас сработает хоть какой-то из способов определения SSD/RAID, то просьба отписаться.
 
У меня нет дисков SSD, а потому проверить варианты не могу.
Если у вас сработает хоть какой-то из способов определения SSD/RAID, то просьба отписаться.

Спасибо огромное. Постараюсь доделать сбор дисков в ближайшее время, опираясь на ваши подсказки в том числе. Исходный код залью сюда.

В принципе, если говорить о распределенной i/o нагрузке, то в этой ветке уже все основные моменты перечисленны:

- Получение физических дисков
- Получение типа диска и других метаданных
- Привязка потоков (кол-во зависит от полученных данных, для этого они и нужны)
- Получение разделов диска, монтирование неактивных
- Payload...

Осталось написать только нормально)
 
Да, можешь скинуть код, гляну.
Ты язык Solidity помимо Rust, понимаешь? В плане смарт-контрактов и ботов.
 
Последнее редактирование:
Блин интересно как ты напишешь утилиту которая делает скриншот и сохраняет его в данное пользывателем из команднай строки месте.
учти утилита должна не откревать акошка или как либо показываться ползевателю
 
Блин интересно как ты напишешь утилиту которая делает скриншот и сохраняет его в данное пользывателем из команднай строки месте.
учти утилита должна не откревать акошка или как либо показываться ползевателю
Напишу - поддержка каких систем нужна? Какие-либо пожелания по функционалу?
 
Напишу - поддержка каких систем нужна? Какие-либо пожелания по функционалу?
планиревал для 10ки можно и 11 а там посмотрим.
кидаю парачку идей каторех можно будет позже воплатит
- имперсанацу пользывателя делала (чтобе админ мог скриншотить других пользыватели на компе).
- еще так чтобе место не забывать (всякие jpegи, чб ...)
 
Последнее редактирование:
- имперсанацу пользывателя делала (чтобе админ мог скриншотить других пользыватели на компе).
Не уверен, что это реализуемо. Если только копировать бинарник к пользователю, добавлять там в авторан, который отработает при входе юзера (планировщик, например).
В остальном реализовал всё по ТЗ. Для сборки нужно установить тулчейн раста, MSVC, далее просто запустить батник build.bat. В архиве есть скомпилированная версия.
Использование:
Код:
 Usage: win-screen.exe [options]
     -h - print help (this message)
     -o "%USERPROFILE%\AppData\some_solder" - output folder for saving screens
     -i 5000 - screen interval in milliseconds
     -f jpg|jpeg|png|gif|bmp - screen format
     -u user_name:user_password - run win-screen.exe on other user // unimplemented
 ~/xss.pro
Линк: DaMaGeLiB - win-screen_0.1.0.zip
 
Последнее редактирование:


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх