2008-12-12 1 views
3

Я уже некоторое время изучаю способ предотвратить случайное попадание моего пользователя в каталог данных моего приложения.Каталог проводника Windows как комплект

В моем приложении используется папка для хранения структурированного проекта. Внутренняя структура папки является критикой и не должна быть перепутана. Я хотел бы, чтобы мой пользователь увидел эту папку в целом и не смог ее открыть (например, пакет Mac).

Есть ли способ сделать это в Windows?

Редактировать от текущих ответов

Конечно, я не пытаюсь помешать своим пользователям доступа к данным, только защищая их от случайного нарушения целостности данных. Поэтому шифрование или защита паролем не нужны.

Благодарим всех вас за ответы .Net, но, к сожалению, это в основном проект C++ без какой-либо зависимости .Net framework.

Данные, которые я упоминаю, не являются светлыми, они получают изображения с электронного микроскопа. Эти данные могут быть огромными (~ 100 MiB до ~ 1 GiB), поэтому загрузка всего в память не является вариантом. Это огромные изображения, поэтому хранилище должно обеспечить способ постепенного чтения данных путем одновременного доступа к одному файлу без загрузки всего архива в память.

Кроме того, приложение в основном наследие с некоторыми компонентами, за которые мы даже не несем ответственности. Предпочтительным является решение, которое позволяет мне сохранить текущий код ввода-вывода.

Shell Extension выглядит интересно, я буду исследовать решение дальше.

LarryF, можете ли вы подробно остановиться на фильтре-драйвере или DefineDOSDevice? Я не знаком с этими понятиями.

+0

Можете ли вы пролить свет на какой язык/среду вы находитесь? – Tomalak 2008-12-12 19:31:15

+0

Конечно, обновленный ответ – 2008-12-13 14:55:56

ответ

0

Похоже на то, что некоторые из Windows ports of FUSE начинают появляться. Я думаю, что это было бы лучшим решением, поскольку это позволило бы мне сохранить прежний код (который довольно большой) нетронутым.

1

Внутри или вне вашей программы?

Есть способы, но ни один из них не является простым. Вероятно, вы будете искать драйвер фильтра в файловой системе.

0

Вы можете обернуть каталог проекта в ZIP-файл и сохранить там свои данные, как и использовать .jar (я знаю, что .jar в значительной степени доступен для чтения, это для примера). Сделайте нестандартное расширение, чтобы двойной щелчок не произвел немедленного эффекта. ;-)

Конечно, это означает, что вам придется обернуть весь файл IO, чтобы использовать .zip вместо этого, в зависимости от того, как ваша программа построена, это может быть утомительным. Это уже сделано для Java: TrueZip. Может быть, вы можете использовать это как вдохновение?

Если у вас возникло искушение - я бы не рекомендовал возиться с разрешениями на папку, по понятным причинам это не поможет.

1

Есть несколько вещей, которые вы могли бы сделать:

Одна вещь, что вы можете создать FolderView для Windows Shell Extension, которая позволит создать пользовательское представление для вашей критической папки. Создав собственный FolderView, вы можете сделать папку просто белой с одной строкой текста «Nothing to see here», или вы можете сделать что-то более сложное, например, средство просмотра GAC, которое использует этот же метод. Этот метод был бы довольно сложным, но эту сложность можно смягчить, используя в качестве основы библиотеку статей, например, this CodeProject.

Другим решением будет создание виртуальной файловой системы ZIP, для этого потребуется заменить любой код, который использует System.IO напрямую, чтобы использовать что-то еще. ASP.NET 2.0 сделал это по этой точной причине, и вы могли бы построить ontop этого довольно легко, взгляните на этот MSDN Article на реализацию VirtualPathProvider.

+0

Похоже, что это в основном для ASP.NET, но он ничего не упоминал об ASP или .NET ... Однако идеи хороши. – LarryF 2008-12-12 20:42:10

0

Имейте в виду: если вы храните его в Файловой системе, пользователь ВСЕГДА сможет ее увидеть. Тампер с проводником, и я вместо этого использую cmd.exe. Или Total Commander. Или что-нибудь еще.

Если вы не хотите, чтобы люди возиться с файлами, я бы рекомендовал

  • их шифрование для предотвращения несанкционированного доступа с файлами
  • ставящих их в архиве (т.е. ZIP), возможно, пароль -protecting, а затем сжатия/разжатия во время выполнения (я бы искать алгоритмы, которые быстро в модифицирующих архивах)

