使用了文本框後:防止 軟體讀取 文本框中 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.