読者です 読者をやめる 読者になる 読者になる

Windows10のログイン画面で好きなことをする

[追記]
TL見れるようにしてみた






Windows10が公開になりました
Windows - マイクロソフト
Microsoft Windows 10 - Wikipedia

8.1から色々な変化がありますが, 相変わらずログイン画面がダサいし不自由…
なんだかスライドショーが出来るとかちょいちょいアップデートはされてるようですが, 何にせよもっと自由に使えたら良いのにな―って思ったので, テキトーにやってみたことを纏めておきます
f:id:kkrnt:20150729173136p:plain


Windows7Windows8, 8.1に関してはこの辺をどうぞkkrnt.hatenablog.com



目標は「ログイン画面上で任意のプログラムを起動する」ことにします
固定キー機能とか, AppInit_DLLsとか方法は色々ありますが, 今回は直接LogonUI.exeを扱った方法でやってみようと思います
(固定キー機能はShiftを5回押さなきゃいけなくてカッコ悪いし, AppInit_DLLsはセキュアブートとか署名とか面倒くさい…)


かなり強引な方法でやっているため, どんな障害が発生するか分かりません
僕が試してみた限りではログイン処理が異常に重くなったり, 起動後の動作が不安定になったりしたこともありました
また, LogonUI.exeはWindowsのログイン処理において非常に重要なプログラムです
絶対にバックアップを取った上で, 自己責任で行って下さい




以下はWindows 10 Proで動作確認を行いました

最終的にこんな感じになりました
ログイン画面で動画を流すヤツ
http://c.arckty.org/win10.webm
f:id:kkrnt:20150729181237p:plain

ログイン画面でTL流すヤツ
http://c.arckty.org/win10.mp4



僕が利用したファイルはこちらに置いておきます
注意してもらいたいのは, 以下ではtarget.exeをWindows\System32にLogonUI.exeとリネームして配置していますが, このzipファイルのプログラムを利用する場合はlogonExt.exeをWindows\System32にLogonUI.exeとリネームして配置して下さい
http://c.arckty.org/logonExt.zip




やることは簡単です
1. Windows\System32のLogonUI.exeを任意のディレクトリに移動させます(ここではC:\tmp)
2. 任意のプログラムとC:\tmpのLogonUI.exeを起動するプログラムをLogonUI.exeという名前でWindows\System32に配置します
これで終わりです

少し注意しなければいけないのは, LogonUI.exeはコマンドライン引数を受け起動するので, LogonUI.exeの呼び出し元から渡されるコマンドライン引数をそのままLogonUI.exeに渡してあげる必要があります

実際に渡されているコマンドライン引数はこんな感じ
(値はちょいちょい変わるので, 渡された値をそのまま流すのが1番良いかなーって思います)
f:id:kkrnt:20150728181435p:plain

それから(Windows\System32の)LogonUI.exeが正常に起動しなかった場合, 呼び出し元は何度も(Windows\System32の)LogonUI.exeを起動します
その度に同じプログラムが起動してしまうと面倒なので多重起動を制限したいんですが, (C:\tmpの)LogonUI.exeはログイン処理以外にもロックであったり, シャットダウンなどでも利用するので迂闊に制限するとやらかす可能性がありそうだなーって思ったので, 僕は任意のプログラムと(C:\tmpの)LogonUI.exeを呼び出した後も(Windows\System32の)LogonUI,exeを終了しないようにwaitを掛けるようにしたほうが良いと思います

まぁその辺は僕がダラダラ考えるより, 実際にやってみて調節したほうが良さそうなので, 色々試してみて下さい

当然ですが, (C:\tmpの)LogonUI.exeは最前面で起動します
任意のプログラムはその後に最前面で起動させないと見えないので気を付けて下さい

そんなわけでこんな感じにすると動くはずです

#include <windows.h>
#include <string.h>

void pExec(char str[], int flag)
{
	PROCESS_INFORMATION pi;
	STARTUPINFO si;
	ZeroMemory(&si, sizeof(si));
	si.cb = sizeof(si);
	CreateProcess(nullptr, str, nullptr, nullptr, FALSE, NORMAL_PRIORITY_CLASS, nullptr, nullptr, &si, &pi);
	CloseHandle(pi.hThread);
	if (flag)
	{
		WaitForSingleObject(pi.hProcess, INFINITE);
	}
	CloseHandle(pi.hProcess);
}

int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
{
	int i;

	/*
		LogonUI.exe /flag:0x0 /state0:0xa3bca855 /state1:0x41c64e6dとかそんな感じ
	*/
	char str[64] = {};

	char* s = " ";
	char* exec = "C:\\tmp\\LogonUI.exe";

	strcat(str, exec);

	for (i = 0; i < __argc; i++)
	{
		strcat(str, s);
		strcat(str, __argv[i]);
	}

	pExec(str, 0);
	//任意のプログラム
	pExec("C:\\tmp\\target.exe", 1);
}

system()とかでも全然大丈夫だったと思います
でもC#で書いたプログラムだとエラー吐かれたりしました



プログラムの準備が出来たところで, LogonUI.exeを差し替えましょう
Shiftを押しながら再起動を行って下さい
すると「オプションの選択」が開きます
そこから「トラブルシューティング」を選択し, 「詳細オプション」を選ぶと「コマンドプロンプト」があるのでそれを選択します
そうしたら再起動が掛かって, 起動するとユーザを選択する画面が出てきて, ユーザを選択するとパスワードを求められます
パスワードを入力するとコマンドプロンプトが起動します
f:id:kkrnt:20150729181013p:plain
f:id:kkrnt:20150729181021p:plain
f:id:kkrnt:20150729181028p:plain
f:id:kkrnt:20150729181034p:plain
f:id:kkrnt:20150729181041p:plain
f:id:kkrnt:20150729181053p:plain


この状態だとXドライブなのでWindowsがインストールされているドライブに移動します
ここで注意して欲しいのは, いつものドライブとは異なっている場合があるということです
僕の場合はCドライブにインストールしているはずなんですが, 何故かDドライブになってたり…
取り敢えずテキトーに漁ってみて, インストールされているドライブに移動して下さい
f:id:kkrnt:20150729181110p:plain

移動出来たらWindows\System32にあるLogonUI.exeを移動させます
僕の場合は, 念のためWindows\System32に_LogonUI.exeという名前でも残しておきます
f:id:kkrnt:20150729181152p:plain

後はさっき作成したプログラムをWindows\System32にLogonUI.exeという名前で配置すれば完了です
f:id:kkrnt:20150729181159p:plain

後はテキトーにexitするとさっきの画面に戻るので, 続行を選択しWindowsを起動します
するとログイン画面で任意のプログラムを起動することが出来るでしょう
f:id:kkrnt:20150729181217p:plain




ログイン画面で遊ぶのは飽きてきたのでこんなテキトーな感じになっちゃいましたが, これで「ログイン画面上で任意のプログラムを起動する」ことが出来たと思います

暇があったら書き直したりしようと思います…