11

だからここにスクープがあります:

しばらく前に、ホスト名、IPアドレス、イメージ化された日付、解凍ステータス(DeepFreezeを使用)、現在のドメイン、現在の日付/時刻を表示する小さなC#アプリを作成し、Windows7ラボマシンのウェルカム画面に表示しました。 。これは、起動時に静的に設定され、実際にテキストが背景に埋め込まれていた以前の情報ブロックを、もう少し動的で機能的なものに置き換えるためのものでした。アプリはタイマーを使用してIPアドレス、deepfreezeステータスを更新し、毎秒クロックを供給し、ユーザーがログインしているかどうかを確認し、そのような状態を検出すると自殺します。

スタートアップスクリプト(グループポリシーで設定)を使用して実行した場合、スクリプトは開いたままになり、マシンがログインプロンプトに到達することはありません。startコマンドやcmdコマンドなどを使用して、別のシェル/プロセスで起動すると、起動スクリプトが終了するまで実行されます。終了した時点で、Windowsはスクリプトのすべての子プロセスをクリーンアップしているように見えます。psexec -s -d -i -x現在、これを使用して起動することを回避できます。これにより、起動スクリプトが完了した後も保持されますが、非常に遅くなる可能性があり、起動時間に5秒から1分以上追加されます。

別のC#アプリを使用して、Processクラスを介して、さまざまな起動フラグなどを使用してWMI呼び出し(Win32_ProcessおよびWin32_ProcessStartup)を使用してプロセスを開始することを試みましたが、すべて同じ結果でスクリプトが終了し、情報ブロックプロセスが取得されます。殺された。私はアプリをサービスとして書き直しましたが、サービスはデスクトップと対話するようには設計されておらず、ログインウィンドウは言うまでもなく、適切なコンテキストで動作させることは実際にはうまくいかなかったようです。

だから質問のために:誰かがこれを達成するための良い方法を持っていますか?起動スクリプトから独立してウェルカム画面上で実行されるようにタスクを起動しますか?

4

5 に答える 5

12

これは、多くのWin32API呼び出しを介して実行できます。私はなんとかGUIを備えたプログラムをWinlogonデスクトップに取り込むことができました(誰もが尋ねる前に、それはインタラクティブなGUIではありません)。基本的に、ローダープロセスをSYSTEMとして実行する必要があります。これにより、新しいプロセスが生成されます。起動時にこのプロセスを実行する可能性が高いため、タスクスケジューラを使用してローダーをSYSTEMとして実行するか、サービスを使用して同じことを実行できます。現在サービスを使用していますが、タスクスケジューラを使用してみましたが、問題なく動作しました。

簡単な要約:

  1. Winlogon.exeプロセスを(プロセスとして)取得します
  2. プロセスの.handleを使用してOpenProcessTokenを使用してwinlogonのトークンを取得します
  3. 新しいトークンを作成し、それにwinlogonトークンを複製します
  4. トークンの特権を上げる
  5. CreateProcessAsUserを使用してプロセスを作成し、lpDesktopを「Winsta0 \ Winlogon」に設定し、作成したトークンを使用していることを確認します。

コード例:

        // grab the winlogon process
        Process winLogon = null;
        foreach (Process p in Process.GetProcesses()) {
            if (p.ProcessName.Contains("winlogon")) {
                winLogon = p;
                break;
            }
        }
        // grab the winlogon's token
        IntPtr userToken = IntPtr.Zero;
        if (!OpenProcessToken(winLogon.Handle, TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_DUPLICATE, out userToken)) {
            log("ERROR: OpenProcessToken returned false - " + Marshal.GetLastWin32Error());
        }

        // create a new token
        IntPtr newToken = IntPtr.Zero;
        SECURITY_ATTRIBUTES tokenAttributes = new SECURITY_ATTRIBUTES();
        tokenAttributes.nLength = Marshal.SizeOf(tokenAttributes);
        SECURITY_ATTRIBUTES threadAttributes = new SECURITY_ATTRIBUTES();
        threadAttributes.nLength = Marshal.SizeOf(threadAttributes);
        // duplicate the winlogon token to the new token
        if (!DuplicateTokenEx(userToken, 0x10000000, ref tokenAttributes, SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation,
            TOKEN_TYPE.TokenImpersonation, out newToken)) {
            log("ERROR: DuplicateTokenEx returned false - " + Marshal.GetLastWin32Error());
        }
        TOKEN_PRIVILEGES tokPrivs = new TOKEN_PRIVILEGES();
        tokPrivs.PrivilegeCount = 1;
        LUID seDebugNameValue = new LUID();
        if (!LookupPrivilegeValue(null, SE_DEBUG_NAME, out seDebugNameValue)) {
            log("ERROR: LookupPrivilegeValue returned false - " + Marshal.GetLastWin32Error());
        }
        tokPrivs.Privileges = new LUID_AND_ATTRIBUTES[1];
        tokPrivs.Privileges[0].Luid = seDebugNameValue;
        tokPrivs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
        // escalate the new token's privileges
        if (!AdjustTokenPrivileges(newToken, false, ref tokPrivs, 0, IntPtr.Zero, IntPtr.Zero)) {
            log("ERROR: AdjustTokenPrivileges returned false - " + Marshal.GetLastWin32Error());
        }
        PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
        STARTUPINFO si = new STARTUPINFO();
        si.cb = Marshal.SizeOf(si);
        si.lpDesktop = "Winsta0\\Winlogon";
        // start the process using the new token
        if (!CreateProcessAsUser(newToken, process, process, ref tokenAttributes, ref threadAttributes,
            true, (uint)CreateProcessFlags.CREATE_NEW_CONSOLE | (uint)CreateProcessFlags.INHERIT_CALLER_PRIORITY, IntPtr.Zero,
            logInfoDir, ref si, out pi)) {
            log("ERROR: CreateProcessAsUser returned false - " + Marshal.GetLastWin32Error());
        }

        Process _p = Process.GetProcessById(pi.dwProcessId);
        if (_p != null) {
            log("Process " + _p.Id + " Name " + _p.ProcessName);
        } else {
            log("Process not found");
        }
