Solved

Global Variables in a DLL?

Posted on 2004-04-05
7
1,439 Views
Last Modified: 2007-12-19
<b>Some background</b>
I'd like to create an intranet-site were passwords can be safely stored/retrieved in a Database. However I must provide a mechanism so that administrators cannot grant access to the passwords. Therefore the passwords cannot be stored on the server, or on the client and may not be stored in cookies. Server-side decryption is also not an option, since I want to protect against network-sniffers. All encryption/decryption must be done on the client-side.

I had an idea in mind where the encryption/decryption would be performed in a client-side DLL. The DLL would be loaded from VBScript from within a HTML-page.

<b>The Problem</b>
The first time a decryption is perfomed, it should popup a form to ask for a password. From then on, the password is kept in memory, as long as the computer stays online. All encryption/decryption functions should then use this same password.

<b>What I already have</b>
My current prototype popups a form, where I can enter a password, and then nicely decrypts the message. But as soon as the VBScript has finished, the secret-password is no longer accessible.
It looks like when VBScript has finished, it always unloads the DLL.

I currently have an ActiveX Library, an Automation Object and a Form.

I tried using different techniques, overriding DllCanUnloadNow, tried to create 'Global Variables' in all the different Units... I changed Instancing and Threading Model... but did not succeed.

Any suggestions?
0
Comment
Question by:Br_nar
  • 4
  • 2
7 Comments
 
LVL 26

Expert Comment

by:Russell Libby
ID: 10762424

What about saving this data in a shared block of memory allocated via CreateFileMapping? The only difference from most implementations (using shared mem) is that the creator would not call UnmapViewOfFile on the shared memory, thus leaving this named memory available until the computer restarted?

If you need some code examples, I would be more than happy to provide them.

Regards,
Russell
0
 

Author Comment

by:Br_nar
ID: 10768849
I found the following Unit, but same problem here. As soon as the DLL i unloaded, the FileMapping disappears (or at least is inaccessible). Any suggestions on how to keep these FileMappings in memory? Or any other way how to keep the DLL in memory? Or another way of creating 'Global Variables'?




// Code of how I called the Unit from my DLL (Also tried to call this in a separate program)
function TApplication.GetKey: String;
var
  mySharedMem : TSharedMemory;
begin
  mySharedMem:=TSharedMemory.Create(nil);
  mySharedMem.Handle:='ClientCrypto';
  if Length(mySharedMem.Contents)=0 then
  begin
    PasswordDlg:=TPasswordDlg.Create(nil);
    PasswordDlg.ShowModal;
    mySharedMem.Contents:=PasswordDlg.Password.Text;
  end;
  result:=mySharedMem.Contents;
end;




// Source of the Unit I found, and modified as follows
// *  I removed UnmapViewOfFile
// *  I emptied the Destructor
// *  I added code for SecurityDescriptors; I thought maybe Windows does not allow me to read the data...

unit SharedMem;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;

type
  TSharedMemory = class( TComponent )
  private
    hFileMapping: THandle;
    FHandle: string;
    lp: pointer;
    FSize: integer;
    procedure SetContents(const Value: string);
    procedure SetHandle(const Value: string);
    function GetContents: string;
    procedure SetSize(const Value: integer);
  protected
  public
    constructor Create( AOwner: TComponent ); override;
    destructor Destroy; override;
    property Contents: string read GetContents write SetContents;
  published
    property Handle: string read FHandle write SetHandle;
    property Size: integer read FSize write SetSize default 255;
  end;

procedure Register;

implementation

procedure Register;
begin
  RegisterComponents( 'Silicon Commander', [TSharedMemory] );
end;

constructor TSharedMemory.Create(AOwner: TComponent);
begin
  inherited Create( AOwner );
  FSize := 255;
end;

destructor TSharedMemory.Destroy;
begin
  inherited Destroy;
//  if lp <> nil then
//    UnmapViewOfFile( lp );
//  if hFileMapping <> 0 then
//    CloseHandle( hFileMapping );
end;

function TSharedMemory.GetContents: string;
begin
  if lp = nil then
    Result := ''
  else
    Result := StrPas( lp );
end;

procedure TSharedMemory.SetContents(const Value: string);
begin
  if ( csDesigning in ComponentState ) then
    Exit;
(* If a mapping does not exist, do nothing *)
  if lp = nil then
    Exit;
  StrPCopy( lp, Value );
end;

procedure TSharedMemory.SetHandle(const Value: string);
const
  SECURITY_DESCRIPTOR_REVISION = 1;
var
  SecurityDescriptor:TSecurityDescriptor;
  SecurityAttr:TSecurityAttributes;
  RetVal:Integer;
function IsNT: Boolean;
var
  OS: TOSVERSIONINFO;
begin
  OS.dwOSVersionInfoSize := SizeOf(TOSVERSIONINFO);
  GetVersionEx(OS);
  Result := (OS.dwPlatformId = VER_PLATFORM_WIN32_NT);
