これは新しい技術ではありません。
Windowsストアアプリ(Windows Store Apps)は、サンドボックスからされるアプリです。Windows 10インストール後現れた「天気」、「カレンダー」などアプリはその例です。Windows Storeからインストールしたアプリもそのれです。
サンドボックス化されたので、普通のプロセスのように、簡単にOpenProcess(FullAccess...) + CreateRemoteThreadやMapViewOfSectionなどクロスプロセス操作はできません。普通のSetWindowsHookExやSetWinEventHook経由のDLLアタッチもできません。
原因は、UIAccessの制限です。WindowsストアアプリにDLLをアタッチするには、UIAccess=trueのプロセスからしかできない。
SetWindowsHookExの中に、[Windows Store Apps]に対して、特別な制限の記述があります。
ただし、記述が不十分です。実際は、これはWindows 7(or Vista?)からの技術です。
例として、SetWindowsHookExでWindowsストアアプリにDLLをアタッチする要点をまとめます:
##SetWindowsHookExを呼び出すEXEは以下の設定が必要です:
2。EXE自体は信頼されるフォルダに置く必要。例えば"C:¥Programe Files¥TestHook"。
3。署名 (自己署名を利用する場合は、自己署名の証明書をルート信頼機関として登録必要)
詳しい方法は、ここに記述されています。少し古かったので、証明書登録する方法を変更しました。
cd %userprofile%\Downloads
@rem ルート証明書作成:
makecert -n "CN=testroot,O=aaa,C=JP,E=foo@hoge.jp" -sv testroot.pvk -r testroot.cer
@rem 証明書を作成
makecert -n "CN=test,O=aaa,C=JP,E=foo@hoge.jp" -sv test.pvk -ic testroot.cer -iv testroot.pvk test.cer
@rem testroot.cerをルート証明機関として導入
certmgr.exe -add testroot.cer -s -r localMachine root
rem test.pfxを作成:
pvk2pfx -pvk test.pvk -spc test.cer -pfx test.pfx
@rem 最後に、関連ファイルを署名:
cd "C:¥Program Files¥TestHook"
Signtool sign /f %userprofile%\Downloads\test.pfx /v .¥TestHook.exe
Signtool sign /f %userprofile%\Downloads\test.pfx /v .¥TestHook.dll
その他注意点:64bitのWindowsの中に、Windowsストアアプリは32bitである場合があります。事前に確認してから、32bitと64bitのDLLやEXEを作成必要です。
署名しないと、どうなるの?TestHook.exeを起動すると、main関数を入る前に、「invalid inferrer ....」みたいなエラーが出ます。
##テスト用ソース:
- TestHook.EXE(機能:パラメータで指定されたdllのapiを呼び出す)
int main(int argc, char** argv)
{
argv++; argc--;
printf("DLL: %s\n", argv[0]);
printf("Function: %s\n", argv[1]);
HMODULE hDll = LoadLibraryA(argv[0]);
PROC proc = GetProcAddress(hDll, argv[1]);
proc();
return 0;
}
- TestHook.dll(機能:hookを設定。ロードされた時、当時のプロセス名が「天気」アプリの特徴と一致すれば強制終了する)
static HMODULE _hModule;
static wchar_t currentExePath[1024] = { 0 };
typedef struct _HOOK_INFO {
int type;
const wchar_t * name;
HHOOK hHook;
} HOOK_INFO;
static HOOK_INFO hooks[] = {
{WH_CALLWNDPROC, L"WH_CALLWNDPROC", 0},
{WH_CBT, L"WH_CBT", 0},
{WH_DEBUG, L"WH_DEBUG", 0},
{WH_GETMESSAGE, L"WH_GETMESSAGE", 0},
{WH_KEYBOARD, L"WH_KEYBOARD", 0},
{WH_MOUSE, L"WH_MOUSE", 0},
{WH_MSGFILTER, L"WH_MSGFILTER", 0}
};
LRESULT CALLBACK CommonCallback(int nCode, WPARAM wParam, LPARAM lParam) {
return CallNextHookEx(0, nCode, wParam, lParam);
}
extern "C"
void __stdcall hook() {
MessageBox(NULL, L"Click me to hook", L"test", MB_OK);
for (int i = 0; i < _countof(hooks); i++) {
hooks[i].hHook = SetWindowsHookEx(hooks[i].type, CommonCallback, _hModule, 0);
if (!hooks[i].hHook) {
DWORD err = GetLastError();
wchar_t msg[2048] = { 0 };
wsprintf(msg, L"Failed to set %s hook. Error %: ", hooks[i].name, err);
FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), msg + wcslen(msg), _countof(msg), NULL);
OutputDebugString(msg);
}
}
MessageBox(NULL, L"Click me to unhook", L"test", MB_OK);
for (int i = 0; i < _countof(hooks); i++) {
if (hooks[i].hHook)
UnhookWindowsHookEx(hooks[i].hHook);
hooks[i].hHook = 0;
}
}
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
_hModule = hModule;
DisableThreadLibraryCalls(hModule);
GetModuleFileName(NULL, currentExePath, _countof(currentExePath));
{
wchar_t msg[4096] = { 0 };
wsprintf(msg, L"I am in process %s cmdline: %s", currentExePath, GetCommandLine());
OutputDebugString(msg);
}
if (wcsstr(currentExePath, L"Microsoft.BingWeather_4.17.74.0_x86__8wekyb3d8bbwe")) {
TerminateProcess(GetCurrentProcess(), 1);
}
break;
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
実行方法は、
cd "C:¥Program Files¥TestHook"
TestHook.exe .¥TestHook.dll hook
[click me to hook]のOKを押して。TestHook.dllを全てのGUIアプリにアタッチ(厳密に言うと、すぐにアタッチするではなく、何らかのWindows関連のMessageが来るとロードされる。)
この状態で、「天気」アプリを起動すると、一瞬画面が現れてすぐに終了されます。