это не полная защита, конечно, но это довольно прямо вперед в реализации, не требует вы устанавливаете фанки операционную систему и следует избегать самых любопытных пользователей.

Конечно, вы никогда не сможете полностью контролировать файлы на компьютере пользователя, не управляя самим компьютером.

0

Я видел программное обеспечение (Agilian Visual Paradigm), которое использовало предложение Tomalak zip-архива как «файл проекта». Zip-файлы хорошо поняты, а использование нестандартного расширения файлов не позволяет случайному пользователю входить в «файл». Одно из больших преимуществ заключается в том, что в случае коррупции стандартные средства могут использоваться для устранения проблемы, и вам не нужно беспокоиться о создании специальных инструментов для поддержки вашего основного приложения.

1

Если вы берете ZIP-файл aproach (который я рассматривал для вас, но не упоминал об этом), я бы предложил использовать алгоритм дефляции, но использовать вашу собственную файловую систему ... Посмотрите на что-то вроде формата TAR , Затем просто напишите свой код, чтобы передать ВСЕ I/O мимо алгоритмов Inflate/Deflate, когда они записываются на диск. Я бы не использовал ZIP «FORMAT», так как слишком просто посмотреть на файл, найти PK в качестве первых двух байтов и разархивировать файл ...

Мне нравятся предложения Joshperry.

Конечно, вы также можете написать драйвер устройства, в котором хранятся все ваши данные внутри одного файла, но опять же мы смотрим на драйвер. (Я не уверен, что вы могли бы реализовать его за пределами драйвера. Вы PROBABLY можете и внутри вашей программы вызывать DefineDOSDevice, указывая ему имя, к которому имеет доступ только ваш код, и он будет рассматриваться как обычная файловая система.). Я буду играть с некоторыми идеями, и если они будут работать, я застрелю вам образец. Теперь ты меня заинтересовал.

0

Я рад слышать, что вы делаете это на C++. Похоже, что никто больше не видит C++ как «необходимого». Это все C# это, и ASP.NET, что ... Даже я работаю во всем доме C#, когда я поклялся, что бы никогда не выключал, поскольку C++ делает все, что мне когда-либо понадобится, а затем и некоторые. Я достаточно взрослый, чтобы очистить свою память! хех .. В любом случае, вернемся к проблеме ...

DefineDOSDevice() - это метод, который используется для назначения букв дисков, имен портов (LPT1, COM1 и т. Д.). Вы передаете ему имя, некоторые флаги и «путь», который обрабатывает это устройство. Но не позволяйте этому обмануть вас. Это не путь к файловой системе, это путь объекта NT. Я уверен, что вы видели их как «\ Device \ HardDisk0» и т. Д. Вы можете использовать WinObj.exe из sysinternals, чтобы понять, что я имею в виду. В любом случае вы можете создать драйвер устройства, а затем указать на него ссылку на MSDOS, и вы выключены и запущены. Но предоставлено это, похоже, большая работа для оригинальной проблемы.

Сколько из этих мега-гигабайтных файлов находится в типичном каталоге? Вам может быть лучше всего вклеить все файлы внутри одного гигантского файла и сохранить рядом с ним индексный файл (или заголовок для каждого файла), который указывает на следующий «файл» в вашем файле «virtual FileSystem».

Хорошим примером может быть просмотр формата Microsoft MSN Archive. Я отменил этот формат архива, когда я работал в AV-компании, и на самом деле он довольно креативен, но ОЧЕНЬ прост. Это может быть сделано в одном файле, и если вы хотите получить фантазию, вы должны сохранить данные по 3 файлам в конфигурации типа RAID 5, поэтому, если какой-либо из 3-х файлов будет запущен, вы можете перестроить остальные , Кроме того, пользователи просто видят 3 ОЧЕНЬ больших файлов в каталоге и не смогут получить доступ к отдельным (внутренним) файлам.

Я предоставил вам код, который распаковывает один из этих форматов MSN Archive. У меня нет кода, который CREATES один, но из источника извлечения, вы могли бы построить/написать один без проблем. Если файлы удаляются и/или часто переименовываются, это может создать проблему с использованным пространством в файле, которое время от времени нужно будет обрезать.

Этот формат даже поддерживает поля CRC, поэтому вы можете проверить, есть ли у вас файл в порядке. Я никогда не мог полностью отменить алгоритм, используемый Microsoft для CRC-данных, но у меня есть довольно хорошая идея.

