通过令牌(Token)获取登录用户信息

通过令牌(Token)获取登录用户信息

我在之前的一篇文章里(小小地实现一个 whoami)写到查询当前进程的登录用户信息,但这个代码对于用 LogonUser 这种函数获取的令牌的 SID(Logon SID)是无效的(可以参考 MSDN 的 LookupAccountSid function 这篇文章的 Remarks 部分)。因此这里需要另外的方法来获取我们所需的信息。

思路:对于登录令牌,如果用之前的方法,LookuoAccountSid 函数会设置 LastError = ERROR_NONE_MAPPED,因此我们不能继续使用 TokenUser 参数了。我在 MSDN 的 GetTokenInformation function 这篇文章里查找相关信息后发现,我们可以使用 TokenAccessInformation 这个参数来获取令牌的访问信息,这里面就包含了我们所需的 SID。

代码(在 Delphi XE2 上编译通过):

program GetTokenIdent;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils,
  Windows;

type
  SID_HASH_ENTRY = ULONG_PTR;

  _SID_AND_ATTRIBUTES_HASH = record
     SidCount: DWORD;
     SidAttr: ^SID_AND_ATTRIBUTES;
     Hash: array [0..31] of SID_HASH_ENTRY;
  end;
  SID_AND_ATTRIBUTES_HASH = _SID_AND_ATTRIBUTES_HASH;
  PSID_AND_ATTRIBUTES_HASH = ^SID_AND_ATTRIBUTES_HASH;

function GetTokenIdentity(hToken: THandle): String;
var
  UserName, UserDomain: String;
  cbName, cbDomainName: ULONG;
  ReturnLength: DWORD;
  Buff: array of Byte;
  tai: PTokenAccessInformation;
  saah: PSID_AND_ATTRIBUTES_HASH;
  saa: PSIDAndAttributes;
  peUse: SID_NAME_USE;
  i: Integer;
label
  Cleanup;
begin
  Result := '';

  // 获取令牌信息
  if not GetTokenInformation(hToken, TokenAccessInformation, nil, 0, ReturnLength) then
    if GetLastError = ERROR_INSUFFICIENT_BUFFER then
    begin
      SetLength(Buff, ReturnLength);
      GetTokenInformation(hToken, TokenAccessInformation, @Buff[0], ReturnLength, ReturnLength);
      tai := @Buff[0];
    end
    else
      Exit
  else
    Exit;

  // 由于 Delphi XE2 里 TOKEN_ACCESS_INFORMATION 的结构有误,因此我必须对其进行转换
  // TOKEN_ACCESS_INFORMATION 的 SidHash 结构包含了用户 SID 和组 SID
  saah := PSID_AND_ATTRIBUTES_HASH(tai.SidHash);
  saa := PSIDAndAttributes(saah.SidAttr);

  for i := 0 to saah.SidCount - 1 do
  begin
    cbName := 0;
    cbDomainName := 0;
    if not LookupAccountSid(nil, saa.Sid, nil, cbName, nil, cbDomainName, peUse) then
      if GetLastError = ERROR_INSUFFICIENT_BUFFER then
      begin
        SetLength(UserName, cbName);
        SetLength(UserDomain, cbDomainName);
        if LookupAccountSid(nil, saa.Sid, @UserName[1], cbName, @UserDomain[1], cbDomainName, peUse) then
        begin
          SetLength(UserName, cbName);
          SetLength(UserDomain, cbDomainName);
          Result := UserDomain + '\' + UserName;
          // 如果 peUse 的类型为 SidTypeUser 则表明这就是我们所需的用户信息了
          if peUse = SidTypeUser then Break;
        end;
      end;
    Inc(saa);
  end;

  SetLength(Buff, 0);
end;

var
  hToken: THandle;

begin
  try
    LogonUser('TestUser', '.', '123456',LOGON32_LOGON_INTERACTIVE,LOGON32_PROVIDER_DEFAULT, hToken);
    Writeln(GetTokenIdentity(hToken));
    CloseHandle(hToken);
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

运行结果:

通过令牌(Token)获取登录用户信息_第1张图片

posted on 2012-10-20 15:43 Ich war HackPascal 阅读( ...) 评论( ...) 编辑 收藏

转载于:https://www.cnblogs.com/hackpascal/archive/2012/10/20/2732207.html

你可能感兴趣的:(通过令牌(Token)获取登录用户信息)