How to securely dynamically load PathAllocCanonicalize at runtime - winapi

I have a Windows desktop C++ application that currently uses ::PathCanonicalizeW. As you can see from the documentation, it was introduced in Windows 2000 and is located in shlwapi.dll. In order to support long paths on Win 10+, I need to start using ::PathAllocCanonicalize (or one of it's friends - ::PathCchCanonicalize or ::PathCchCanonicalizeEx).
This function was added in Windows 8, but I still need to support the older OS's. In order to support all OS's, I need to dynamically load ::PathAllocCanonicalize by calling ::LoadLibrary at runtime. The problem is that the documentation doesn't provide the DLL that includes this function.
After doing some searching, I found this documentation that includes all 3 of the new PathCanonicalize functions and it claims that they are in api-ms-win-core-path-l1-1-0.dll. After more searching, it appears that this is not a traditional DLL because there is no file anywhere in the OS with that name. This application has always loaded system libraries using the full path to the file in the system directory (typically C:\Windows\system32) to make sure that it's not loading malicious DLLs, but for this it will be impossible without a physical file to point to.
I have been able to test that calling ::LoadLibrary("api-ms-win-core-path-l1-1-0.dll") does work, but the fact that that documentation mentions UWP worries me. Is there any documentation for the supported way to dynamically load these kinds of functions at runtime in a desktop app? Is there a more secure way to load this DLL?
P.S. This app cannot be deployed with that DLL, and even if it were possible there's no point since any OS that doesn't have that function wouldn't have full support for long paths anyway. Using the documented pathcch.lib would require upgrading the target Windows version. Dropping support for the older OS's is also completely out of the question. The function must be manually dynamically loaded at runtime.

As pointed out by Hans, api-ms-win-core-path-l1-1-0 is known as an API set along with many others starting with api-ms-win-core. Based on the documentation there, it appears that the documentation for PathAllocCanonicalize is incomplete. It should list the API set on that page along with the DLL for desktop apps. Looking at the source on GitHub, it looks like there is a bug with that page and the other pathcch functions where that information is in the header but not rendered onto the page. That header lists api-ms-win-core-path-l1-1-0.dll and KernelBase.dll.
If for some reason I wanted to continue to load the API set instead of KernelBase.dll, ::LoadLibraryExW(L"api-ms-win-core-path-l1-1-0.dll", NULL, LOAD_LIBRARY_SEARCH_SYSTEM32) worked which would be just as secure as specifying the full path to a DLL in the system32 folder. Note that LOAD_LIBRARY_SEARCH_SYSTEM32 was not supported without KB2533623 on RTM versions of Vista, Windows 7, Server 2008, and Server 2008 R2 so that might not actually be secure on those OS's.

Related

Comprehensive list of programs on different operating systems

How would I get a list of EVERY program into a text file for windows 95-windows 10. The uninstall programs in control panel doesn't have the version and publisher for the older operating systems, and wmic does not display every program. Even the uninstall registry, which I thought would be my savior, does not list every program. I can see discrepancies between that and the uninstall programs tab. Powershell and the like are off the table since it is relatively new.
Some combination of the following:
Enumerate registry for HKEY_CURRENT_USER\Software\Microsoft\CurrentVersion\Uninstall and HKEY_LOCAL_MACHINE\Software\Microsoft\CurrentVersion\Uninstall. And probably HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall on 64-bit os (might be duplicated). These are the list of installed programs that appear in the Control Panel's "Program and Features" section. Notice that some of the entries are straight-forward and have most of the data you want. Others are a GUID - this corresponds to an MSI installation.
For all the entries obtained in #1 that reference a GUID, use the MSI API to find the installation information you seek. Start with MsiEnumProducts. From there you can get at version info of installed applications.
Brute force search for EXEs installed in C:\Program Files and C:\Program Files (x86). For each EXE found, you can use this method to get the version information.
You want a list of applications installed from the Windows Store? Ask me for a code sample if that's important too.
The registry uninstall registration requirements in the 90's was just the display name and the command to start the uninstallation. Windows 2000 added support for more values and exposed them in the new UI but they were still optional. In recent years a couple of them became a requirement to pass the Windows Logo tests but they are still optional for non-certified applications so the uninstall key is not guaranteed to contain version/publisher information for every entry. Portable applications are not listed in the registry so if you need a inventory of everything then you need to inspect all exe files and ignore the registry.
Supporting everything back to Win95 RTM is going to be tough since you have nothing except batch files as a scripting option. VBScript is a optional component that normally gets installed with IE 4 and I don't even remember if it is possible to get Powershell on these systems.
I don't think it is possible to extract the version information with a simple batch file, you probably need the help of a 3rd-party tool. The issue with 3rd-party tools is that a lot of them depend on the Microsoft CRT run-time .DLLs and Windows 95 RTM does not have them out of the box, not even msvcrt.dll.
If you can raise your requirement for Win95 to have Windows Scripting Host installed (redistributable or part of IE4) then you could write a VB/Jscript file that uses the FileSystemObject to both walk the entire directory tree on every drive and to get version information from .exe files.
If that is unacceptable then you need to try to find a tool that can extract version information. There is a Microsoft tool named filever.exe listed here but I don't know if it works on Win95 and a NirSoft tool here but I'm not sure if it supports stdout redirection from the commandline (but it is open source so you could fix that if needed). Even if you find a suitable tool you would still need to walk the directory tree looking for .exe files and that is not going to be fun when you are limited to command.com and its DOS compatible batch handling.
My recommendation is to write a new application. I can't recommend writing it in a .NET language because you would be dealing with versions 1-4 and it is not installed on XP and older by default.
The way I see it, you have 3 options if you are writing it yourself: Visual Basic 6, Delphi (something old, v3 or older perhaps) or C/C++.
For C/C++ any version of Microsoft Visual C++ or MinGW/GCC will do but the older the better and you must not link to or use any C run-time library stuff (you might get away with static linking with MinGW but not recent versions of Visual Studio). If I was doing this I would use Visual Studio 6 or 2003 and build with /Zl & /NODEFAULTLIB. There are multiple small standalone CRT libraries if you need them. If you use any recent version of Visual Studio you will manually have to hex-edit the file to make it run on anything older than XP.
The actual implementation needs to call FindFirstFileA (and friends) on Windows 95/98/ME and FindFirstFileW on other systems to walk the directory tree and GetFileVersionInfoA/W (and friends) to get version info.
If you are feeling fancy you could perhaps filter out files in %WinDir% signed by Microsoft. Good luck...

PDFCreator and VB6 on 64-bit: ActiveX component can't create object

I'm using PDFCreator to create PDFs in VB6. My VB6 development VM is Windows XP 32-bit. On that system PDF generation works both from a desktop app and from ASP (via VB web class runtime).
When I create an exe to run on Windows 7 or Windows Server 2008 R2 or use it in the web class runtime I get:
Run-time error '429':
ActiveX component can't create object
This is when using early binding. I add a project reference to "C:\Program Files\PDFCreator\PDFCreator.exe" and then in my code I do:
Public WithEvents mPDFCreator As PDFCreator.clsPDFCreator
Set mPDFCreator = New PDFCreator.clsPDFCreator
If I don't use a project references and use late binding instead, then it works on the desktop app but still not in the web class runtime. Late binding is done like so:
Set mPDFCreator = CreateObject("PDFCreator.clsPDFCreator")
I want to use early binding so that I can use the events, plus I need it to work in ASP/Web Class Runtime.
I realise I'm dealing with ancient technologies here and I should have tempered expectations when running such things on modern 64-bit Windows and IIS. If porting this legacy app to .NET were an option, I would.
On IIS I have set the Enable 32-bit Applications setting on my app pool. I have also tried running it as Administrator to rule-out security problems.
I've done everything I know how to debug this, but I'm stumped. I suspect it has something to do with PDFCreator being a 32-bit app and COM registration. I've also tried running regsvr32 out of SYSWOW64 but PDFCreator.exe can't be registered.
Windows 64-bit architecture does not allow the load of 32-bit dll into 64-bit processes.
But you can modify the configuration of your vb project to convert it from an in-process dll COM component into an out-of-process exe COM server. This will allow you to instantiate your 32-bit component from a 64-bit process.
See Process Interoperability
Since this is a VB6 question there aren't any 64-bit processes to worry about.
It seems far more likely than anything else that this library just isn't being registered properly. I haven't use it since I don't know whether its setup works properly. I do know that the download itself does not display with a UAC Shield on its icon, suspicious in itself. For all I know the setup program spawns a run of the wrong regsvr32.exe.
But it seems more likely you have misregistered the library manually after copying it naked over to these 64-bit Win7/Server 2008 systems.
In any case, going over all of the symptoms you describe, I'd guess it got registered as a 32-bit ActiveX library but registered in the per-user virtualized part of the registry for the user you were logged on as when you registered it.
This can be a hassle to clean up after. However you should, and then be sure to manually run the original setup once again with elevation.
These threads that include hand-wringing over "ancient technologies" really get old. It's a poor workman who blames his tools. In the future why not hire an experienced programmer to handle tasks like this?
I use PDFCreator in my accounting software written in VB6. Years ago, I noticed that after a certain update from the makers of PDFCreator, my software stopped working properly with it. The problem stopped after I re-installed the older version, and came back when yet another new update was released from them, so I have had my customers freeze at the version that worked. I don't know off the top of my head what version that was, but I can check my own web site since I made it downloadable for my customers if it would help, but it's likely many years old now.

The truth behind DLL injection with metro applications, Nektra vs Komodia

Komodia says:
DLL injection is not possible with Modern UI on Windows 8,It is
possible to inject DLLs into Metro apps, BUT, you will not be able to
redirect Winsock traffic to localhost.
In other words windows metro application working into sandboxed environment, which DLL injection can't be done.
Let's see what Nektra says:
We realized we needed to sign our DLL with a cross-certificate, like
those used to sign kernel-mode drivers.
We already had a method for injecting a DLL in WinRT applications: copy the DLL file inside the System32 folder and voilá!
As you can see Komodia and Nektra says a conflicting information, my question is what's the true behind DLL injection under windows 8, can I inject my code into metro application as usual(NT,win9x) like Nektra says?
I'm the author of Nektra's article. The research began when we wanted to add more features to the limited Metro Mail application that comes with Windows 8.
Although the process was not exactly the same than in desktop applications because usually metro apps are suspended, we hooked first DCOM service.
When DCOM service launches the Metro Mail application, in that point we inject the dll using the well-known method CreateRemoteThread/LoadLibrary call.
In the initial tests we tried to inject a dll located in the same folder were our test was located and discovered that, if the dll was in system32, it loads fine.
Later we do the further research to see why the dll was not loading if not on system32 folder.
About hooking winsock, we didn't test that but I think it should be possible because, at least on desktop computers, behind metro there are the commonly known dlls (kernel32, user32 and so on) and we hooked some api's without problems.
I'm the author of the Komodia article and our article doesn't conflict with Nektra, it is possible to hook Metro apps, or the sandbox that runs the Metro apps, but you can't connect to localhost, not because of hooking but because of Metro limitation on localhost connections. In our first test we used our Win7 WFP (which is a network driver) and modified the IP of packets to localhost which didn't work with Metro apps, NDIS will not work just the same, the only way to do so is using Microsoft's WFP proxy redirection.
Maybe someone will eventually find or already found a hack that allows for localhost direct connection, and as with any hacks, there are risks to consider. If you want an approved method, WFP proxy redirection is the only way to go.
I hereby answer because everyone else is out of point with this. The dll file needs to have read/execute permission to "All Application Packages" group. With this, the loader will allow you to load arbitrary dlls in Immersive apps(=metro apps).
In the initial tests we tried to inject a dll located in the same folder were our test was located and discovered that, if the dll was in system32, it loads fine.
Yes, because System32 is in the search order for Metro (Windows store) applications. There's no magic to it.
Likewise your test's folder was likely not in the DLL search order for the app (System32, the app's package dependency graph, etc), thus the Loader wouldn't find your DLL for the app.