Вы не сможете поддерживать текущие процедуры ввода-вывода, то есть CreateFile() не сможет просто открыть любой файл в архиве, однако с uber-coolness на C++ вы можете переопределить CreateFile для реализации формата архива.

Если вам нужна помощь, и это довольно серьезная проблема, возможно, мы могли бы поговорить в автономном режиме и найти решение для вас.

Я не против писать вам FileSystemDriver, но для этого нам придется начать говорить о компенсации. Я был бы более чем счастлив дать вам направление и идеи бесплатно, как и сейчас.

Я не уверен, что для меня здесь кошерный адрес, чтобы сообщить вам свой адрес электронной почты, я не уверен в политике SO, поскольку мы можем говорить о потенциальной работе/приглашении, но это не моя единственная намерение. Я бы скорее помог вам найти ваши собственные решения.

Перед тем, как заглянуть в драйвер устройства, загрузите WinDDK. На нем есть образцы драйверов.

Если вы задаетесь вопросом, почему я так сильно об этом беспокоюсь, это связано с тем, что в течение многих лет мне приходилось писать драйвер, похожий на этот, который должен был быть Windows И OSX совместим, что позволит пользователям для защиты томов накопителей (USB-ключей, съемных томов) БЕЗ установки каких-либо драйверов или сложного (и громоздкого, иногда раздражающего) программного обеспечения. В последние годы многие производители оборудования сделали аналогичные вещи, но я не думаю, что безопасность - все это безопасно. Я смотрю на использование RSA и AES, точно так же, как GPG и PGP.Первоначально меня связали об этом, для чего (я считаю, но не имею никаких доказательств) собирались использовать для защиты файлов MP3. Поскольку они будут храниться в зашифрованном формате, они просто не будут работать без правильной кодовой фразы. Но я видел и другие варианты использования. (Это было обратно, когда 16 Мб (да MEG) USB-ключ стоил более 100 долларов или около того).

Этот проект также сочетался с моей системой безопасности ПК в нефтяной и газовой промышленности, которая использовала нечто похожее на смарт-карты, гораздо проще в использовании, повторное использование/повторное выдачу, невозможное (читай: ОЧЕНЬ сложно и маловероятно) взломать, и я мог бы использовать его у своих детей дома! (Поскольку всегда есть борьба за то, кто получает время на компьютере, и кто получил больше всего, и дальше, и дальше, и дальше, и ...)

Phew .. Думаю, я ушел от темы здесь. В любом случае, вот пример формата архива Microsoft MSN. Посмотрите, можете ли вы использовать что-то вроде этого, зная, что вы всегда можете «пропустить» право на файл, выполнив смещения в файле при анализе/поиске запрошенного файла в главном файле; или в предварительно проанализированных данных, хранящихся в памяти. И так как вы не загружаете необработанные двоичные данные файла в памяти, ваш единственный предел, вероятно, будет ограничением файла 4gb на 32-битных машинах.

Формат MARC (Microsoft MSN Archive) выложена (свободно), как это:

  • 12 байт заголовка (только один)
    • Файл Волшебства
    • МАРК версия
    • Номер файлов (в следующей таблице)
  • 68 Байт файла Таблица заголовков (от 1 до Hea der.NumFiles из них)
    • Имя файла
    • Размер файла
    • Контрольная сумма
    • смещение к Необработанные данные файла

Теперь, в 12 байт записей таблицы файлов, 32 биты используются для длины файла и смещения. Для ваших ОЧЕНЬ больших файлов вам может потребоваться до 48 или 64 бит целых чисел.

Вот код, который я написал, чтобы справиться с этим.

#define MARC_FILE_MAGIC   0x4352414D // In Little Endian 
#define MARC_FILENAME_LEN  56 //(You'll notice this is rather small) 
#define MARC_HEADER_SIZE  12 
#define MARC_FILE_ENT_SIZE  68 

#define MARC_DATA_SIZE   1024 * 128 // 128k Read Buffer should be enough. 

#define MARC_ERR_OK    0  // No error 
#define MARC_ERR_OOD    314 // Out of data error 
#define MARC_ERR_OS    315 // Error returned by the OS 
#define MARC_ERR_CRC    316 // CRC error 

struct marc_file_hdr 
{ 
    ULONG   h_magic; 
    ULONG   h_version; 
    ULONG   h_files; 
    int    h_fd; 
    struct marc_dir *h_dir; 
}; 

