Форум программистов, компьютерный форум, киберфорум
Наши страницы
C++ и WinAPI
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг: Рейтинг темы: голосов - 14, средняя оценка - 5.00
AdamWest
0 / 0 / 2
Регистрация: 21.03.2015
Сообщений: 29
#1

Отслеживание закрытия файла процессом, запущенным через CreateProcess - C++ WinAPI

23.07.2015, 18:18. Просмотров 2311. Ответов 50
Метки нет (Все метки)

Доброго времени суток!
Возникла нетривиальная(на мой взгляд) задачка: Открываем какой нибудь файл через какую нибудь программу(условно говоря file.docx с помощью MS Word) и нужно отследить закрытие этого файла.
Запуск осуществляю с помощью CreateProcess, а именно:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
STARTUPINFO si;
PROCESS_INFORMATION pi;
 
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
 
CreateProcess
    (
        TEXT("C:\\Program Files (x86)\\Microsoft Office\\Office15\\WINWORD.EXE"),
        L"/t C:\\Temp\\file.docx", NULL, NULL, TRUE,
        CREATE_NEW_CONSOLE,
        NULL, NULL,
        &si,
        &pi
    );
Далее казалось бы всё просто, мониторь себе список запущенных процессов по pi.dwProcessId и всё.
Но есть одно но. Если при этом будет запущен ещё какой либо файл (например something.docx), то он запустится в том же процессе и в таком случае при закрытии отслеживаемого файла, процесс останется. И я не смогу своевременно отреагировать на его закрытие

