全國最多中醫師線上諮詢網站-台灣中醫網
發文 回覆 瀏覽次數:3912
推到 Plurk!
推到 Facebook!

OpenProcess 無法取得某些process 是權限不夠?還是什麼原因呢?

答題得分者是:thf
dino
一般會員


發表:20
回覆:72
積分:23
註冊:2002-07-29

發送簡訊給我
#1 引用回覆 回覆 發表時間:2009-02-20 18:13:58 IP:61.63.xxx.xxx 訂閱
請教各位:
查閱了K.Top 各位先進前輩關於取得process 資訊的寫法,寫了下列的程式,
功能是取得指定的process 的CPU usage(工作管理員CPU這個欄位,沒有的話可從檢視-選擇欄位 選取CPU使用率 ),
問題是一般的process 都可以取得,但是一些例如windows 服務所啟動的process 抓不到(例如:服務 World Wide WebPublishing Service 所create 的dllhost.exe), 用procexp 這個工具去觀察發現 dllhost 是掛在svchost.exe下面,不知道是不是這個原因的關係,還是因為系統權限的關係才無法抓到呢?
uses
TlHelp32, PsAPI

var
Form1: TForm1;
dtStart, dtCPUPrev: Int64;
hProcess: THandle;
iCount:Integer;

procedure TForm1.Button1Click(Sender: TObject);
begin
timer1.Enabled := False;
Label2.Caption := '';
iCount:=0;
hProcess := OpenProcess(PROCESS_QUERY_INFORMATION, true, StrToInt(EdtByPID.Text));//EdtByPID.Text 輸入Process 的PID
showmessage(inttostr(hProcess));//這邊得到的都是0
if hProcess > 0 then
timer1.Enabled := True;
end;

procedure TForm1.Timer1Timer(Sender: TObject);
var
timespan,dtProcess: Int64;
begin
if (iCount > 0) then
begin
timespan := DateTimeToInt64(now) - dtStart;
if timespan > 0 then
begin
dtProcess := GetProcessCPU(hProcess) - dtCPUPrev;
Label2.Caption := FloatToStr(100 * (dtProcess / timespan)) ' %';
end;
end;
dtStart := DateTimeToInt64(now);
dtCPUPrev := GetProcessCPU(hProcess);
Inc(iCount);
end;

function GetProcessCPU(hP: THandle): Int64;
var
CreationTime, ExitTime, KernelTime, UserTime: TFileTime;
kernel_LARGE, user_LARGE: LARGE_INTEGER;
begin
Result := 0;
if hP > 0 then
begin
GetProcessTimes(hP, CreationTime, ExitTime, KernelTime, UserTime);
kernel_LARGE.LowPart := KernelTime.dwLowDateTime;
kernel_LARGE.HighPart := KernelTime.dwHighDateTime;
user_LARGE.LowPart := UserTime.dwLowDateTime;
user_LARGE.HighPart := UserTime.dwHighDateTime;
Result := kernel_LARGE.QuadPart user_LARGE.QuadPart;
end;
end;

function DateTimeToInt64(dt: TDatetime): Int64;
var
systemtime1: TSystemTime;
filetime1: TFileTime;
large1: LARGE_INTEGER;
begin
DatetimeToSystemTime(dt, systemtime1);
SystemTimeToFileTime(systemtime1, filetime1);
large1.LowPart := filetime1.dwLowDateTime;
large1.HighPart := filetime1.dwHighDateTime;
Result := large1.QuadPart;
end;







編輯記錄
taishyang 重新編輯於 2009-02-20 18:33:40, 註解 歸類成[問題]‧
RootKit
資深會員


發表:16
回覆:357
積分:419
註冊:2008-01-02

發送簡訊給我
#2 引用回覆 回覆 發表時間:2009-02-23 17:11:01 IP:61.222.xxx.xxx 訂閱
有可能要 DEBUG 權限吧。
一般是使用 NtQuerySystemInformation 來查詢地
dino
一般會員


發表:20
回覆:72
積分:23
註冊:2002-07-29

發送簡訊給我
#3 引用回覆 回覆 發表時間:2009-02-25 01:12:46 IP:220.132.xxx.xxx 訂閱
感謝 RootKit 兄的回覆^^
NtQuerySystemInformation 看起來就蠻難的
sample code應該也不多吧
再努力搜尋資料好了
看來要跟API打交道真的是會'讓人心力交瘁的@@
謝謝囉

===================引 用 RootKit 文 章===================
有可能要 DEBUG 權限吧。
一般是使用 NtQuerySystemInformation 來查詢地
thf
一般會員


發表:1
回覆:3
積分:10
註冊:2009-03-02

發送簡訊給我
#4 引用回覆 回覆 發表時間:2009-03-09 13:22:33 IP:221.5.xxx.xxx 訂閱
你可能没有明白ROOTKIT兄的意思,其实就是没有DEDUG权限的原因,你可以试试这样,不用改到你原有的代码,只是加上这样一个PROCEDURE

function AdjustProcessPrivilege(Processhandle:Thandle;Token_Name:pchar):boolean;
var
Token:cardinal;
TokenPri:_TOKEN_PRIVILEGES;
processDest:int64;
i:DWORD;
begin
Result:=false;
if OpenProcessToken(Processhandle,TOKEN_ADJUST_PRIVILEGES,Token) then
begin
if LookupPrivilegeValue(nil,Token_Name,processDest) then
begin
TokenPri.PrivilegeCount:=1;
TokenPri.Privileges[0].Attributes:=SE_PRIVILEGE_ENABLED;
TokenPri.Privileges[0].Luid:=processDest;
i:=0;
if AdjustTokenPrivileges(Token,false,TokenPri,sizeof(TokenPri),nil,i) then
Result:=true;
end;
end;
end;

然后在FORM的ONCREATE 中加上这一句:
AdjustProcessPrivilege(GetCurrentProcess,'SeDebugPrivilege');
SeDebugPrivilege 就是ROOTKIT提到的DEBUG权限了
提升到这个权限你的进程就相当于SYSTEM用户了(比ADMINISTRATOR还要高级的用户),这样才能查看用户是SYSTEM的进程SVCHOST了
你还可以看看我的另一个主题:
http://delphi.ktop.com.tw/board.php?cid=30&fid=72&tid=97469
也是关于这些方面的

===================引 用 dino 文 章===================
感謝 RootKit 兄的回覆^^
NtQuerySystemInformation 看起來就蠻難的
sample code應該也不多吧
再努力搜尋資料好了
看來要跟API打交道真的是會'讓人心力交瘁的@@
謝謝囉

===================引 用 RootKit 文 章===================
有可能要 DEBUG 權限吧。
一般是使用 NtQuerySystemInformation 來查詢地
dino
一般會員


發表:20
回覆:72
積分:23
註冊:2002-07-29

發送簡訊給我
#5 引用回覆 回覆 發表時間:2009-03-11 22:49:48 IP:220.132.xxx.xxx 訂閱
感謝 thf 兄的回答,並且寫了範例,
果然讓我一個列舉所有process(模擬工作管理員)的程式,可以列舉出原本無法列舉出來的process
真的是各位回答問題的前輩所說,是權限的問題。
只是我前面寫的那個例子,取單一個process的usage的範例還是取不到某個dllhost.exe。
但是我想應該是小問題而已,可能是哪個地方用錯了。
待我好好review thf 所提供的範例再改寫看看問題在哪裡。
相信很快就可以結案了。
再次感謝各位前輩的鼎力相助,感激不盡^^。
dino
一般會員


發表:20
回覆:72
積分:23
註冊:2002-07-29

發送簡訊給我
#6 引用回覆 回覆 發表時間:2009-03-19 10:56:22 IP:219.87.xxx.xxx 訂閱
還是有個疑問,使用AdjustProcessPrivilege取得權限之後,所有的Process都可以找到它的使用者名稱嗎?
下列程式碼對於下列Process 使用 OpenProcessToken是 回傳false的

影像名稱 使用者名稱
svchost.exe LOCAL SERVICE
svchost.exe NEWWORK SERVICE

程式碼:

//列舉所有進程,取得User, Domain
procedure TForm1.Button1Click(Sender: TObject);
var
hProcSnap: THandle;
pe32: TProcessEntry32;
Domain, User: string;
s: string;
begin
hProcSnap := CreateToolHelp32SnapShot(TH32CS_SNAPALL, 0);
if hProcSnap = INVALID_HANDLE_VALUE then
Exit;
pe32.dwSize := SizeOf(ProcessEntry32);
if Process32First(hProcSnap, pe32) = True then
while Process32Next(hProcSnap, pe32) = True do
begin
if GetUserAndDomainFromPID(pe32.th32ProcessID, User, Domain) then //這邊有問題
begin
s := Format('%s User: %s ; Domain: %s',[StrPas(pe32.szExeFile), User, Domain]);
Listbox1.Items.Add(s);
end else
Listbox1.Items.Add(StrPas(pe32.szExeFile) ' PID:' IntToStr(pe32.th32ProcessID));
end;
CloseHandle(hProcSnap);
end;

//GetUserAndDomainFromPID 的程式碼
function GetUserAndDomainFromPID(ProcessId: DWORD; var User, Domain: string): Boolean;
var
hToken: THandle;
cbBuf: Cardinal;
ptiUser: PTOKEN_USER;
snu: SID_NAME_USE;
ProcessHandle: THandle;
UserSize, DomainSize: DWORD;
bSuccess: Boolean;
begin
Result := False;
ProcessHandle := OpenProcess(PROCESS_QUERY_INFORMATION, False, ProcessId);
if ProcessHandle <> 0 then
begin
if OpenProcessToken(ProcessHandle, TOKEN_QUERY, hToken) then //對於使用者是LOCAL SERVICE 或是 NEWWORK SERVICE的進程,這邊得到false,所以取不到 User, Domain
begin
bSuccess := GetTokenInformation(hToken, TokenUser, nil, 0, cbBuf);
ptiUser := nil;
while (not bSuccess) and (GetLastError = ERROR_INSUFFICIENT_BUFFER) do
begin
ReallocMem(ptiUser, cbBuf);
bSuccess := GetTokenInformation(hToken, TokenUser, ptiUser, cbBuf, cbBuf);
end;
CloseHandle(hToken);

if not bSuccess then
begin
Exit;
end;

UserSize := 0;
DomainSize := 0;
LookupAccountSid(nil, ptiUser.User.Sid, nil, UserSize, nil, DomainSize, snu);
if (UserSize <> 0) and (DomainSize <> 0) then
begin
SetLength(User, UserSize);
SetLength(Domain, DomainSize);
if LookupAccountSid(nil, ptiUser.User.Sid, PChar(User), UserSize,
PChar(Domain), DomainSize, snu) then
begin
Result := True;
User := StrPas(PChar(User));
Domain := StrPas(PChar(Domain));
end;
end;

if bSuccess then
begin
FreeMem(ptiUser);
end;
end;
CloseHandle(ProcessHandle);
end;
end;
thf
一般會員


發表:1
回覆:3
積分:10
註冊:2009-03-02

發送簡訊給我
#7 引用回覆 回覆 發表時間:2009-03-19 14:59:16 IP:221.5.xxx.xxx 訂閱
对于 USER 为 NETWORK SERVICE和LOCAL SERVICE的PROCESS用OPENPROCESSTOKEN是不成功的,好象这一点在MSDN上有提到,
不过你可以在网上查一下用WTSEnumerateProcesses 这个FUNC可以得到PROCESS的SID
dino
一般會員


發表:20
回覆:72
積分:23
註冊:2002-07-29

發送簡訊給我
#8 引用回覆 回覆 發表時間:2009-03-19 18:17:42 IP:61.63.xxx.xxx 訂閱
感謝 thf 的鼎力相助,熱心的回答讓我總算找到解決的方法了
運用WTSEnumerateProcesses 搭配 LookupAccountSid 總算把所有的Process的使用者名稱都列出來了
晚點整理一下程式碼貼上來,感恩^^
===================引 用 thf 文 章===================
对于 USER 为 NETWORK SERVICE和LOCAL SERVICE的PROCESS用OPENPROCESSTOKEN是不成功的,好象这一点在MSDN上有提到,
不过你可以在网上查一下用WTSEnumerateProcesses 这个FUNC可以得到PROCESS的SID
系統時間:2017-12-14 20:57:27
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!