Tankbuster Posted March 13, 2013 Share Posted March 13, 2013 (edited) If someone gets offended by this, because he knows already 200 posts about it. Do not reply. Yes, some wrote already here some words what to do. Yes, you are right I created nothing new. But I want this summed up for forum searchers, that maybe find this posting useful in spending less time to find an answer in one place. I don't want to re-animate very old postings. So forgive me if I try to help other idiots like myself. ==================== First I need to give credits to: For summing it up in a nearly complete way. ==================== There is a nice Gui existing that wrapps it up: Digital Sign Tool Below you also find some instructions how to add it to the compiler. ==================== I tested this on a Windows 7 (x64) - but all codes used is x86 (32bit) - for 64bit I need to create another package (or make the script smarter). So here is the sequence in general: general purpose: I created several EXE files of the years, and I do not want to use the SIGNUI to click each file. So I want a command line version. Create a folder - I named it x:cert4me Download from : http://www.kastaban.de/cert4me/MAKE_MY_CERT_FILE.zip The zip: Contains: 1999-04-15 17:10:28 PVKIMPRT.EXE 2003-03-24 23:03:00 makecert.exe 2005-09-23 07:56:00 cert2spc.exe 2006-03-03 23:22:44 signtool.exe 2007-04-11 11:11:20 capicom.dll 2007-09-27 14:17:44 pvk2pfx.exe 2013-03-13 15:24:27 MAKE_MY_CERT_FILE.CMD 2013-03-13 15:31:52 SIGN_FILE.CMD Extract the files in : X:Cert4me now open a cmd in the created folder with the extracted files (the script will also work from other folder but so you are closer to the result...) cd /D x:\cert4me Now you either watch this little video with a sample of the signing process (a little bit fast - but you are to pause it if you like, and sorry for the German screen texts) http://www.kastaban.de/cert4me/CERT4ME/CERT4ME.html or First start : MAKE_MY_CERT_FILE.CMD myNewCertificate secret01 MAKE_MY_CERT_FILE.CMD needs two arguments 1=the name of the certificate 2=your password Sign now the EXE with: SIGN_FILE.CMD "d:\1work\mit space\TFTP_HELPER.exe" keys\myNewCertificate_cert.pfx secret01 SIGN_FILE.CMD needs three arguments 1=the file path of your executable 2=the filepath to the pfx folder (created before !) 3=your password Done. in case you want to sign more than one EXE repeat the "Sign now" step with the other EXE. ================= I packed the files from the original post and added additional files to offer a complete package. this was tested on Windows 7 (64bit) but all tools and my EXE are 32bit . Keep this in mind. For 64bit the similar tools of 64bit are maybe needed (not sure). Maybe someone could start to convert this to a AU3.....because some fields are still left open. Like the End DATE, email field, timestamps URL..... And "if" someone got additional stuff to add here (for other idio.....mmmh......searchers), do it. And most important , in case I wrote something wrong or it does not work for you please comment. ======================================================================== //edit: 16.03.2013 - Thx Emiel - as always I face problems with the NOT and Or :-) Edited February 9, 2017 by Tankbuster TheSaint, tarretarretarre, Xandy and 1 other 4 Link to comment Share on other sites More sharing options...
Emiel Wieldraaijer Posted March 15, 2013 Share Posted March 15, 2013 @TankbusterThanks for the nice tutorial -> i believe you've missed a wordGeneral purpose: I created several EXE files of the years, and I do NOT want to use the SIGNUI to click each file. So I want a command line version. Best regards,Emiel Wieldraaijer Link to comment Share on other sites More sharing options...
MrPinkComputerShrink Posted March 27, 2015 Share Posted March 27, 2015 @Tankbuster Your tutorial was great and I am successfully signing my .exe but now Windows 8 SmartScreen is flagging the file. Has anyone successfully applied an EV Code Signing Certificate to their .exe file created with AutoIt? If so, were there any additional steps required or was it just like the regular code signing Certificate? Reference: https://www.digicert.com/code-signing/ev-code-signing-compared.htm Link to comment Share on other sites More sharing options...
argumentum Posted July 6, 2015 Share Posted July 6, 2015 (edited) ...as to save others from the implementation and/or learning curve, here is the batch files as a script. expandcollapse popup#Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_UseX64=n #AutoIt3Wrapper_Res_Description=sign my EXEs #AutoIt3Wrapper_Res_requestedExecutionLevel=requireAdministrator #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** #include <File.au3> If Not StringInStr($CmdLineRaw, "/ErrorStdOut") And Not @Compiled Then Exit MsgBox(262144, @ScriptName, "...please run from editor.", 3) Global $iCheckIni = 0 Global $ini = StringTrimRight(@ScriptFullPath, 3) & "ini" Global $sCERTIFICATE_PASSWORD = "replace with unique password" Global $sCN = "replace with unique CN" If BinaryToString(IniRead($ini, "section", "CERTIFICATE_PASSWORD", $sCERTIFICATE_PASSWORD)) = $sCERTIFICATE_PASSWORD Then $iCheckIni = 1 If BinaryToString(IniRead($ini, "section", "CN", $sCN)) = $sCN Then $iCheckIni = 1 If $iCheckIni Then If FileExists(@ScriptDir & '\keys') Then DirMove(@ScriptDir & '\keys', @ScriptDir & '\keys_' & @YEAR & '.' & @MON & '.' & @MDAY & '-' & @HOUR & '' & @MIN & '' & @SEC) IniWrite($ini, "section", "CERTIFICATE_PASSWORD", $sCERTIFICATE_PASSWORD) IniWrite($ini, "section", "CN", $sCN) IniWrite($ini, "section", "UniqueSamplePasswordCreatedOn" & @YEAR & @MON & @MDAY & @HOUR & @MIN & @SEC, UniquePasswordGen()) ShellExecute($ini) MsgBox(262144 + 64, @ScriptName, "edit the ini file" & @CR & 'and run again.', 10) Exit EndIf $sCERTIFICATE_PASSWORD = IniRead($ini, "section", "CERTIFICATE_PASSWORD", $sCERTIFICATE_PASSWORD) $sCN = IniRead($ini, "section", "CN", $sCN) If BinaryToString($sCERTIFICATE_PASSWORD) = $sCERTIFICATE_PASSWORD Then IniWrite($ini, "section", "CERTIFICATE_PASSWORD", StringToBinary($sCERTIFICATE_PASSWORD)) If BinaryToString($sCN) = $sCN Then IniWrite($ini, "section", "CN", StringToBinary($sCN)) $sCERTIFICATE_PASSWORD = BinaryToString($sCERTIFICATE_PASSWORD) $sCN = BinaryToString($sCN) $sCERTIFICATE_PASSWORD = BinaryToString(IniRead($ini, "section", "CERTIFICATE_PASSWORD", $sCERTIFICATE_PASSWORD)) $sCN = BinaryToString(IniRead($ini, "section", "CN", $sCN)) Global $WindowsDir = @WindowsDir FileChangeDir(@ScriptDir) If Not FileExists("makecert.exe") Then Exit MsgBox(262144, @ScriptName, 'can''t find "makecert.exe" , bye.', 30) If Not FileExists("cert2spc.exe") Then Exit MsgBox(262144, @ScriptName, 'can''t find "cert2spc.exe" , bye.', 30) If Not FileExists("pvk2pfx.exe") Then Exit MsgBox(262144, @ScriptName, 'can''t find "pvk2pfx.exe" , bye.', 30) If Not FileExists("signtool.exe") Then Exit MsgBox(262144, @ScriptName, 'can''t find "signtool.exe" , bye.', 30) Local $sFileToSign = StringTrimRight(@ScriptName, 3) & 'exe' ; should sign this exe Local $iNoPopupMsgBox = 0 If StringInStr($CmdLineRaw, "/NoPopup") Then $iNoPopupMsgBox = 1 If @Compiled Then If $CmdLine[0] Then $sFileToSign = $CmdLine[1] Else FileChangeDir($WindowsDir) MsgBox(262144, @ScriptName, "...please, pass a file." & @CR & '"filename.exe" /NoPopup', 30) Exit EndIf EndIf $sFileToSign = _PathFull($sFileToSign) If Not FileExists($sFileToSign) Then FileChangeDir($WindowsDir) Exit MsgBox(262144, @ScriptName, 'file "' & $sFileToSign & '" does not exist !', 60) EndIf If StringInStr($sFileToSign, " ") Then $sFileToSign = '"' & $sFileToSign & '"' Global $sOut = "" ConsoleWrite(@CRLF) ConsoleWrite('+ CertSigner - FileToSign >' & $sFileToSign & '<' & @CRLF & @CRLF) Local $sKEYDIR = @ScriptDir & "\keys" DirCreate($sKEYDIR) Local $sTIMESTAMP_URL = "http://timestamp.verisign.com/scripts/timestamp.dll" If Not FileExists(@ScriptDir & '\keys\' & $sCN & '_cert.pvk') Then createTheCerts($sCERTIFICATE_PASSWORD, $sCN) If FileExists(@ScriptDir & '\keys\' & $sCN & '_cert.pvk') Then signTheFile($sFileToSign, $sCERTIFICATE_PASSWORD) Local $sRun = 'signtool verify /pa ' & $sFileToSign $sOut &= $sRun & @CRLF & @CRLF $sOut &= runCmd($sRun) ConsoleWrite('+ CertSigner - done.' & @CRLF) If $iNoPopupMsgBox Then ; nothing Else MsgBox(262144, @ScriptName, "Signing of: " & $sFileToSign & @CR & _ "=====================================================" & @CR & _ StringReplace($sOut, @LF, "")) EndIf FileChangeDir($WindowsDir) Func createTheCerts($sCERTIFICATE_PASSWORD, $sCN = "MyPersonalCert") Local $sRun = 'makecert -r -n "CN=' & $sCN & '" -b 01/01/1973 -e 01/01/2030 -eku 1.3.6.1.5.5.7.3.3 -sv keys\' & $sCN & '_cert.pvk keys\' & $sCN & '_cert.cer' $sOut &= $sRun & @CRLF & @CRLF Local $Pid = Run($sRun, @ScriptDir, @SW_HIDE, 8) Local $Handle = _ProcessExitCode($Pid) While ProcessExists($Pid) Sleep(10) $sOut &= ShowStdOutErr($Pid, 1, "", "", 1) ; the executable may show an error to console, I'd like to read it. If WinExists("Enter Private Key Password", "") Then ConsoleWrite(">Enter Private Key Password<" & @CRLF) ControlSend("Enter Private Key Password", "", "Edit1", $sCERTIFICATE_PASSWORD) Sleep(50) ControlClick("Enter Private Key Password", "", "Button1") Sleep(500) EndIf If WinExists("Create Private Key Password", "") Then ConsoleWrite(">Create Private Key Password<" & @CRLF) Sleep(50) ControlSend("Create Private Key Password", "", "Edit1", $sCERTIFICATE_PASSWORD) Sleep(50) ControlSend("Create Private Key Password", "", "Edit2", $sCERTIFICATE_PASSWORD) Sleep(50) ControlClick("Create Private Key Password", "", "Button1") Sleep(500) EndIf WEnd Local $ExitCode = _ProcessExitCode($Pid, $Handle) $sOut &= @CRLF & "ExitCode : " & $ExitCode & @CRLF & "=====================================================" & @CRLF $sRun = 'cert2spc keys\' & $sCN & '_cert.cer keys\' & $sCN & '_cert.spc' $sOut &= $sRun & @CRLF & @CRLF $sOut &= runCmd($sRun) $sRun = 'pvk2pfx -pvk keys\' & $sCN & '_cert.pvk -pi ' & $sCERTIFICATE_PASSWORD & ' -spc keys\' & $sCN & '_cert.spc -pfx keys\' & $sCN & '_cert.pfx -po ' & $sCERTIFICATE_PASSWORD $sOut &= $sRun & @CRLF & @CRLF $sOut &= runCmd($sRun) EndFunc ;==>createTheCerts Func signTheFile($sFileToSign, $sCERTIFICATE_PASSWORD, $sTIMESTAMP_URL = "http://timestamp.verisign.com/scripts/timestamp.dll") Local $sRun = 'signtool sign /f keys\' & $sCN & '_cert.pfx /p ' & $sCERTIFICATE_PASSWORD & ' ' & $sFileToSign $sOut &= $sRun & @CRLF & @CRLF $sOut &= runCmd($sRun) $sRun = 'signtool timestamp /t ' & $sTIMESTAMP_URL & ' ' & $sFileToSign $sOut &= $sRun & @CRLF & @CRLF $sOut &= runCmd($sRun) EndFunc ;==>signTheFile ConsoleWrite(@CRLF) Func runCmd($sRun) Local $Pid = Run($sRun, @ScriptDir, @SW_HIDE, 8) ; 0x8 ($STDERR_MERGED) = Provides the same handle for STDOUT and STDERR. Implies both $STDOUT_CHILD and $STDERR_CHILD. Local $Handle = _ProcessExitCode($Pid) Local $Return_Text = ShowStdOutErr($Pid) Local $ExitCode = _ProcessExitCode($Pid, $Handle) _ProcessCloseHandle($Handle) Return $Return_Text & @CRLF & "ExitCode : " & $ExitCode & @CRLF & "=====================================================" & @CRLF EndFunc ;==>runCmd ; Get STDOUT and ERROUT from commandline tool Func ShowStdOutErr($l_Handle, $ShowConsole = 1, $Replace = "", $ReplaceWith = "", $dontLoop = 0) Local $Line = "x", $Line2 = "x", $tot_out, $err1 = 0, $err2 = 0, $cnt1 = 0, $cnt2 = 0 Do $Line = StdoutRead($l_Handle) $err1 = @error If $Replace <> "" Then $Line = StringReplace($Line, $Replace, $ReplaceWith) $tot_out &= $Line If $ShowConsole Then ConsoleWrite($Line) $Line2 = StderrRead($l_Handle) $err2 = @error If $Replace <> "" Then $Line2 = StringReplace($Line2, $Replace, $ReplaceWith) $tot_out &= $Line2 If $ShowConsole Then ConsoleWrite($Line2) ; end the loop also when AutoIt3 has ended but a sub process was shelled with Run() that is still active ; only do this every 50 cycles to avoid cpu hunger If $cnt1 = 50 Then $cnt1 = 0 ; loop another 50 times just to ensure the buffers emptied. If Not ProcessExists($l_Handle) Then If $cnt2 > 2 Then ExitLoop $cnt2 += 1 EndIf EndIf $cnt1 += 1 If $dontLoop Then Return $tot_out Sleep(10) Until ($err1 And $err2) Return $tot_out EndFunc ;==>ShowStdOutErr Func _ProcessCloseHandle($h_Process) ; Close the process handle of a PID DllCall('kernel32.dll', 'ptr', 'CloseHandle', 'ptr', $h_Process) If Not @error Then Return 1 Return 0 EndFunc ;==>_ProcessCloseHandle ;=============================================================================== ; ; Function Name: _ProcessExitCode() ; Description: Returns a handle/exitcode from use of Run(). ; Parameter(s): $i_Pid - ProcessID returned from a Run() execution ; $h_Process - Process handle ; Requirement(s): None ; Return Value(s): On Success - Returns Process handle while Run() is executing ; (use above directly after Run() line with only PID parameter) ; - Returns Process Exitcode when Process does not exist ; (use above with PID and Process Handle parameter returned from first UDF call) ; On Failure - 0 ; Author(s): MHz (Thanks to DaveF for posting these DllCalls in Support Forum) ; ;=============================================================================== ; Func _ProcessExitCode($i_Pid, $h_Process = 0) ; 0 = Return Process Handle of PID else use Handle to Return Exitcode of a PID Local $v_Placeholder If Not IsArray($h_Process) Then ; Return the process handle of a PID $h_Process = DllCall('kernel32.dll', 'ptr', 'OpenProcess', 'int', 0x400, 'int', 0, 'int', $i_Pid) If Not @error Then Return $h_Process Else ; Return Process Exitcode of PID $h_Process = DllCall('kernel32.dll', 'ptr', 'GetExitCodeProcess', 'ptr', $h_Process[0], 'int*', $v_Placeholder) If Not @error Then Return $h_Process[2] EndIf Return 0 EndFunc ;==>_ProcessExitCode Func UniquePasswordGen() Local $n, $t For $n = 48 To 57 ; 0..9 $t &= Chr($n) Next For $n = 65 To 90 ; A..Z $t &= Chr($n) Next For $n = 97 To 122 ; a..z $t &= Chr($n) Next Local $a = StringSplit($t, "") $t = "" For $n = 1 To 50 $t &= $a[Random(1, $a[0], 1)] Next Return $t EndFunc ;==>UniquePasswordGen I'm new at this. Any comments are very welcomed. you can add a line like this to your au3 file: #AutoIt3Wrapper_Run_After=""%scitedir%\tools\SignThisFile\CertSigner.exe" "%out%" /NoPopup" where this script is compiled as CertSigner.exe in a folder named "tools\SignThisFile" under the SciTE editor's folder. Edited June 27, 2016 by argumentum revised the code Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting. Link to comment Share on other sites More sharing options...
jpm Posted December 6, 2015 Share Posted December 6, 2015 Nice,Are they restrictions in characters used in MAKE_MY_CERT_FILE.CMD parameters?blanks, special chars as :;., ansi chars > 127Thanks for the help Link to comment Share on other sites More sharing options...
argumentum Posted June 27, 2016 Share Posted June 27, 2016 On 12/6/2015 at 3:48 AM, jpm said: blanks, special chars as :;., ansi chars > 127 no idea, could not find an answer to this question but I use a random string as such: Func UniquePasswordGen() Local $n, $t For $n = 48 To 57 ; 0..9 $t &= Chr($n) Next For $n = 65 To 90 ; A..Z $t &= Chr($n) Next For $n = 97 To 122 ; a..z $t &= Chr($n) Next Local $a = StringSplit($t, "") $t = "" For $n = 1 To 50 $t &= $a[Random(1, $a[0], 1)] Next Return $t EndFunc ;==>UniquePasswordGen ..late answer but, did not have one. ( still don't ) Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting. Link to comment Share on other sites More sharing options...
jpm Posted June 28, 2016 Share Posted June 28, 2016 thanks for sharing. I can't even have the script successful as the Key generation is failing Under Win10 the pvk2pfx.exe is failing with 0x80090005 I use the files of MAKE_MY_CERT_FILE.zip as suggested in the first post. How can have it working? Thanks for the help Link to comment Share on other sites More sharing options...
argumentum Posted June 28, 2016 Share Posted June 28, 2016 (edited) This nice pic. shows how the self signed certificate is force fed to the certificate store ( win 10 pic. )  Edited May 14, 2018 by argumentum Removed the file. There is a newer version anyway. Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting. Link to comment Share on other sites More sharing options...
argumentum Posted June 30, 2016 Share Posted June 30, 2016 (edited) this code should take care of any language other than english in working automatically.  did not make the code to require Administrator rights for the fact that only at key creation is required. Not so for signing an EXE. expandcollapse popup#Region ;**** Directives created by AutoIt3Wrapper_GUI **** #AutoIt3Wrapper_Icon=CertSigner.ico #AutoIt3Wrapper_UseUpx=n #AutoIt3Wrapper_UseAnsi=y #AutoIt3Wrapper_Res_Comment=sign my EXEs #AutoIt3Wrapper_Res_Description=sign my EXEs #AutoIt3Wrapper_Res_Fileversion=0.2016.6.29 #AutoIt3Wrapper_Res_LegalCopyright=you bet ;~ #AutoIt3Wrapper_res_requestedExecutionLevel=requireAdministrator #EndRegion ;**** Directives created by AutoIt3Wrapper_GUI **** ;~ #AutoIt3Wrapper_Run_Au3Stripper=y ;~ #Au3Stripper_Parameters=/MO #cs ---------------------------------------------------------------------------- converted the batch files to a, not so nice, script #ce ---------------------------------------------------------------------------- ; Script Start - Add your code below here #include <File.au3> Global $iCheckIni = 0 Global $ini = StringTrimRight(@ScriptFullPath, 3) & "ini" Global $sCERTIFICATE_PASSWORD = "replace with unique password" Global $sCN = "replace with unique CN" If BinaryToString(IniRead($ini, "cert data", "CERTIFICATE_PASSWORD", $sCERTIFICATE_PASSWORD)) = $sCERTIFICATE_PASSWORD Then $iCheckIni = 1 If BinaryToString(IniRead($ini, "cert data", "CN", $sCN)) = $sCN Then $iCheckIni = 1 If $iCheckIni Then If FileExists(@ScriptDir & '\keys') Then DirMove(@ScriptDir & '\keys', @ScriptDir & '\keys_' & @YEAR & '.' & @MON & '.' & @MDAY & '-' & @HOUR & '' & @MIN & '' & @SEC) IniWrite($ini, "cert data", "CERTIFICATE_PASSWORD", $sCERTIFICATE_PASSWORD) IniWrite($ini, "cert data", "CN", $sCN) IniWrite($ini, "sample data", "sample data", "this sample data generated a unique CERTIFICATE_PASSWORD you can use if you don't have one, the CN, is up to you.") IniWrite($ini, "sample data", "CERTIFICATE_PASSWORD", UniquePasswordGen()) IniWrite($ini, "sample data", "CN", "my unique self sign name") IniWrite($ini, "sample data", "HashAlgorithm", "4 ; 0=md5, 1=sha1, 2=sha256, 3=sha384, 4=sha512, default is 1 (sha1)") IniWrite($ini, "sample data", "GeneratedKeyLengthBits", "4096 ; minimum is 512, default 2048") ShellExecute($ini) MsgBox(262144 + 64, @ScriptName, "edit the ini file" & @CR & 'and run again.', 10) Exit EndIf Global $g_aHashAlgorithm[5] = ["md5", "sha1", "sha256", "sha384", "sha512"] Global $g_iHashAlgorithm = Int(IniRead($ini, "cert data", "HashAlgorithm", "1")) If $g_iHashAlgorithm > 4 Or $g_iHashAlgorithm < 0 Then $g_iHashAlgorithm = 1 Global $g_sHashAlgorithm = " -a " & $g_aHashAlgorithm[$g_iHashAlgorithm] Global $g_sGeneratedKeyLengthBits = Int(IniRead($ini, "cert data", "GeneratedKeyLengthBits", "2048")) If $g_sGeneratedKeyLengthBits < 512 Then $g_sGeneratedKeyLengthBits = 2048 $g_sGeneratedKeyLengthBits = ' -len ' & $g_sGeneratedKeyLengthBits $sCERTIFICATE_PASSWORD = IniRead($ini, "cert data", "CERTIFICATE_PASSWORD", $sCERTIFICATE_PASSWORD) $sCN = IniRead($ini, "cert data", "CN", $sCN) If BinaryToString($sCERTIFICATE_PASSWORD) = $sCERTIFICATE_PASSWORD Then IniWrite($ini, "cert data", "CERTIFICATE_PASSWORD", StringToBinary($sCERTIFICATE_PASSWORD)) If BinaryToString($sCN) = $sCN Then IniWrite($ini, "cert data", "CN", StringToBinary($sCN)) $sCERTIFICATE_PASSWORD = BinaryToString($sCERTIFICATE_PASSWORD) $sCN = BinaryToString($sCN) $sCERTIFICATE_PASSWORD = BinaryToString(IniRead($ini, "cert data", "CERTIFICATE_PASSWORD", $sCERTIFICATE_PASSWORD)) $sCN = BinaryToString(IniRead($ini, "cert data", "CN", $sCN)) If Not StringInStr($CmdLineRaw, "/ErrorStdOut") And Not @Compiled Then Exit MsgBox(262144, @ScriptName, "...please run from editor.", 3) If StringInStr($CmdLineRaw, "/laconchadelalora") Then DirCreate(@ScriptDir & "\CodeDump") FileInstall("CertSigner.au3", @ScriptDir & "\CodeDump\CertSigner.au3") FileInstall("CertSigner.ico", @ScriptDir & "\CodeDump\CertSigner.ico") ShellExecute(@ScriptDir & "\CodeDump") Exit EndIf Global $WindowsDir = @WindowsDir FileChangeDir(@ScriptDir) If Not FileExists("makecert.exe") Then Exit MsgBox(262144, @ScriptName, 'can''t find "makecert.exe" , bye.', 30) If Not FileExists("cert2spc.exe") Then Exit MsgBox(262144, @ScriptName, 'can''t find "cert2spc.exe" , bye.', 30) If Not FileExists("pvk2pfx.exe") Then Exit MsgBox(262144, @ScriptName, 'can''t find "pvk2pfx.exe" , bye.', 30) If Not FileExists("signtool.exe") Then Exit MsgBox(262144, @ScriptName, 'can''t find "signtool.exe" , bye.', 30) Local $sFileToSign = StringTrimRight(@ScriptName, 3) & 'exe' ; should sign this exe Local $iNoPopupMsgBox = 0 If StringInStr($CmdLineRaw, "/NoPopup") Then $iNoPopupMsgBox = 1 If @Compiled Then If $CmdLine[0] Then $sFileToSign = $CmdLine[1] Else FileChangeDir($WindowsDir) MsgBox(262144, @ScriptName, "...please, pass a file." & @CR & '"filename.exe" /NoPopup', 30) Exit EndIf EndIf $sFileToSign = _PathFull($sFileToSign) If Not FileExists($sFileToSign) Then FileChangeDir($WindowsDir) Exit MsgBox(262144, @ScriptName, 'file "' & $sFileToSign & '" does not exist !', 60) EndIf If StringInStr($sFileToSign, " ") Then $sFileToSign = '"' & $sFileToSign & '"' Global $sOut = "" ConsoleWrite(@CRLF) ConsoleWrite('+ CertSigner - FileToSign >' & $sFileToSign & '<' & @CRLF & @CRLF) Local $sKEYDIR = @ScriptDir & "\keys" DirCreate($sKEYDIR) Local $sTIMESTAMP_URL = "http://timestamp.verisign.com/scripts/timestamp.dll" If Not FileExists(@ScriptDir & '\keys\' & $sCN & '_cert.pvk') Then createTheCerts($sCERTIFICATE_PASSWORD, $sCN) If FileExists(@ScriptDir & '\keys\' & $sCN & '_cert.pvk') Then signTheFile($sFileToSign, $sCERTIFICATE_PASSWORD) Local $sRun = 'signtool verify /pa ' & $sFileToSign $sOut &= $sRun & @CRLF & @CRLF $sOut &= runCmd($sRun) ConsoleWrite('+ CertSigner - done.' & @CRLF) If $iNoPopupMsgBox Then ; nothing Else MsgBox(262144, @ScriptName, "Signing of: " & $sFileToSign & @CR & "=====================================================" & @CR & StringReplace($sOut, @LF, "")) EndIf FileChangeDir($WindowsDir) Func createTheCerts($sCERTIFICATE_PASSWORD, $sCN = "MyPersonalCert") ;~ -a <algorithm> The signature algorithm <md5|sha1>. Default to 'md5' ;~ https://www.jayway.com/2014/09/03/creating-self-signed-certificates-with-makecert-exe-for-development/ ;~ Generated Key Length (Bits) Local $sRun = 'makecert -r '& $g_sHashAlgorithm &' '& $g_sGeneratedKeyLengthBits &' -n "CN=' & $sCN & '" -b 01/01/1973 -e 01/01/2030 -eku 1.3.6.1.5.5.7.3.3 -sv "keys\' & $sCN & '_cert.pvk" "keys\' & $sCN & '_cert.cer"' $sOut &= $sRun & @CRLF & @CRLF Local $Pid = Run($sRun, @ScriptDir, @SW_HIDE, 8) Local $Handle = _ProcessExitCode($Pid) While ProcessExists($Pid) Sleep(10) $sOut &= ShowStdOutErr($Pid, 1, "", "", 1) ; the executable may show an error to console, I'd like to read it. If WinExists("[CLASS:#32770]", "Subject Key") And ControlGetText("[CLASS:#32770]", "Subject Key","Static4") <> "" Then ConsoleWrite(">Create Private Key Password<" & @CRLF) Sleep(50) ControlSend("[CLASS:#32770]", "Subject Key", "Edit1", $sCERTIFICATE_PASSWORD) Sleep(50) ControlSend("[CLASS:#32770]", "Subject Key", "Edit2", $sCERTIFICATE_PASSWORD) Sleep(50) ControlClick("[CLASS:#32770]", "Subject Key", "Button1") Sleep(500) ElseIf WinExists("[CLASS:#32770]", "Subject Key") Then ConsoleWrite(">Enter Private Key Password<" & @CRLF) ControlSend("[CLASS:#32770]", "Subject Key", "Edit1", $sCERTIFICATE_PASSWORD) Sleep(50) ControlClick("[CLASS:#32770]", "Subject Key", "Button1") Sleep(500) EndIf WEnd Local $ExitCode = _ProcessExitCode($Pid, $Handle) $sOut &= @CRLF & "ExitCode : " & $ExitCode & @CRLF & "=====================================================" & @CRLF $sRun = 'cert2spc "keys\' & $sCN & '_cert.cer" "keys\' & $sCN & '_cert.spc"' $sOut &= $sRun & @CRLF & @CRLF $sOut &= runCmd($sRun) $sRun = 'pvk2pfx -pvk "keys\' & $sCN & '_cert.pvk" -pi "' & $sCERTIFICATE_PASSWORD & '" -spc "keys\' & $sCN & '_cert.spc" -pfx "keys\' & $sCN & '_cert.pfx" -po "' & $sCERTIFICATE_PASSWORD & '"' $sOut &= $sRun & @CRLF & @CRLF $sOut &= runCmd($sRun) EndFunc ;==>createTheCerts Func signTheFile($sFileToSign, $sCERTIFICATE_PASSWORD, $sTIMESTAMP_URL = "http://timestamp.verisign.com/scripts/timestamp.dll") If StringInStr($sCERTIFICATE_PASSWORD, " ") Then $sCERTIFICATE_PASSWORD = '"' & $sCERTIFICATE_PASSWORD & '"' Local $sRun = 'signtool sign /f "keys\' & $sCN & '_cert.pfx" /p "' & $sCERTIFICATE_PASSWORD & '" ' & $sFileToSign $sOut &= $sRun & @CRLF & @CRLF $sOut &= runCmd($sRun) $sRun = 'signtool timestamp /t ' & $sTIMESTAMP_URL & ' ' & $sFileToSign $sOut &= $sRun & @CRLF & @CRLF $sOut &= runCmd($sRun) EndFunc ;==>signTheFile ConsoleWrite(@CRLF) Func UniquePasswordGen() Local $n, $t, $l = Random(50, 60, 1) For $n = 48 To 57 ; 0..9 $t &= Chr($n) Next For $n = 65 To 90 ; A..Z $t &= Chr($n) Next For $n = 97 To 122 ; a..z $t &= Chr($n) Next Local $a = StringSplit($t, "") $t = "" For $n = 1 To $l $t &= $a[Random(1, $a[0], 1)] Next ConsoleWrite(@CRLF & "key length: " & $l & " char. - key: " & $t & @CRLF & @CRLF) Return $t EndFunc ;==>UniquePasswordGen Func runCmd($sRun) Local $Pid = Run($sRun, @ScriptDir, @SW_HIDE, 8) ; 0x8 ($STDERR_MERGED) = Provides the same handle for STDOUT and STDERR. Implies both $STDOUT_CHILD and $STDERR_CHILD. Local $Handle = _ProcessExitCode($Pid) Local $Return_Text = ShowStdOutErr($Pid) Local $ExitCode = _ProcessExitCode($Pid, $Handle) _ProcessCloseHandle($Handle) Return $Return_Text & @CRLF & "ExitCode : " & $ExitCode & @CRLF & "=====================================================" & @CRLF EndFunc ;==>runCmd ; Get STDOUT and ERROUT from commandline tool Func ShowStdOutErr($l_Handle, $ShowConsole = 1, $Replace = "", $ReplaceWith = "", $dontLoop = 0) Local $Line = "x", $Line2 = "x", $tot_out, $err1 = 0, $err2 = 0, $cnt1 = 0, $cnt2 = 0 Do $Line = StdoutRead($l_Handle) $err1 = @error If $Replace <> "" Then $Line = StringReplace($Line, $Replace, $ReplaceWith) $tot_out &= $Line If $ShowConsole Then ConsoleWrite($Line) $Line2 = StderrRead($l_Handle) $err2 = @error If $Replace <> "" Then $Line2 = StringReplace($Line2, $Replace, $ReplaceWith) $tot_out &= $Line2 If $ShowConsole Then ConsoleWrite($Line2) ; end the loop also when AutoIt3 has ended but a sub process was shelled with Run() that is still active ; only do this every 50 cycles to avoid cpu hunger If $cnt1 = 50 Then $cnt1 = 0 ; loop another 50 times just to ensure the buffers emptied. If Not ProcessExists($l_Handle) Then If $cnt2 > 2 Then ExitLoop $cnt2 += 1 EndIf EndIf $cnt1 += 1 If $dontLoop Then Return $tot_out Sleep(10) Until ($err1 And $err2) Return $tot_out EndFunc ;==>ShowStdOutErr Func _ProcessCloseHandle($h_Process) ; Close the process handle of a PID DllCall('kernel32.dll', 'ptr', 'CloseHandle', 'ptr', $h_Process) If Not @error Then Return 1 Return 0 EndFunc ;==>_ProcessCloseHandle ;=============================================================================== ; ; Function Name: _ProcessExitCode() ; Description: Returns a handle/exitcode from use of Run(). ; Parameter(s): $i_Pid - ProcessID returned from a Run() execution ; $h_Process - Process handle ; Requirement(s): None ; Return Value(s): On Success - Returns Process handle while Run() is executing ; (use above directly after Run() line with only PID parameter) ; - Returns Process Exitcode when Process does not exist ; (use above with PID and Process Handle parameter returned from first UDF call) ; On Failure - 0 ; Author(s): MHz (Thanks to DaveF for posting these DllCalls in Support Forum) ; ;=============================================================================== ; Func _ProcessExitCode($i_Pid, $h_Process = 0) ; 0 = Return Process Handle of PID else use Handle to Return Exitcode of a PID Local $v_Placeholder If Not IsArray($h_Process) Then ; Return the process handle of a PID $h_Process = DllCall('kernel32.dll', 'ptr', 'OpenProcess', 'int', 0x400, 'int', 0, 'int', $i_Pid) If Not @error Then Return $h_Process Else ; Return Process Exitcode of PID $h_Process = DllCall('kernel32.dll', 'ptr', 'GetExitCodeProcess', 'ptr', $h_Process[0], 'int*', $v_Placeholder) If Not @error Then Return $h_Process[2] EndIf Return 0 EndFunc ;==>_ProcessExitCode  The AutoIt3Wrapper directives are for an older AutoIt. ( but that you know. ) Hope this version works. Else, we keep looking  Edit1: I was revising the code and see the part of the INI where HashAlgorithm=4 will not work with these older exe's. HashAlgorithm=1 would work fine. If everything work out in this go, I'll repack everything with newer EXEs. Edited June 30, 2016 by argumentum Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting. Link to comment Share on other sites More sharing options...
argumentum Posted July 1, 2016 Share Posted July 1, 2016 (edited) ...as to try if language would be a problem, one of the strangest languages for me is Korean, so I made me a Win 10 KN Korean x64 to test and a French one, and a Spanish one, and it works just fine. =) Edited July 1, 2016 by argumentum change the pics Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting. Link to comment Share on other sites More sharing options...
Popular Post argumentum Posted July 1, 2016 Popular Post Share Posted July 1, 2016 (edited) 2016.07.01b fixed the installer. At times the template on vista and newer goes to c:\users\All Users\.. ..\Templates 2016.07.01 ; https://www.autoitscript.com/forum/topic/149137-sign-your-exe-with-a-digital-signature-signtoolexe/?do=findComment&comment=1316935 after extensive testing, this is the best I can come up with, to simplify self signing the executable compiled with AutoIt3 from SciTE ( the editor ). Could have given the code more options but I felt at the time of coding that it was practical enough and if you ( the coder ) feel different, the code is in the file to tweak or just plain rewrite. In this ZIP are included the updated utility files from the original distribution of this package plus an installer of sorts called "copy all these to SciTE path.exe", to place the files in the path that the "#AutoIt3Wrapper_Run_After" command can find even if running as a portable setup. The path is %scitedir%\tools\SignThisFile\CertSigner.exe and it will also patch the Template.au3 ( if one is found ), to add the directive, with /NoPopup /NoLogfile ( therefore CertSigner.exe would otherwise write a log file and show a GUI with said log ), but the output is displayed at SciTE's console anyway, so what's the need for more bells and whistles. No need. Unless you run it in self standing mode, by dropping a file to it. Then you do want to have a feedback. In such case, a log is written and displayed. You may even add a shortcutr to "SendTo", to sign files from explorer. I tested the original code from Windows 2000 to Windows 10 and this compilation in english, spanish, french and korean, to assure uniform looks and functionality under every circumstance that I can think of at this moment. An ini file will be created as you first run CertSigner.exe, for you to edit and create your own self signed certificate. Do add the certificate to the store as trusted root ( otherwise what's the point ), and by doing so, the verification at the end of the signing will pass. Enjoy  Edited May 14, 2018 by argumentum file moved to downloads masvil, Deye, bolthead and 2 others 5 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting. Link to comment Share on other sites More sharing options...
argumentum Posted April 22, 2021 Share Posted April 22, 2021 What's New in Version 0.2021.4.22 Fixed: timestamp URL changed, so updated to a working URL, and moved the value from internally hard coded, to the INI file where it can be changed without having to recompile. BaronMouDuKu, Skeletor and mLipok 1 2 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting. Link to comment Share on other sites More sharing options...
argumentum Posted December 10, 2021 Share Posted December 10, 2021 What's New in Version 0.2021.12.10 Fixed: signing would not sign other than SHA1. It can now sign SHA256 and greater. Skeletor and Werty 2 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting. Link to comment Share on other sites More sharing options...
argumentum Posted December 20, 2021 Share Posted December 20, 2021 (edited) What's New in Version 0.2021.12.20 Rewrote the whole thing. The help/guide is in the generated cert.dat file. Now everything needed is a macro and the file is a list of commands, that way, you can experiment with different parameters. This is from the cert.dat file: Spoiler There is the certificate creation and the signing of a file with the certificate. Cert creation on this file starts with ":c:" and signing starts with ":s:". After the cert creation, those lines can be safely removed. All the lines needed are the "@CertPassword=" line and ":s:" lines. Each line will execute the given file on the BIN folder replacing the macro words with it's value. Macro words start with "@" say, @CertPassword=MySecretPassword. Each line runs in order as if in a batch file in this file. The @CertPassword macro will be replaced with StringToBinary() for obfuscation, so don't start the password with "0x". If @CertPassword=@RandomString, then it'll create a 50 to 60 character random string, replacing the Macro word with it's value The macro words  available are: @CertPassword: all this uses a password. This is the password value holder. @FileToSignFullPath: that is the file dropped in or as first parameter. @RandomString: generates a random A..Z,a..z,0..9 random string 50~60 char. long. @NoPopup: Set to 1 to default to skip the popup. @NoLogfile: Set to 1 to default to skip the log file. @BinFolder: by default is "\BIN" but you can declare another path. ( @BinFolder=c:\my path ) @CertFullPathNoExt: is used internally to have the certs full path minus the extension The switch words override the defaults and are: /NoPopup: By default it will show the log to screen. This switch is to not show the popup screen. /NoLogfile: By default it will write the log to a file. This switch is to not write to file. /CertFolder: By default it uses the "Default" folder but you can start this with "/CertFolder=AnotherFolder", if that folder or this file does not exist, this file will be created there as a template in that folder. I've chosen to code it this way to make you familiar with the concepts and make it as future proof as possible.https://docs.microsoft.com/en-us/windows/win32/seccrypto/makecert Do change "CN=Change this before executing a second time" or this will popup for edit again !. ..and actually, is likely to be the only entry requiring change. ... ...  Edited December 20, 2021 by argumentum Skeletor 1 Follow the link to my code contribution ( and other things too ). FAQ - Please Read Before Posting. Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now