如何防止文本框中加密的字符被窃取??

来源:互联网 发布:淘宝运营kpi考核指标 编辑:程序博客网 时间:2024/05/22 10:58

使用了文本框后:防止 软件读取 文本框中 TEXT
在WINDOWS下的密码输入框一般都是以 “*” 来显示密码的,而有许多工具软件可以窃取密码,下面我就分析下如何防止“*” 密码泄露。

1. 取同一程序密码框中的内容
   一般我们的密码框用 TEDIT 的PasswordChar 属性为 “*”,首先还是了解下EDIT1.TEXT 取文本框内容的原理。在DELPHI
中可以知道TEDIT继承自TCustomEdit,而TCustomEdit 继承自TControl. TControl中的Property Text是调用Gettext,而,GetText
调用了GetTextBuf,GetTextBuf 调用了Perform(SendMessage)最终实现了读取Edit中的内容。
关键代码可以在DELPHI的Controls.pas 和StdCtrls.pas文件中看到。

property Text: TCaption read GetText write SetText;

function TControl.GetText: TCaption;
var
  Len: Integer;
begin
  Len := GetTextLen;
  SetString(Result, PChar(nil), Len);
  if Len <> 0 then GetTextBuf(Pointer(Result), Len + 1);
end;

function TControl.GetTextBuf(Buffer: PChar; BufSize: Integer): Integer;
begin
  Result := Perform(WM_GETTEXT, BufSize, Longint(Buffer));
end;


通过看代码可以知道要获得Edit1的内容可以用下面的语句:
    SendMessage(Edit1.handle,WM_GETTEXT,i,integer(buffer));
其中,buffer是PCHAR类型,用于存放Edit1中的内容,i 是buffer的空间大小。
示例代码如下:

procedure TForm1.Button1Click(Sender: TObject);
var
    buffer:PChar;
    L:integer;
begin
    L:=GetWindowTextLength(Edit1.handle);
    GetMem(buffer,L+1);
    SendMessage(Edit1.handle,WM_GETTEXT,L,integer(buffer));
    label1.Caption:=String(buffer);
    FreeMem(buffer);
end;

实际使用 SendMessage(Edit1.handle,WM_GETTEXT,L,integer(Name));语句可以用
GetWindowText(Edit1.handle,buffer,L);代替,GetWindowText 是Windows API函数
这是在本地程序中取密码,如果在其他程序中取密码框中的内容时,必须先用各种方法取的密码框的句柄
再用SendMessage取的密码框的内容,为了保证通用性比较常用的办法是用鼠标钩子取鼠标当前位置的控件
句柄。具体的实现方法,在我的另外的读书笔记“钩子”中可以看到。

2.如何防范密码框密码泄露

 现在软件的登陆密码时间上是一种很脆弱的安全防范方式,除了用上面说的方法窃取到,还可以用
更简单的办法可以得到,那就是用SendMessage向密码框发送一个EM_GETPASSWORDCHAR消息,将Passwordchar
设置为#0,就可以让密码显示出来,所以对重要的密码加上一曾保护是必要的。
  因为现在的WINDOWS下的开发工具编写密码框时都是调用了WINDOWS系统编辑框,所以为了避免这种情况,一个
简单的饿办法就是子类化(Subclassing),也就是使用自己自定义的编辑框,并使字定义的WindowProc来进行消息
处理,对 Passwordchar的设置和文本读取消息(分别是EM_SETPASSWORDCHAR和WM_GETTEXT)进行检查,把那些
非法操作过滤掉,下面的子类化的TPasswordEdit完全过滤了以上两个消息,其基本原则是在密码框的消息处理
函数中使用一个变量(见下例中的FAllowPasswordRead或FAllowPasswordCharChange)来标志是否是自己的代码
如果是来历不明的代码试图设置passwordchar或读取文本,就不给它返回任何数值。

