Skip to content

Commit de4809c

Browse files
committed
Utility to timestamp Authenticode signatures of PowerShell or VBScript files
1 parent aa02b57 commit de4809c

13 files changed

+817
-0
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
bin/
2+
obj/
3+
.vs/

App.config

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<configuration>
3+
<startup>
4+
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7.2" />
5+
</startup>
6+
</configuration>

IAuthenticodeSignatureTraits.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
namespace PowershellScriptTimestamp
2+
{
3+
internal interface IAuthenticodeSignatureTraits
4+
{
5+
/// <summary>
6+
/// Code point sequence that is found before every signature
7+
/// </summary>
8+
string SignatureBeginSequence { get; }
9+
10+
/// <summary>
11+
/// Code point sequence that is found after every signature
12+
/// </summary>
13+
string SignatureEndSequence { get; }
14+
15+
/// <summary>
16+
/// Code point sequence that is found at the beginning of each signature chunk
17+
/// </summary>
18+
string SignatureLineBeginning { get; }
19+
20+
/// <summary>
21+
/// Code point sequence that is found at the end of each signature chunk, including the line terminator
22+
/// </summary>
23+
string SignatureLineEnding { get; }
24+
25+
/// <summary>
26+
/// Number of base64 characters found on each signature chunk.
27+
/// </summary>
28+
int SignatureCharsPerLine { get; }
29+
}
30+
}
File renamed without changes.

PowershellScriptTimestamp.csproj

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
4+
<PropertyGroup>
5+
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
6+
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
7+
<ProjectGuid>{DA9D348A-026B-4217-B507-8D6A11B73979}</ProjectGuid>
8+
<OutputType>Exe</OutputType>
9+
<RootNamespace>PowershellScriptTimestamp</RootNamespace>
10+
<AssemblyName>PowershellScriptTimestamp</AssemblyName>
11+
<TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion>
12+
<FileAlignment>512</FileAlignment>
13+
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
14+
<Deterministic>true</Deterministic>
15+
</PropertyGroup>
16+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
17+
<PlatformTarget>AnyCPU</PlatformTarget>
18+
<DebugSymbols>true</DebugSymbols>
19+
<DebugType>full</DebugType>
20+
<Optimize>false</Optimize>
21+
<OutputPath>bin\Debug\</OutputPath>
22+
<DefineConstants>DEBUG;TRACE</DefineConstants>
23+
<ErrorReport>prompt</ErrorReport>
24+
<WarningLevel>4</WarningLevel>
25+
</PropertyGroup>
26+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
27+
<PlatformTarget>AnyCPU</PlatformTarget>
28+
<DebugType>pdbonly</DebugType>
29+
<Optimize>true</Optimize>
30+
<OutputPath>bin\Release\</OutputPath>
31+
<DefineConstants>TRACE</DefineConstants>
32+
<ErrorReport>prompt</ErrorReport>
33+
<WarningLevel>4</WarningLevel>
34+
</PropertyGroup>
35+
<ItemGroup>
36+
<Reference Include="System" />
37+
<Reference Include="System.Core" />
38+
<Reference Include="System.Xml.Linq" />
39+
<Reference Include="System.Data.DataSetExtensions" />
40+
<Reference Include="Microsoft.CSharp" />
41+
<Reference Include="System.Data" />
42+
<Reference Include="System.Net.Http" />
43+
<Reference Include="System.Xml" />
44+
</ItemGroup>
45+
<ItemGroup>
46+
<Compile Include="IAuthenticodeSignatureTraits.cs" />
47+
<Compile Include="PowershellSignatureTraits.cs" />
48+
<Compile Include="ProcessExecutionResult.cs" />
49+
<Compile Include="Program.cs" />
50+
<Compile Include="Properties\AssemblyInfo.cs" />
51+
<Compile Include="TextFileTimestamp.cs" />
52+
<Compile Include="VbscriptSignatureTraits.cs" />
53+
</ItemGroup>
54+
<ItemGroup>
55+
<None Include="App.config" />
56+
</ItemGroup>
57+
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
58+
</Project>

PowershellScriptTimestamp.sln

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.6.33829.357
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PowershellScriptTimestamp", "PowershellScriptTimestamp.csproj", "{DA9D348A-026B-4217-B507-8D6A11B73979}"
7+
EndProject
8+
Global
9+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
10+
Debug|Any CPU = Debug|Any CPU
11+
Release|Any CPU = Release|Any CPU
12+
EndGlobalSection
13+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
14+
{DA9D348A-026B-4217-B507-8D6A11B73979}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15+
{DA9D348A-026B-4217-B507-8D6A11B73979}.Debug|Any CPU.Build.0 = Debug|Any CPU
16+
{DA9D348A-026B-4217-B507-8D6A11B73979}.Release|Any CPU.ActiveCfg = Release|Any CPU
17+
{DA9D348A-026B-4217-B507-8D6A11B73979}.Release|Any CPU.Build.0 = Release|Any CPU
18+
EndGlobalSection
19+
GlobalSection(SolutionProperties) = preSolution
20+
HideSolutionNode = FALSE
21+
EndGlobalSection
22+
GlobalSection(ExtensibilityGlobals) = postSolution
23+
SolutionGuid = {CA8E06A2-FA4E-4CAC-9DC2-79FCE76F2931}
24+
EndGlobalSection
25+
EndGlobal