Вопрос в том можно ли как то отследить закрытие конкретного файла в программе?? Или же можно запустить процесс выполнения программы так, что бы при выполнении других файлов такого типа, они выполнялись в другом процессе??
Помогите пожалуйста(
0
Лучшие ответы (1)
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
23.07.2015, 18:18
Я подобрал для вас темы с готовыми решениями и ответами на вопрос Отслеживание закрытия файла процессом, запущенным через CreateProcess (C++ WinAPI):

Как дождаться закрытия файла другим процессом/потоком
Всем привет. Допустим известно имя файла. Необходимо: * найти его. * если...

Передача параметров через CreateProcess
такое дело, программа открывает консольную и считывает результат ее работы , но...

Не запускается exe через CreateProcess
Здравствуйте! Стоит задача запустить exe файл с параметрами тихой установки, а...

Запуск стороннего приложения через CreateProcess
Доброго времени суток! Есть два одинаковых консольных приложения, но с разными...

Условие к использованию памяти созданного процесса через CreateProcess()
Здравствуйте, через CreateProcess() запускаю внешнюю програму (у меня это VLC...

Запуск приложения через CreateProcess(), передать параметры запуска, указать тот же каталог
Здравствуйте, помогите побороться с CreateProcess() Есть рабочая программа,...

50
shmkv
652 / 371 / 57
Регистрация: 21.07.2015
Сообщений: 1,059
23.07.2015, 18:50 #2
Есть утилита Filemon с открытыми исходниками она это умеет, но там вроде даже свой драйвер для этого используется.
Есть вариант (хотя не слишком надежный) просто ожидать разблокировки файла на запись.
Есть еще вариант с перечислением всех дескрипторов
1
Убежденный
Ушел с форума
Эксперт С++
15941 / 7252 / 1176
Регистрация: 02.05.2013
Сообщений: 11,637
Записей в блоге: 1
Завершенные тесты: 1
23.07.2015, 21:40 #3
Цитата Сообщение от AdamWest Посмотреть сообщение
Возникла нетривиальная(на мой взгляд) задачка
...
Из описания я так и не понял: в чем конкретно состоит задачка ?
0
AdamWest
0 / 0 / 2
Регистрация: 21.03.2015
Сообщений: 29
24.07.2015, 10:44  [ТС] #4
С помощью CreateProcess нужно запустить такой процесс, в котором откроется документ(а) и чтобы при открытии любого другого документа(б) из этого процесса, документ(б) открывался в другом процессе. Как то так

Добавлено через 10 часов 0 минут
Или как вообще можно на с++ отследить закрытие файла в программе
0
Убежденный
Ушел с форума
Эксперт С++
15941 / 7252 / 1176
Регистрация: 02.05.2013
Сообщений: 11,637
Записей в блоге: 1
Завершенные тесты: 1
24.07.2015, 11:17 #5
Цитата Сообщение от AdamWest Посмотреть сообщение
С помощью CreateProcess нужно запустить такой процесс, в котором откроется документ(а) и чтобы при открытии любого другого документа(б) из этого процесса, документ(б) открывался в другом процессе
А что должно произойти с процессом, который открывал документ (а) ?
0
shmkv
652 / 371 / 57
Регистрация: 21.07.2015
Сообщений: 1,059
24.07.2015, 11:47 #6
Цитата Сообщение от AdamWest Посмотреть сообщение
Или как вообще можно на с++ отследить закрытие файла в программе
Чем мои варианты не устраивают?
0
AdamWest
0 / 0 / 2
Регистрация: 21.03.2015
Сообщений: 29
24.07.2015, 12:02  [ТС] #7
Убежденный: Процесс открытия документа(а) должен завершиться.
shmkv: я не понял как подключиться из с++ к FileMon/Procecc Monitor. Гугление по отлову дескрипторов файлов на с++ мне к сожалению ничего не дало.
0
shmkv
652 / 371 / 57
Регистрация: 21.07.2015
Сообщений: 1,059
24.07.2015, 12:08 #8
Цитата Сообщение от AdamWest Посмотреть сообщение
я не понял как подключиться из с++ к FileMon/Procecc Monitor
У FileMon есть исходники.
Цитата Сообщение от AdamWest Посмотреть сообщение
угление по отлову дескрипторов файлов на с++ мне к сожалению ничего не дало.
Я тебе дал ссылку на пример. Там делфи, но разобраться можно.
0
Убежденный
Ушел с форума
Эксперт С++
15941 / 7252 / 1176
Регистрация: 02.05.2013
Сообщений: 11,637
Записей в блоге: 1
Завершенные тесты: 1
24.07.2015, 12:21 #9
Лучший ответ Сообщение было отмечено AdamWest как решение

Решение

Я бы сделал так: запускаем процесс с помощью CreateProcess, далее ждем,
пока в него не будет загружена kernel32.dll. После этого ставим в процессе
хук на CreateFileA/W, или даже сразу на ntdll!NtCreateFile.
Далее, когда срабатывает наш перехватчик с интересующим именем файла,
запускаем из него новый процесс и возвращаем какой-нибудь NT-код
ошибки, например 0xc0000022 (access denied). И никаких драйверов
писать не нужно для этого.
3
AdamWest
0 / 0 / 2
Регистрация: 21.03.2015
Сообщений: 29
29.07.2015, 17:53  [ТС] #10
А как понять что kernel32.dll уже загружена? А хуки на изменения файлов можно ставить?
0
Убежденный
Ушел с форума
Эксперт С++
15941 / 7252 / 1176
Регистрация: 02.05.2013
Сообщений: 11,637
Записей в блоге: 1
Завершенные тесты: 1
29.07.2015, 20:39 #11
Цитата Сообщение от AdamWest Посмотреть сообщение
А как понять что kernel32.dll уже загружена?
Ну можно запускать процесс в режиме DEBUG_PROCESS (флаг CreateProcess),
затем подписываться на события через WaitForDebugEvent и ловить загрузку
kernel32.dll. Или в цикле вызывать CreateToolhelp32Snapshot и смотреть,
загрузилась ли kernel32 в нужный процесс или еще нет.

Цитата Сообщение от AdamWest Посмотреть сообщение
А хуки на изменения файлов можно ставить?
Да. Например, хук на NtWriteFile, на NtSetFileInformation и т.д.
1
AdamWest
0 / 0 / 2
Регистрация: 21.03.2015
Сообщений: 29
02.09.2015, 15:11  [ТС] #12
Что то у меня не выходит.
Как уже было описано:
1. Запускаю процесс через CreateProcess
2. Снимаю снэпшот системы и ищу нужный мне процесс(по pId).
3. Когда процесс найден, то смотрю загруженные модули для этого процесса
4. Когда найден kernel32.dll Нужно ставить хук. Вот здесь и возникли проблемы и вопросы

Можно ли подобные хуки ставить средствами с++? Если можно то как это делается?
Я пока что пытаюсь поставить хук с помощью библиотеки MinHook, к сожалению безуспешно(kernel32.dll was found выводится в консоль, а HOOKED не выводится, как я понимаю, это значит что DetourCreateFile не вызывается). И нужно ли ставить хук на CreateFile, если мне нужна реакция на закрытие или изменение файла?


C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
typedef int (WINAPI *CREATEFILE)(LPCTSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES, DWORD, DWORD, HANDLE);
 
CREATEFILE fpCreateFile = NULL;
 
int WINAPI DetourCreateFile(LPCTSTR lpctst, DWORD dw1, DWORD dw2, LPSECURITY_ATTRIBUTES sec_attr, DWORD dw3, DWORD dw4, HANDLE hndl)
{
    cout << "HOOKED" << endl;
    return 0;
}
 
VOID PrintModuleList(HANDLE CONST hStdOut, DWORD CONST dwProcessId);
 
int _tmain(int argc, _TCHAR* argv[])
{
    STARTUPINFO si;
    PROCESS_INFORMATION pi;
 
    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);
    ZeroMemory(&pi, sizeof(pi));
    
        MH_Initialize();
    
        CreateProcess
        (
    TEXT("C:\\Program Files (x86)\\Microsoft Office\\Office15\\WINWORD.EXE"),
    L"/t C:\\Temp\\sendMEplease.docx", NULL, NULL, TRUE,
    CREATE_NEW_CONSOLE,
    NULL, NULL,
    &si,
    &pi
    );
 
    DWORD pId = pi.dwProcessId;
    DWORD ExitCode;
    PROCESSENTRY32 peProcessEntry;
    TCHAR szBuff[1024];
    DWORD dwTemp;
    HANDLE CONST hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
    HANDLE CONST hSnapshot = CreateToolhelp32Snapshot(
        TH32CS_SNAPPROCESS, pId);
 
    if (INVALID_HANDLE_VALUE == hSnapshot) {
        return 0;
    }
    peProcessEntry.dwSize = sizeof(PROCESSENTRY32);
    Process32First(hSnapshot, &peProcessEntry);
    do {
        if (peProcessEntry.th32ProcessID == pId) {
            PrintModuleList(hStdOut, peProcessEntry.th32ProcessID);
            break;
        }
    } while (Process32Next(hSnapshot, &peProcessEntry));
 
    CloseHandle(hSnapshot);
    MH_Uninitialize();
    return 0;
}
 
 
VOID PrintModuleList(HANDLE CONST hStdOut, DWORD CONST dwProcessId) {
    MODULEENTRY32 meModuleEntry;
    TCHAR szBuff[1024];
    DWORD dwTemp;
    HANDLE CONST hSnapshot = CreateToolhelp32Snapshot(
        TH32CS_SNAPMODULE, dwProcessId);
    if (INVALID_HANDLE_VALUE == hSnapshot) {
        return;
    }
 
    meModuleEntry.dwSize = sizeof(MODULEENTRY32);
    Module32First(hSnapshot, &meModuleEntry);
    string str = "kernel32.dll";
    wstring w_str(str.begin(), str.end());
    do {
        if (meModuleEntry.szModule == w_str)
        {
            MH_CreateHook(&CreateFile, &DetourCreateFile,
        reinterpret_cast<LPVOID*>(&fpCreateFile));
            MH_EnableHook(&CreateFile);
            cout <<"kernel32.dll was found" << endl;
            break;
        }
    } while (Module32Next(hSnapshot, &meModuleEntry));
 
    CloseHandle(hSnapshot);
}
0
Убежденный
Ушел с форума
Эксперт С++
15941 / 7252 / 1176
Регистрация: 02.05.2013
Сообщений: 11,637
Записей в блоге: 1
Завершенные тесты: 1
02.09.2015, 15:14 #13
Цитата Сообщение от AdamWest Посмотреть сообщение
kernel32.dll was found выводится в консоль, а HOOKED не выводится, как я понимаю, это значит что DetourCreateFile не вызывается
Хуки надо ставить в процесс, который вы запускаете.
А здесь они ставятся в исходный процесс.
Естественно, ничего не работает.
0
AdamWest
0 / 0 / 2
Регистрация: 21.03.2015
Сообщений: 29
02.09.2015, 16:00  [ТС] #14
Цитата Сообщение от Убежденный Посмотреть сообщение
Хуки надо ставить в процесс, который вы запускаете.
Хм. А как это делается? Ведь, как я понимаю, процесс создан и запущен после того как вызвана функция CreateProcess. То есть мне нужно каким то образом в CreateProcess зарегистрировать какую то callback функцию?
0
Убежденный
Ушел с форума
Эксперт С++
15941 / 7252 / 1176
Регистрация: 02.05.2013
Сообщений: 11,637
Записей в блоге: 1
Завершенные тесты: 1
02.09.2015, 17:42 #15
1) Находите адрес функции LoadLibrary в своем процессе (GetProcAddress).
С вероятностью 99% он будет таким же и в дочернем процессе.