代码如下:
type
  TPasswordEdit = class(TEdit)  //建立新的控件
  private
    FFalsePassword: TCaption;
    FAllowPasswordRead: Boolean;
    FAllowPasswordCharChange: Boolean;
    function GetPasswordChar: Char;
    function GetText: TCaption;
    procedure SetPasswordChar(const Value: Char);
    procedure SetText(const Value: TCaption);
  public
    constructor Create(AOwner: TComponent); override;
    procedure DefaultHandler(var Message); override;
  published
    property AllowPasswordCharChange: Boolean read FAllowPasswordCharChange write FAllowPasswordCharChange;
    property AllowPasswordRead: Boolean read FAllowPasswordRead write FAllowPasswordRead;
    property PasswordChar: Char read GetPasswordChar write SetPasswordChar default '*';
    property FalsePassword: TCaption read FFalsePassword write FFalsePassword;
    property Text: TCaption read GetText write SetText;
  end;

  TForm1 = class(TForm)
    Edit1: TEdit;
    Label1: TLabel;
    Label2: TLabel;
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    PasswordEdit1: TPasswordEdit;
  end;
var
  Form1: TForm1;

implementation

{$R *.DFM}

constructor TPasswordEdit.Create(AOwner: TComponent);
begin
  AllowPasswordCharChange := true;
  AllowPasswordRead := true;
  inherited Create(AOwner);
  AllowPasswordCharChange := false;
  AllowPasswordRead := false;
  PasswordChar := '*'; {显示*}
end;

procedure TPasswordEdit.SetPasswordChar(const Value: Char);
var
  OldAPCC, OldAPR: boolean;
begin
  OldAPCC := FAllowPasswordCharChange;
  OldAPR := FAllowPasswordRead;
  FAllowPasswordCharChange := true;
  FAllowPasswordRead := true;
  if HandleAllocated then
    inherited PasswordChar := Char(Sendmessage(Handle, EM_GETPASSWORDCHAR, 0, 0));
  inherited PasswordChar := Value;
  FAllowPasswordCharChange := OldAPCC;
  FAllowPasswordRead := OldAPR;
end;

function TPasswordEdit.GetPasswordChar: Char;
begin
  if HandleAllocated then
    Result := Char(Sendmessage(Handle, EM_GETPASSWORDCHAR, 0, 0))
  else
    Result := inherited PasswordChar;
end;

procedure TPasswordEdit.SetText(const Value: TCaption);
begin
  inherited Text := Value;
end;

function TPasswordEdit.GetText: TCaption;
var
  OldAPCC, OldAPR: boolean;
begin
  OldAPCC := FAllowPasswordCharChange;
  OldAPR := FAllowPasswordRead;
  FAllowPasswordCharChange := true;
  FAllowPasswordRead := true;
  Result := inherited Text;
  FAllowPasswordCharChange := OldAPCC;
  FAllowPasswordRead := OldAPR;
end;

procedure TPasswordEdit.DefaultHandler(var Message);
var
  P: PChar;
begin
  if (csDesigning in ComponentState) or (csCreating in ControlState) then
    inherited //如果在程序设计和正在建立阶段不需要做任何变动
  else
    with TMessage(Message) do
      case msg of
        EM_SETPASSWORDCHAR: if FAllowPasswordCharChange then
            inherited;  //如果允许设置EM_SETPASSWORDCHAR才可以继续
        WM_GETTEXT: if FAllowPasswordRead then inherited
          else begin
            P := PChar(FFalsePassword);
            Result := StrLen(StrLCopy(PChar(LParam), P, WParam - 1));
          end;  //如果允许读文本才可以继续否则返回(FFalsePassword)的长度
        WM_GETTEXTLENGTH: if FAllowPasswordRead then inherited
          else
            if PChar(FFalsePassword) = nil then Result := 0
            else Result := StrLen(PChar(FFalsePassword));  //如果允许读文本 才可以继续否则返回0或位密码
      else
        inherited;
      end
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  PasswordEdit1 := TPasswordEdit.Create(self);
  PasswordEdit1.parent := form1;
  PasswordEdit1.Width := 150;
  PassWordEdit1.Height := 21;
  PasswordEdit1.Top := 115;
  PasswordEdit1.Left := 80;
  PasswordEdit1.PasswordChar := '*';
  PasswordEdit1.AllowPasswordRead := false;
  PasswordEdit1.Visible := true;
  PasswordEdit1.Text:='Hello';
  PasswordEdit1.FalsePassword:= '想读我?没门!'
end;

end.

 

 

原创粉丝点击