if (!([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
    Start-Process PowerShell -Verb RunAs "-NoProfile -ExecutionPolicy Bypass -Command `"cd '$pwd'; & '$PSCommandPath';`"";
    exit;
}

Function ExitOnError ([string]$message) {
    Write-Error $message
    Read-Host -Prompt "Press Enter to continue"
    exit -1
}

$Supported = @{
    "B3448BF077665F2E1CA67094BCF2A7C5" = 0x14DE1;
    "DE5FA392A825332AB3E348EF0316B514" = 0x16A61;
    "F653C99D4A0C61D4B2C64358B8213BD8" = 0x15C11;
    "C8BC76C87563E78C9BC85EE9F4F96760" = 0x15C11;
}
$ChsIME = "ChsIME"
$ChsIMEExe = "${ChsIME}.exe"

# make sure CheIme.exe is the right version
$ChsImeExePath = "$env:windir\System32\InputMethod\CHS\$ChsIMEExe"
$ChsIMEHash = (Get-FileHash $ChsImeExePath -Algorithm MD5).Hash
$offsetAddr = $Supported[$ChsIMEHash]
if (-not $offsetAddr) {
    ExitOnError 'Unsupported ChsIme.exe'
}

Add-Type -MemberDefinition @'
[DllImport("kernel32.dll", SetLastError = true)]
  public static extern bool WriteProcessMemory(
  IntPtr hProcess,
  IntPtr lpBaseAddress,
  byte[] lpBuffer,
  Int32 nSize,
  out IntPtr lpNumberOfBytesWritten);
'@ -Name Kernel32 -Namespace Pinvoke


$i = 0
while ($i++ -lt 30) {
    $ps = Get-Process -Name $ChsIME
    foreach ($p in $ps) {
        $hModule = $p.Modules | Where-Object {$_.ModuleName -eq $ChsIMEExe}
        if (!$hModule) {
            continue
        }
        $hModule = $hModule[0]
        $addr = [IntPtr]::Add($hModule.BaseAddress, $offsetAddr)
        [Int32]$n = 0
        $pidd = $p.id
        if ([Pinvoke.Kernel32]::WriteProcessMemory($p.Handle[0], $addr, @(0x31, 0xc0), 2, [ref]$n)) {
            Write-Output "$pidd is patched"
        } else {
            ExitOnError "Failed to patch $pidd"
        }
    }
    if ($ps) {
        break
    }
    Start-Sleep -Milliseconds 100
}