Where is the guideline that says you shouldn't write to the Program Files area?

Many questions on SO say "Windows developer guidelines" or "windows design guidelines" say that you shouldn't write temporary or program data to the Program Files area, but as far as I can tell none of them actually link to a piece of documentation that says as much. Searching the MSDN has yielded me no results. Windows will make the area read-only, so it can be enforced by the OS, but that doesn't mean developers didn't try to write there anyway (e.g., when porting older, XP and earlier based programs forward.)
I realize that it seems odd to ask about it this late into Windows development (since, as a commenter below pointed out, has been enforced by the OS for more than a decade), but a document that says so is sometimes necessary to satisfy people.
With that in mind, Does Microsoft have a document published stating we shouldn't write application data to the Program Files area, and if so, where is it?
From Technical requirements for the Windows 7 Client Software Logo Program:
Install to the correct folders by default
Users should have a consistent and secure experience with the default
installation location of files, while maintaining the option to
install an application to the location they choose. It is also
necessary to store application data in the correct location to allow
several people to use the same computer without corrupting or
overwriting each other's data and settings.
Windows provides specific locations in the file system to store
programs and software components, shared application data, and
application data specific to a user:
Applications should be installed to the Program Files folder by default. User data or application data must never be stored in this
location because of the security permissions configured for this
folder (emphasis added)
All application data that must be shared among users on the computer should be stored within ProgramData
All application data exclusive to a specific user and not to be shared with other users of the computer must be stored in
Users\<username>\AppData
Never write directly to the "Windows" directory and or subdirectories. Use the correct methods for installing files, such as
fonts or drivers
In “per-machine” installations, user data must be written at first run and not during the installation. This is because there is no
correct user location to store data at time of installation. Attempts
by an application to modify default association behaviors at a machine
level after installation will be unsuccessful. Instead, defaults must
be claimed on a per-user level, which prevents multiple users from
overwriting each other's defaults.
And I'm quite sure that there's similar stuff for every Windows version of the NT family going back to Windows NT 4 or even earlier.
See also this question.
Edit: the original link in this post to the Windows 7 Logo program exists no more. Here you find the current link to the Certification requirements for Windows Desktop Apps. See Section 10, Apps must install to the correct folders by default
In later versions of windows (Vista, 7 and of course server versions) access permission are restricted for "special folders" including "Program Files". Even if your program is elevated to have sufficient privileges to write to this folder it is still a bad idea.
I don't know of any guidelines that state this but there is a list of special folders and what they are meant for. The fact that there is a special folder for nearly all types of data I can image means there is no need to use the program files folder.

