C# 解密Windows凭据文件
我进入了一个需要管理(写/读)缓存凭据的项目。在我的例子中,特别是(TERMSRV)或流行的远程桌面 在我的Windows 7上,我已经发现文件存储在“AppData\Local\Microsoft\Credentials”中。当我打开mstsc(远程桌面客户端)并保存凭证时,将在此目录上创建一个新文件(神秘且受系统保护)。我试着在记事本上打开文件,它是加密数据。据我所见,Windows似乎使用数据保护API(DPAPI),特别是/functions来保存/检索缓存的凭据 我的第一次尝试是在函数上,但我发现域密码(正是终端服务的类型)只能由身份验证包读取。在这个发现之后,我开始搜索一些工具,我发现一些人正在向LSASS进程中注入一个DLL来完成这项工作。但我看到它成功地解密了我保存的密码,并且通过Process Explorer,我没有看到在LSASS上注入任何新的DLL。看起来他使用CryptUnprotectData直接处理凭证文件 问题是:是否有任何方法可以从这个文件中检索缓存的密码,而无需插入dll并执行此类操作?如果是,方法将是加密未保护的数据?最后,如果是,函数接收的数据是什么?文件的内容是什么?我只是不明白如何使用这个函数,从哪里开始 编辑:: 我只在Windows/WinAPI标签上发布了这个问题,但几乎没有视图,也没有答案。我相信主要的问题是语言无关的,但我在Delphi中做这个项目,所以这里是CredRead的Delphi代码,它只获取用户名,但不能列出密码,因为帐户是域类型(CRED_type_domain_password)C# 解密Windows凭据文件,c#,c++,delphi,winapi,C#,C++,Delphi,Winapi,我进入了一个需要管理(写/读)缓存凭据的项目。在我的例子中,特别是(TERMSRV)或流行的远程桌面 在我的Windows 7上,我已经发现文件存储在“AppData\Local\Microsoft\Credentials”中。当我打开mstsc(远程桌面客户端)并保存凭证时,将在此目录上创建一个新文件(神秘且受系统保护)。我试着在记事本上打开文件,它是加密数据。据我所见,Windows似乎使用数据保护API(DPAPI),特别是/functions来保存/检索缓存的凭据 我的第一次尝试是在函数
这与C++/C#有什么关系?在WinAPI上没有人知道答案。这个问题与语言无关,是一个关于windows功能的问题,你可以在这里回答并粘贴你的C++/C#代码(如果你有),如果这个问题解决了,我会接受答案。Delphi中的代码只是人们对我尝试的内容有一个想法的一个片段。您的最终目标是什么,使用缓存凭据登录到终端服务,还是模仿Netpass中的功能?PS:您的代码泄漏内存,您需要通过
CredFree
释放CreadReadW返回的缓冲区。我的第一个目标是模拟功能,以便能够读取/写入已创建的凭据,包括现有凭据。是的,CredFree是必要的,我只是没有这样做,因为我看到代码不起作用,所以我不知道我是应该继续这样做(crederead)还是尝试其他方法…你必须同时做这两件事(CredEnumerate/CreadRead)并解密文件以恢复密码…这与C++/C#有什么关系?在WinAPI上没有人知道答案。这个问题与语言无关,是一个关于windows功能的问题,你可以在这里回答并粘贴你的C++/C#代码(如果你有),如果这个问题解决了,我会接受答案。Delphi中的代码只是人们对我尝试的内容有一个想法的一个片段。您的最终目标是什么,使用缓存凭据登录到终端服务,还是模仿Netpass中的功能?PS:您的代码泄漏内存,您需要通过CredFree
释放CreadReadW返回的缓冲区。我的第一个目标是模拟功能,以便能够读取/写入已创建的凭据,包括现有凭据。是的,CredFree是必要的,我只是没有这样做,因为我看到代码不起作用,所以我不知道我是应该继续这样做(crederead)还是尝试其他方法…你必须同时做(CredEnumerate/CreadRead)和解密文件来恢复密码。。。
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;