Solved

Global Variables in a DLL?

Posted on 2004-04-05
7
1,438 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
Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
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

Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

Join & Write a Comment

Objective: - This article will help user in how to convert their numeric value become words. How to use 1. You can copy this code in your Unit as function 2. than you can perform your function by type this code The Code   (CODE) The Im…
Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
Access reports are powerful and flexible. Learn how to create a query and then a grouped report using the wizard. Modify the report design after the wizard is done to make it look better. There will be another video to explain how to put the final p…
This video shows how to remove a single email address from the Outlook 2010 Auto Suggestion memory. NOTE: For Outlook 2016 and 2013 perform the exact same steps. Open a new email: Click the New email button in Outlook. Start typing the address: …

758 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

21 Experts available now in Live!

Get 1:1 Help Now