Doing a virus check on a file from a build script

I would like to be be able to invoke a virus check as the final stage of the build process (please don't question why a dev machine would get a virus, it's just a belt-and-braces approach to avoid the risk of getting sued by customers...). Also I'd like the option of having AV on a machine but switching the auto file system protection off (at least for the build directories).
What I would like is a generic way of scanning a file using whatever AV system is in place. I'm assuming that there's an Windows API to do this, given that Windows detects the presence of an AV system, and browsers such as Firefox invoke a virus scan whenever a file is downloaded. So what's the API that they're using? There's the Microsoft AntiVirus API but that seems to be specific to Office documents. Does the approach involve using WMI? (and if you can detect the AV provider from there, how do you then invoke it to scan a file?)
I know that I could write the script to manually call the AV scanner that I know to be installed, but as an intellectual exercise I'm more interested to know how apps like Firefox are doing this.
Well, you may want to take a look at the nsDownloadScanner system directly on the Firefox source code:
nsDownloadScanner.h
nsDownloadScanner.cpp
As told by the comments on that files:
Download scanner attempts to make use of one of two different
virus scanning interfaces available on Windows - IOfficeAntiVirus
(Windows 95/NT 4 and IE 5) and IAttachmentExecute (XPSP2 and up).
The latter interface supports calling IOfficeAntiVirus internally,
while also adding support for XPSP2+ ADS forks which define security
related prompting on downloaded content.
Documentations on those interfaces can be found here:
IAttachmentExecute
IOfficeAntiVirus
If your software is open-source is compliant with the MPL licence (thanks, #MSalters), you may also directly use Firefox' code, to avoid reinventing the wheel.
Firefox uses the IAttachmentExecute API. However, you don't want to use that in a build script since it will add alternate stream information telling windows to show an annoying warning window when executing the file.

Resources