Mark Russinovich’s technical blog covering topics such as Windows troubleshooting, technologies and security.
I digitally sign code on a regular basis in the course of preparing Sysinternals executables for upload to the site. When you digitally sign a file, you encrypt the hash of the file with the private key of a public/private key pair. Someone can verify that you’ve signed the file by decrypting the encrypted hash with your public key and comparing the result with the hash of the file they calculate themselves. The signing process is made simple with Signtool.exe, a utility that comes with the Platform SDK and the .NET Framework. You pass it your signing certificate, private key file, and target file as command-line arguments and it does the rest, appending the signed hash in the file as a final step.
The other day I went to sign an updated Sysinternals tool and ran into this error message:
It had been a week or so since the last time I had tried signing anything, but I couldn’t think of any changes I had made to the system that would have lead to this failure. However, anyone that’s used computers for any length of time knows that they’re not really deterministic and that system configuration is often subject to spontaneous corruption. I resigned myself to never knowing the root cause and set out to resolve the problem.
The first thing I did was search for capicom.dll with the built-in Where utility, which looks for the file you specify in each of the directories listed in the PATH environment variable. The PATH environment variable is used for DLL searches, so I expected this step to confirm that I was missing Capicom.dll:
The output appeared to confirm it, but then I realized that because I was running on a 64-bit system and Signtool is a 32-bit executable, Where.exe wouldn’t look in the %SystemRoot%\Syswow64 directory, which is the directory in which 32-bit system DLLs are stored. When I manually looked in that directory I was surprised to find a copy of Capicom.dll:
Signtool must therefore not be looking for Capicom.dll in the directories listed in the PATH environment variable, so the question before me was, where was Signtool looking? I knew Process Monitor was the perfect tool to answer a question like that, so ran it, configured an Include filter for any Path ending in “capicom.dll” and then repeated the Nmake command that triggered the error:
The trace shows that, for some reason, Signtool only looks for Capicom.dll in two directories: the Microsoft Shared sub-directory of the system’s Common Files directory, and the \Bin directory, which was where Signtool is located on my system.
To fix the problem I simply copied the Capicom.dll file from the \Windows\Syswow64 to the \Bin directory. I reran the make command and, as I expected, it succeeded. Process Monitor to the rescue!
"However, anyone that’s used computers for any length of time knows that they’re not really deterministic and that system configuration is often subject to spontaneous corruption."
Um, no...that may be true of Windows, but not of mature systems, such as z/VM, z/OS, z/VSE, and perhaps even Linux.
Hate to be a pismire -- and I'm generally NOT a Microsoft-basher -- but this assertion is a bit scary from someone as senior as you.
Actually phs3, I've had plenty of system configuration corruption with Fedora Linux, especially when updating, as the built in updater likes to replace my NVidia supplied graphics-card LKM with an 'open source' alternative that cannot handle dual screens. Resulting in the system refusing to boot properly.
(In particular, an X server cannot be started.)
In fact computers are very deterministic, it's the creators of crappy operating systems and applications that introduce this non-determinism.
You need only review the trace output and notice how many times the same path is searched for the dll to see the type of poor quality I am talking about. Once the dll is not found there, why search again ? This is especially true for Windows where registry corruption of one form or another is a daily occurance and subsystems like .NET and COM and others are haphazardly bolted on to each other producing millions of duplicated instructions and yet are still unable to provide the requested service - in this case digitally signing your app.
The 4NT shell from JP Software has an intrinsic "which" command.
It sounds like Where doesn't work properly with the 64/32 bit path differences... does it perhaps have a flag to look in the 32-bit side?
Cygwin which has the -a switch that causes it to output all instances, not just the first one it finds.
Regardless of what operating system you use, it is still a piece of software. And ALL software can be hacked - period. This is as old as the day is long!
Windows is one of the most secure software programs out today - it just has a larger user group.
If you think your other operating system is unhackable, just provide the challenge, and a hacker will be glad to show you some flaws! I have seen published hacks for just about every piece of major software on the market (including the operating systems Linux and Apple), and the programs I haven't seen hacks for - well, I simply didn't have the time to read about them, but, they do exist!
2007 is going to be one of the worse years in malware history for all software programs connected to internet. Just as Firefox didn't have issues for a "short" while, as their numbers grew - so did the hacks & flaws. Once software grows in numbers, IT IS ATTACKED, period.
I know this may seem like a silly solution, and I understand that Windows does things Windows' way, but common sense would tell me to look in my /BIN folder for a file that signtool.exe is telling me should be in my /BIN folder. Upon noticing its absence, initiating a search for the missing file would allow me to find it, place it in the /BIN folder and see if this corrected the problem. I understand that exploring the Ins and Outs of Windows is fun, and explaining it in a useful way is very helpful. [you are exceptionally good at it, and for this we are all indebted] But wouldn't it sometimes be easier to say that sometimes, rarely, when you least expect it, Windows behaves the way it used to/should?
Put this into where.bat, somewhere in your PATH
for %%i in (%1) do echo %%~dp$PATH:i
Works in Win2K and XP.
If you're using VS2005, launch the Visual Studio 2005 command prompt and use where.exe.
or add it to your path:
n:\Program Files\Microsoft Visual Studio 8\Common7\Tools\Bin\;
or have the VS cmd prompt init at startup...
Well the most interesting thing is that you do not have any chance finding out which file they are lookign for without something like procmon.
I run into a similiar problem once which just resulted in a 0x000003 or so error code meaning "file not found" no hint which file was missing.
I guess it's not important why something is broken, just that it is....
These comments have been invaluable to me as is this whole site. I thank you for your comment.
However, anyone that’s used computers for any length of time knows that they’re not really deterministic and that system configuration is often subject to spontaneous corruption."
I stumbled across this blog after experiencing the same error message as Mark. Difference is, I'm just using a plain old 32-bit version of Vista. I downloaded the latest capicom.dll from the Microsoft site, but it didn't make the slightest difference where I installed it, I got the same error.
Fortunately I prefer working in XP. I was just testing a little code signing tool I made to check that it worked under Vista. The old signcode.exe still works, anyway.