PowershellSignatureTraits.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
namespace PowershellScriptTimestamp
2+
{
3+
internal class PowershellSignatureTraits : IAuthenticodeSignatureTraits
4+
{
5+
/// <summary>
6+
/// Code point sequence that is found before every signature
7+
/// </summary>
8+
string IAuthenticodeSignatureTraits.SignatureBeginSequence => "\r\n# SIG # Begin signature block\r\n";
9+
10+
/// <summary>
11+
/// Code point sequence that is found after every signature
12+
/// </summary>
13+
string IAuthenticodeSignatureTraits.SignatureEndSequence => "\r\n# SIG # End signature block\r\n";
14+
15+
/// <summary>
16+
/// Code point sequence that is found at the beginning of each signature chunk
17+
/// </summary>
18+
string IAuthenticodeSignatureTraits.SignatureLineBeginning => "# ";
19+
20+
/// <summary>
21+
/// Code point sequence that is found at the end of each signature chunk, including the line terminator
22+
/// </summary>
23+
string IAuthenticodeSignatureTraits.SignatureLineEnding => "\r\n";
24+
25+
/// <summary>
26+
/// Number of base64 characters found on each signature chunk.
27+
/// </summary>
28+
int IAuthenticodeSignatureTraits.SignatureCharsPerLine => 64;
29+
}
30+
}

ProcessExecutionResult.cs

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
using System;
2+
using System.Diagnostics;
3+
using System.Text;
4+
using System.Threading;
5+
6+
namespace PowershellScriptTimestamp
7+
{
8+
internal class ProcessExecutionResult
9+
{
10+
public string ExecutablePath { get; }
11+
public string CommandLineArguments { get; }
12+
13+
public bool Successful { get; }
14+
public int ExitCode { get; }
15+
16+
public string Stdout { get; }
17+
public string Stderr { get; }
18+
19+
20+
public ProcessExecutionResult(string path, string arguments)
21+
{
22+
23+
ExecutablePath = path;
24+
CommandLineArguments = arguments;
25+
26+
var outStringBuilder = new StringBuilder();
27+
var errStringBuilder = new StringBuilder();
28+
using (var process = new Process())
29+
try
30+
{
31+
32+
process.StartInfo.CreateNoWindow = true;
33+
process.StartInfo.Arguments = arguments;
34+
process.StartInfo.FileName = path;
35+
process.StartInfo.RedirectStandardError = true;
36+
process.StartInfo.RedirectStandardOutput = true;
37+
process.StartInfo.UseShellExecute = false;
38+
39+
using (AutoResetEvent stdoutConsumed = new AutoResetEvent(false))
40+
using (AutoResetEvent stderrConsumed = new AutoResetEvent(false))
41+
{
42+
process.OutputDataReceived += (sender, evtArgs) =>
43+
{
44+
if (evtArgs.Data == null)
45+
{
46+
stdoutConsumed.Set();
47+
}
48+
else
49+
{
50+
outStringBuilder.AppendLine(evtArgs.Data);
51+
}
52+
};
53+
process.ErrorDataReceived += (sender, evtArgs) =>
54+
{
55+
if (evtArgs.Data == null)
56+
{
57+
stderrConsumed.Set();
58+
}
59+
else
60+
{
61+
errStringBuilder.AppendLine(evtArgs.Data);
62+
}
63+
};
64+
65+
Console.WriteLine($"[INFO] About to run process {path} with arguments {arguments}.");
66+
67+
if (!process.Start())
68+
{
69+
Console.WriteLine($"[ERROR] Could not start process.");
70+
return;
71+
}
72+
73+
try
74+
{
75+
process.BeginOutputReadLine();
76+
process.BeginErrorReadLine();
77+
process.WaitForExit();
78+
stdoutConsumed.WaitOne();
79+
stderrConsumed.WaitOne();
80+
}
81+
catch (Exception ex)
82+
{
83+
Console.WriteLine($"[ERROR] Could not wait for end of process. Dumping exception.");
84+
Console.WriteLine(ex);
85+
return;
86+
}
87+
}
88+
89+
ExitCode = process.ExitCode;
90+
Successful = true;
91+
92+
return;
93+
}
94+
catch (Exception ex)
95+
{
96+
Console.WriteLine($"[ERROR] Could not run process. Dumping exception.");
97+
Console.WriteLine(ex);
98+
}
99+
finally
100+
{
101+
Stdout = outStringBuilder.ToString();
102+
Stderr = errStringBuilder.ToString();
103+
}
104+
}
105+
106+
}
107+
}

0 commit comments

Comments
 (0)