Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > Виртуальная память


Автор: freezeman 27.3.2012, 19:36
Привет всем!

Подскажите, пожалуйста. Я сделал перехват winapi функции ReadFile и нужно занести файл, который читался этой функцией в ОП.
Какой метод будет самым быстрым? Проецирование или виртуальная память? 

И ещё, после того как я записал файл в память, мне нужно при следующем перехвате ReadFile передать указатель на мой файл в ОП,
просто подменив HANDLE у ReadFile... как получить этот HANDLE у файла в ОП?

Или все же проецирование использовать?? Я уже запутался, помогите...

Автор: Akira 27.3.2012, 21:55
Честно, несколько раз перечитывал и не понял что нужно. Выдохни и опиши что ты хочешь хочешь сделать и что хукаешь (импорт или dll). Насколько я понял подмену чтения файла, если так, то открывай файл который будешь подсовывать, как открывать зависит от размера, если несколько килло то нет смысла мапить и прописывай HANDLE своего файла, указатель трогать незачем, буфер уже выделен (или нужно?), а так, проще и правильнее (хуки зло) хукнуть CreateFile.

Автор: freezeman 27.3.2012, 22:09
Цитата(Akira @ 27.3.2012,  21:55)
Честно, несколько раз перечитывал и не понял что нужно. Выдохни и опиши что ты хочешь хочешь сделать и что хукаешь (импорт или dll). Насколько я понял подмену чтения файла, если так, то открывай файл который будешь подсовывать, как открывать зависит от размера, если несколько килло то нет смысла мапить и прописывай HANDLE своего файла, указатель трогать незачем, буфер уже выделен (или нужно?), а так, проще и правильнее (хуки зло) хукнуть CreateFile.

У меня перехватывается функция ReadFile, я набираю статистику по перехвату/обращению и наиболее часто используемые файлы хочу поместить в ОП.
Затем при следующем перехвате, если я определю, что файл уже в ОП, то в перехваченную функцию ReadFile нужно как-то передать "указатель" на этот же файл, но в ОП.

Вопроса в общем 2: как лучше заносить файл в ОП и как получить HANDLE этого файла в ОП (чтобы просто подставить в перехваченную ReadFile и все) или можно как-то другим методом это реализовать?

Автор: Akira 27.3.2012, 23:03
Решение в лоб - Мапить файл и из проекции заполнять буфер (указатель) размер сколько читать передается. ReadFile не трогать. 

Автор: freezeman 27.3.2012, 23:20
Цитата(Akira @ 27.3.2012,  23:03)
Решение в лоб - Мапить файл и из проекции заполнять буфер (указатель) размер сколько читать передается. ReadFile не трогать.

Спасибо за совет, проверю его завтра..)

Добавлено через 6 минут и 44 секунды
Цитата(freezeman @ 27.3.2012,  23:20)
Цитата(Akira @ 27.3.2012,  23:03)
Решение в лоб - Мапить файл и из проекции заполнять буфер (указатель) размер сколько читать передается. ReadFile не трогать.

Спасибо за совет, проверю его завтра..)

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

Автор: freezeman 28.3.2012, 11:43
Подскажите, please!!))

Автор: Akira 28.3.2012, 13:06
Если я просто заполню буфер тупо по параметрам вызова ReadFile, то вернуть системе этот ReadFile не получится без проблем...
Какие еще проблемы?

Автор: freezeman 28.3.2012, 13:35
Цитата(Akira @ 28.3.2012,  13:06)
Если я просто заполню буфер тупо по параметрам вызова ReadFile, то вернуть системе этот ReadFile не получится без проблем...
Какие еще проблемы?

После перехвата функции ReadFile нужно вернуть её системе, модифицированную или нет, а если я просто заполню буфер, то что указывать в указателе на файл (первый параметр - HANDLE), NULL?

Автор: GremlinProg 28.3.2012, 13:40
Цитата(freezeman @  28.3.2012,  15:35 Найти цитируемый пост)
После перехвата функции ReadFile нужно вернуть её системе

