コンパイラなどのEXE/DLLファイルを作成・編集するソフトを作っているとき、Windows Defenderなどのセキュリティ対策ソフトと協調しないといけないときがある。
セキュリティ対策ソフトは作成・改変されたEXE/DLLを検出するとそれを検疫しようとする。検疫中はEXE/DLLファイルを書き込みできない。検疫処理とEXE/DLL出力処理は、場合によっては相性が悪くなる恐れがある。よってさらなる出力の際に検疫を待つ必要がある。
最初にC++/Win32でファイルが書き込み可能か確かめる関数を書く。
#include <windows.h>
// ファイルが書き込み可能か確かめる関数。
BOOL IsFileWritable(LPCWSTR pszFileName)
{
HANDLE hFile = CreateFileW(pszFileName, GENERIC_WRITE, 0, NULL,
OPEN_EXISTING, 0, NULL);
CloseHandle(hFile);
return hFile != INVALID_HANDLE_VALUE;
}
次はウイルス対策の検疫が終わるまで待つ関数を書く。
// ウイルス対策の検疫が終わるまで待つ関数。
BOOL WaitForVirusScan(LPCWSTR pszFileName, DWORD dwTimeout)
{
::Sleep(300);
const INT cRetry = 10;
for (INT i = 0; i < cRetry; ++i)
{
if (IsFileWritable(pszFileName))
{
::Sleep(300);
return TRUE;
}
::Sleep(dwTimeout / cRetry);
}
return FALSE;
}
検疫の開始をWin32APIのSleep関数で300ミリ秒待つ。検疫が開始したら書き込み不可のロックがかかると仮定する。書き込み不可が書き込み可能になるまで待ち、書き込み可能になったら再び300ミリ秒待ち、脱出する。
最後に実際にEXE/DLLを書き換えるコードと検疫を待つコードを次のように書く。
...
// ここにa.exeを書き換えるコードを書く。
WriteExe(L"a.exe", 1);
// セキュリティ対策の検疫を10秒ほど待つ。
WaitForVirusScan(L"a.exe", 10 * 1000);
// ここに再びa.exeを書き換えるコードを書く。
WriteExe(L"a.exe", 2);
...
ここにWriteExe
は、適当なEXE/DLLを出力する自作の関数とする。これでEXE/DLL出力処理とEXE/DLL検疫処理の協調が可能だ。めでたしめでたし。
コメント