[Tizen] Unify dnetmemoryenumlib terms to match the codebase (#291)
[platform/upstream/coreclr.git] / src / vm / amsi.cpp
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 //
5 // File: amsi.cpp
6 //
7
8 #include "common.h"
9 #include "amsi.h"
10
11 namespace
12 {
13     // https://docs.microsoft.com/en-us/windows/desktop/api/amsi/
14     DECLARE_HANDLE(HAMSICONTEXT);
15     DECLARE_HANDLE(HAMSISESSION);
16
17     enum AMSI_RESULT
18     {
19         AMSI_RESULT_CLEAN                   = 0,
20         AMSI_RESULT_NOT_DETECTED            = 1,
21         AMSI_RESULT_BLOCKED_BY_ADMIN_START  = 0x4000,
22         AMSI_RESULT_BLOCKED_BY_ADMIN_END    = 0x4fff,
23         AMSI_RESULT_DETECTED                = 0x8000
24     }   AMSI_RESULT;
25
26     bool AmsiResultIsMalware(DWORD result)
27     {
28         return result >= AMSI_RESULT_DETECTED;
29     }
30
31     bool AmsiResultIsBlockedByAdmin(DWORD result)
32     {
33         return result >= AMSI_RESULT_BLOCKED_BY_ADMIN_START
34             && result <= AMSI_RESULT_BLOCKED_BY_ADMIN_END;
35     }
36
37     using PAMSI_AMSISCANBUFFER_API = HRESULT(WINAPI *)(
38         _In_ HAMSICONTEXT amsiContext,
39         _In_ PVOID buffer,
40         _In_ ULONG length,
41         _In_ LPCWSTR contentName,
42         _In_opt_ HAMSISESSION session,
43         _Out_ DWORD *result);
44
45     using PAMSI_AMSIINITIALIZE_API = HRESULT(WINAPI *)(
46         _In_ LPCWSTR appName,
47         _Out_ HAMSICONTEXT *amsiContext);
48
49     PAMSI_AMSISCANBUFFER_API AmsiScanBuffer;
50     HAMSICONTEXT s_amsiContext;
51     CRITSEC_COOKIE s_csAmsi;
52
53     bool InitializeLock()
54     {
55         if (s_csAmsi != nullptr)
56             return true;
57
58         CRITSEC_COOKIE lock = ClrCreateCriticalSection(CrstLeafLock, CRST_REENTRANCY);
59         if (lock == nullptr)
60             return false;
61
62         if (InterlockedCompareExchangeT<CRITSEC_COOKIE>(&s_csAmsi, lock, nullptr) != nullptr)
63             ClrDeleteCriticalSection(lock);
64
65         return true;
66     }
67 }
68
69 // Here we will invoke into AmsiScanBuffer, a centralized area for non-OS
70 // programs to report into Defender (and potentially other anti-malware tools).
71 // This should only run on in memory loads, Assembly.Load(byte[]) for example.
72 // Loads from disk are already instrumented by Defender, so calling AmsiScanBuffer
73 // wouldn't do anything.
74 bool Amsi::IsBlockedByAmsiScan(PVOID flatImageBytes, COUNT_T size)
75 {
76     STANDARD_VM_CONTRACT;
77
78     if (!InitializeLock())
79         return false;
80
81     // Lazily initialize AMSI because it is very expensive
82     {
83         CRITSEC_Holder csh(s_csAmsi);
84
85         // Cache that we failed if this didn't work so we don't keep trying to reinitialize
86         static bool amsiInitializationAttempted = false;
87         if (s_amsiContext == nullptr && !amsiInitializationAttempted)
88         {
89             HMODULE amsi = CLRLoadLibraryEx(W("amsi.dll"), nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
90             if (amsi != nullptr)
91             {
92                 PAMSI_AMSIINITIALIZE_API AmsiInitialize = (PAMSI_AMSIINITIALIZE_API)GetProcAddress(amsi, "AmsiInitialize");
93                 if (AmsiInitialize != nullptr)
94                 {
95                     HAMSICONTEXT amsiContext = nullptr;
96                     if (AmsiInitialize(W("coreclr"), &amsiContext) == S_OK)
97                     {
98                         AmsiScanBuffer = (PAMSI_AMSISCANBUFFER_API)GetProcAddress(amsi, "AmsiScanBuffer");
99                         if (AmsiScanBuffer != nullptr)
100                         {
101                             s_amsiContext = amsiContext;
102                         }
103                     }
104                 }
105             }
106
107             amsiInitializationAttempted = true;
108         }
109     }
110
111     if (s_amsiContext == nullptr || AmsiScanBuffer == nullptr)
112         return false;
113
114     DWORD result;
115     HRESULT hr = AmsiScanBuffer(s_amsiContext, flatImageBytes, size, nullptr, nullptr, &result);
116     if (hr == S_OK && (AmsiResultIsMalware(result) || AmsiResultIsBlockedByAdmin(result)))
117         return true;
118
119     return false;
120 }