1

I know how to check the signing of an executable or dll by location from this question: Checking digital signature programmatically from Delphi

How can I know that an ActiveX library that I am using is signed with my certificate?

The executable can check the dll if it knows its location, but I want to be very sure that it is the one the executable is using at that moment. I know I can use the registry to find the library dll location (from the object IDs or library ID), but this seems like a weak spot vulnerable to spoofing.

Background:

I created an ActiveX library with an automation object. I sign the library dll and the consuming application with the same certificate. I can already check the consumer application from the library as follows

TSomeAutomationObj = class(TAutoObject, ISomeAutomationObj)
public
   procedure Initialize; override; 
end;

procedure TSomeAutomationObj.Initialize;
const
  BufferSize = 2048;
var
  LProcessPath: PChar;
begin

  LProcessPath := StrAlloc(BufferSize);
  try
    GetModuleFileName(0, LProcessPath, BufferSize);
    //Check signature of LProcessPath Executable as described here https://stackoverflow.com/questions/5993877/checking-digital-signature-programmatically-from-delphi
  finally
    StrDispose(LProcessPath);
  end;

end;

initialization
  TAutoObjectFactory.Create(ComServer, TSomeAutomationObj, Class_SomeAutomationObj,
ciMultiInstance, tmApartment);

What remains now is the check in the other direction (Executable to dll).

The automation objects will be registered and I will be using the Automation Object as follows

uses
  LibraryThatHoldsAutomationObject_TLB;

TObjectWithApplicationLifetime = class
private
  FSomeAutoObj : ISomeAutomationObj;
public
  Constructor Create; 
end;

Constructor TObjectWithApplicationLifetime.Create;
begin
  FSomeAutoObj := CoSomeAutomationObj.Create;
  // Check that the source library of this object is signed with my certificate

  // If so, then use FSomeAutoObj else set it to nil, set a flag or prevent usage other ways

end; 
Community
  • 1
  • 1
Jasper Schellingerhout
  • 1,070
  • 1
  • 6
  • 24

1 Answers1

3

A similar problem was covered in another question last year. The technique involves fetching the address of the interface's VMT (or vtable) and then asking the OS which module owns that memory.

An interface reference is a pointer to some data for the object. The first bytes of that data are in turn a pointer to the VMT for the interface.

var
  VMT: Pointer;
  Information: TMemoryBasicInformation;
  DLL: HModule;

VMT := PPointer(FSomeAutoObj)^;
Win32Check(VirtualQueryEx(GetCurrentProcess, VMT, Information, SizeOf(Information)) = SizeOf(Information));
DLL := HModule(Information.AllocationBase);

When that code is finished, DLL should hold the handle of the DLL that holds the object that implements the interface. Call GetModuleFileName on it as in the question.

There are a few assumptions required for it to work:

  • It must be an in-process COM object; for an out-of-process object, the VMT will be that of the proxy, not the real object.

  • The object mustn't be behind any other sort of proxy, such as one inserted by the compiler. (I don't think Delphi does this, but I'm not sure. Just make sure the interface pointer you have was provided by the DLL and not by the RTL.)

  • The VMT of the interface needs to by static. This will be the case for most interfaces implemented in Delphi or C++, but interfaces implemented in other ways, such as with scripting languages, might have method tables allocated on the heap. In that case, the DLL variable above won't really hold a module handle.

Another assumption is that even if the DLL isn't signed by your required certificate, it's still trustworthy enough to load into memory in the first place. You're only testing the DLL after you've loaded it into your process space and started executing its code. (Loading the DLL calls its DllMain function. Instantiating the COM object involves calling the DLL's DllGetClassObject function plus whatever else the constructor of the COM object decides to do.) If you can't trust improperly signed DLLs, then you're already too late.

Community
  • 1
  • 1
Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
  • Great answer I will test Monday and mark if it works. As to your point about loading, I guess I'm back to trusting the registry to check the dll in the registered location before constructing the autoobject. – Jasper Schellingerhout Nov 14 '15 at 15:15
  • Tested and works with minor modification. XE4 has the signature for `VirtualQueryEx` in `Winapi.Windows` as follows `function VirtualQueryEx(hProcess: THandle; lpAddress: Pointer; var lpBuffer: TMemoryBasicInformation; dwLength: SIZE_T): SIZE_T; stdcall;` so I just had to remove the `@` before `Information`. I also had to remove the `Win32Check` since the return type is not `BOOL` – Jasper Schellingerhout Nov 16 '15 at 19:44