struct marc_file 
{ 
    char   f_filename[MARC_FILENAME_LEN]; 
    long   f_filesize; 
    unsigned long f_checksum; 
    long   f_offset; 
}; 

struct marc_dir 
{ 
    struct marc_file  *dir_file; 
    ULONG     dir_filenum; 
    struct marc_dir  *dir_next; 
}; 

Это дает вам представление о заголовках, которые я написал для них, и вот открытая функция. Да, у него отсутствуют все вызовы поддержки, процедуры err и т. Д., Но вы получаете эту идею. Извините, пожалуйста, код стиля кода C и C++. Наш сканер представлял собой множество различных проблем, таких как ... Я использовал античные звонки, такие как open(), fopen(), чтобы поддерживать стандарты с остальной базой кода.

struct marc_file_hdr *marc_open(char *filename) 
{ 
    struct marc_file_hdr *fhdr = (struct marc_file_hdr*)malloc(sizeof(marc_file_hdr)); 
    fhdr->h_dir = NULL; 

#if defined(_sopen_s) 
    int errno = _sopen_s(fhdr->h_fd, filename, _O_BINARY | _O_RDONLY, _SH_DENYWR, _S_IREAD | _S_IWRITE); 
#else 
    fhdr->h_fd = open(filename, _O_BINARY | _O_RDONLY); 
#endif 
    if(fhdr->h_fd < 0) 
    { 
     marc_close(fhdr); 
     return NULL; 
    } 

    //Once we have the file open, read all the file headers, and populate our main headers linked list. 
    if(read(fhdr->h_fd, fhdr, MARC_HEADER_SIZE) != MARC_HEADER_SIZE) 
    { 
     errmsg("MARC: Could not read MARC header from file %s.\n", filename); 
     marc_close(fhdr); 
     return NULL; 
    } 

    // Verify the file magic 
    if(fhdr->h_magic != MARC_FILE_MAGIC) 
    { 
     errmsg("MARC: Incorrect file magic %x found in MARC file.", fhdr->h_magic); 
     marc_close(fhdr); 
     return NULL; 
    } 

    if(fhdr->h_files <= 0) 
    { 
     errmsg("MARC: No files found in archive.\n"); 
     marc_close(fhdr); 
     return NULL; 
    } 

    // Get all the file headers from this archive, and link them to the main header. 
    struct marc_dir *lastdir = NULL, *curdir = NULL; 
    curdir = (struct marc_dir*)malloc(sizeof(marc_dir)); 
    fhdr->h_dir = curdir; 

    for(int x = 0;x < fhdr->h_files;x++) 
    { 
     if(lastdir) 
     { 
      lastdir->dir_next = (struct marc_dir*)malloc(sizeof(marc_dir)); 
      lastdir->dir_next->dir_next = NULL; 
      curdir = lastdir->dir_next; 
     } 

     curdir->dir_file = (struct marc_file*)malloc(sizeof(marc_file)); 
     curdir->dir_filenum = x + 1; 

     if(read(fhdr->h_fd, curdir->dir_file, MARC_FILE_ENT_SIZE) != MARC_FILE_ENT_SIZE) 
     { 
      errmsg("MARC: Could not read file header for file %d\n", x); 
      marc_close(fhdr); 
      return NULL; 
     } 
     // LEF: Just a little extra insurance... 
     curdir->dir_file->f_filename[MARC_FILENAME_LEN] = NULL; 

     lastdir = curdir; 
    } 
    lastdir->dir_next = NULL; 

    return fhdr; 
} 

Затем у вас есть простой способ экстракции. Имейте в виду, что это было строго для сканирования вирусов, поэтому нет поисковых подпрограмм и т. Д. Это было предназначено, чтобы просто выгрузить файл, отсканировать его и продолжить. Ниже приведена программа CRC-кода, которую я ВЕРЮ, чтобы использовать Microsoft, но я не уверен WHAT именно они CRC'ed. Он может включать данные заголовка + данные файла и т. Д. Я просто не заботился о том, чтобы вернуться и попытаться отменить его. В любом случае, как вы можете видеть, в этом архиве нет сжатия, но это ОЧЕНЬ легко добавить.Если вы хотите, можно предоставить полный источник. (Я думаю, что все, что осталось, это близко() рутина, и код, который вызывает и извлекает каждый файл, и т.д. !!)