в данном случае, совсем не обязательно, можно просто вернуть TRUE

Автор: freezeman 28.3.2012, 13:44
Цитата(GremlinProg @ 28.3.2012,  13:40)
Цитата(freezeman @  28.3.2012,  15:35 Найти цитируемый пост)
После перехвата функции ReadFile нужно вернуть её системе

в данном случае, совсем не обязательно, можно просто вернуть TRUE

Ок, а подскажите ещё, пожалуйста, как этот буфер заполнить...

Автор: Akira 28.3.2012, 14:12
Например успешно промапил файл и считал то return true если нет,то return false. Примеры работы с проекциями с мотри в MSDN или в гугле - Чтение фала + FileMapping, примеров овер 9000 на всех языках.

Автор: GremlinProg 28.3.2012, 14:12
Цитата(freezeman @  28.3.2012,  15:44 Найти цитируемый пост)
как этот буфер заполнить...

это зависит от твоей конкретной реализации свопа,

если перехватывать CreateFile и в нем создавать объект мепирования (CreateFileMapping), как предлагает Akira,
то дескриптор этого маппинга и нужно вернуть из CreateFile,

в таком случае, на ReadFile нужно вызвать MapViewOfFile со смещением и размером, пришедшими из ReadFile,
MapViewOfFile вернет указатель на исходный буфер,

вот данные из этого буфера и нужно перекинуть в буфер, пришедший в ReadFile и вернуть TRUE,
конечно, если MapViewOfFile вернет NULL, ReadFile должен вернуть FALSE, соответственно

только на CloseHandle, нужно соответственно закрыть дескриптор исходного файла

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

Автор: freezeman 28.3.2012, 14:46
Цитата(GremlinProg @ 28.3.2012,  14:12)
Цитата(freezeman @  28.3.2012,  15:44 Найти цитируемый пост)
как этот буфер заполнить...

это зависит от твоей конкретной реализации свопа,

если перехватывать CreateFile и в нем создавать объект мепирования (CreateFileMapping), как предлагает Akira,
то дескриптор этого маппинга и нужно вернуть из CreateFile,

в таком случае, на ReadFile нужно вызвать MapViewOfFile со смещением и размером, пришедшими из ReadFile,
MapViewOfFile вернет указатель на исходный буфер,

вот данные из этого буфера и нужно перекинуть в буфер, пришедший в ReadFile и вернуть TRUE,
конечно, если MapViewOfFile вернет NULL, ReadFile должен вернуть FALSE, соответственно

только на CloseHandle, нужно соответственно закрыть дескриптор исходного файла

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

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

Если я на этапе копирования файла в ОП, сделаю проекцию и назову её по имени файла+какие-нибудь доп. атрибуты, а когда произойдет след перехват я проверю сущ ли такая проекция, если да, то 
заполню буфер как вы описали, если нет просто верну ReadFile до перехвата...

И ещё при проекции скорость чтения из неё так как из ОП или как с жесткого диска??

Автор: Akira 28.3.2012, 15:02
Можно и из ОП раз так хочется (только где столько памяти взять? smile ) из одного буфера будешь передавать в другой буфер, а ReadFile не нужно трогать, оно там и нах не нужно. Потеря из за проекции не значительны и на фоне чтения из диска можно и не думать об этом. Плюс в проекции это то что ты можешь открывать и читать файлы в несколько гигов, а вот такие держать в памяти не вариант. Я бы выбрал проекцию.

Автор: GremlinProg 28.3.2012, 15:21
Цитата(freezeman @  28.3.2012,  16:46 Найти цитируемый пост)
у меня набирается статистика по обращениям к файлам, затем по алгоритму выбираются файлы, которые нужно поместить в ОП,а после очередного перехвата ReadFile, если этот файл, к которому идет обращение функцией ReadFile, занесен в ОП, то считать его из ОП.Это было общее описание задачи.

