07 March, 2024

The Secret of Access Denied

A client contacted us and said that he could not install EurekaLog. More precisely: EurekaLog is installed, but subsequent launch of the IDE raises an error:
Can't load package C:\Program Files (x86)\Neos Eureka S.r.l\EurekaLog 7\Packages\Studio25\EurekaLogExpert250.bpl. Access is denied.
Moreover, the client claimed that the file exists, there is access to it, reinstalling EurekaLog does not help.

Additionally, it was found that the code from the EurekaLogExpert250.bpl package actually does not receive control (is not executed).

The IDE uses the same LoadPackage function from the SysUtils unit that you (your code) use. The IDE does not execute any secret code. The LoadPackage function is implemented as follows:
function LoadPackage(const Name: string; AValidatePackage: TValidatePackageProc): HMODULE;
begin
  Result := SafeLoadLibrary(Name);
  if Result = 0 then
    raise EPackageError.CreateResFmt(@sErrorLoadingPackage, [Name, SysErrorMessage(GetLastError)]); // -----
  try
    InitializePackage(Result, AValidatePackage);
  except
    FreeLibrary(Result);
    raise;
  end;
end;
where the InitializePackage function is implemented as:
procedure InitializePackage(Module: HMODULE; AValidatePackage: TValidatePackageProc);
type
  TPackageLoad = procedure;
var
  PackageLoad: TPackageLoad;
begin
  CheckForDuplicateUnits(Module, AValidatePackage);
  @PackageLoad := GetProcAddress(Module, 'Initialize'); //Do not localize
  if Assigned(PackageLoad) then
    PackageLoad
  else
    raise EPackageError.CreateFmt(sInvalidPackageFile, [GetModuleName(Module)]);
end;
As you can see: the only place where an exception with an error code from the OS (5 = ERROR_ACCESS_DENIED) can be raised when loading a package is the marked line. This means that an Access Denied error when loading a package can only occur if the call to the LoadLibrary function fails.

Therefore, the client was asked to create a new empty VCL application with the following test code:
procedure TForm1.Button1Click(Sender: TObject);
var
  Lib: HMODULE;
begin
  Lib := LoadPackage('C:\Program Files (x86)\Neos Eureka S.r.l\EurekaLog 7\Packages\Studio25\EurekaLogExpert250.bpl');
  if Lib = 0 then
    RaiseLastOSError
  else
    MessageBox(0, 'The package was loaded!', 'Test', 0);
end;
As it turns out, the test application loads the package successfully.

To be sure that the IDE was not executing any additional hidden code, we asked the client to create a new Design-Time package with a new unit containing only the test code:
unit Unit1;

procedure Register;

implementation

uses
  Windows, SysUtils;

procedure Register;
var
  Lib: HMODULE;
begin
  Lib := LoadPackage('C:\Program Files (x86)\Neos Eureka S.r.l\EurekaLog 7\Packages\Studio25\EurekaLogExpert250.bpl');
  if Lib = 0 then
    RaiseLastOSError
  else
    MessageBox(0, 'The package was loaded!', 'Test', 0);
end;

end.
And when the client tried to load this test package, the IDE again gave an error message.

Let's make an intermediate result:
  • The test application successfully loads the package;
  • The test package (and IDE) cannot load the package.
This strongly suggests that the problem is not with the package, but with the IDE itself.

We also tried the following:
  1. Launch the IDE (without EurekaLog);
  2. Open the Run / Load Process menu item;
  3. Specify bds.exe as the target process for debugging;
  4. Launch the second instance of the IDE. In this case: the first instance will be the debugger, and the second will be the debugged one;
  5. In the process being debugged: try to add/load the EurekaLogExpert250.bpl package;
  6. In the debugger: monitor for exceptions that occur.
This algorithm did not provide any new information. In the debugger: we saw that in the process being debugged, the LoadLibrary function returns 0, which leads to an error being raised - as we assumed above.
Since both we and the client had already checked the access rights to the file EurekaLogExpert250.bpl a hundred times and saw no problems, we had to do something else.

