I have a problem maybe related to the Subprocess module in Python 3.10.
We have a list of files stored in a Queue. Thanks to the a function we get the files in the Queue and run the signtool.exe with subprocess.Popen to apply the signature.
process = subprocess.Popen(f'"{cmd}" {" ".join(params)}',
shell=shell,
stdout=sys.stdout,
stderr=sys.stderr,
cwd=cwd,
universal_newlines=True)
if process.wait(timeout=20) != 0:
raise Exception(f'Error executing command {cmd}')
This is the signtool command executed:
signtool.exe sign /sm /fd sha256 /a /n "CERTIFICATE_NAME" /t http://timestamp.digicert.com binary_file
The process.wait() is triggered correctly but the process persist on the machine.
Do you know what can produce this problem? We never face any issues with subprocess until Python 3.10
Related
The following command
#Set "installed_version=" & #(FOR /F %a IN ('curl 192.168.1.151:5000/getversion') DO #SET installed_version=%a)
is failing when running on a Windows agent in Teamcity with error
) was unexpected at this time. Process exited with code 255
However, the same command runs smoothly when running on a command prompt on my local Windows 10 machine. The teamcity agent is a Windows Server 2008 R2, version 6.1.
What am I doing wrong?
It turns out, % has to be escaped when in a bat file, so it should be %%.
At the same time, in Kotlin DSL % also needs to be escaped, so we end up with %%%%.
I'm trying to make a .msi installation package using CMake, CPack, and Wix. The issue is I'm trying to sign the executables and DLLs that are going to be installed.
Currently I am trying to use a custom cmake script by setting CPACK_INSTALL_SCRIPTS
SET( CPACK_INSTALL_SCRIPTS "${CMAKE_CURRENT_LIST_DIR}/signcert.cmake")
And inside signcert.cmake is where I run into issue. I want to use signtool to sign:
execute_process(
COMMAND cmd /c signtool sign /debug /v /sm /fd sha256 /tr http://timestamp.comodoca.com /td sha256 /sha1 ${THUMBPRINT} "${CMAKE_INSTALL_PREFIX}applications/bin/*"
)
The signtool command execute properly when done in a VS Command Console (vcvarsall.bat), however the wild card does not expand properly in the execute_process, it says cannot find *.
How can I find a list of files in a particular directory and store it in a CMake variable? For example ${CMAKE_INSTALL_PREFIX}applications/bin/* ?
This issue is likely caused by the fact that your signcert.cmake script will not know the path for CMAKE_INSTALL_PREFIX. It is not forwarded from the main CMake invocation.
To get around this, you can make a script template signcert.cmake.in, and use configure_file to insert the CMAKE_INSTALL_PREFIX path into your script.
Within your script, one option to more safely obtain and pass a list of files is to use file(GLOB ...) to get a list of files in the directory, before calling execute_process. Here's what your script could look like (note the #CMAKE_INSTALL_PREFIX# marked for variable substitution):
file(GLOB MY_FILES_TO_SIGN
LIST_DIRECTORIES false
#CMAKE_INSTALL_PREFIX#applications/bin/*)
# Pass MY_FILES_TO_SIGN variable to execute_process.
execute_process(
COMMAND cmd /c signtool sign /debug /v /sm /fd sha256 /tr http://timestamp.comodoca.com /td sha256 /sha1 ${THUMBPRINT} ${MY_FILES_TO_SIGN}
)
In your main CMake project, configure this file using the following, which will generate signcert.cmake with the value of CMAKE_INSTALL_PREFIX substituted inside:
configure_file(signcert.cmake.in ${CMAKE_CURRENT_LIST_DIR}/signcert.cmake #ONLY)
I've noticed that my command line didn't start anymore, it just immediately minimized and closed itself upon running. I suspect this is due to a virus or at least some kind of malicious program having been executed. I found the following code inside my registry. It seems legible but my knowledge of batch / the command line is limited. Can anyone tell me what it does?
#mode 20,5 & tasklist /FI "IMAGENAME eq SoundModule.exe" 2>NUL | find /I /N "SoundModule.exe">NUL && exit & if exist "C:\Users\Leon\AppData\Roaming\Microsoft\SoundModule\SoundModule.exe" ( start /MIN "" "C:\Users\Leon\AppData\Roaming\Microsoft\SoundModule\SoundModule.exe" & tasklist /FI "IMAGENAME eq explorer.exe" 2>NUL | find /I /N "explorer.exe">NUL && exit & explorer.exe & exit ) else ( tasklist /FI "IMAGENAME eq explorer.exe" 2>NUL | find /I /N "explorer.exe">NUL && exit & explorer.exe & exit )
According to this reddit thread, it's a "vmprotected cryptocurrency miner".
You most likely got it if you installed anything you downloaded from the torrent network, for example a popular game released in the past few weeks :^)
The following SO thread contains part of the solution: CMD.exe closes immediately after calling (Win7 64)
The malicious party added an AutoRun directive via registry to the Windows Command Processor (cmd.exe usually), which you need to remove from any of the following locations it's present in:
Computer\HKEY_CURRENT_USER\Software\Microsoft\Command Processor
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Command Processor
What the directive does is to execute SoundModule.exe and then explorer.exe (if not already started).
According to the other reply in this thread, they set %comspec% to run at startup, via Computer\HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Winlogon.
So on startup, it's running %comspec% (instead of the default Windows Explorer), which itself on start first runs SoundModule.exe and then explorer.exe. Not sure why they did it this way, anyone who makes use of cmd.exe was bound to figure it out and spread the word.
There are at least two confirmed VirusTotal records for this file: [1], [2]
I had the same program on my computer, check Computer\HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Winlogon for the shell value which is most likely "%comspec%" (which makes sense why it was just cmd running on startup since %comspec% is cmd.exe) and change it to "explorer.exe"
Run regedit
Go to HKLM\Software\Microsoft\Command Processor\ or HKEY_CURRENT_USER\Software\Microsoft\Command Processor\ or HKEY_LOCAL_MACHINE\Software\Microsoft\Command Processor\
For some reason there was AUTORUN key with "EXIT" inside.
Remove the AutoRun key and cmd will work fine.
Then check Computer\HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Winlogon for the shell value which is most likely "%comspec%" (which makes sense why it was just cmd running on startup since %comspec% is cmd.exe) and change it to "explorer.exe" as the user above said.
Edit: I also found that it was a cryptocurrency mining virus located at %appdata%\Microsoft\SoundModule or SoundMixer on my case.
You should probably delete this file too.
For reference, I will add that I was able to verify that my issue was the Autorun registry key by using Win-R to bring up the "Run" dialog, and typing cmd /d (which disables any autorun per the windows docs [https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/cmd] . This successfully opened a command prompt window.
Inspecting the registry, my HKEY_CURRENT_USER\Software\Microsoft\Command Processor had Autorun as Type=REG_SZ and Data=if exist. I made a restore point, then renamed that key to AutorunOld ... and then I was able to open a command prompt without issue.
We have a project in Visual Studio 2010 that runs a batch file in the post-build event. That batch calls to signtool.exe from Microsoft SDK to sign and timestamp the binary.
Timestamp servers (we use http://timestamp.verisign.com/scripts/timstamp.dll), however, tend to be unreliable for some reason, failing sometimes. This caused build to fail.
We implemented a more advanced batch script then (based on this code), splitting signing and timestamping, and allowing to retry the timestamp operation, if it failed.
Here is a simplified version of the batch script (signfile.bat):
#echo off
REM sign the file...
signtool.exe /f Authenticode.pfx /p PASS %1
if %errorlevel% neq 0 exit /b %errorlevel%
set timestamp_server=http://timestamp.verisign.com/scripts/timstamp.dll
for /L %%a in (1,1,10) do (
REM try to timestamp the file...
signtool.exe timestamp /t %timestamp_server% %1
if errorlevel 0 if not errorlevel 1 GOTO succeeded
REM wait 2 seconds...
ping -n 2 127.0.0.1 > nul
)
REM return an error code...
echo signfile.bat exit code is 1.
exit /b 1
:succeeded
REM return a successful code...
echo signfile.bat exit code is 0.
exit /b 0
And the post-build event code would look like:
signfile.bat "$(OutDir)$(TargetName)$(TargetExt)"
So, if the timestamping fails, it retries 10 times with 2-seconds intervals.
But, what we observed was, if the timestamping went fine from the first attempt, everything was OK. However, if the first attempt failed, then the whole post-build event failed with code -1, even though the timestamping succeeded on the next try.
1>------ Build started: Project: myproject, Configuration: NonOptimized x64 ------
1> Done Adding Additional Store
1> Successfully signed: E:\tfs\MySolution\bin\x64\NonOptimized\myproject.dll
1>
1>EXEC : SignTool error : The specified timestamp server either could not be reached
1> or returned an invalid response.
1> This may happen if you specify an RFC 3161 timestamp URL but used
1> the /t option or you specified a legacy Authenticode timestamp URL
1> but used the /tr option.
1>EXEC : SignTool error : An error occurred while attempting to timestamp: E:\tfs\MySolution\bin\x64\NonOptimized\myproject.dll
1>
1>
1> Number of errors: 1
1>
1> Successfully timestamped: E:\tfs\MySolution\bin\x64\NonOptimized\myproject.dll
1>
1> signfile.bat exit code is 0.
1>C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\Microsoft.CppCommon.targets(113,5): error MSB3073: The command "signfile.bat "E:\tfs\MySolution\bin\x64\NonOptimized\myproject.dll"
1>C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4.0\Microsoft.CppCommon.targets(113,5): error MSB3073: :VCEnd" exited with code -1.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
So, as you can see, even though the error code returned from signfile.bat is 0, Visual Studio thinks it is -1 and fails the event.
All attempts to clear the error flag, like adding ver>nul here and there, or adding exit 0 in the end (certainly with adding "call" before signfile.bat) didn't help since it seemed like Visual Studio checked not just for errorlevel but also for something else. In fact, the batch as well as signfile.bat only return 0 or 1 in case of error, but not -1. And if signtool.exe returns an error once, it seems like there is no way to convince Visual Studio not to fail the post-build event.
After spending much time experimenting and searching, found an article, mentioned here in a comment. It looks like Visual Studio scans the output, searching for some special keywords. Signtool.exe outputs among the other EXEC : SignTool error : An error occurred, which seems like enough to alert Visual Studio that there was an error.
So, the solution proposed was to redirect output and error streams to nul as 2>nul 1>nul. Errorlevel will still be set, so you will be able to figure out if error occured. But you may have to print some extra messages to see the status:
REM try to timestamp the file...
signtool.exe timestamp /t %timestamp_server% %1 2>nul 1>nul
if errorlevel 0 if not errorlevel 1 (
echo Successfully timestamped: %1
GOTO succeeded
)
echo Timestamping failed for %1
Now Visual Studio is happy:
1>------ Build started: Project: myproject, Configuration: NonOptimized x64 ------
1> Done Adding Additional Store
1> Successfully signed: E:\tfs\MySolution\bin\x64\NonOptimized\myproject.dll
1>
1> Timestamping failed for "E:\tfs\MySolution\bin\x64\NonOptimized\myproject.dll"
1> Successfully timestamped: "E:\tfs\MySolution\bin\x64\NonOptimized\myproject.dll"
1> signfile.bat exit code is 0.
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
In fact, just adding 2>nul would be enough to fix it. Error stream will still be printed: Number of errors: 1, but it does not cause a problem.
I experienced a very similar problem, but with the added difficulty that rather than calling SignTool directly, our post-build step calls a PowerShell script which itself calls SignTool. I set up some retry logic in the PowerShell script (to try various timestamp servers, with delays), but found that if the first attempt failed then the whole build would fail, even though the error was being caught and handled properly and a subsequent signing attempt was succeeding.
I appreciate this isn't exactly what the original question is asking, but I wasted hours and hours on this before eventually working out a solution (having stumbled upon this Q&A - thank you!), so I'm posting this info in the hope that it will help others.
From PowerShell, the standard call to SignTool would be something like this:
$output = & $signToolPath sign `
/n $companyName `
/d $productName `
/du $productWebsite `
/t $timestampServer `
/sha1 $shaHash `
$filePath
If SignTool returns an error code, this will immediately fail the build (as shown in the TeamCity screenshot), which is not desirable if the script is capable of automatically retrying:
To prevent the build failing, the PowerShell error stream can be suppressed (similarly to the solution in the accepted answer) with the PowerShell redirect statement 2>&1 as follows:
$output = & $signToolPath sign `
<switches and args as above>
$filePath 2>&1
However, this means you can't see the error output when SignTool returns an error code, which is obviously unhelpful. You can address this by writing the output to the host like this:
$output = & $signToolPath sign `
<switches and args as above>
$filePath 2>&1
$output | Write-Host
but then Visual Studio / MSBuild will resume trying to be "clever" and fail the build again!
The only solution I have found which allows SignTool error messages to be displayed without failing the build is both to redirect the error stream and to garble the error output before writing to the host, something like this:
$output = & $signToolPath sign `
<switches and args as above>
$filePath 2>&1
$output -split "([a-z0-9])" -join " " | Write-Host
The error message is then human-readable but doesn't fail the build, as shown here:
Of course, if all the retry attempts fail then you need to return an appropriate non-zero exit code from the PowerShell script so that the build does fail.
Thanks again for the original Q&A, and I hope this extra info on PowerShell helps someone else.
(PS: one of the links in the accepted answer is broken, but the referenced article is archived here: http://web.archive.org/web/20180729111947/http://blog.robertromito.com/2010/08/ignore-error-from-visual-studio-post.html )
I'm building an MSI installer for windows and sign the installer using signtool. When I run the .msi to test it, the UAC (User Account Control) prompt shows up to ask me if I want to allow the installation to proceed. That's fine, but the prompt shows a number of fields, and for the Program Name field it displays something like "403b3.msi". This is not the name of the msi I'm running.
How can I get the correct Program Name to be displayed?
Use the /d command line argument with the required program name when executing signtool to sign the msi.
It appears that the windows installer creates a temporary copy of the msi file and assigns it a generated name before running it. If you don't use /d with signtool, you get to see the temporary filename which isn't very useful for your users.
this is an applied version of #Scott-langham's comment.
this was directly from the PostBuildEvent of a visual studio installer project - VDPROJ file
set signtool="C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\signtool.exe"
set timestampurl=http://timestamp.digicert.com
set certpath="$(ProjectDir)CodeSigningCert.pfx"
:: Setup in your user environment variables
:: using something with low sort order to force off screen ZZCODECERTPASSWORD
if []==[%ZZCODECERTPASSWORD%] (
echo must set code signing certificate in ZZCODECERTPASSWORD environment variable. stopping build.
exit /b 2
)
:: need the filename with extension that is being generated
FOR /f %%i IN ("$(BuiltOuputPath)") DO (
SET outputfilename=%%~nxi
)
%signtool% sign /t %timestampurl% /f %certpath% /p %CODECERTPW% /d %outputfilename% "$(BuiltOuputPath)"
IF ERRORLEVEL 1 (
echo failed to sign MSI
exit /b 3
)
%signtool% sign /t %timestampurl% /f %certpath% /p %CODECERTPW% "$(ProjectDir)$(Configuration)\Setup.exe"
IF ERRORLEVEL 1 (
echo failed to sign boostrap setup EXE
exit /b 4
)