bool marc_extract(struct marc_file_hdr *marc, struct marc_file *marcfile, char *file, int &err) 
{ 
    // Create the file from marcfile, in *file's location, return any errors. 
    int ofd = 0; 
#if defined(_sopen_s) 
    err = _sopen_s(ofd, filename, _O_CREAT | _O_SHORT_LIVED | _O_BINARY | _O_RDWR, _SH_DENYNO, _S_IREAD | _S_IWRITE); 
#else 
    ofd = open(file, _O_CREAT | _O_SHORT_LIVED | _O_BINARY | _O_RDWR); 
#endif 

    // Seek to the offset of the file to extract 
    if(lseek(marc->h_fd, marcfile->f_offset, SEEK_SET) != marcfile->f_offset) 
    { 
     errmsg("MARC: Could not seek to offset 0x%04x for file %s.\n", marcfile->f_offset, marcfile->f_filename); 
     close(ofd); 
     err = MARC_ERR_OS; // Get the last error from the OS. 
     return false; 
    } 

    unsigned char *buffer = (unsigned char*)malloc(MARC_DATA_SIZE); 

    long bytesleft = marcfile->f_filesize; 
    long readsize = MARC_DATA_SIZE >= marcfile->f_filesize ? marcfile->f_filesize : MARC_DATA_SIZE; 
    unsigned long crc = 0; 

    while(bytesleft) 
    { 
     if(read(marc->h_fd, buffer, readsize) != readsize) 
     { 
      errmsg("MARC: Failed to extract data from MARC archive.\n"); 
      free(buffer); 
      close(ofd); 
      err = MARC_ERR_OOD; 
      return false; 
     } 

     crc = marc_checksum(buffer, readsize, crc); 

     if(write(ofd, buffer, readsize) != readsize) 
     { 
      errmsg("MARC: Failed to write data to file.\n"); 
      free(buffer); 
      close(ofd); 
      err = MARC_ERR_OS; // Get the last error from the OS. 
      return false; 
     } 
     bytesleft -= readsize; 
     readsize = MARC_DATA_SIZE >= bytesleft ? bytesleft : MARC_DATA_SIZE; 
    } 

    // LEF: I can't quite figure out how the checksum is computed, but I think it has to do with the file header, PLUS the data in the file, or it's checked on the data in the file 
    //  minus any BOM's at the start... So, we'll just rem out this code for now, but I wrote it anyways. 
    //if(crc != marcfile->f_checksum) 
    //{ 
    // warningmsg("MARC: File CRC does not match. File could be corrupt, or altered. CRC=0x%08X, expected 0x%08X\n", crc, marcfile->f_checksum); 
    // err = MARC_ERR_CRC; 
    //} 

    free(buffer); 
    close(ofd); 

    return true; 
} 

Здесь MY предполагается процедура CRC (я, возможно, украл из Стюарта Caie и libmspack, я не могу вспомнить):

static unsigned long marc_checksum(void *pv, UINT cb, unsigned long seed) 
{ 
    int count = cb/4; 
    unsigned long csum = seed; 
    BYTE *p = (BYTE*)pv; 
    unsigned long ul; 

    while(count-- > 0) 
    { 
     ul = *p++; 
     ul |= (((unsigned long)(*p++)) << 8); 
     ul |= (((unsigned long)(*p++)) << 16); 
     ul |= (((unsigned long)(*p++)) << 24); 
     csum ^= ul; 
    } 

    ul = 0; 
    switch(cb % 4) 
    { 
     case 3: ul |= (((unsigned long)(*p++)) << 16); 
     case 2: ul |= (((unsigned long)(*p++)) << 8); 
     case 1: ul |= *p++; 
     default: break; 
    } 
    csum ^= ul; 

    return csum; 
}                      

Ну, я думаю, что сейчас этот пост достаточно долго ... Свяжитесь со мной, если вам нужна помощь или есть вопросы.

1

Structured Storage был разработан для сценария, который вы описываете:

Structured Storage обеспечивает файл и сохранение данных в COM с помощью обработки одного файла как структурированный набор объектов, известных как хранилища и потоков.

«Хранилище» аналогично папке, а «поток» аналогичен файлу. В основном у вас есть один файл, который при доступе с использованием API структурированных хранилищ ведет себя и выглядит как полная автономная файловая система.

Примите к сведению, однако, что:

Четкое понимание COM технологий является необходимым условием для использования развивающего структурированных хранения.