2) Выделяете в дочернем процессе память - VirtualAllocEx.
Тип - MEM_COMMIT, атрибуты - PAGE_READWRITE.

3) В выделенную память пишете с помощью функции WriteProcessMemory
полный путь к dll, которую нужно загрузить.

4) Запускаете удаленный поток в дочернем процессе - CreateRemoteThread.
В качестве точки входа передаете адрес LoadLibrary, а в качестве аргумента -
указатель на выделенную ранее память. В итоге в удаленном процессе
будет создан поток, который вызовет LoadLibrary и завершится.

5) Из загруженной dll уже можно ставить перехваты.
Только делать это не нужно из DllMain, лучше создать отдельный поток.
2
AdamWest
0 / 0 / 2
Регистрация: 21.03.2015
Сообщений: 29
03.09.2015, 14:15  [ТС] #16
Цитата Сообщение от Убежденный Посмотреть сообщение
Находите адрес функции LoadLibrary в своем процессе (GetProcAddress).
С вероятностью 99% он будет таким же и в дочернем процессе.
Функция GetProcAddress принимает два аргумента:
HMODULE - Дескриптор модуля. Тк мне нужно искать LoadLibrary для моего процесса, то, насколько я понимаю,
в этот аргумент нужно передать результат выполнения функции GetModuleHandle(NULL)(который и возвращает HMODULE для данного процесса)
LPCSTR - имя функции(тоесть "LoadLibrary")
В итоге я не могу найти адрес вызова LoadLibrary, функция GetProcAddress возвращает NULL
В чём моя ошибка?