end;
begin
  if FHandle = Value then
    Exit;
  FHandle := Value;
  if ( csDesigning in ComponentState ) then
    Exit;
(* Close down any file mapping that may be currently open *)
//  if lp <> nil then
//    UnmapViewOfFile( lp );
  if hFileMapping <> 0 then
    CloseHandle( hFileMapping );
(* See if a file mapping already exists with this name *)
  hFileMapping := OpenFileMapping( FILE_MAP_ALL_ACCESS, FALSE, PChar( FHandle ) );
(* If not, create a new one *)
  if hFileMapping = 0 then

//    lpHookRec:=NIL;
    if (IsNT) then
    begin
      SecurityAttr.nLength:=SizeOf(SECURITY_ATTRIBUTES);
      SecurityAttr.bInheritHandle:=TRUE;
      SecurityAttr.lpSecurityDescriptor:=@SecurityDescriptor;
      if not InitializeSecurityDescriptor(@SecurityDescriptor,SECURITY_DESCRIPTOR_REVISION) then
      begin
          RetVal:=GetLastError;
          raise Exception.CreateFmt('Unable to initialize security descriptor. Windows error=%d', [RetVal]);
      end;
      if not SetSecurityDescriptorDacl(@SecurityDescriptor,TRUE,NIL,FALSE) then
      begin
          RetVal:=GetLastError;
          raise Exception.CreateFmt('Unable to set security descriptor dacl. Windows error=%d', [RetVal]);
      end;
      if not SetKernelObjectSecurity(GetCurrentProcess,DACL_SECURITY_INFORMATION,@SecurityDescriptor) then
      begin
          RetVal:=GetLastError;
          raise Exception.CreateFmt( 'Unable to set kernel object security. Windows error=%d', [RetVal]);
      end;
      hFileMapping:=CreateFileMapping($FFFFFFFF, @SecurityAttr, PAGE_READWRITE or SEC_COMMIT, 0, FSize, PChar( FHandle ));
    end else
    begin
      hFileMapping := CreateFileMapping( $ffffffff, nil, PAGE_READWRITE or SEC_COMMIT, 0, FSize, PChar( FHandle ) );
    end;

  if hFileMapping = 0 then
    raise Exception.Create( 'CreateFileMapping failed with error code ' + IntToStr( GetLastError) );
(* Map the view of the file *)
  lp := MapViewOfFile( hFileMapping, FILE_MAP_ALL_ACCESS, 0, 0, FSize );
  if lp = nil then
    raise Exception.Create( 'MapViewOfFile failed with error code ' + IntToStr( GetLastError ) );
end;

procedure TSharedMemory.SetSize(const Value: integer);
begin
  FSize := Value;
end;

end.

0
 
LVL 26

Accepted Solution

by:
Russell Libby earned 250 total points
ID: 10770087
Hmmm...
Figures that it doesn't work the way it is supposed to (according to the MS docs). It does close the handle as soon as the process goes away. In fact, even the following is not enough to keep the handle open

     // Protect the handle
     SetHandleInformation(FHandle, HANDLE_FLAG_PROTECT_FROM_CLOSE, HANDLE_FLAG_PROTECT_FROM_CLOSE);

Leaves you with very few choices:
1.) Inject your library into a running system process, so it always remains running.
3.) Start another process (hidden), then use the DuplicateHandle function so the new process has access to the handle (and thus keeps it open).
2.) Persist the information to a file or the registry entry

Sorry I could not help further.

Russell
0
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 
LVL 14

Expert Comment

by:DragonSlayer
ID: 10772779
Russell, it's 1, 2, 3... not 1, 3, 2... time to go back to elementary school ;-)
0
 
LVL 26

Expert Comment

by:Russell Libby
ID: 10774923
;-) Funny guy.....

Regards,
Russell
0
 

Author Comment

by:Br_nar
ID: 10784841
I tried HANDLE_FLAG_PROTECT_FROM_CLOSE, but as you say it didn't work...

But as you say, I can fix it by having the DLL interact with a 'running process'. The user enters his password in the 'unlock program' which creates a FileMapping (containing the password).

The DLL will check for the FileMapping and use it to decrypt/encrypt the data. If the FileMapping is not present decryption will return 'No Access'.

Thanks for the suggestions!
0
 
LVL 26

Expert Comment

by:Russell Libby
ID: 10784886
Glad I could assist, and thank you

Russell
0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
This Micro Tutorial will teach you how to censor certain areas of your screen. The example in this video will show a little boy's face being blurred. This will be demonstrated using Adobe Premiere Pro CS6.
This Micro Tutorial will give you a basic overview how to record your screen with Microsoft Expression Encoder. This program is still free and open for the public to download. This will be demonstrated using Microsoft Expression Encoder 4.

912 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

25 Experts available now in Live!

Get 1:1 Help Now