значит нужно завести список таких файлов и на ReadFile искать эти данные в нем,

вроде же все очевидно, можно сделать так:
1. перехватываем CreateFile:
 - проходим по списку files, ищем по имени запись файла
 - нашли - возвращаем его индекс (или его уникальный номер)
 - не нашли - создали такую запись, открыли файл и вернули индекс новой записи(или ее уникальный номер)
2. перехватываем ReadFile:
 - переходим в списке files к записи файла (в первом параметре, соответственно будет индекс или уникальный номер этой записи)
 - не нашли - передали параметр в реальную ReadFile
 - нашли - расчитываем его статистику, сохраняем ее результаты в записи
 - если требуется отобразить файл в память, создаем отображение, сохраняем дескриптор в записи
 - если требуется прочитать отображение, делаем это по схеме постом выше, используя дескриптор отображения, он же уже находится в записи
 - если требуется прочитать файл напрямую, делаем это, передав параметры в реальную ReadFile, дескриптор файла ведь там же
3. перехватываем CloseHandle:
 - переходим в списке files к записи файла (в первом параметре, соответственно будет индекс или уникальный номер этой записи)
 - не нашли - передали параметр в реальную CloseHandle
 - нашли - закрыли открытые дескрипторы, удалили запись

Цитата(freezeman @  28.3.2012,  16:46 Найти цитируемый пост)
При проекции скорость чтения из неё так как из ОП или как с жесткого диска??

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

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

Автор: freezeman 28.3.2012, 16:58
Цитата(GremlinProg @ 28.3.2012,  15:21)
вроде же все очевидно

Уффф... для вас, для кого-нибудь ещё на форуме это, конечно, не сложно... Я программист .NET и с WINAPI не работал, пишу сейчас на С++ и параллельно изучаю особенности языка...

Цитата

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


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

