我正在进入一个需要管理(写/读)缓存凭据的项目。就我而言,特别是(TERMSRV)或流行的远程桌面。
在我的Windows 7上,我发现文件存储在“AppData \ Local \ Microsoft \ Credentials”中。当我打开mstsc(远程桌面客户端)并保存凭证时,会在此目录上创建一个新文件(隐藏并受系统保护)。我试着在记事本上打开文件,它是加密数据。就我所看到的,看起来像Windows使用Data Protection API(DPAPI),特别是CryptProtectData / CryptUnprotectData函数来保存/检索缓存的凭据。
我的第一次尝试是在CredRead函数上,但我发现域密码(CRED_TYPE_DOMAIN_PASSWORD - 完全是终端服务的类型)只能由身份验证包读取。在发现之后,我开始搜索一些工具,我发现有些人正在将一个DLL注入LSASS进程,以完成这项工作。但是我看到Nirsoft NetPass成功解密了我保存的密码,并且通过Process Explorer,我没有在LSASS上看到任何新的DLL注入。看起来他使用CryptUnprotectData直接在凭证文件上工作。
问题是:无论如何从这个文件中检索缓存的密码,而不需要注入dll并执行此类操作?如果是,那么CryptUnprotectData的方式是什么?最后,如果是,那么函数接收的DATA_BLOB是什么?文件的内容?我只是无法理解如何使用该功能,从哪里获取blob?
修改::
我仅在Windows / WinAPI标签上发布此问题,但几乎没有视图,也没有答案。我相信主要的问题,是语言无关,但我在Delphi中做项目,所以这里是CredRead的Delphi代码,它只获取用户名,但无法列出密码,因为该帐户是域类型(CRED_TYPE_DOMAIN_PASSWORD)
type
PCREDENTIAL_ATTRIBUTEW = ^_CREDENTIAL_ATTRIBUTEW;
_CREDENTIAL_ATTRIBUTEW = record
Keyword: LPWSTR;
Flags: DWORD;
ValueSize: DWORD;
Value: LPBYTE;
end;
PCREDENTIALW = ^_CREDENTIALW;
_CREDENTIALW = record
Flags: DWORD;
Type_: DWORD;
TargetName: LPWSTR;
Comment: LPWSTR;
LastWritten: FILETIME;
CredentialBlobSize: DWORD;
CredentialBlob: LPBYTE;
Persist: DWORD;
AttributeCount: DWORD;
Attributes: PCREDENTIAL_ATTRIBUTEW;
TargetAlias: LPWSTR;
UserName: LPWSTR;
end;
PCredentialArray = array of PCREDENTIALW;
const
CRED_TYPE_GENERIC = 1;
CRED_TYPE_DOMAIN_PASSWORD = 2;
CRED_TYPE_DOMAIN_CERTIFICATE = 3;
CRED_TYPE_DOMAIN_VISIBLE_PASSWORD = 4;
CRED_TYPE_MAXIMUM = 5; // Maximum supported cred type
CRED_TYPE_MAXIMUM_EX = CRED_TYPE_MAXIMUM + 1000; // Allow new applications to run on old OSes
var
Form1: TForm1;
function CredReadW(TargetName: LPCWSTR; Type_: DWORD; Flags: DWORD; var Credential: PCREDENTIALW): BOOL; stdcall; external 'advapi32.dll';
function CredEnumerateW(Filter: LPCWSTR; Flags: DWORD; out Count: DWORD; out Credential: PCredentialArray): BOOL; stdcall; external 'advapi32.dll';
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
var
Credentials: PCredentialArray;
Credential: PCREDENTIALW;
UserName: WideString;
i: integer;
dwCount: DWORD;
begin
if CredEnumerateW(PChar('TERM*'), 0, dwCount, Credentials) then
begin
for i:= 0 to dwCount - 1 do
begin
if CredReadW(Credentials[i].TargetName, Credentials[i].Type_, 0, Credential) then
begin
UserName:= Credential.UserName;
Memo1.Lines.Add(Credentials[i].TargetName + ' :: ' + UserName + ' >> ' + IntToStr(Credentials[i].Type_));
Memo1.Lines.Add(IntToStr(Credential.CredentialBlobSize));
end;
end;
end;
end;