Add Instrumentation to AmsiUtil and make the init variable readonly (#18727)

* Add Insturmentation to AmsiUtil and make the init variable readonly

* remove unwanted file

* Fix task to hex

* ingnore AsmiInit when not windows

* rename event name

* CR feedback

* the missing dot in the argument documentation because that is very very important.

* CR feedback

Co-authored-by: Jose Sua <josesua@ntdev.microsoft.com>
This commit is contained in:
Jose Sua
2023-04-07 11:54:47 -07:00
committed by Dongbo Wang
co-authored by Jose Sua
parent 699d2e8175
commit f9dd349d72
7 changed files with 123 additions and 14 deletions
@@ -2208,6 +2208,18 @@
value="0x6017"
version="1"
/>
<event
channel="C_ANALYTIC"
keywords="AmsiState"
level="win:Verbose"
message="$(string.PS_PROVIDER.event.E_A_AmsiState.message)"
opcode="Method"
symbol="AmsiState"
task="Amsi"
template="T_AmsiState"
value="0x4001"
version="1"
/>
</events>
<channels>
<!--There are three channels defined for PowerShell instrumentation
@@ -2415,6 +2427,12 @@
symbol="T_ISEOperation"
value="120"
/>
<task
message="$(string.PS_PROVIDER.task.T_AmsiState.message)"
name="Amsi"
symbol="T_Amsi"
value="130"
/>
</tasks>
<opcodes>
<opcode
@@ -2575,6 +2593,12 @@
name="PSWorkflow"
symbol="K_PSWORKFLOW"
/>
<keyword
mask="0x400"
message="$(string.PS_PROVIDER.keyword.K_AmsiState.message)"
name="AmsiState"
symbol="K_AmsiState"
/>
</keywords>
<maps>
<!-- please keep in sync with SerializationMethod from
@@ -4056,6 +4080,16 @@
name="FileName"
/>
</template>
<template tid="T_AmsiState">
<data
inType="win:UnicodeString"
name="Action"
/>
<data
inType="win:UnicodeString"
name="AmsiContext"
/>
</template>
</templates>
</provider>
</events>
@@ -4949,7 +4983,11 @@
id="PS_PROVIDER.event.E_O_M3PWorkflowExecutionStarted.message"
value="Workflow execution started. %n %t WorkflowId: %1 %n %t ManagedNodes: %2"
/>
<string
<string
id="PS_PROVIDER.event.E_A_AmsiState.message"
value="AmsiUtil state. %n %t state: %1 %n %t Context: %2"
/>
<string
id="PS_PROVIDER.event.E_O_M3PEndpointRegistered.message"
value="A new PowerShell endpoint was registered. %n %t EndpointName: %1 %n %t EndpointType: %2 %n %t RegisteredBy: %3"
/>
@@ -5417,7 +5455,11 @@
id="PS_PROVIDER.keyword.K_PSWORKFLOW.message"
value="PSWorkflow Hosting And Execution Layer"
/>
<string
<string
id="PS_PROVIDER.keyword.K_AmsiState.message"
value="Amsi state"
/>
<string
id="PS_PROVIDER.keyword.K_SESSION.message"
value="All session layer"
/>
@@ -5589,7 +5631,11 @@
id="PS_PROVIDER.task.T_ISEOperation.message"
value="PowerShell ISE Operation"
/>
<string
<string
id="PS_PROVIDER.task.T_AmsiState.message"
value="Amsi State"
/>
<string
id="PS_PROVIDER.event.E_O_ISEExecuteScript.message"
value="Windows PowerShell ISE has started to run script file %1."
/>
@@ -158,6 +158,7 @@ namespace System.Management.Automation.Internal
Provider_Lifecycle = 0x1F03,
Settings = 0x1F04,
Engine_Trace = 0x1F06,
Amsi_Init = 0x4001,
// Experimental Features
ExperimentalFeature_InvalidName = 0x3001,
@@ -239,7 +240,8 @@ namespace System.Management.Automation.Internal
ExperimentalFeature = 0x6B,
ScheduledJob = 0x6E,
NamedPipe = 0x6F,
ISEOperation = 0x78
ISEOperation = 0x78,
Amsi = 0X82
}
/// <summary>
@@ -102,6 +102,13 @@ namespace System.Management.Automation
/// <param name="previousValue"></param>
internal abstract void LogSettingsEvent(LogContext logContext, string variableName, string value, string previousValue);
/// <summary>
/// Provider interface function for logging AmsiUtil State event.
/// </summary>
/// <param name="state">This the action performed in AmsiUtil class, like init, scan, etc.</param>
/// <param name="context">The amsiContext handled - Session pair.</param>
internal abstract void LogAmsiUtilStateEvent(string state, string context);
/// <summary>
/// True if the log provider needs to use logging variables.
/// </summary>
@@ -370,6 +377,15 @@ namespace System.Management.Automation
{
}
/// <summary>
/// Provider interface function for logging provider health event.
/// </summary>
/// <param name="state">This the action performed in AmsiUtil class, like init, scan, etc.</param>
/// <param name="context">The amsiContext handled - Session pair.</param>
internal override void LogAmsiUtilStateEvent(string state, string context)
{
}
#endregion
}
}
@@ -856,6 +856,7 @@ namespace Microsoft.PowerShell.Commands
namespace System.Management.Automation
{
using System.Management.Automation.Tracing;
using System.Security.Cryptography.Pkcs;
/// <summary>
@@ -1336,6 +1337,14 @@ namespace System.Management.Automation
internal static class AmsiUtils
{
static AmsiUtils()
{
#if !UNIX
s_amsiInitFailed = !CheckAmsiInit();
PSEtwLog.LogAmsiUtilStateEvent($"init-{s_amsiInitFailed}", $"{s_amsiContext}-{s_amsiSession}");
#endif
}
internal static int Init()
{
Diagnostics.Assert(s_amsiContext == IntPtr.Zero, "Init should be called just once");
@@ -1357,11 +1366,6 @@ namespace System.Management.Automation
AppDomain.CurrentDomain.ProcessExit += CurrentDomain_ProcessExit;
var hr = AmsiNativeMethods.AmsiInitialize(appName, ref s_amsiContext);
if (!Utils.Succeeded(hr))
{
s_amsiInitFailed = true;
}
return hr;
}
}
@@ -1405,6 +1409,7 @@ namespace System.Management.Automation
// If we had a previous initialization failure, just return the neutral result.
if (s_amsiInitFailed)
{
PSEtwLog.LogAmsiUtilStateEvent("ScanContent-InitFail", $"{s_amsiContext}-{s_amsiSession}");
return AmsiNativeMethods.AMSI_RESULT.AMSI_RESULT_NOT_DETECTED;
}
@@ -1412,6 +1417,7 @@ namespace System.Management.Automation
{
if (s_amsiInitFailed)
{
PSEtwLog.LogAmsiUtilStateEvent("ScanContent-InitFail", $"{s_amsiContext}-{s_amsiSession}");
return AmsiNativeMethods.AMSI_RESULT.AMSI_RESULT_NOT_DETECTED;
}
@@ -1451,6 +1457,7 @@ namespace System.Management.Automation
if (!Utils.Succeeded(hr))
{
// If we got a failure, just return the neutral result ("AMSI_RESULT_NOT_DETECTED")
PSEtwLog.LogAmsiUtilStateEvent($"AmsiScanBuffer-{hr}", $"{s_amsiContext}-{s_amsiSession}");
return AmsiNativeMethods.AMSI_RESULT.AMSI_RESULT_NOT_DETECTED;
}
@@ -1458,7 +1465,7 @@ namespace System.Management.Automation
}
catch (DllNotFoundException)
{
s_amsiInitFailed = true;
PSEtwLog.LogAmsiUtilStateEvent("DllNotFoundException", $"{s_amsiContext}-{s_amsiSession}");
return AmsiNativeMethods.AMSI_RESULT.AMSI_RESULT_NOT_DETECTED;
}
}
@@ -1559,7 +1566,6 @@ namespace System.Management.Automation
if (!Utils.Succeeded(hr))
{
s_amsiInitFailed = true;
return false;
}
}
@@ -1573,7 +1579,6 @@ namespace System.Management.Automation
if (!Utils.Succeeded(hr))
{
s_amsiInitFailed = true;
return false;
}
}
@@ -1595,7 +1600,7 @@ namespace System.Management.Automation
[SuppressMessage("Microsoft.Reliability", "CA2006:UseSafeHandleToEncapsulateNativeResources")]
private static IntPtr s_amsiSession = IntPtr.Zero;
private static bool s_amsiInitFailed = false;
private static readonly bool s_amsiInitFailed = false;
private static bool s_amsiNotifyFailed = false;
private static readonly object s_amsiLockObject = new object();
@@ -118,6 +118,16 @@ namespace System.Management.Automation.Tracing
provider.LogProviderLifecycleEvent(logContext, providerName, newState);
}
/// <summary>
/// Provider interface function for logging AmsiUtil State event.
/// </summary>
/// <param name="state">This the action performed in AmsiUtil class, like init, scan, etc.</param>
/// <param name="context">The amsiContext handled - Session pair.</param>
internal static void LogAmsiUtilStateEvent(string state, string context)
{
provider.LogAmsiUtilStateEvent(state, context);
}
/// <summary>
/// Provider interface function for logging settings event.
/// </summary>
@@ -124,7 +124,17 @@ namespace System.Management.Automation.Tracing
}
else
{
payload.AppendLine(StringUtil.Format(EtwLoggingStrings.CommandStateChange, logContext.CommandName, newState.ToString()));
if (newState == CommandState.Stopped ||
newState == CommandState.Terminated)
{
// When state is stopped or termianted only log the CommandName
payload.AppendLine(StringUtil.Format(EtwLoggingStrings.CommandStateChange, logContext, newState.ToString()));
}
else
{
// When state is Start log the CommandLine which has arguments for completeness.
payload.AppendLine(StringUtil.Format(EtwLoggingStrings.CommandStateChange, logContext.CommandLine, newState.ToString()));
}
}
}
@@ -182,6 +192,16 @@ namespace System.Management.Automation.Tracing
WriteEvent(PSEventId.Provider_Health, PSChannel.Operational, PSOpcode.Exception, PSTask.ExecutePipeline, logContext, payload.ToString());
}
/// <summary>
/// Provider interface function for logging provider health event.
/// </summary>
/// <param name="state">This the action performed in AmsiUtil class, like init, scan, etc.</param>
/// <param name="context">The amsiContext handled - Session pair.</param>
internal override void LogAmsiUtilStateEvent(string state, string context)
{
WriteEvent(PSEventId.Amsi_Init, PSChannel.Analytic, PSOpcode.Method, PSLevel.Informational, PSTask.Amsi, (PSKeyword)0x0, state, context);
}
/// <summary>
/// Provider interface function for logging provider lifecycle event.
/// </summary>
@@ -92,6 +92,16 @@ namespace System.Management.Automation.Tracing
WriteEvent(PSEventId.Engine_Health, PSChannel.Operational, PSOpcode.Exception, PSTask.ExecutePipeline, logContext, payload.ToString());
}
/// <summary>
/// Provider interface function for logging provider health event.
/// </summary>
/// <param name="state">This the action performed in AmsiUtil class, like init, scan, etc</param>
/// <param name="context">The amsiContext handled - Session pair</param>
internal override void LogAmsiUtilStateEvent(string state, string context)
{
WriteEvent(PSEventId.Amsi_Init, PSChannel.Analytic, PSOpcode.Method, PSLevel.Informational, PSTask.Amsi, (PSKeyword)0x0, state, context);
}
/// <summary>
/// Provider interface function for logging engine lifecycle event.
/// </summary>