Перехват у меня есть функции ReadFile, через проекцию сведения о перехваченном файле передаются в мою службу, где там обрабатываются, принимается решение заносить их в ОП или нет, когда занес группу файлов в ОП, я планировал сделать проекцию (для межпроцессного взаимодействия), где хранил сведения о уже занесенных файла в ОП...Когда произошел перехват вновь, открывается эта проекция и проверяет на наличие этого файла в ОП...
ну дальше понятно, что я должен считать его с ОП... но как это сделать, как это реализовать....не знаю((  И не совсем подходит описанная схема...Моожет через кучу, заносить туда, а потом, как писал Akira, считать в буффер и все??

Автор: Akira 28.3.2012, 18:06
Как читать особой разницы нет, реализация примерно одинакова. Почитай про работу с указателями. Хранить, если много параметров которые надо хранить то можно завести структуру и сделать масив. Например, как то так 
struct Save
{
   char name[MAX_PATH]; 
   void* ptr
};
А в память грузи так, как тебе нравится.

Функция что бы получить из HANDLE имя - NtQueryObject(hFileHandle,ObjectNameInformation,(PVOID)lpBuffer, size, &ret);

Автор: freezeman 28.3.2012, 20:15
Цитата(Akira @ 28.3.2012,  18:06)
Как читать особой разницы нет, реализация примерно одинакова. Почитай про работу с указателями. Хранить, если много параметров которые надо хранить то можно завести структуру и сделать масив. Например, как то так 
struct Save
{
   char name[MAX_PATH]; 
   void* ptr
};
А в память грузи так, как тебе нравится.

Функция что бы получить из HANDLE имя - NtQueryObject(hFileHandle,ObjectNameInformation,(PVOID)lpBuffer, size, &ret);

Получил имя из HANDLE чуть-чуть по другому, и передаю тоже в структуре массив TCHAR, но при передаче, почему-то путь ограничивается 18 символами, хотя в момент преобразования HANDEL в путь к файлу он бывает корректен.

Цитата

А в память грузи так, как тебе нравится.

То есть сначала загрузить, а потом просто прочитать из памяти, как вы описывали ранее и вернуть в случае успеха TRUE... буду пробовать, спасибо большое!

Автор: Akira 28.3.2012, 20:23
но при передаче, почему-то путь ограничивается 18 символами
Мб проблема в типах (WCHAR) покажи код получения имени.

Add:

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

Автор: freezeman 28.3.2012, 20:32
Цитата(Akira @ 28.3.2012,  20:23)
но при передаче, почему-то путь ограничивается 18 символами
Мб проблема в типах (WCHAR) покажи код получения имени.

В тестовом примере ставлю точку останова, проверяю и все нормально, но когда передаю через проекцию передает только первые 18 символов...

Код получения путь к файлу по его HANDLE:
Код

#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <string.h>
#include <psapi.h>
#include <strsafe.h>

#define BUFSIZE 512

BOOL GetFileNameFromHandle(HANDLE hFile) 
{
  BOOL bSuccess = FALSE;
  TCHAR pszFilename[MAX_PATH+1];
  HANDLE hFileMap;

  // Get the file size.
  DWORD dwFileSizeHi = 0;
  DWORD dwFileSizeLo = GetFileSize(hFile, &dwFileSizeHi); 

  if( dwFileSizeLo == 0 && dwFileSizeHi == 0 )
  {
     _tprintf(TEXT("Cannot map a file with a length of zero.\n"));
     return FALSE;
  }

  // Create a file mapping object.
  hFileMap = CreateFileMapping(hFile, 
                    NULL, 
                    PAGE_READONLY,
                    0, 
                    1,
                    NULL);

  if (hFileMap) 
  {
    // Create a file mapping to get the file name.
    void* pMem = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 1);

    if (pMem) 
    {
      if (GetMappedFileName (GetCurrentProcess(), 
                             pMem, 
                             pszFilename,
                             MAX_PATH)) 
      {

        // Translate path with device name to drive letters.
        TCHAR szTemp[BUFSIZE];
        szTemp[0] = '\0';

        if (GetLogicalDriveStrings(BUFSIZE-1, szTemp)) 
        {
          TCHAR szName[MAX_PATH];
          TCHAR szDrive[3] = TEXT(" :");
          BOOL bFound = FALSE;
          TCHAR* p = szTemp;

          do 
          {
            // Copy the drive letter to the template string
            *szDrive = *p;

            // Look up each device name
            if (QueryDosDevice(szDrive, szName, MAX_PATH))
            {
              size_t uNameLen = _tcslen(szName);

              if (uNameLen < MAX_PATH) 
              {
                bFound = _tcsnicmp(pszFilename, szName, uNameLen) == 0
                         && *(pszFilename + uNameLen) == _T('\\');

                if (bFound) 
                {
                  // Reconstruct pszFilename using szTempFile
                  // Replace device path with DOS path
                  TCHAR szTempFile[MAX_PATH];
                  StringCchPrintf(szTempFile,
                            MAX_PATH,
                            TEXT("%s%s"),
                            szDrive,
                            pszFilename+uNameLen);
                  StringCchCopyN(pszFilename, MAX_PATH+1, szTempFile, _tcslen(szTempFile));
                }
              }
            }

            // Go to the next NULL character.
            while (*p++);
          } while (!bFound && *p); // end of string
        }
      }
      bSuccess = TRUE;
      UnmapViewOfFile(pMem);
    } 

    CloseHandle(hFileMap);
  }
  _tprintf(TEXT("File name is %s\n"), pszFilename);
  return(bSuccess);
}

int _tmain(int argc, TCHAR *argv[])
{
    HANDLE hFile;

    if( argc != 2 )
    {
        _tprintf(TEXT("This sample takes a file name as a parameter.\n"));
        return 0;
    }
    hFile = CreateFile(argv[1], GENERIC_READ, FILE_SHARE_READ, NULL,
        OPEN_EXISTING, 0, NULL);

    if(hFile == INVALID_HANDLE_VALUE)
    {
        _tprintf(TEXT("CreateFile failed with %d\n"), GetLastError());
        return 0;
    }
    GetFileNameFromHandle( hFile );
}





Скорее всего дело в типе, может получать не в массиве TCHAR, а просто в массиве char?

Автор: freezeman 30.3.2012, 08:27
А как узнать какие именно данные будут считываться, какая часть файла?
Можно ли получить из параметров readfile?

Я подумал, что при вызове системой функции ReadFile считывается определенный блок из файла, но  в параметрах кроме количества толком ничего нет, как узнать что именно читается?

Автор: xvr 30.3.2012, 13:24
Цитата(freezeman @  30.3.2012,  08:27 Найти цитируемый пост)
как узнать что именно читается?

Если файл был открыт в OVERLAPPED режиме, то в структуре overlapped (последний параметр) передается смещение, откуда читать. Иначе чтение производится с текущей позиции. Ее можно отслеживать самому, или запросить у системы (через SetFilePointer(handle,0,NULL,FILE_CURRENT) )

Автор: Akira 30.3.2012, 14:28
freezeman
А зачем ты путь конвертируешь?
В этот нет нужды, да и в хукнутой функции это точно не нужно делать.

Автор: freezeman 30.3.2012, 15:35
Цитата(Akira @ 30.3.2012,  14:28)
freezeman
А зачем ты путь конвертируешь?
В этот нет нужды, да и в хукнутой функции это точно не нужно делать.

А как я узнаю, какой именно файл читает ReadFile и есть ли он у меня в памяти... ведь HANDLE не будет при следующем обращении совпадать...

Автор: Akira 30.3.2012, 15:41
Я об этом - QueryDosDevice достаточно этого - GetMappedFileName
Конвертирование нужно что бы из этого \Device\HarddiskVolume1\Temp\ сделать C:\Temp в твоем случае это излишне.

Автор: freezeman 30.3.2012, 15:51
Цитата(Akira @ 30.3.2012,  15:41)
Я об этом - QueryDosDevice достаточно этого - GetMappedFileName
Конвертирование нужно что бы из этого \Device\HarddiskVolume1\Temp\ сделать C:\Temp в твоем случае это излишне.

Проверю... Подскажите как мне заполнить буфер, который указан в перехваченной функции ReadFile... 
Вот алгоритм:
1 создать однонаправленный динамический список, загрузить туда файлы, отфильтрованные по алгоритму
2 проверить в перехваченной ReadFile на наличие этого файла в моем динамическом списке
3 если файл в памяти, то нужно заполнить буфер со смещением overlapped
4 иначе просто вернуть ReadFile системе.

Подскажите, пожалуйста, как реализовать 3 пункт, как заполнить буфер со смещением?

Добавлено через 53 секунды
Цитата(xvr @ 30.3.2012,  13:24)
Цитата(freezeman @  30.3.2012,  08:27 Найти цитируемый пост)
как узнать что именно читается?

Если файл был открыт в OVERLAPPED режиме, то в структуре overlapped (последний параметр) передается смещение, откуда читать. Иначе чтение производится с текущей позиции. Ее можно отслеживать самому, или запросить у системы (через SetFilePointer(handle,0,NULL,FILE_CURRENT) )

Спасибо, отлично...

Автор: Akira 30.3.2012, 16:20
Я же говорил, читай про работу с указателями.
Примерно так
char* str = "primer";
void* pout = str;
void* pin;
memcpy(pin, pout, 4);
printf("%s", pin);

Автор: freezeman 30.3.2012, 16:45
Цитата(Akira @ 30.3.2012,  16:20)
Я же говорил, читай про работу с указателями.
Примерно так
char* str = "primer";
void* pout = str;
void* pin;
memcpy(pin, pout, 4);
printf("%s", pin);

Спасибо большое! почитаю, разберусь!)

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)