2010-03-11 29 views
14

Tôi đang sử dụng dịch vụ Windows bên thứ ba xử lý một số tác vụ tự động bằng cách chạy tập lệnh và thực thi bằng cách sử dụng CreateProcessAsUser(). Tôi đang chạy vào các vấn đề trên Windows Server 2008 do UAC và cách độ cao LUA được xử lý thông qua các API.bắt đầu quá trình nâng cấp UAC từ dịch vụ không tương tác (win32/.net/powershell)

Dịch vụ chạy dưới dạng LocalSystem và không bật "Tương tác với máy tính để bàn". Các tiến trình đang được chạy như người dùng trong nhóm quản trị viên, nhưng không phải là tài khoản quản trị viên (được miễn khỏi nhiều hạn chế UAC). Tất cả các cài đặt mặc định của UAC đều được áp dụng.

Tôi có thể chuyển các lệnh tùy ý hoặc mã powerhell cho dịch vụ, nhưng dường như tôi không thể 'thoát' khỏi quy trình không nâng cao, không tương tác bị dịch vụ khởi động.

Điểm mấu chốt của vấn đề có vẻ là tùy chọn API (công khai) duy nhất để bắt đầu quá trình nâng cao là ShellExecute() với động từ 'runas', nhưng tôi có thể nói rằng không thể gọi từ một dịch vụ không tương tác hoặc bạn gặp lỗi như "Thao tác này yêu cầu một trạm cửa sổ tương tác".

Cách giải quyết duy nhất mà tôi đã tìm thấy được đề cập ở đây: http://www.eggheadcafe.com/software/aspnet/29620442/how-to-proper-use-sendinp.aspx

Trong Vista, chính thức ghi nhận cách để nâng cao một quá trình chỉ sử dụng API vỏ ShellExecute (Ex) (không CreateProcess hoặc CreateProcessAsUser). Vì vậy, ứng dụng của bạn phải gọi ShellExecute (Ex) để khởi chạy trình trợ giúp được nâng lên để gọi cho SendInput. Hơn nữa, do phiên 0 cách ly, dịch vụ chỉ có thể sử dụng CreateProcessAsUser hoặc CreateProcessWithLogonW (không thể sử dụng ShellExecute (Ex)) để chỉ định máy tính để bàn tương tác.

..Tôi nghĩ rằng không có cách nào trực tiếp để sinh ra một quy trình nâng cao từ dịch vụ cửa sổ. Chúng tôi chỉ có thể sử dụng lần đầu tiên CreateProcessAsUser hoặc CreateProcessWithLogonW để sinh ra một quy trình không được nâng lên vào người dùng phiên (máy tính để bàn tương tác). Sau đó, trong quy trình không nâng cao, nó có thể sử dụng ShellExecute (Ex) để sinh ra một quy trình nâng cao cho nhiệm vụ thực sự.

Để làm điều này từ mã .net/PowerShell, có vẻ như tôi sẽ phải làm một số P công phu/Gọi công cụ để gọi CreateProcessAsUser hoặc CreateProcessWithLogonW kể từ Net System.Diagnostics.ProcessStartInfo không có một tương đương với lpDesktop mà tôi có thể đặt thành "winsta0 \ default". Và tôi không rõ liệu LocalSystem có quyền gọi CreateProcessAsUser hoặc CreateProcessWithLogonW hay không.

Tôi cũng nhìn http://blogs.msdn.com/alejacma/archive/2007/12/20/how-to-call-createprocesswithlogonw-createprocessasuser-in-net.aspxProcess.Start with different credentials with UAC on

Dựa trên tất cả những gì, tôi đạt kết luận rằng không có cách nào đơn giản để làm điều này. Tui bỏ lỡ điều gì vậy? Điều này thực sự không có vẻ như nó nên được khó khăn như vậy. Có vẻ như UAC không bao giờ được thiết kế để xử lý các trường hợp sử dụng phi tương tác.