C++
1
2
3
    HMODULE hModuleSelf = GetModuleHandle(NULL);
    void* p = GetProcAddress(hModuleSelf, "LoadLibrary");
    cout << p << endl;
Цитата Сообщение от Убежденный Посмотреть сообщение
Выделяете в дочернем процессе память - VirtualAllocEx.
Тип - MEM_COMMIT, атрибуты - PAGE_READWRITE.
Дочерний процесс это получается процесс запуска файла(который порождается функцией CreateProcess )? Как выделить в дочернем процессе память? Просто после CreateProcess вызвать VirtualAllocEx, куда передать HANDLE процесса созданного CreateProcess ?
0
Убежденный
Ушел с форума
Эксперт С++
15941 / 7252 / 1176
Регистрация: 02.05.2013
Сообщений: 11,637
Записей в блоге: 1
Завершенные тесты: 1
03.09.2015, 17:54 #17
Цитата Сообщение от AdamWest Посмотреть сообщение
HMODULE - Дескриптор модуля. Тк мне нужно искать LoadLibrary для моего процесса, то, насколько я понимаю,
в этот аргумент нужно передать результат выполнения функции GetModuleHandle(NULL)(который и возвращает HMODULE для данного процесса)
А зачем гадать ?
В MSDN все описано, какой HMODULE нужно передавать в функцию.