于 2010-06-29T17:11:31.040 に答える
6

これは、「これを行うには本当に正当な理由が必要です」という質問の1つです。マイクロソフトは、起動画面で実行されているアプリケーションをブロックするように非常に努力しています-ログオン画面で実行されているコードのバグのセキュリティへの影響は悲惨であるため、ログオン画面と相互作用するWindowsのコードのすべてのビットは非常に慎重にコードレビューされます-少しでも上昇すると、マルウェアがコンピュータに侵入できるようになります。

なぜログオン画面でプログラムを実行したいのですか?たぶん、それほど危険ではない、それを行うための文書化された方法があります。

于 2010-06-19T02:03:27.680 に答える
6

上記のコードを C++ に翻訳しました。他の誰かが必要とする場合に備えて...私のコードの一部への参照があることに注意してください。

static bool StartProcess(LPCTSTR lpApplicationPath)
{
    CAutoGeneralHandle hWinlogonProcess = FindWinlogonProcess();
    if (hWinlogonProcess == INVALID_HANDLE_VALUE) 
    {
        DU_OutputDebugStringff(L"ERROR: Can't find the 'winlogon' process");
        return false;
    }

    CAutoGeneralHandle hUserToken;
    if (!OpenProcessToken(hWinlogonProcess, TOKEN_QUERY|TOKEN_IMPERSONATE|TOKEN_DUPLICATE, &hUserToken)) 
    {
        DU_OutputDebugStringff(L"ERROR: OpenProcessToken returned false (error %u)", GetLastError());
        return false;
    }

    // Create a new token
    SECURITY_ATTRIBUTES tokenAttributes = {0};
    tokenAttributes.nLength = sizeof tokenAttributes;

    SECURITY_ATTRIBUTES threadAttributes = {0};
    threadAttributes.nLength = sizeof threadAttributes;

    // Duplicate the winlogon token to the new token
    CAutoGeneralHandle hNewToken;
    if (!DuplicateTokenEx(hUserToken, 0x10000000, &tokenAttributes, 
            SECURITY_IMPERSONATION_LEVEL::SecurityImpersonation,
            TOKEN_TYPE::TokenImpersonation, &hNewToken)) 
    {
        DU_OutputDebugStringff(L"ERROR: DuplicateTokenEx returned false (error %u)", GetLastError());
        return false;
    }

    TOKEN_PRIVILEGES tokPrivs = {0};
    tokPrivs.PrivilegeCount = 1;

    LUID seDebugNameValue = {0};
    if (!LookupPrivilegeValue(nullptr, SE_DEBUG_NAME, &seDebugNameValue)) 
    {
        DU_OutputDebugStringff(L"ERROR: LookupPrivilegeValue returned false (error %u)", GetLastError());
        return false;
    }

    tokPrivs.Privileges[0].Luid = seDebugNameValue;
    tokPrivs.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    // Escalate the new token's privileges
    if (!AdjustTokenPrivileges(hNewToken, false, &tokPrivs, 0, nullptr, nullptr))
    {
        DU_OutputDebugStringff(L"ERROR: AdjustTokenPrivileges returned false (error %u)", GetLastError());
        return false;
    }

    PROCESS_INFORMATION pi = {0};
    STARTUPINFO si = {0};
    si.cb = sizeof si;
    si.lpDesktop = L"Winsta0\\Winlogon";

    // Start the process using the new token
    if (!CreateProcessAsUser(hNewToken, lpApplicationPath, nullptr, &tokenAttributes, &threadAttributes,
        true, CREATE_NEW_CONSOLE|INHERIT_CALLER_PRIORITY, nullptr, nullptr, &si, &pi)) 
    {
        DU_OutputDebugStringff(L"ERROR: CreateProcessAsUser returned false (error %u)", GetLastError());
        return false;
    }

    return true;
}
于 2014-07-23T20:11:46.300 に答える
1

あなたならできると思いますが、かなり複雑です。対話型アプリは、通常、ようこそ画面で実行することは許可されていません。大まかに言えば、次のことを行う必要があります。

  • 自動的に開始する Windows サービスを作成する
  • Windows サービスを使用して、現在のセッションとデスクトップに別のプロセスを作成します (Win32 メソッドWTSGetActiveConsoleSessionIdとを使用OpenInputDesktop) 。

ログイン画面とある程度対話できるアプリを作成しましたが、UI は表示されません。おそらく実行できますが、さらに複雑になる可能性があります。

OpenInputDesktop注: Windows サービスから結果を取得できないことがわかりました。代わりに、他のプロセスで呼び出しを行い、サービスに通知して、正しいデスクトップでプロセスを再起動する必要がありました。

少なくとも開始できることを願っています。幸運を!

于 2010-06-18T16:40:22.710 に答える