Và nếu bất kỳ người nào Microsoft cuối cùng đọc được điều này, tôi nhận thấy cách ShellExecute xử lý nội bộ độ cao bằng cách gọi đến Dịch vụ thông tin ứng dụng (AIS). Tại sao không phải là cùng một cuộc gọi đến AIS có sẵn thông qua một số Win32 hoặc .NET API? http://msdn.microsoft.com/en-us/library/bb756945.aspx

Xin lỗi đã chạy một chút thời gian. Cảm ơn mọi ý tưởng.

+0

Thay vào đó, hãy nói rằng Server Core không hỗ trợ UAC. Dường như để xác nhận đánh giá của tôi. http://blogs.technet.com/server_core/archive/2009/01/19/user-account-control-uac-and-server-core.aspx –

+0

Xem bài đăng của tôi ở đây, giải thích cách, đặc biệt nhìn vào LinkedToken phần: http://brianbondy.com/blog/id/100/understanding-windows-at-a-deeper-level-sessions-window-stations-and-desktops –

Trả lời

16

Cách "chính thức" để ngắt phân tách số phiên là sử dụng kết hợp API dịch vụ đầu cuối và CreateProcessAsUser() để khởi chạy quá trình trong phiên của người dùng. Tại công việc cũ của tôi, chúng tôi đã làm như vậy, vì chúng tôi cần hiển thị hộp thoại cho người dùng từ một dịch vụ trước khi cài đặt bản cập nhật đã tải xuống Vì vậy, tôi biết nó hoạt động, trên WinXP, Win2K3, Vista và Win7 ít nhất, nhưng tôi không mong đợi rằng Win 2K8 sẽ là quá khác nhau. Về cơ bản, quá trình này diễn ra như sau:

  1. Gọi WTSGetActiveConsoleSessionId() để có được giao diện điều khiển phiên tích cực id (RẤT quan trọng, vì các phiên tương tác là KHÔNG luôn phiên 1, ngay cả trên các hệ thống khách hàng). API này cũng sẽ trả lại -1 nếu không có người dùng đang hoạt động nào đăng nhập vào phiên tương tác (nghĩa là đăng nhập cục bộ vào máy vật lý, thay vì sử dụng RDP).
  2. Chuyển id phiên từ lệnh gọi API trước đó sang WTSQueryUserToken() để nhận mã thông báo mở cho phép người dùng đăng nhập vào bảng điều khiển.
  3. Gọi DuplicateTokenEx() để chuyển đổi mã thông báo mạo danh (từ WTSQueryUserToken) thành mã thông báo chính.
  4. Gọi CreateEnvironmentBlock() để tạo môi trường mới cho quy trình (tùy chọn, nhưng nếu không, quy trình sẽ không có).
  5. Chuyển mã thông báo chính từ bướC# 3 vào cuộc gọi đến CreateProccessAsUser(), cùng với dòng lệnh cho tệp thực thi. Nếu bạn đã tạo một khối môi trường từ bướC# 4, bạn cũng phải vượt qua cờ CREATE_UNICODE_ENVIRONMENT (luôn luôn). Điều này có vẻ ngớ ngẩn, nhưng API thất bại khủng khiếp nếu bạn không (với ERROR_INVALID_PARAMTER).
  6. Nếu bạn đã tạo một khối môi trường, sau đó bạn cần gọi DestroyEnvironmentBlock, nếu không bạn sẽ tạo ra rò rỉ bộ nhớ. Quá trình này được đưa ra một bản sao riêng biệt của khối môi trường khi nó khởi chạy, vì vậy bạn chỉ phá hủy dữ liệu cục bộ.

