2

I just wonder if there is an efficient way of protecting an TEdit field with password char set from tools which can read it back in plain text.

I think those tools for example grab the target handle of the TEdit and use gettext or something similar.

What I have tried so far is creating a hash for the password stored it in a variable and write it back on focus lost of the TEdit but that doesn't make sense to me since I would need to store another password for calculating the hash inside of the executable.

Maybe someone has a better idea of how the TEdit text could be protected against those tools.

Hans Harz
  • 203
  • 2
  • 13
  • Something has to store and retrieve the password. Why are you letting malicious software run on your machine? – David Heffernan Jun 20 '16 at 06:22
  • What does that have to do with my machine? The program could run on any machine where I have no access to... – Hans Harz Jun 20 '16 at 06:24
  • The only way would be to create an extended version of TEdit with a hash, like you said. The component could create a random hash when it's instantiated, making it very difficult for external tools to hack the password. But usually the best way is to not send the true password back to the GUI, only a placeholder. – Guillaume F. Jun 20 '16 at 06:28
  • Once the machine has malicious software running it's game over. It's naive and pointless to imagine that you can remain secure at that point. – David Heffernan Jun 20 '16 at 06:46
  • @Guillaume something has to store the password and if the program can read the password as it needs to then so can the attacker. – David Heffernan Jun 20 '16 at 06:47
  • You do not store a password in a GUI, you store it in a safe place, hashed. The only time a password should appear in a TEdit is when the user types it for the first time. – Guillaume F. Jun 20 '16 at 06:49
  • 1
    @Guillaume When the user types it is exactly the point of the question. You'veissed the point. – David Heffernan Jun 20 '16 at 06:50
  • @David sure you can not be 100% safe but make it harder... The tools which I referring to use normally pure winapi to get the text. I'm not talking about reverse engineering, keyloggers, rootkits or something... – Hans Harz Jun 20 '16 at 06:52
  • You are deluding yourself in my view. The false illusion of security. Don't let malicious software into your machine. It's over once you do that. – David Heffernan Jun 20 '16 at 06:59
  • I'll think you miss the point, if you write a program which runs on somebody else computer what will you do? Tell them don't run malicious software? There are situations where it in not on your hand but you can like I say make it harder to get these passwords also I'll told before I'm not talking about programs where you have no chance against them there I'll fully agree with you! But again I'm talking about tools which any one could use which are in my opinion are not so malicious (imagine you forgot your password?) there might be a reason to use them for a legal user. – Hans Harz Jun 20 '16 at 07:07
  • The possible approach of hiding secret data is to encrypt it with a public key. If a malicious software cannot intercept the plaintext, it can't restore the plaintext even if it knows the public key, because this operation requires private key; the private key in this scenario is not present in a user computer at all. – kludg Jun 20 '16 at 07:18
  • Muddled thinking in my view. Up to you. – David Heffernan Jun 20 '16 at 07:42
  • @user246408 Can you describe how that works with a password edit control – David Heffernan Jun 20 '16 at 07:51
  • If its not your point of view it must be wrong... – Hans Harz Jun 20 '16 at 07:56
  • The question as I understand it has no relation to edit control. – kludg Jun 20 '16 at 07:58
  • Why I've added the editfield tag to the question :) – Hans Harz Jun 20 '16 at 08:00
  • Have you thought of going the route that banks use - rather than entering the full password users are asked for, say, the 1st 3rd and last character of the password. The full password is never present on the user's PC at one time and the digits asked for can be recorded and different every time. You can also use drop down lists rather than Tedits to foil key loggers. More work for the coder, but not significantly more inconvenient that a full password for a user. I does depend on how valuable the resource that you are trying to protect is, of course. – Michael Vincent Jun 20 '16 at 08:23
  • @user246408 There are 5 mentions of TEdit, and content talking about extracting text from an edit control using its window handle – David Heffernan Jun 20 '16 at 08:23

3 Answers3

1