Цитата Сообщение от AdamWest Посмотреть сообщение
Просто после CreateProcess вызвать VirtualAllocEx, куда передать HANDLE процесса созданного CreateProcess ?
Да.
0
Dragokas
Эксперт WindowsАвтор FAQ
16927 / 7012 / 851
Регистрация: 25.12.2011
Сообщений: 10,808
Записей в блоге: 16
09.09.2015, 10:00 #18
AdamWest, пример части с внедрением: http://www.cyberforum.ru/win-api/thread1527363.html
0
AdamWest
0 / 0 / 2
Регистрация: 21.03.2015
Сообщений: 29
09.09.2015, 10:42  [ТС] #19
Dragokas, Спасибо. Внедрение я всё таки осилил сам и вчера столкнулся с точно такой же проблемой. Код из DLL не выполняется(т.к. не показывается MessageBox сообщение и файл C:\temp.txt не создаётся), хотя внедрение вроде отрабатывает корректно.

Внедрение DLL:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void injectDLL(HANDLE hProcess)
{
    char* dll = "c:\\users\\adam\\documents\\visual studio 2015\\Projects\\HookDll\\Debug\\HookDll.dll";
 
    LPVOID lpSpace = (LPVOID)VirtualAllocEx(hProcess, NULL, strlen(dll), MEM_COMMIT, PAGE_READWRITE);
    
    int n = WriteProcessMemory(hProcess, lpSpace, dll, strlen(dll), NULL);
 
    HMODULE hModule = GetModuleHandle(L"kernel32.dll");
    
    LPVOID lpBaseAddress = (LPVOID)GetProcAddress(hModule, "LoadLibraryW");
    
    HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)lpBaseAddress, lpSpace, NULL, NULL);
    
};
Смотрел в отладчике, ни одна из переменных lpSpace / n / hModule / lpBaseAddress / hThread не равна NULL

Код HookDll.dll:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <stdio.h>
#include <winsock2.h>
#include <windows.h>
 
INT APIENTRY DllMain(HMODULE hDll, DWORD Reason, LPVOID Reserved)
{
    MessageBox(NULL,L"DLL", L"DllMain",MB_OK);
    FILE *file;
    fopen_s(&file, "c:\\temp.txt", "a+");
 
    switch (Reason)
    {
    case DLL_PROCESS_ATTACH:
        fprintf(file, "DLL attach function called.n");
        break;
    case DLL_PROCESS_DETACH:
        fprintf(file, "DLL detach function called.n");
        break;
    case DLL_THREAD_ATTACH:
        fprintf(file, "DLL thread attach function called.n");
        break;
    case DLL_THREAD_DETACH:
        fprintf(file, "DLL thread detach function called.n");
        break;
    }
 
    fclose(file);
    return TRUE;
};
Кто нибудь знает в чём проблема? Что я делаю не правильно?
P.S Внедрение происходит в Microsoft Word
0
Убежденный
Ушел с форума
Эксперт С++
15941 / 7252 / 1176
Регистрация: 02.05.2013
Сообщений: 11,637
Записей в блоге: 1
Завершенные тесты: 1
09.09.2015, 12:06 #20
Цитата Сообщение от AdamWest Посмотреть сообщение
Кто нибудь знает в чём проблема?
Путь к dll задан в char-символах, а удаленный поток зовет LoadLibraryW,
которому нужна строка в wchar_t-символах. Да, и MSDN крайне не советует
звать MessageBox из DllMain...

И путь к dll нужно писать WriteProcessMemory вместе с завершающим нулем,
а здесь его нет (strlen(dll) вообще вернет размер указателя).
0
09.09.2015, 12:06
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
09.09.2015, 12:06
Привет! Вот еще темы с решениями:

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

Как дождаться закрытия файла?
Допустим открываем файл, а потом закрываем file.close(); Или открываем для...

Получить список dll, используемых запущенным процессом
Делаю античит для сетевой игры(готовых решений нет) по способу белого\черного...

Отслеживание создания файлов чужим процессом
Здравствуйте. Возникла проблемка с отслеживанием создания новых файлов в...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru