Windows 里有一个程序叫做 whoami.exe,它用来显示调用者的用户身份。whoami.exe 的功能很多,在这里我只实现它最基本的功能——显示当前登录的用户(NTLM 格式)。
思路:首先知道 LookupAccountSid 函数可以获取我们所需的用户名和登陆域->LookupAccountSid 通过 SID 来查询信息->可以通过 GetTokenInformation 查询进程令牌里的 SID->用 OpenProcessToken 可以获取进程的令牌。
代码(在 Delphi XE2 上编译通过):
1 function GetProcessIdentity(): String; 2 var 3 hToken: THandle; 4 UserName, UserDomain: String; 5 cbName, cbDomainName: ULONG; 6 ReturnLength: DWORD; 7 Buff: array of Byte; 8 tu: PTokenUser; 9 peUse: SID_NAME_USE; 10 label 11 Cleanup; 12 begin 13 Result := ''; 14 // 打开进程令牌 15 if not OpenProcessToken(GetCurrentProcess, MAXIMUM_ALLOWED, hToken) then Exit; 16 17 // 查询用户账户令牌 18 19 // 首先获取需要的缓冲区大小 20 if not GetTokenInformation(hToken, TokenUser, nil, 0, ReturnLength) then 21 if GetLastError = ERROR_INSUFFICIENT_BUFFER then 22 begin 23 // 设置缓冲区大小 24 SetLength(Buff, ReturnLength); 25 // 获取数据 26 GetTokenInformation(hToken, TokenUser, @Buff[0], ReturnLength, ReturnLength);
27 tu := PTokenUser(@Buff[0]);
28 end 29 else 30 goto Cleanup 31 else 32 goto Cleanup; 33 34 // 通过 SID 查询用户名及登陆域 35 cbName := 0; 36 cbDomainName := 0; 37 // 获取需要的缓冲区大小 38 if not LookupAccountSid(nil, tu.User.Sid, nil, cbName, nil, cbDomainName, peUse) then 39 if GetLastError = ERROR_INSUFFICIENT_BUFFER then 40 begin 41 // 设置字符串长度(包含 NULL 字符) 42 SetLength(UserName, cbName); 43 SetLength(UserDomain, cbDomainName); 44 // 获取数据 45 if LookupAccountSid(nil, tu.User.Sid, @UserName[1], cbName, @UserDomain[1], cbDomainName, peUse) then 46 begin 47 // 截去最后的 NULL 字符 48 SetLength(UserName, cbName); 49 SetLength(UserDomain, cbDomainName); 50 end 51 else 52 goto Cleanup; 53 end 54 else 55 goto Cleanup 56 else 57 goto Cleanup; 58 59 // 组合信息 60 Result := UserDomain + '\' + UserName; 61 62 Cleanup: 63 // 关闭令牌 64 CloseHandle(hToken); 65 end;
运行结果:

whoami.exe 的其他功能都是通过 GetTokenInformation 和 LookupAccountSid 这两个函数完成的,至于其他功能的实现,我将在以后更新。
浙公网安备 33010602011771号