我只是想知道是否有一种有效的方法可以保护带有密码字符集的 TEdit 字段,这些工具可以从可以以纯文本形式读回的工具。
我认为这些工具例如抓取 TEdit 的目标句柄并使用 gettext 或类似的东西。
到目前为止,我尝试的是为存储在变量中的密码创建一个哈希,并将其写回 TEdit 丢失的焦点,但这对我来说没有意义,因为我需要存储另一个密码来计算里面的哈希的可执行文件。
也许有人对如何保护 TEdit 文本免受这些工具的影响有更好的了解。
带有样式的编辑控件ES_PASSWORD
可防止将其文本复制到剪贴板。剩下的就是拒绝向其他应用程序显示其窗口文本并将密码字符重置为空。后代类可以处理这些。
type
TPasswordEdit = class(TEdit)
protected
procedure EmGetPasswordChar(var Message: TMessage); message EM_GETPASSWORDCHAR;
procedure EmSetPasswordChar(var Message: TMessage); message EM_SETPASSWORDCHAR;
procedure WMGetText(var Message: TMessage); message WM_GETTEXT;
end;
procedure TPasswordEdit.EmGetPasswordChar(var Message: TMessage);
begin
// for nirsoft's BulletsPassView, probably only prevents further inspection,
// injecting a thread perhaps - I have no idea what it's doing..
if (PasswordChar = #0) or not InSendMessage then
inherited;
end;
procedure TPasswordEdit.EmSetPasswordChar(var Message: TMessage);
begin
if (PasswordChar <> #0) and (Message.WParam <> 0) then
inherited;
end;
procedure TPasswordEdit.WMGetText(var Message: TMessage);
begin
if (PasswordChar = #0) or not InSendMessage then // allow owning thread
inherited;
end;
如果您真的只对通过从 TEdit 组件读取文本来防止其他程序提取密码感兴趣,那么我建议您改用 TMaskEdit ( http://docwiki.embarcadero.com/Libraries/Berlin/en/Vcl.Mask.TMaskEdit ) .
与 TEdit 不同,TMaskEdit 将原始文本存储在局部变量中,同时它可以显示不同格式的文本。这意味着这些程序总是会得到格式化的文本,而不是真正的密码文本。
但正如许多其他人所说,这不会为您提供太多保护,因为大多数恶意软件都依赖于按键记录方法,它们只是记录按下了哪些键。
愚弄他们的最佳选择是使用完全自定义的组件,它甚至不使用标准的 Windows 文本处理 API,因此他们甚至不知道何时输入密码。
你可以做这样的事情。使用 ReadOnly=true 的普通编辑并隐藏您自己的密码。只有编辑中的内容是 *. 此示例适用于字母数字字符,但您可以轻松添加其他字符。此外,如果您想在编辑中使用选择,您也需要处理它。
代码:
uses
StrUtils;
var
password: String;
...
procedure TForm1.FormCreate(Sender: TObject);
begin
password:='';
end;
...
procedure TForm1.Edit1KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
var sel: Integer;
begin
sel:=Edit1.SelStart;
if((Key>=48) and (Key<=90))then
begin
if(ssShift in Shift)then
password:=LeftStr(password, sel)+Char(Key)+RightStr(password, Length(Edit1.Text)-sel)
else
password:=LeftStr(password, sel)+LowerCase(Char(Key))+RightStr(password, Length(Edit1.Text)-sel);
Edit1.Text:=Edit1.Text+'*';
Edit1.SelStart:=sel+1;
end
else if((Key>=VK_NUMPAD0) and (Key<=VK_NUMPAD9))then
begin
password:=LeftStr(password, sel)+Char(Key-48)+RightStr(password, Length(Edit1.Text)-sel);
Edit1.Text:=Edit1.Text+'*';
Edit1.SelStart:=sel+1;
end
else if((Key=VK_BACK) and (sel>0))then
begin
Delete(password, sel, 1);
Edit1.Text:=Copy(Edit1.Text, 1, Length(Edit1.Text)-1);
Edit1.SelStart:=sel-1;
end
else if((Key=VK_DELETE) and (sel<Length(Edit1.Text)))then
begin
Delete(password, sel+1, 1);
Edit1.Text:=Copy(Edit1.Text, 1, Length(Edit1.Text)-1);
Edit1.SelStart:=sel;
end
else if(Key=VK_RETURN)then
begin
//handle the password check here (make hash etc)
ShowMessage(password);
password:='';
Edit1.Text:='';
end;
//just for the testing, this should be removed of course
Form1.Caption:=password;
end;