Và thì đấy! Windows thực hiện một số phép thuật nội bộ, và bạn thấy việc khởi chạy ứng dụng. Tuy nhiên, mặc dù điều này sẽ khởi động và quá trình tương tác từ một dịch vụ, tôi không chắc chắn nếu nó sẽ bỏ qua UAC (nhưng không báo cho tôi về điều đó). Nói cách khác, nó có thể không khởi động như một tiến trình nâng cao trừ khi sổ đăng ký hoặc tệp kê khai nội bộ nói để làm như vậy, và thậm chí sau đó, bạn vẫn có thể nhận được lời nhắc UAC. Nếu mã thông báo bạn nhận được từ bướC# 3 là mã thông báo bị hạn chế, bạn có thể sử dụng AdjustTokenPrivileges() để khôi phục mã thông báo (đầy đủ) cao, nhưng cũng không báo cho tôi biết điều đó. Tuy nhiên, như đã nêu trong tài liệu MSDN, xin lưu ý rằng không thể "thêm" đặc quyền trên mã thông báo chưa có chúng (ví dụ: bạn không thể chuyển mã thông báo người dùng bị hạn chế thành quản trị viên bằng cách sử dụng AdjustTokenPrivileges; người dùng sẽ phải là quản trị viên để bắt đầu).

Về mặt kỹ thuật, bạn có thể thực hiện tất cả điều này từ Win2K về phía trước. Tuy nhiên, nó thực sự chỉ khả thi bắt đầu với WinXP, vì Win2K thiếu các API WTSGetActiveConsoleSessionId()WTSQueryUserToken() (cùng với WTSEnumerateProcesses() cho Win2K Pro). Bạn có thể mã cứng 0 làm id phiên (vì luôn luôn là trường hợp trong Win2K), và tôi cho rằng bạn có thể nhận được mã thông báo người dùng bằng cách liệt kê các quy trình đang chạy và sao chép một trong các mã thông báo của họ (nó phải là SID tương tác hiện tại).Bất kể, CreateProcessAsUser() sẽ hoạt động theo cách tương tự khi chuyển mã thông báo người dùng tương tác, ngay cả khi bạn không chọn "Tương tác với màn hình" từ cài đặt dịch vụ. Nó cũng an toàn hơn việc khởi chạy trực tiếp từ dịch vụ, vì quá trình này sẽ không kế thừa mã thông báo truy cập LocalSystem.

Bây giờ, tôi không biết liệu ứng dụng của bên thứ ba có thực hiện bất kỳ điều này khi chạy script/process hay không, nhưng nếu bạn muốn thực hiện nó từ một dịch vụ, đó là cách (và với Vista hoặc Win7, cách duy nhất để khắc phục sự cô lập phiên 0).

+3

Không cần phải gọi 'DuplicateTokenEx'. 'CreateProcessAsUser' sẽ chạy quá trình với mã thông báo thu được từ' WTSQueryUserToken'. Câu trả lời của bạn khá chi tiết, nhưng không trả lời "Làm thế nào để bắt đầu quá trình nâng cao từ dịch vụ? (UAC được bật)" – Ajay

+1

Thực tế là không. Điều này sẽ để lại cho bạn một mã thông báo bị hạn chế. – Joshua

+0

Có một vài điều cần lưu ý: 1) Vì @Ajay đề cập đến 'WTSQueryUserToken' đã trả về một mã thông báo chính, vì vậy bạn có thể bỏ qua bước 3. 2) Với UAC, bạn thực sự cần có mã thông báo được nối kết sau bước 2 , mà bạn làm bằng cách gọi 'GetTokenInformation' với lớp thông tin' TokenLinkedToken', nhưng chỉ khi truy vấn 'TokenElevationType' nói độ cao bị giới hạn. 3) Nếu bạn không tạo ra một khối môi trường thì quy trình mới sẽ có môi trường của quá trình tạo, đó là dịch vụ của bạn –

1

Tùy thuộc vào trường hợp sử dụng của bạn, bạn có thể làm những gì tôi làm. Tôi săn lùng quy trình winlogon cho phiên hoạt động và lấy cắp mã thông báo của nó. Nếu không có phiên hoạt động (API trả về -1), hãy sử dụng 1 nếu WINVER> = 6 nếu không 0. Kết quả này trong SYSTEM trên phiên hoạt động.

Các vấn đề liên quan