The EurekaLogExpert250.bpl package is a Design-Time package. It depends on the Run-Time package EurekaLogCore250.bpl. This means that if the LoadLibrary function loads the EurekaLogExpert250.bpl package, it will see that the EurekaLogExpert250.bpl package references the EurekaLogCore250.bpl file and will try to load it too. And if a problem arose while loading the EurekaLogCore250.bpl package, it will bubble up to the top level and will be returned to the caller by the LoadLibrary function.

Therefore, the client also checked the file EurekaLogCore250.bpl (located in the C:\Windows\System32 folder) and found no problems.

Next, we asked the client to use Microsoft/SysInternals Process Monitor tool to monitor how the IDE was accessing files. It was necessary to launch the IDE, open the adding component dialog, then launch the Process Monitor tool and specify the "Process Name=bds.exe => include" filter. Then try to add the package, see the error message and save the resulting report.

In the resulting report, we ran a search for the "Eureka" word and immediately saw that the bds.exe was able to open and read the EurekaLogExpert250.bpl file - which further confirms that there is nothing wrong with the EurekaLogExpert250.bpl file.

But the lines immediately below confused us: Process Monitor reported that the bds.exe is trying to access the EurekaLogCore250.bpl from IDE's \bin folder. This is strange because modern versions of EurekaLog do not touch IDE's \bin folder.
(Very) old versions of EurekaLog installed the ecc32.exe file in IDE's \bin folder. We had to remove this behavior because Modern versions of the IDE may throw an integrity/license verification error if there are third-party files in IDE's \bin folder:
Question: I’ve installed and registered C++ Builder or Delphi, yet when it starts I am brought to a web page with the error “Product or License Validation Error”. How can I fix this?
Answer: By far the most common cause for this error is having files or applications not provided by Embarcadero that are copied into the bin folder below where RAD Studio is installed. Only files provided by Embarcadero may reside in the bin folder.
Therefore, modern versions of EurekaLog do not copy any files to IDE's \bin folder.
But when we tried to check the access rights to the \bin\EurekaLogCore250.bpl file, we... did not find such file!

As it turns out: the \bin\EurekaLogCore250.bpl is, in fact, a directory! The mystery is solved!

So, the following happened:
  1. The IDE calls the LoadPackage function to load the package;
  2. The LoadPackage function calls the LoadLibrary function to load the EurekaLogExpert250.bpl file;
  3. The LoadLibrary function (successfully) opens and reads the EurekaLogExpert250.bpl file;
  4. The LoadLibrary function sees that the EurekaLogExpert250.bpl file contains a link/reference to the EurekaLogCore250.bpl file;
  5. The LoadLibrary function tries to load the EurekaLogCore250.bpl file;
  6. The LoadLibrary function uses standard operating system's library search rules and sees that EurekaLogCore250.bpl is located right here: in IDE's \bin folder;
  7. The LoadLibrary function tries to load EurekaLogCore250.bpl from IDE's \bin folder;
  8. The LoadLibrary function returns error 5 (Access Denied) because the EurekaLogCore250.bpl folder in IDE's \bin folder does not have the "EXECUTE" access right".

And, indeed, everything worked after deleting the EurekaLogCore250.bpl folder from IDE's \bin folder.

But where did the EurekaLogCore250.bpl folder in IDE's \bin folder came from? I don't know. The EurekaLog installer is made using InnoSetup. Of course, the InnoSetup installation file for EurekaLog has no idea about IDEs you have installed and folders in which they are installed. And therefore the InnoSetup installation file for EurekaLog will not be able to create any folder there - simply because it does not know where it is.

Registration of EurekaLog in the IDE is carried out by the standalone registration program: .exe file compiled in Delphi from our source code. The problem is that in our source code for EurekaLog registration does not have a single call to MkDir or ForceDirectories functions: the EurekaLog registration application does not create directories, it copies files and enters data about them into Windows registry.

Even if the EurekaLogCore250.bpl in IDE's \bin folder was created by our installer: why is it a directory and not a file? And why is it alone? Why are there no EurekaLogExpert250.bpl and EurekaLogComponent250.bpl - after all, these three files go together.

So far it looks like someone has created a EurekaLogCore250.bpl directory in IDE's \bin folder. Perhaps it was some kind of IDE expert?

If you are our client, if you saw this error and know who creates the EurekaLogCore250.bpl directory in IDE's \bin folder - please let us know.
P.S. Read more stories like this one or read feedback from our customers.