Creating a SecureString type for Delphi, Part 1.

As developers, we often deal with sensitive data; credit cards, passwords, maybe even medical records. We read such data from drive, or the user gives it to us via the UI, and we then have it in memory.

How do we protect sensitive in-memory data? Surely the operating system forbids processes from accessing each other’s allocated memory, right? While that is generally correct, here are a few scenario’s where our process memory can fall into the wrong hands:

  1. Process memory can get written unencrypted to the hibernation file, and perhaps the page file is it is not marked as non-pageable.
  2. If your application were to ever crash, the tool chain in use by your customer could automatically upload the memory dump file to a central server for engineers to figure out why it crashed.
  3. Malware could create a dump file, and then run a dictionary attack on your process memory.

How do we protect our applications? Sure, you can encrypt your process memory. ASProtect, for example, is a very cool product. But such techniques are known to make anti-virus “solutions” very upset. Expect your customers reporting false positives to you.

Developers often think they can solve this problem with encryption. Yes you should encrypt your customer’s data where possible. But at some moment in time during your application session, anything that is decrypted or waiting to be encrypted is stored in memory in plain-text.

Apart from encryption, what we should do is keep sensitive data in memory for the shortest life span possible, and then immediately zero those bytes out when we’re done with them. Because when everything is constantly decrypted (and never zero’ed out), then this provides a much larger attack vector.

First, let us take a look at Delphi strings and see how they can help us.

While Delphi strings look and feel like value types, they are actually pointers to dynamically allocated data; their value holds the actual memory location of the string.

Delphi strings are reference counted. This mechanism keeps track of how many string variables are referring to the same string in memory. Assume you have a string-type variable named A. When variable A is assigned to variable B, then both variables “point” to the same bytes in memory.

This reference counting mechanism is also used to free the memory when a string isn’t used anymore. When both our variables A and B go out of scope, then the reference count drops to zero and the associated memory is released automatically. Awesome, it sounds like we’re good here.

Unfortunately, it is not that simple. While the Delphi run-time library will release the memory your variables were pointing to, those bytes aren’t zero’ed out, and that could be a problem if those strings were credit cards or passwords.

Here is how you can reproduce this problem:

  1. Create a new Delphi VCL application, then add a password dialog.
  2. When the user has logged into our application, we will then process the password he/she has given to us (hopefully, we will salt and then hash the password, but that is a story for another day).
  3. We will make sure the Delphi string variable that used to hold the plain-text password goes out of scope.
  4. We will create a dump file, and
  5. We will try and find the plain-text password in the memory dump, using Mark Russinovich’ excellent Strings.

Step 1: Create a new Delphi VCL application

  1. Create a new Delphi VCL application
  2. Drop a button from the Tool Palette onto the main form
  3. Click on: File > New > Other > Delphi Files > Password Dialog
  4. Double-click on Button1, then enter this code:
uses
PASSWORD,
System.StrUtils;
procedure TForm1.Button1Click(Sender: TObject);
var
S: string;
begin
with TPasswordDlg.Create(Self) do
try
if ShowModal <> mrOk then
EXIT;
S := Password.Text;
if S <> '' then
ShowMessage(ReverseString(S));
finally
Free;
end;
end;

This code is pretty straightforward. We are assigning the password that the user has given to us to a local string variable. For the sake of this simple demo, we then reverse the string (in a real world application, you should salt and then hash the password using a key derivation function, but let us not go there right now).

Step 4: Create a dump file

  1. Start your application
  2. Enter this password: MyStupidPass123, and then dismiss the dialog
  3. Open Task Manager (Ctrl+Shift+Esc)
  4. Right-click on: Project1.exe (32 bit)
  5. Click on: Create dump file

Step 5: Search the memory dump

  1. Download Mark Russinovich’ excellent Strings.
  2. Unzip strings.zip to %temp%\strings.exe
  3. Open command prompt in %temp%
  4. Assuming the dump file is named Project1.DMP, enter this:
strings "Project1.DMP" | findstr /i MyStupidPass123

Result: you will find MyStupidPass123 in memory, probably several times.

How can we make sure our sensitive strings are zero’ed out, preferably automatically (e.g. when they go out of scope)? Unfortunately, the Delphi string type does not have a destructor, and neither does it send us an event nor a message.

In Part 2 of this blog post, we will look at Interfaces, and see if we can piggyback our Delphi strings on this other reference counted concept maybe.

Continue to Part 2 →

Like what you read? Give Stefan van As a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.