If you are realy only interested in preventing other programs from extracting the pasword by reading text from TEdit component then I suggest you use TMaskEdit instead (http://docwiki.embarcadero.com/Libraries/Berlin/en/Vcl.Mask.TMaskEdit).

Unlike TEdit TMaskEdit stores the orginal text inside local variable while it can display different formated text. This means that those programs would always get that formated text instead of real password text.

But as many others said this won't give you much protection as most malicious software instead rely on Key-Logging approach where they are simply loging which keys were pressed.

Best option in fooling them would be to use compleetely custom component which doesen't even use standard Windows text handling API, so they don't know when the pasword is even being entered.

SilverWarior
  • 7,372
  • 2
  • 16
  • 22
  • A MaskEdit is a standard edit control. The only difference of the text the control displays and the internal non-masked text is the formatting of the mask. I don't think a maskedit can be used to conceal what it holds. – Sertac Akyuz Jun 20 '16 at 19:03
1

Edit controls with ES_PASSWORD style prevent their text to be copied to the clipboard. What remains is to deny revealing its window text to other applications and resetting the password character to null. A descendant class can handle these.

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;
Sertac Akyuz
  • 54,131
  • 4
  • 102
  • 169
  • I can confirm Password Revealer [here](http://www.rekenwonder.com/revealer.htm) sends a EM_SETPASSWORDCHAR. Password Reveal 2.0 [here](http://www.majorgeeks.com/files/details/password_reveal.html) ($19.95 - I used the trial) sends a WM_GETTEXT. There should be of course tons of their kind, but they should be similar. – Sertac Akyuz Jun 20 '16 at 19:18
  • It's going to be simple to inject code and call the default window proc. It's all pointless since the user just types the password anyway. Why would anyone pay $20 to show what they just typed? – David Heffernan Jun 21 '16 at 06:17
  • @Sertac I think Bulletpassview uses ReadProcessMemory I've created a small test like: SetProcessHandleRights(PROCESS_ALL_ACCESS and not PROCESS_VM_READ); getWindowThreadProcessId(self.Handle, ProcId); ProcHandle := OpenProcess(PROCESS_ALL_ACCESS, false, ProcId); closeHandle(ProcHandle); called in form create which prevents bulletpass successfully from getting the edit.text – Hans Harz Jun 21 '16 at 07:03
  • @David - I guess the use case is for already typed passwords - for programs that have an option for remembering passwords - they launch a dialog with the password filled in. The pricing is probably from a previous era - the home site seems to be gone. – Sertac Akyuz Jun 21 '16 at 11:45
  • @Hans - Makes sense, need to retrieve the result f.i. if you ran a remote thread to get the text. – Sertac Akyuz Jun 21 '16 at 11:46
  • @SertacAkyuz It would be a truly lame program that filled out the password edit box with the actual value when displaying already typed passwords! – David Heffernan Jun 21 '16 at 11:59
-3

You can do something like this. Use a normal Edit with ReadOnly=true and make your own password hiding. Only content which would be in the Edit are the *. This example works with alphanumeric characters but you can easily add the others. Also if you want to use selection in the Edit, you need to handle that too.

Code:

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;
jano152
  • 147
  • 1
  • 7
  • Doesn't look like it's going to be remotely robust. What if the keyboard layout is not what you expect? The handling of virtual key codes seems rather naive. And what if the user pastes the password? Or uses accessibility or automation? – David Heffernan Jun 20 '16 at 08:39
  • Well, that all depends on the purpose of your application. You can easily block pasting so user needs to fill it manually. In this case just add "if(ssCtrl in Shift)then Exit;" to the beginning of the KeyDown event and Ctrl+V won't do anything. Right click doesn't help neither because of the ReadOnly. As for the key codes, you can use other method to catch the pressed keys. – jano152 Jun 20 '16 at 08:44
  • Blocking pasting would greatly reduce usability, for example when working with a password manager – David Heffernan Jun 20 '16 at 09:06
  • Then you can easily handle the pasting too. It's really simple to add pasting to this example. Just another test with ssCtrl and Key=56. – jano152 Jun 20 '16 at 09:19